Spring MVC + Springfox 2.9.2 downloads damaged PDF - spring

I have a Spring MVC project (no SpringBoot) with a GET endpoint which returns a PDF file. The PDF file is either generated manually or read from resources. I also have a SpringFox dependency to generate swagger-ui.html.
Dependency versions:
Spring: 4.3.25.RELEASE
SpringFox: 2.9.2
The problem is that when I try to download the PDF directly using the "Download file" button then the file is downloaded but somehow corrupted and impossible to open. But when I use the "Request URL" I'm able to download the PDF without any problem.
My REST request:
#RequestMapping(value = "/v1/generatePdfSync", method = RequestMethod.GET)
public ResponseEntity<Resource> generatePdfSync(#RequestParam String templateName) {
Map<String, Object> model = new HashMap<>();
model.put("title", "Hello world!");
model.put("pages", new ArrayList<>(Arrays.asList(1, 2, 3)));
byte[] bytes = pdfGenerator.generatePdf(templateName, model);
// Create response
ByteArrayResource resource = new ByteArrayResource(bytes);
return ResponseEntity.ok()
.contentType(MediaType.APPLICATION_OCTET_STREAM)
.contentLength(resource.contentLength())
.header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=\"test.pdf\"")
.body(resource);
}
My question is whether I don't have some mistake in the request itself.

The error was mine, this code worked for me:
#RequestMapping(value = "/v2/generatePdfSync", method = RequestMethod.POST, produces = {MediaType.APPLICATION_PDF_VALUE, MediaType.APPLICATION_OCTET_STREAM_VALUE, MediaType.APPLICATION_JSON_UTF8_VALUE, MediaType.APPLICATION_JSON_VALUE})
public ResponseEntity<Resource> generatePdfSync(#RequestBody GeneratePdfRequest generatePdfRequest) {
// Map<String, Object> model = new HashMap<>();
// model.put("title", "Hello world!");
// model.put("pages", new ArrayList<>(Arrays.asList(1, 2, 3)));
LOGGER.info("GeneratePdfSync: {}", generatePdfRequest);
byte[] bytes = pdfGenerator.generatePdf(generatePdfRequest.getTemplateName(), generatePdfRequest.getTemplateModel());
// Create response
ByteArrayResource resource = new ByteArrayResource(bytes);
return ResponseEntity.ok()
.contentType(MediaType.APPLICATION_OCTET_STREAM)
.contentLength(resource.contentLength())
.header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=\"" + generatePdfRequest.getResultPdfName() + "\"")
.body(resource);
}

Related

How to use MockMVC test the controller which use org.apache.commons.fileupload?

