How can I configure the Content-Length in the header? - spring-boot

I have a code that generates a csv. And I want to have Content-Length in the header for a functionality that I want to do from the frontend.
I don't know how to add it, any idea
#GetMapping("/report-csv")
public ResponseEntity<Resource> getReportCSV() {
InputStreamResource file = new InputStreamResource(generate_report_csv.port_list());
return ResponseEntity.ok()
.header(HttpHeaders.CONTENT_DISPOSITION, CSV_HEADER)
.contentType(MediaType.parseMediaType(CSV_MEDIA_TYPE))
//.contentLength()
.cacheControl(CacheControl.noCache())
.body(file);
}

Related

I use springBoot And Vue , i want send a response to vue , But response always is garbled

#Controller
#Slf4j
public class SeckillGoodsController {
#Autowired
RedisTemplate redisTemplate;
#GetMapping("/captcha")
public void verifyCode(Long userId,Long goodsId, HttpServletResponse response){
//set Header as pic
response.setContentType("image/gif");
// no cookie keep every flush is new captcha
response.setContentType("text/html;charset=UTF-8");
response.setCharacterEncoding("utf-8");
response.setHeader("Pragma", "No-cache");
response.setHeader("Cache-Control", "no-cache");
response.setDateHeader("Expires", 0);//never expires
//Use a util [enter image description here][1]
ArithmeticCaptcha captcha = new ArithmeticCaptcha(130, 32, 3);
redisTemplate.opsForValue().set("captcha:"+userId+":"+goodsId,captcha.text(),60, TimeUnit.SECONDS);
try {
System.out.println(response.getOutputStream().toString());
captcha.out(response.getOutputStream());
} catch (IOException e) {
log.error("Errot",e.getMessage());
}
}
}
I send a response to vue.js but use postman test the Body always is captcha, I've set the UTF-8, but it's still wrong
[1]: https://i.stack.imgur.com/04RKS.png
this has nothing to do with Spring Boot.
I'm not entirely sure what the ArithmeticCaptcha does but I guess it creates an image and stream it to the response stream
I don't know what you would expect... You are sending binary data (an image) so it is quite normal that you can't read it.
You are setting the content type twice. You can't do that. In addition, it seems to be png so you might want to check it out.
I guess that you want to would like to get a JSON back or similar. In that case, you need to change your code
Here is an example:
#ResponseBody
#RequestMapping("/captcha")
public JsonResult captcha(Long userId, Long goodsId, HttpServletResponse response) throws Exception {
ArithmeticCaptcha captcha = new ArithmeticCaptcha(130, 32, 3);
String key = "captcha:"+userId+":"+goodsId
redisTemplate.opsForValue().set(key, captcha.text(), 60, TimeUnit.SECONDS);
return JsonResult.ok().put("key", key).put("image", captcha.toBase64());
}
Might need some tweaks to fit 100% your case but this will return a json with a key that is the one you probably will need to match in your next step and the image base64 encoded so it would be (almost) readable.
You can then add the base64 encoded string from the response as the src of your img tag.

How do I stream multiple multipart messages of different mimetypes in spring?

