File download via ajax+spring-web - java

I have some xml files stored as strings in my database and scala+spring based backend with this controller:
#RequestMapping(value = Array("/download"), method = Array(RequestMethod.GET))
def downloadFile(#RequestParam filename: String, //some more params
response: HttpServletResponse) = {
val fileContent = // some logic here, returns file content as String
response.setContentType("application/xml")
response.setHeader("Content-Disposition", s"attachment;filename=$filename")
response.setStatus(HttpServletResponse.SC_OK)
response.getOutputStream.write(fileContent.getBytes)
response.flushBuffer()
}
Also i have this script:
$.ajax({
type: "GET",
url: url,
data: {
filename: filename //and some more params
}
})
Then i send HTTP request to server, get right HTTP response and then nothing happens. All info i have from browser logs is that response has file content in body and headers, but download never starts.
What am i doing wrong?
I saw these SO Q&A but they didnt help me at all:
download file using an ajax request
Downloading a file from spring controllers
UPD1:
Also tried this one, with no result.

This is how I made a file to download from a server.
output = (byte[]) processedDocumentObject;
HttpHeaders responseHeaders = new HttpHeaders();
responseHeaders.setContentType(MediaType.APPLICATION_OCTET_STREAM);
responseHeaders.setContentDispositionFormData("attachment", "file.xml");
HttpEntity<byte[]> fileEntity = new HttpEntity<byte[]>(output,responseHeaders);
return fileEntity;
However this is in java and HttpHeaders is org.springframework.http.HttpHeaders and HttpEntity is org.springframework.http.HttpEntity<byte[]>
Also, you need to convert your string into byte array initially.

Related

Spring RestTemplate upload binary file

Image
I want to write a client code to consume an API. The API is expecting a text file. When I select the binary file option in the postman tool and select any text file from my local it worked. how to implement this in spring ?. I have tried MULTIPART_FORM_DATA but no luck.
If You mean file
#RestController
public class FileContentController {
#RequestMapping(value="/up", method = RequestMethod.POST)
public ResponseEntity<?> upload(#RequestParam("file") MultipartFile file)
throws IOException {
String contentType=file.getContentType());
InputStream i=file.getInputStream();
return new ResponseEntity<>(HttpStatus.OK);
}
return null;
}
also spring boot has multi part confs, you should enable it and set size and tempdir
,In Earlier version spring boot need to add:
spring.servlet.multipart.max-file-size=128KB
spring.servlet.multipart.max-request-size=128KB
spring.servlet.multipart.enabled=true
spring.servlet.multipart.location=${java.io.tmpdir}
However in your client code you should not set content-type application/json in your header post request
simple fetch should be such
const input = document.getElementById('uploadInput');
const data = new FormData();
data.append('file', input.files[0]);
var resp = await fetch('upload/', {
method: 'POST',
body: data
});
if (!resp.ok) {
throw new Error(`HTTP error! status: ${resp.status}`);
}
if (resp.ok) {
await this.images();
}

How to receive file csv from java with angular