My Controller use " org.apache.commons.fileupload " realized the file UPload.
see it:
#PostMapping("/upload")
public String upload2(HttpServletRequest request) throws Exception {
ServletFileUpload upload = new ServletFileUpload();
FileItemIterator iter = upload.getItemIterator(request);
boolean uploaded = false;
while (iter.hasNext() && !uploaded) {
FileItemStream item = iter.next();
if (item.isFormField()) {
item.openStream().close();
} else {
String fieldName = item.getFieldName();
if (!"file".equals(fieldName)) {
item.openStream().close();
} else {
InputStream stream = item.openStream();
// dosomething here.
uploaded = true;
}
}
}
if (uploaded) {
return "ok";
} else {
throw new BaseResponseException(HttpStatus.BAD_REQUEST, "400", "no file field or data file is empty.");
}
}
and my MockMvc code is
public void upload() throws Exception {
File file = new File("/Users/jianxiaowen/Documents/a.txt");
MockMultipartFile multipartFile = new MockMultipartFile("file", new FileInputStream(file));
HashMap<String, String> contentTypeParams = new HashMap<String, String>();
contentTypeParams.put("boundary", "----WebKitFormBoundaryaDEFKSFMY18ehkjt");
MediaType mediaType = new MediaType("multipart", "form-data", contentTypeParams);
MvcResult mvcResult = mockMvc.perform(MockMvcRequestBuilders.post(baseUrl+"/upload")
.content(multipartFile.getBytes())
.contentType(mediaType)
.header(Origin,OriginValue)
.cookie(cookie))
.andReturn();
logResult(mvcResult);
}
my controller is right , it has successed in my web project,
but I want to test it use MvcMock, it has some mistake, see :
can someOne can help me?
"status":"400","msg":"no file field or data file is empty.","data":null
I don't know why it says my file is empty.
my English is poor, thank you very much if someone can help me.
The MockMvc can be used for integration testing for controllers using Apache Commons Fileupload too!
Import the org.apache.httpcomponents:httpmime into your pom.xml or gradle.properties
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpmime</artifactId>
<version>4.5.13</version>
</dependency>
Update the code to use MultipartEntityBuilder to build the multipart request on the client, and then serialize the entity into bytes, which is then set in the request content
public void upload() throws Exception {
File file = new File("/Users/jianxiaowen/Documents/a.txt");
String boundary = "----WebKitFormBoundaryaDEFKSFMY18ehkjt";
// create 'Content-Type' header for multipart along with boundary
HashMap<String, String> contentTypeParams = new HashMap<String, String>();
contentTypeParams.put("boundary", boundary); // set boundary in the header
MediaType mediaType = new MediaType("multipart", "form-data", contentTypeParams);
// create a multipart entity builder, and add parts (file/form data)
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
HttpEntity multipartEntity = MultipartEntityBuilder.create()
.addPart("file", new FileBody(file, ContentType.create("text/plain"), file.getName())) // add file
// .addTextBody("param1", "value1") // optionally add form data
.setBoundary(boundary) // set boundary to be used
.build();
multipartEntity.writeTo(outputStream); // or getContent() to get content stream
byte[] content = outputStream.toByteArray(); // serialize the content to bytes
MvcResult mvcResult = mockMvc.perform(
MockMvcRequestBuilders.post(baseUrl + "/upload")
.contentType(mediaType)
.content(content) // finally set the content
.header(Origin,OriginValue)
.cookie(cookie)
).andReturn();
logResult(mvcResult);
}
Can you try the below?
mockMvc.perform(
MockMvcRequestBuilders.multipart(baseUrl+"/upload")
.file(multiPartFile)
).andReturn();
Update:
You need to update the controller to handle the MultipartFile:
#PostMapping("/upload")
public String upload2(#RequestParam(name="nameOfRequestParamWhichContainsFileData")
MultipartFile uploadedFile, HttpServletRequest request) throws Exception {
//the uploaded file gets copied to uploadedFile object.
}
You need not use another library for managing file uploads. You can use the file upload capabilities provided by Spring MVC.

Spring Controller return static HTML site from any directory

I would like to return in my #Controller static HTML website that was generated by other process. Let's say that generated .html files are in /tmp/generated. I'm trying to read file and pass its content to ResponseEntity:
#GetMapping(value = "test")
ResponseEntity<String> test(#RequestParam("filename") String filename) throws IOException {
String content = new String(Files.readAllBytes(Paths.get("/tmp/generated/" + filename)), "UTF-8");
final HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.TEXT_HTML);
return new ResponseEntity<String>(content, headers, HttpStatus.OK);
}
But when I open url in browser I get badly encoded html content (stating and ending with '"'):
"\u003chtml\u003e\n\u003chead\u003e\n \u003cmeta charset\u003d\"utf-8\" /\u003e\n \u003cmeta http-equiv\u003d\"X-UA-Compatible\" content\u003d\"IE\u003dedge\" /\u003e\n \u003cmeta name\u003d\"viewport\" content\u003d\"width\u003ddevice-width, initial-scale\u003d1\" /\u003e [.....]
If I add produces = MediaType.TEXT_HTML_VALUE to my #GetMapping annotation then I get 406 Not Acceptable error response (but no exception in my spring app)...
How to fix it?
I'm not sure why you are facing problems when using produces in your mapping.
I gave a quick try and it worked for me.
#GetMapping(value = "test", produces=MediaType.TEXT_HTML_VALUE)
public ResponseEntity<String> test(#RequestParam("filename") String filename) throws IOException {
String content = new String(Files.readAllBytes(Paths.get("/tmp/generated/" + filename)), "UTF-8");
return new ResponseEntity<String>(content, HttpStatus.OK);
}
Tested in Chrome browser:
File
NOTE: I tested this controller using SpringBoot v2.0.5.RELEASE
Cheers!
I have successfully build application with Spring Boot 1.5.2.RELEASE and it will return static HTML site from any directory
you can checkout here

Camel rest API to provide dynamic download