I'm currently using Springs ResponseBodyEmitter to stream a multipart/related response consisting of multiple parts (of mimetype application/json as well as application/octet-stream) to a client. Therefore I am manually setting the boundary in the Content-Type header as well as creating the encapsulation boundaries between the different message parts within the payload. I'm pretty sure there is a more convenient way to achieve this. What would be the idiomatic way in Spring to achieve this?
#GetMapping(value = "/data", produces = {MediaType.MULTIPART_FORM_DATA_VALUE})
public ResponseEntity<ResponseBodyEmitter> streamMultipart() {
// omitting actual contents for the sake of brevity
InputStream audio = new ByteArrayInputStream(null); //asynchronously retrieved
String json = "{}";
ResponseBodyEmitter speakEmitter = new ResponseBodyEmitter();
executor.execute(() -> {
try {
speakEmitter.send("\r\n--myBoundary\r\n");
speakEmitter.send("Content-Type: application/json;\r\n\r\n");
speakEmitter.send(json, MediaType.APPLICATION_JSON);
speakEmitter.send("\r\n--myBoundary\r\n");
speakEmitter.send("Content-Type: application/octet-stream;\r\n\r\n");
speakEmitter.send(audio.readAllBytes(), MediaType.APPLICATION_OCTET_STREAM);
speakEmitter.send("\r\n--myBoundary--\r\n");
} catch (IOException ignoredForBrevity) {}
});
HttpHeaders responseHeaders = new HttpHeaders();
responseHeaders.add(HttpHeaders.CONTENT_TYPE, "multipart/related; boundary=myBoundary");
return ResponseEntity.ok().headers(responseHeaders).body(speakEmitter);
}

corrupted PDF file downloaded from spring rest api

