SpringBoot base64 pdf downloading - spring-boot

When user makes a get request this should download a pdf file, so far I am getting base64 of the pdf file but I don't know how to download. Can someone help me out?
#ResponseBody
#GetMapping("/download/pdf/{uuid}/{userid}")
public String downloadPdf (#PathVariable String uuid,#PathVariable String userid, Model model) {
JSONObject jsonObject = RequestHelper.getResponse("pdf", uuid);
JSONArray d =(JSONArray) jsonObject.get("data");
String str = (String) d.get(0);
byte[] bytes = str.getBytes(StandardCharsets.UTF_8);
// I have base64 pdf how can I start downloading this pdf
return("file downloaded");
}

Add Rest Controller to spring boot project and below method to download pdf file from base64 content.
Assign the pdf base64 string to content variable.
#GetMapping(value = "/donw1")
public ResponseEntity<Resource> donw1() {
logger.info("Start the file processing");
String content = "<<Add_pdf_base64 content here>>";
byte[] decoder = Base64.getDecoder().decode(content);
InputStream is = new ByteArrayInputStream(decoder);
InputStreamResource resource = new InputStreamResource(is);
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_PDF);
ContentDisposition disposition = ContentDisposition.attachment().filename("textdown.pdf").build();
headers.setContentDisposition(disposition);
return new ResponseEntity<>(resource, headers, HttpStatus.OK);
}

Related

Spring MVC + Springfox 2.9.2 downloads damaged PDF

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);
}

spring convert buffered image into response entity

I have BufferedImage in my spring boot application. Now I want to send that file to user. How can I do that ?
I'm looking for method to convert BufferedImage into ResponseEntity.
you can also convert it to byte[] using javax.imageio.ImageIO
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
ImageIO.write(bufferedImage , "png", byteArrayOutputStream);
byte[] imageInByte = baos.toByteArray();
then you controller is simplified:
#RequestMapping(value = "/path", method = GET)
public ResponseEntity<byte[]> getResource() {
return ResponseEntity.status(HttpStatus.OK)
.header(HttpHeaders.CONTENT_DISPOSITION, "filename=\"image.png"\")
.contentType(MediaType.IMAGE_PNG)
.body(imageInByte);

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.

Angular 4 and Spring Rest: How to post FormData containing File and model object in a single request

I would like to send a File object along with custom model object in a single request.
let formData:FormData = new FormData();
let file = this.fileList[0];
formData.append('file', file, file.name);
formData.append('address', JSON.stringify(customObj));
...
this.http.post(fileServeUrl, formData)
My backend is in Spring Rest as below
#RequestMapping(value = "/fileServe",
produces = {"application/json"},
consumes = {MediaType.APPLICATION_JSON_VALUE, MediaType.MULTIPART_FORM_DATA_VALUE},
method = RequestMethod.POST)
ResponseEntity<Image> uploadFile(#RequestPart("file") MultipartFile imageData, #RequestPart("address") Address address) throws IOException {...}
I was able to receive the data if I pass simple String along with File though.
formData.append('file', file, file.name);
formData.append('address', addressText);
Backend
#RequestMapping(value = "/fileServe",
produces = {"application/json"},
consumes = {MediaType.APPLICATION_JSON_VALUE, MediaType.MULTIPART_FORM_DATA_VALUE},
method = RequestMethod.POST)
ResponseEntity<Image> uploadFile(#RequestPart("file") MultipartFile imageData, #RequestPart("address") String addressText) throws IOException {...}
I tried #RequestBody for my custom object but even that didn't work. Any advise please.
The problem with #Requestbody and #RequestPart annotation is that spring use the HttpMessageConverter to take convert the incoming json message into the your object. As you send form data with a file and a text value spring can not convert it into your object. I am afraid you have to pass the value of address seperatetly.
#RequestMapping(value = "/fileupload", headers = ("content-type=multipart/*"), method = RequestMethod.POST)
public ResponseEntity<AjaxResponseBody> upload(#RequestParam("file") MultipartFile file, #RequestParam String name, #RequestParam String postCode) {
AjaxResponseBody result = new AjaxResponseBody();
HttpHeaders headers = new HttpHeaders();
if (!file.isEmpty()) {
try {
Address address = new Address();
address.setName(name);
result.setMsg("ok");
return new ResponseEntity<AjaxResponseBody>(result, headers, HttpStatus.OK);
} catch (Exception e) {
return new ResponseEntity<AjaxResponseBody>(HttpStatus.BAD_REQUEST);
}
} else {
return new ResponseEntity<AjaxResponseBody>(HttpStatus.BAD_REQUEST);
}
}
Expept if you find a way your client app send a file with MimeType of image/jpg and and an address of application/json which allow spring to parse the json and map to your Address object which i couldn't do it.

Encoding for downloaded files in Spring

I want to create a controller which will sent to client a CSV file, and I created the next controller:
#ResponseStatus(value = HttpStatus.OK)
#RequestMapping(value = "/csv", method = RequestMethod.GET)
public ResponseEntity downloadCsvAllInvoiceTransactionsByFilter(
#PageableDefault(direction = DESC, sort = "invoiceDate", size = 30) Pageable pageRequest) throws IOException {
String someVariable = "Some text";
byte[] out = someVariable.getBytes(Charset.forName("UTF-8"));
HttpHeaders responseHeaders = new HttpHeaders();
LOGGER.info(new String(out));
responseHeaders.add("content-disposition", "attachment; filename=transactions.csv" );
responseHeaders.add("Content-Type","text/csv; charset=utf-8");
return new ResponseEntity<>(out,responseHeaders,HttpStatus.OK);
}
Logger is displaying the correct string:
Some text
but in downloaded file there is another one
U29tZSB0ZXh0
How can I fix this?
Body of ResponseEntity goes through a message converter before it gets sent. The choice of the particular converter depends on class of the body and response and request headers.
I tried to reproduce the issue with your code snippet and got expected text in csv file. So I assume that you got a message converter registered that converts byte arrays the way you observe.
You can debug AbstractMessageConverterMethodProcessor#writeWithMessageConverters and see which converter is chosen and why.

Resources