How can we provide document download using camel API, I need to provide an api using camel rest to response the file as download and I have the logic to create the pdf using apache fop, but i need to get some information how to respond the file as rest response using camel rest.
#RestController
public class MyController {
#Autowired
ICityService cityService;
#RequestMapping(
value = "/pdfreport",
method = RequestMethod.GET,
produces = MediaType.APPLICATION_PDF_VALUE
)
public ResponseEntity<InputStreamResource> citiesReport() throws IOException {
List<City> cities = (List<City>) cityService.findAll();
ByteArrayInputStream bis = GeneratePdfReport.citiesReport(cities);
HttpHeaders headers = new HttpHeaders();
headers.add("Content-Disposition", "inline;
filename = citiesreport.pdf");
return ResponseEntity
.ok()
.headers(headers)
.contentType(MediaType.APPLICATION_PDF)
.body(new InputStreamResource(bis));
}
}

from andriod i am trying to upload image and i am using web services in java

below is the android part
new MultipartUploadRequest(this,uploadid,UPLOAD_URL)
.addFileToUpload(path,"image")
.addParameter("name",name)
.setNotificationConfig(new UploadNotificationConfig())
.setMaxRetries(2)
.startUpload();
below is my java controller in web services
#RequestMapping(value = "/uploadm",method=RequestMethod.POST)
public void submitQuestionuploading(#RequestBody String image) throws Exception
{
System.out.println(1+""+image);
try {
byte[] bytes = image.getBytes();
System.out.println(11);
BufferedOutputStream stream =new BufferedOutputStream(new
FileOutputStream(new File(UPLOAD_DIRECTORY +"11.png")));
stream.write(bytes);
stream.flush();
stream.close();
}
catch (Exception e) {
System.out.println(e);
}
output is this one i got in console but file is created but it is corrupted and it s size 0bytes ,
---------AndroidUploadService1518510071115 Content-Disposition: form-data; name="image"; filename="IMG_20180211_000033.jpg"
Content-Type: image/jpeg
ÿØÿá3ØExif
i tried to put this in java controller but it is not working
#RequestMapping(value = "/upload", method = RequestMethod.POST ,
headers = "Content-Type=multipart/form-data") public String
fileUpload(#RequestParam("image") CommonsMultipartFile file) {}
but i want to do in spring MVC only, help me to take uploaded file
This is a working file uploader
#ResponseStatus(code = HttpStatus.CREATED)
#RequestMapping(value = "asset", method = RequestMethod.POST, consumes = {
MediaType.MULTIPART_FORM_DATA_VALUE}, produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
#ResponseBody
public String uploadImage(
#RequestParam("image") MultipartFile file) {
byte[] bytes = file.getBytes();
//do something with byte
return "ok or anything you want to return";
}
And also you need to register MultipartResolver as a depandency.
#Bean(name = "multipartResolver")
public CommonsMultipartResolver multipartResolver() {
CommonsMultipartResolver multipartResolver = new CommonsMultipartResolver();
multipartResolver.setMaxUploadSize(100000);
return multipartResolver;
}
you can deploy this code and then test using postman.
there are various tutorials for this.
you may have a look at
http://www.baeldung.com/spring-file-upload
https://www.boraji.com/spring-4-mvc-file-upload-example-with-commons-fileupload

How can I fix this issue, when file download in the browser, it change encoding in file, I used Spring boot

I used it code for response Excel byte[] to browser. But I have problem, because Spring boot encode file, and I got bad file than download from browser.
//This method returned response on controller
public ResponseEntity<ByteArrayResource>
returnAllTransactionAsExcel(TransactionSearchFilter
transactionSearchFilter) throws IOException {
List<Transaction> transactions =
getAllTransactions(transactionSearchFilter);
byte[] ourFile=writeIntoExcel(transactions);
//headers
HttpHeaders headers = new HttpHeaders();
headers.add("Pragma", "no-cache");
headers.add("Expires", "0");
headers.add("Content-Disposition", "attachment;
filename=list_transactions.xls");
headers.setCacheControl("must-revalidate, post-check=0, pre-check=0");
headers.setContentType(MediaType.parseMediaType("application/vnd.ms-excel"));
return
ResponseEntity
.ok()
.headers(headers)
.contentLength(ourFile.length)
.contentType(MediaType.parseMediaType("application/vnd.ms-excel"))
.body(new ByteArrayResource(ourFile));
}
//This method on controller
#ApiOperation(value = "Retrieve all transactions in Excel")
#RequestMapping(value = "/allExcel", method = RequestMethod.POST,
produces "application/vnd.ms-excel")
public ResponseEntity<ByteArrayResource>
getAllTransactionsAsExcel(#RequestBody TransactionSearchFilter
transactionSearchFilter) throws IOException {
return returnAllTransactionAsExcel(transactionSearchFilter);
}
I solved my problem, all problem was in swagger-ui
https://github.com/webanno/webanno/issues/459

Resources