I am developing a rest end point to download a existing pdf file. I'm able to download PDF with size, but when I open, getting error as
'Adobe reader couldnot open it is either not supported file type or
because file has been damaged'.
I have noticed that in postman, response header content type is application/pdf;charset=UTF-8. I'm not sure if this is the cause.
With simple spring boot application I'm able to download, but in our project when I implement the same code, it is not working.
#GetMapping( path= "/s3/downloads")
public ResponseEntity<byte[]> downloadFile()
{
InputStream in = getClass().getResourceAsStream("/com/consulting/cloud/filetransfers/rest/template_attendance_en_green_full.pdf");
byte[] generatedCertificate = null;
String downloadFileName = "pdfFile1.pdf";
ResponseEntity<byte[]> responseEntity = ResponseEntity.status( HttpStatus.NO_CONTENT ).body( generatedCertificate );
try {
generatedCertificate = StreamUtils.copyToByteArray(in);
HttpHeaders headers = new HttpHeaders();
headers.add("Access-Control-Allow-Origin", "*");
headers.setContentType( MediaType.APPLICATION_PDF );
headers.setContentLength( generatedCertificate.length );
headers.setContentDispositionFormData( "attachment", downloadFileName );
responseEntity = ResponseEntity.ok().headers( headers ).body( generatedCertificate );
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return responseEntity;
}
The file is opened as expected.

Spring REST file download unable to set header content-type attachment

I have a Springboot REST application that downloads files from a given directory.
The downloads can be any file file and have any format, and I want to use the original filename as the filename of the downloaded file.
I used the code below to set the filename in the header, and add the header to the response:
#RestController
#RequestMapping("/downloads")
public class DownloadCsontroller {
...
#GetMapping
public void downloadSingleFile(#RequestParam("file") String filename, HttpServletResponse response) throws IOException {
String filepath = m_attachmentPathLocation + File.separator + filename;
File file = new File(filepath);
String contentType = getContentType(file);
response.setStatus(HttpServletResponse.SC_OK);
response.setContentType(contentType);
response.setHeader("Content-Disposition:", "attachment;filename=\"" + file.getName() + "\"");
...
}
...
}
Tested using both "Content-Disposition" and "Content-Disposition:" in setHeader().
Almost everything works (file types), except for PDF, ZIP, RAR, EXE, etc.
Any files (types) not on the list can be downloaded with the desired filenames.
But when any of the file download (PDF, ZIP, RAR, EXE, etc)... it seems it continuously loads like forever... and I cannot even see any request sent in POSTMAN, inspector, firebug, etc.
If I comment out:
//response.setHeader("Content-Disposition:", "attachment;filename=\"" + file.getName() + "\"");
It would work, but the filename would be set to the name of the request mapping. which in this case is "downloads".
I have seen lots of samples that uses "Content-Disposition" header to change the attachment filename... but it seems it fails on these file types.
I have no configurations yet, and it is kinda weird since in most samples I searched... this should be running or working.
TIA
Please add #GetMapping(produces = MediaType.APPLICATION_OCTET_STREAM_VALUE)
and instead of returning direct file try to return stream.
Also make a note that "Content-Disposition:" header will not work if the requesting app IP & Port number is different from server app IP & Port number.
Things would work If you can alter the code a bit, by setting all header values using org.springframework.http.HttpHeaders class.
Now looking at your code, i suspect you trying to expose an API that allows to download a multipart File.
I would suggest you not to use HttpServletResponse Class to set the Content- Dispositionheader but use HttpHeaders class. Below is the reformatted code
#RestController
public class DownloadCsontroller {
#GetMapping(value="/downloads")
public ResponseEntity<Object> downloadSingleFile(#RequestParam("file")
String filename) throws IOException {
String filepath = m_attachmentPathLocation + File.separator + filename;
File file = new File(filepath);
String contentType = getContentType(file);
/* response.setStatus(HttpServletResponse.SC_OK);
response.setContentType(contentType);
response.setHeader("Content-Disposition:", "attachment;filename=\""
+ file.getName() + "\"");
*/
// Here is the below Code you need to reform for Content-
//Disposition and the remaining header values too.
HttpHeaders headers= new HttpHeaders();
headers.add("Content-Disposition", "attachment; filename
=whatever.pdf");
headers.add("Content-Type",contentType);
// you shall add the body too in the ResponseEntity Return object
return new ResponseEntity<Object>(headers, HttpStatus.OK);
}
}

How to upload just an image using Retrofit 2.0

Trying to upload an image and it keeps sending as just bytes, not an image file. This is a very simple call, I don't need to send any params other than the image itself. I don't know how to format logs so I won't post the error here unless requested to.
The service:
public interface FileUploadService {
#Multipart
#POST("upload_profile_picture")
Call<ResponseBody> uploadProfilePicture(#Part("profile_picture") RequestBody file);
}
The call being made (a file is generated earlier, had to remove this code because SO needs the post to be mainly words..dumb..):
// Generate the service from interface
FileUploadService service = ServiceGenerator.createService(FileUploadService.class, this);
// Create RequestBody instance from file
RequestBody requestFile =
RequestBody.create(MediaType.parse("image/*"), imageFile);
Log.d(LOG_TAG, "formed file");
// finally, execute the request
Call<ResponseBody> call = service.uploadProfilePicture(requestFile);
Log.d(LOG_TAG, "sending call");
call.enqueue(new Callback<ResponseBody>() {
#Override
public void onResponse(Call<ResponseBody> call,
Response<ResponseBody> response) {
Log.d(LOG_TAG, "success");
Log.d(LOG_TAG, response.toString());
}
#Override
public void onFailure(Call<ResponseBody> call, Throwable t) {
Log.d(LOG_TAG, "failure");
Log.e(LOG_TAG, t.getMessage());
}
});
Is the issue with the MediaType.parse method? I've tried "multipart/form-data", "image/jpeg", and the above as well and nothing has worked.
The server team has said they are receiving the call, just as bytes and no image file.
I keep getting a 400 because it's sending all bytes. How can I just send this? Do I need to send as a multipart or what? From what I've seen, you just need to tag the param in the method with #Body and do the above and it should all work. Can anybody tell me why this is happening? Thanks!
This is a known issue in Retrofit 2.
Edit: Support for OkHttp's MultipartBody.Part has been added in the final 2.0 release.
In order to get it working, you need to change your interface a little bit first:
#Multipart
#POST("upload_profile_picture")
Call<ResponseBody> uploadProfilePicture(#Part MultipartBody.Part file);
Then you have to create the Part and make the call like this:
MultipartBody.Part file = MultipartBody.Part.createFormData(
"file",
imageFile.getName(),
RequestBody.create(MediaType.parse("image/*"), imageFile));
Call<ResponseBody> call = service.uploadProfilePicture(file);

Resources