I have a rest api which returns a file.csv
and then I check that the response is 200, and datas are also in responsed.body.
But the brower didn't download the csv file.
Here is the API :
ResponseEntity<Resource> exportCsv() throws IOException {
/*
*
*/
InputStreamResource resource = new InputStreamResource(new FileInputStream(file));
HttpHeaders headers = new HttpHeaders();
headers.add("Content-disposition", "attachment; filename=sample.csv");
headers.add("Cache-Control", "no-cache, no-store, must-revalidate");
headers.add("Pragma", "no-cache");
headers.add("Expires", "0");
return ResponseEntity.ok()
.headers(headers)
.contentLength(file.length())
.contentType(MediaType.parseMediaType("text/csv"))
.body(resource);
}
Here is the Angular
this.stickService.exportCsv( this.stickSearch ).subscribe(
response => this.downloadFile(response),
err => console.log('Error downloading the file.' + err.message
));
downloadFile(data: Response) {
const blob = new Blob([data], { type: 'text/csv' });
const url = window.URL.createObjectURL(blob);
window.open(url);
}
exportCsv( stickSearch: StickSearch ): Observable<any> {
const headers = this.oAuthService.putTokenInHeaders(this.headers);
let params = new HttpParams({encoder: new HttpURIEncoder()});
if (stickSearch.searchString() !== '') {
params = params
.append('search', stickSearch.searchString())
}
return this.httpClient.get(this.exportCsvUrl + '/exportCsv',
{
responseType: 'text',
params: params,
headers
});
}
I got correct data at response body.
But the download failed. 'Error downloading the file.Http failure during parsing for myURL '
Thanks for helping
It work now, this is consequence
Thanks a lot !
I can see that you are taking the output provided by the server and then building an URL off that CSV. That won't be necessary.
If you just want to download the CSV, then all you are missing is the following in your Java code:
headers.add("Content-disposition", "attachment; filename=sample.csv");
Once you have the header in place, you can get rid of the downloadFile method and probably change the this.httpClient.get request into a window.open.
See if this solves your problem and provide feedback in either case.
By default HttpClient expects that data from server will come in json format. Angular tries to parse text body as json. And that leads to exсeption. In the stickService when you do request the data, you have to specify type or result as text:
constructor (private httpClient: HttpClient){
}
public exportCsv(stickSearch: any) {
return httpClient.get('http://someurl', {responseType: 'text'});
}
Another one point that you use window.open(url). Most browsers block popup windows by default. So maybe it would be better to use an anchor element.
downloadFile(data: Response) {
const blob = new Blob([data], { type: 'text/csv' });
const url = window.URL.createObjectURL(blob);
const anchor = document.createElement('a');
anchor.download = 'myfile.txt'; // here you can specify file name
anchor.href = url;
document.body.appendChild(anchor);
anchor.click();
document.body.removeChild(anchor);
}
Here is the I'm using for this feature.
First, use 'Accept' headers.
Second, set responseType to 'text', the default is 'json'.
Third, the download code.
getCsv(): Observable<any> {
let headers = new HttpHeaders();
headers = headers.set('Accept', 'application/csv');
return this.http.get('SOME__URL', {
headers: headers,
responseType: 'text'
});
}
exportReportCSV() {
getCsv().subscribe( response => {
const link = document.createElement('a');
link.href = window.URL.createObjectURL(new Blob([response], {type: 'text/csv'}));
link.download = this.report.name + '.csv';
link.click();
});

Spring Boot optional multipart POST request

I have a service where I want to be able to optionally upload a file (including a file will run a separate function) with a POST request.
A simplified version of what my ReqestMapping looks like is this:
#ApiOperation(value = "Data", nickname = "Create a new data object")
#RequestMapping(value = "/add/{user_id}", produces = "application/json", method = RequestMethod.POST)
public ResponseEntity<Data> addData(#RequestParam("note") String body,
#RequestParam("location") String location,
#RequestParam(value = "file", required = false) List<MultipartFile> file,
#PathVariable String user_id){
if (file != null) {
doSomething(file);
}
doRegularStuff(body, location, user_id);
return new ResponseEntity(HttpStatus.OK);
}
As can be seen, I have the required = false option for my List of multipart files. However, when I attempt to curl the endpoint without any files and while stating that my content type is Content-Type: application/json, I get the error that my request isn't a multipart request.
Fine. So I change to Content-Type: multipart/form-data and without any files, I get the request was rejected because no multipart boundary was found (obviously, since I don't have a file).
This leads me to wonder how I can have a optional multipart parameter in my Spring endpoints? I would like to avoid having to add additional parameters to my request, such as "File Attached: True/False" as that can become cumbersome and unnecessary when the server can just check for existence.
Thanks!
There is no problem in your code, but the problem in client request, because Content-Type should be like below if you want to upload image,
multipart/form-data; boundary="123123"
try to remove the Content-Type header and test, i will put one example for server code and client request
Server code:
#RequestMapping(method = RequestMethod.POST, value = "/users/profile")
public ResponseEntity<?> handleFileUpload(#RequestParam("name") String name,
#RequestParam(name="file", required=false) MultipartFile file) {
log.info(" name : {}", name);
if(file!=null)
{
log.info("image : {}", file.getOriginalFilename());
log.info("image content type : {}", file.getContentType());
}
return new ResponseEntity<String>("Uploaded",HttpStatus.OK);
}
Client Request using Postman
with image
without image
Curl example:
without image, with Content-Type
curl -X POST -H "Content-Type: multipart/form-data; boundary=----WebKitFormBoundary7MA4YWxkTrZu0gW" -F "name=test" "http://localhost:8080/api/users/profile"
without image, without Content-Type
curl -X POST -F "name=test" "http://localhost:8080/api/users/profile"

Handle a FormData send from Ajax in a Java File

I am sending a file via Ajax like this:
// Get the selected files from the input.
var files = fileSelect.files;
// Create a new FormData object.
var formData = new FormData();
// Add the file to the request.
formData.append('photos[]', files[0], files[0].name);
$.ajax({
type:"POST",
url:"URL,
dataType:"json",
headers : {"cache-control":"no-cache"},
timeout : 12000,
processData: false,
data:{
formdata:formData
}
Now I want to work with the send file in my java class, in a ressource like this:
#PermitAll
#POST
#Path(URL)
#Produces(MediaType.APPLICATION_JSON)
public Map<String, Object> fileHandler(#FormParam("formdata") File formdata){ }
But accessing the file does not work, #FormParam("formdata") File formdata seems to be wrong (or more things?). I want to get access to this file in my ressource class somehow. What am I doing wrong? Maybe someone knows a better solution for this.
You can handle it this way:
I have changed the way FormData is passed. Used id of the form and passed it to create form data:
Javacript:
$.ajax({
type : 'POST',
url : rquestURL,
cache:false,
processData:false,
contentType:false,
data : new FormData($("#"+<your_form_id>)[0])}
Rresource (Added #Consumes(MediaType.MULTIPART_FORM_DATA) annotation):
#Path("/upload")
#POST
#Consumes(MediaType.MULTIPART_FORM_DATA)
public ResponseDTO doUpload(FormDataMultiPart multiPartData) {
// non-file fields
final String imageId = multiPartData.getField("<your_field_name>").getValue();
// for file field
final FormDataBodyPart filePart = multiPartData.getField("<file_field_name>");
final ContentDisposition fileDetails = filePart.getContentDisposition();
final InputStream fileInputStream = filePart.getValueAs(InputStream.class);
// use the above fields as required
// file name can be accessed from field "fileDetails"
}
When you deal with files, it's not just FormParam, it's FormDataParam. Also, class File is for entity in your filesystem, not for files inside request. It should be InputStream instead.
So signature should look like this:
#PermitAll
#POST
#Path(URL)
#Produces(MediaType.APPLICATION_JSON)
public Map<String, Object> fileHandler(
#FormDataParam("formdata") InputStream formdata,
#FormDataParam("formdata") FormDataContentDisposition fileDetail
){ }
Here you could also see another parameter "FormDataContentDisposition", from it you could take details about data, like filename and size (would be useful, when you will read InputStream).
Note that I wrote this example for JAX-RS. Not sure what library you use.

spring mvc jquery ajax response as json encoding issue

Recenlty I have big problem with Polish Characters in JSON response from the server. I have simple Ajax request for this:
jQuery.ajax( "/GetSimpleRuleList",
{
type:"GET",
responseType:"application/json;charset=utf-8",
contentType:"application/json;charset=utf-8",
cache:false
} ).done( function ( data )
{
console.log( data );
//nevermind here
} );
And appropriate Controller at server end:
#RequestMapping(value = "/GetSimpleRuleList", method = RequestMethod.GET)
public
#ResponseBody
String getRuleList( ServletResponse response )
{
//magically getting my list here
response.setCharacterEncoding( "UTF-8" );
return //Using JACKSON ObjectWriter here
}
Now I'm 100% sure that encoidng on server side and database from where I take data from is OK, no problem with that.
But when It comes to reading response from server it is:
???
instead of Polish char like:
ąćź
Moreover it only fails when receiving response from server, while sending a request with data is encoded correctly.
In my web.xml I have filter for character encoding.
Any help with this? I'm out of ideas.
Now I'm 100% sure that encoidng on server side and database from where I take data from is OK
try adding the Content-Type header if it's not already present int your response:
response.setHeader("Content-Type", "application/json;charset=UTF-8")
Get sure to use UTF-8 charset when reading from database. Jackson's encoding defaults to UTF-8, so your data might not be encoded using UTF-8?!?
what encoding do you use when reading from database? maybe ISO-8859-2?
Try changing your response type to org.springframework.http.ResponseEntity
public ResponseEntity<String> getRuleList(){
HttpHeaders responseHeaders = new HttpHeaders();
responseHeaders.add("Content-Type", "application/json; charset=utf-8");
responseHeaders.setCacheControl("no-cache, max-age=0");
String allyourjson = "yourjsongoeshere";
return new ResponseEntity<String>(allyourjson, responseHeaders, HttpStatus.OK);
}
You can use spring annotation RequestMapping above controller class for receveing application/json;utf-8 in all responses
#Controller
#RequestMapping(produces = {"application/json; charset=UTF-8","*/*;charset=UTF-8"})
public class MyController{
...
#RequestMapping(value = "/GetSimpleRuleList", method = RequestMethod.GET)
public
#ResponseBody
String getRuleList( ServletResponse response )
{
//magically getting my list here
response.setCharacterEncoding( "UTF-8" );
return //Using JACKSON ObjectWriter here
}
...
}

Categories

Resources