how return multivalued response - java

I'm currently writing a post API that gets a list of invoices number and then calls another API with resttamplate to obtain a pdf for every invoice number after that I concatenate all these pdf files to one file and return this file as a response, the problem here that there are invoices have an invalid invoice number so when I send this invoice number to the rest API can't get pdf so I want to get the failed invoices and send them back to the caller of my rest API, how to return pdf of the successful invoice and JSON object that contain a list of failed invoices number. Thanks in advance
that's my postApi
#PostMapping(value = "/gen-report")
public ResponseEntity<byte[]> generateReport(
#RequestHeader(value = HttpHeaders.AUTHORIZATION) String headerAuthorization) {
byte[] res = null;
List<String> failedInvoices = new ArrayList<>();
ResponseEntity<byte[]> response = null;
ArrayList<RequestParameters> requests = new ArrayList<>();
RequestParameters rp1 = new RequestParameters("360", "3600382368", "N");
RequestParameters rp2 = new RequestParameters("360", "3600382367", "N");
requests.add(rp1);
requests.add(rp2);
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
List<byte[]> responses = new ArrayList<>();
for (RequestParameters parameter : requests) {
MultiValueMap<String, String> map = mobileOrderReportService.genrateReportService(parameter);
HttpEntity<MultiValueMap<String, String>> entity = new HttpEntity<>(map, headers);
response = null;
byte[] content = null;
content = requestReportByInvoiceNumber(entity);
if (content != null) {
responses.add(content);
} else {
failedInvoices.add(parameter.getOrderNum());
}
}
try {
res = mergePDF(responses);
} catch (DocumentException ex) {
Logger.getLogger(MobileOrderReportController.class.getName()).log(Level.SEVERE, null, ex);
} catch (IOException ex) {
Logger.getLogger(MobileOrderReportController.class.getName()).log(Level.SEVERE, null, ex);
}
headers.setContentType(MediaType.parseMediaType("application/pdf"));
String filename = "pdf1.pdf";
headers.add("content-disposition", "inline;filename=" + filename);
headers.setCacheControl("must-revalidate, post-check=0, pre-check=0");
response = new ResponseEntity<byte[]>(res, headers, HttpStatus.OK);
return response;
}
this method returns the byte[] with the successful invoice or null with the failed invoice
public byte[] requestReportByInvoiceNumber(HttpEntity<MultiValueMap<String, String>> entity) {
RestTemplate restTemplate = new RestTemplate();
ResponseEntity<byte[]> response = null;
try {
response = restTemplate.exchange(mobileOrderReportService.getUrl(), HttpMethod.POST, entity,
byte[].class);
byte[] content = response.getBody();
return content;
} catch (RestClientException ex) {
logger.error("request to UReport failed in requestReportByInvoiceNumber method !...");
return null;
}
}
method merge pdf and return one pdf
public byte[] mergePDF(List<byte[]> pdfFilesAsByteArray) throws DocumentException, IOException {
ByteArrayOutputStream outStream = new ByteArrayOutputStream();
Document document = null;
PdfCopy writer = null;
for (byte[] pdfByteArray : pdfFilesAsByteArray) {
try {
PdfReader reader = new PdfReader(pdfByteArray);
int numberOfPages = reader.getNumberOfPages();
if (document == null) {
document = new Document(reader.getPageSizeWithRotation(1));
writer = new PdfCopy(document, outStream); // new
document.open();
}
PdfImportedPage page;
for (int i = 0; i < numberOfPages;) {
++i;
page = writer.getImportedPage(reader, i);
writer.addPage(page);
}
} catch (Exception e) {
e.printStackTrace();
}
}
document.close();
outStream.close();
return outStream.toByteArray();
}

You already tagged "Multipart", which could be a solution. You're currently not sending one but just a byte array i.e. a file. With a multipart response, you could indeed have multiple (or in your case 2) parts:
Part with the merged PDF
List of failed invoice numbers either as plain text, JSON, or however you would like to send it.
A multipart response looks like this https://www.w3.org/Protocols/rfc1341/7_2_Multipart.html (scroll down to the example)
An easier and "dirtier" way would be, to just include the faulty invoice numbers in your header response. You can define custom headers, so feel free to name it as you wish.
Either way, your client needs to be adapted, either by being able to read a multipart response (for which you need to write an HttpMessageConverter if your client isn't communicating reactively (Webflux)) or by reading the custom header.

Related

Why Multipart form "restream" from gateway microservice isn't working and attached file isn't resent?

I have a controller in gateway microservice that accepts the MultipartFile and resends to the service behind it
#PostMapping
public ResponseEntity upload(#ApiParam(name = "file", value = "File", required = true) MultipartFile file)
throws BaseException {
if (Objects.isNull(file)){
throw new CheckFieldException("file", MultipartFile.class);
}
if (megabyte * maxFileSize - file.getSize() < 0){
return ResponseEntity.accepted().body(new DocumentResponseDTO(false, "File size exceeds " + maxFileSize + "MB"));
}
DiscoveryConfig.CashTracking config = discoveryConfig.getCashTracking();
UriComponents uriStatementUpload = UriComponentsBuilder.newInstance().scheme(config.getScheme())
.host(config.getHost()).port(config.getPort()).path(config.getExcelNominalOperationsPath()).build(true);
try {
HttpEntity<byte[]> fileEntity = new HttpEntity(file.getBytes());
ResponseEntity<DocumentResponseDTO> entity = restTemplate.postForEntity(uriStatementUpload.toUri(), fileEntity, DocumentResponseDTO.class);
return entity;
} catch (HttpClientErrorException e) {
return ResponseEntity.status(e.getStatusCode()).body(e.getResponseBodyAsString());
} catch (IOException e) {
return ResponseEntity.status(500).body("IOException while getting bytes stream from file");
}
}
and in CashTracking service there is also file upload like that:
#PostMapping(value = "/upload")
public ResponseEntity uploadExcelNominalOperationsFile(#ApiParam(name = "file", value = "File", required = true) MultipartFile file) throws IOException {
try (InputStream is = file.getInputStream()) {
log.info("Processing incoming Excel file with nominal operations");
Workbook workbook = new XSSFWorkbook(is);
log.info("Processing workbook");
Sheet sheet = workbook.getSheetAt(0);
log.info("Processing the first sheet");
List<NominalOperationVO> nominalOperationVOs = new ArrayList<>();
List<String> fileHeaders = new ArrayList<>();
And when the file is actually uploaded to the gateway service, the service behind it starts processing the file upload, but the MultipartFile file is null. I have explicitly put it in the Entity I have sent to the service behind the gateway, the question, what I'm doing wrong if it is null? If I do upload to that microservice directly, it process the request correctly.
The main stuff I was missing was putting the Http headers per specific multipart form's parts. They should be identical to what has been sent to the gateway service.
public ResponseEntity upload(#ApiParam(name = "file", value = "Файл", required = true) MultipartFile file)
throws BaseException {
if (Objects.isNull(file)){
throw new CheckFieldException("file", MultipartFile.class);
}
if (megabyte * maxFileSize - file.getSize() < 0){
return ResponseEntity.accepted().body(new DocumentResponseDTO(false, "File size exceeds " + maxFileSize + "MB"));
}
DiscoveryConfig.CashTracking config = discoveryConfig.getCashTracking();
UriComponents uriStatementUpload = UriComponentsBuilder.newInstance().scheme(config.getScheme())
.host(config.getHost()).port(config.getPort()).path(config.getExcelNominalOperationsPath()).build(true);
try {
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.MULTIPART_FORM_DATA);
MultipartBodyBuilder multipartBodyBuilder = new MultipartBodyBuilder();
//here is the really needed stuff with 2 headers
Resource resource = new ByteArrayResource(file.getBytes());
multipartBodyBuilder.part("file", resource)
.header("Content-Type",file.getContentType())
.header("Content-Disposition","form-data; name=\"file\"; filename=\""+file.getOriginalFilename()+"\"");
// multipart/form-data request body
MultiValueMap<String, HttpEntity<?>> body = multipartBodyBuilder.build();
HttpEntity<MultiValueMap<String, HttpEntity<?>>> requestEntity
= new HttpEntity<>(body, headers);
ResponseEntity<DocumentResponseDTO> entity = restTemplate.postForEntity(uriStatementUpload.toUri(), requestEntity, DocumentResponseDTO.class);
return entity;
} catch (HttpClientErrorException e) {
return ResponseEntity.status(e.getStatusCode()).body(e.getResponseBodyAsString());
} catch (IOException e) {
return ResponseEntity.status(500).body("IOException while getting bytes stream from file");
}
}

Error while sending Video File from Java Spring Microservice to other Microservice on other port using Spring Rest Template

Right now I have 2 Spring App.
App A will have a controller that will receive a video file ad Multipart file and sending the file to App B via rest template.
Some Code from App A that handle sending request to App B.
#RestController
public class AppAController {
#Autowired
private final AppBService service;
#PostMapping("/sendToB")
public ResponseEntity<String> contoller(#RequestParam("file") MultipartFile file) {
String result = service.sendToB(file);
return new ResponseEntity<>(result, HttpStatus.OK);
}
}
#Service
public class AppBService {
public String sendToB(MultipartFile file) throws ResponseStatusException {
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.MULTIPART_FORM_DATA);
MultiValueMap<String, Object> body = new LinkedMultiValueMap<>();
body.add("file", file);
HttpEntity<MultiValueMap<String, Object>> requestEntity = new HttpEntity<>(body, headers);
String serverUrl = "http://127.0.0.1:8090/makeFrames";
RestTemplate restTemplate = new RestTemplate();
ResponseEntity<String> response = restTemplate.exchange(
serverUrl,
HttpMethod.POST,
requestEntity,
String.class
);
if (response.getStatusCode() != HttpStatus.OK) {
throw new ResponseStatusException(response.getStatusCode(), response.getBody());
}
return response.getBody();
}
}
And for App B, it will receive a video and extracting key frames from a video using JavaCV.
#RestController
public class ProcessorController {
#PostMapping("/makeFrames")
public ResponseEntity<String> framesExtractorController(#RequestParam("file") MultipartFile file) {
try {
File result = FramesExtractor.grabFrames(file);
return new ResponseEntity<>(result.getAbsolutePath(), HttpStatus.OK);
} catch (IOException e) {
return new ResponseEntity<>(e.getMessage(), HttpStatus.NOT_FOUND);
}
}
}
public class FramesExtractor {
private static final Logger LOG = LoggerFactory.getLogger(FramesExtractor.class);
private FramesExtractor() {
}
public static File grabFrames(MultipartFile video) throws IOException {
LOG.info("Extracting Frames from the video " + video.getName());
String directoryName = video.getOriginalFilename() + "-frames-result";
directoryAssurance(directoryName);
try (FFmpegFrameGrabber frameGrabber = new FFmpegFrameGrabber(video.getInputStream());
Java2DFrameConverter converter = new Java2DFrameConverter()) {
frameGrabber.setImageWidth(480);
frameGrabber.setImageHeight(360);
frameGrabber.start();
Frame frame;
int i = 0;
while ((frame = frameGrabber.grabKeyFrame()) != null) {
BufferedImage bi = converter.getBufferedImage(frame);
ImageIO.write(bi, "png", new File(directoryName + "/" + String.format("%03d", i) + ".png"));
i++;
}
frameGrabber.stop();
LOG.info("Finish Extracting Frames");
return new File(directoryName);
} catch (Exception e) {
LOG.error(e.getMessage());
throw e;
}
}
}
Both app A and B have these properties set to their application.properties files.
server.port={There respective port}
spring.servlet.multipart.enabled=true
spring.servlet.multipart.max-file-size=100MB
spring.servlet.multipart.max-request-size=100MB
And when i testing the application by using PostMan to send post request with video file in form-data body to App A /sendToB api i receive this error message.
"Type definition error: [simple type, class java.io.FileDescriptor]; nested exception is com.fasterxml.jackson.databind.exc.InvalidDefinitionException: No serializer found for class java.io.FileDescriptor and no properties discovered to create BeanSerializer (to avoid exception, disable SerializationFeature.FAIL_ON_EMPTY_BEANS) (through reference chain: org.springframework.web.multipart.support.StandardMultipartHttpServletRequest$StandardMultipartFile[\"inputStream\"]->java.io.FileInputStream[\"fd\"])"
So I want to ask what cause this problems and how I can fix it or sending video file to other Spring App running on other port properly.
I edited my previous answer because you can actually get parameters from a response body in a POST with #RequestParam annotation.
I would use JSON as content type. This is my solution:
public String sendToB(MultipartFile file) throws ResponseStatusException {
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
byte[] bytesFile = file.getBytes();
String base64String = Base64.getEncoder().encodeToString(bytesFile);
Map<String, Object> body = new HashMap<>();
body.put("file", base64String);
body.put("directoryName", file.getOriginalFilename());
body.put("videoName", file.getName())
HttpEntity<Map<String, Object>> requestEntity = new HttpEntity<>(body, headers);
String serverUrl = "http://127.0.0.1:8090/makeFrames";
RestTemplate restTemplate = new RestTemplate();
ResponseEntity<String> response = restTemplate.exchange(
serverUrl,
HttpMethod.POST,
requestEntity,
String.class
);
if (response.getStatusCode() != HttpStatus.OK) {
throw new ResponseStatusException(response.getStatusCode(), response.getBody());
}
return response.getBody();
}
For App B, the code would be:
#PostMapping("/makeFrames")
public ResponseEntity<String> framesExtractorController(#RequestBody Map<String, Object> requestBody) {
try {
String base64String = requestBody.get("file").toString();
byte[] bytesFile = Base64.getDecoder().decode(base64String);
InputStream inputStream = new ByteArrayInputStream(bytesFile);
String directoryName = requestBody.get("directoryName").toString();
String videoName = requestBody.get("videoName").toString();
File result = FramesExtractor.grabFrames(inputStream, directoryName, videoName);
return new ResponseEntity<>(result.getAbsolutePath(), HttpStatus.OK);
} catch (IOException e) {
return new ResponseEntity<>(e.getMessage(), HttpStatus.NOT_FOUND);
}
}
}
public static File grabFrames(InputStream inputStream, String directoryName, String videoName) throws IOException {
//Your code
}

Read attached PDF file using spring

I have a Get API by which can download PDF. Using Spring rest template I am able to get content but when I am creating PDF file it's creating a blank pdf.
I am using byte[] to create a new file.
RestTemplate restTemplate = new RestTemplate();
HttpHeaders headers = new HttpHeaders();
headers.setAccept(Arrays.asList(MediaType.APPLICATION_PDF));
HttpEntity<String> entity = new HttpEntity<>(headers);
ResponseEntity<String> result =
restTemplate.exchange(uri, HttpMethod.GET, entity, String.class);
String content = response.getBody();
byte[] bytes = content.getBytes();
Files.write(Paths.get("/home/123.pdf"), bytes, StandardOpenOption.CREATE );
Please suggest me anyway to do it, Finally my objective
to upload in S3.
Your request headers should also include MediaType.APPLICATION_OCTET_STREAM
This response object will return a byte array- which will be your pdf.
So, the complete example would be something like this-
RestTemplate restTemplate = new RestTemplate();
HttpHeaders headers = new HttpHeaders();
headers.setAccept(Arrays.asList(MediaType.APPLICATION_PDF, MediaType.APPLICATION_OCTET_STREAM));
HttpEntity<String> entity = new HttpEntity<>(headers);
ResponseEntity<byte[]> result =
restTemplate.exchange(uri, HttpMethod.GET, entity, byte[].class);
byte[] content = result.getBody();
Files.write(Paths.get("/home/123.pdf"), content, StandardOpenOption.CREATE );
Hope this helps.
You can Use PDFbox(or itext) API, which is a great way of parsing and creating PDF. It will allow you to place your text etc,
That said
public static void writeToFIle(InputStream uploadedInputStream, String uploadedFileLocation) {
try {
OutputStream out = new FileOutputStream(new File(uploadedFileLocation));
int read = 0;
byte[] bytes = new byte[1024];
out = new FileOutputStream(new File(uploadedFileLocation));
while ((read = uploadedInputStream.read(bytes)) != -1) {
out.write(bytes, 0, read);
}
out.flush();
out.close();
} catch (IOException e) {
e.printStackTrace();
}
}
should be enough to create a PDF, if its blank check if the value arn't null
I personnaly use jersey to link client and server so i cant really tell you if your method to get the pdf works

Download large file through Spring rest template

Server Code :
#POST
#Path("reportDownload")
#Consumes(MediaType.APPLICATION_JSON)
public Response generateReport(QueryData queryData) {
File file = new File("report.xlsx") // large file
StreamingOutput stream = new FileStreamingOutput(file) ;
return Response.ok(stream, MediaType.APPLICATION_OCTET_STREAM)
.header("filename" , file.getName())
.build();
}
Client Code :
Using the following code I'm able to download files upto some limit. Getting out of memory heap error for large files.
final String uri = buildUri("/reportGenerate/reportDownload");
HttpComponentsClientHttpRequestFactory factory = new HttpComponentsClientHttpRequestFactory();
factory.setReadTimeout(read_timeout);
factory.setConnectTimeout(connection_timeout);
RestTemplate restTemplate = new RestTemplate(factory);
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
List<MediaType> mediaTypeList = new ArrayList<>();
mediaTypeList.add(MediaType.APPLICATION_OCTET_STREAM);
headers.setAccept(mediaTypeList);
HttpEntity entity = new HttpEntity(queryData, headers);
ResponseEntity<byte[]> data = restTemplate.exchange(uri, HttpMethod.POST, entity, byte[].class);
HttpHeaders responseHeader = data.getHeaders();
String fileName = (String) responseHeader.get("filename").get(0);
String downloadFolder = ApplicationConfig.REPORT_DOWNLOAD_FOLDER.getValue();
if (data.getStatusCode() == HttpStatus.OK) {
FileOutputStream fos = null;
File toFile = null;
try {
toFile = new File(downloadFolder + File.separator + fileName);
fos = new FileOutputStream(toFile);
ByteArrayOutputStream bos = new ByteArrayOutputStream();
IOUtils.write(data.getBody(), bos);
bos.writeTo(fos);
} catch (Exception e) {
convertReportException(e);
} finally {
if (fos != null) {
try {
fos.close();
} catch (IOException ex) {
convertReportException(ex);
}
}
return toFile;
}
}
How to use stream for download larger files.
Here is how I do it with a ResponseExtractor. Based on hints from this Spring Jira issue.
RestTemplate restTemplate // = ...;
// Optional Accept header
RequestCallback requestCallback = request -> request.getHeaders()
.setAccept(Arrays.asList(MediaType.APPLICATION_OCTET_STREAM, MediaType.ALL));
// Streams the response instead of loading it all in memory
ResponseExtractor<Void> responseExtractor = response -> {
// Here I write the response to a file but do what you like
Path path = Paths.get("some/path");
Files.copy(response.getBody(), path);
return null;
};
restTemplate.execute(URI.create("www.something.com"), HttpMethod.GET, requestCallback, responseExtractor);
update
Here is what RestTemplate does behind the scenes on postForObject and friends (inline comments from me):
#Override
public <T> T postForObject(String url, Object request, Class<T> responseType, Map<String, ?> uriVariables)
throws RestClientException {
// From RequestCallback's javadoc:
// Callback interface for code that operates on a ClientHttpRequest.
// Allows to manipulate the request headers, and write to the request body.
//
// Used internally by the RestTemplate, but also useful for application code.
RequestCallback requestCallback = httpEntityCallback(request, responseType);
// HttpMessageConverterExtractor checks the response type header and requested
// responseType class to select the proper message converter to handle the response.
// It also implements ResponseExtractor.
HttpMessageConverterExtractor<T> responseExtractor =
new HttpMessageConverterExtractor<T>(responseType, getMessageConverters(), logger);
return execute(url, HttpMethod.POST, requestCallback, responseExtractor, uriVariables);
}
/**
* Returns a request callback implementation that writes the given object to the
* request stream.
*/
protected <T> RequestCallback httpEntityCallback(Object requestBody, Type responseType) {
return new HttpEntityRequestCallback(requestBody, responseType);
}
Note: This is essentially a duplicate of my answer at https://stackoverflow.com/a/38664475/1030527 but I can't mark the questions as duplicate since neither this one or that one have upvoted answers.
At the client that you mentioned
don't store the file in memory to download a large via the RestTemplate, it can cause the Java heap exception.
it should be stored on disk.
Here is some code sample to download a large file via the RestTemplate
#GetMapping("largeFile")
public ResponseEntity<InputStreamResource> downloadLargeFile(
#RequestParam("fileName") String fileName
) throws IOException {
RestTemplate restTemplate = new RestTemplate();
// Optional Accept header
RequestCallback requestCallback = request -> request.getHeaders()
.setAccept(Arrays.asList(MediaType.APPLICATION_OCTET_STREAM, MediaType.ALL));
// Streams the response instead of loading it all in memory
ResponseExtractor<InputStreamResource> responseExtractor = response -> {
// Here I write the response to a file but do what you like
Path path = Paths.get("tmp/" + fileName);
Files.copy(response.getBody(), path, StandardCopyOption.REPLACE_EXISTING);
return new InputStreamResource(new FileInputStream(String.format("tmp/%s", fileName)));
};
InputStreamResource response = restTemplate.execute(
String.format("http://%s:%s/file/largeFileRestTemplate?fileName=%s", host, "9091", fileName),
HttpMethod.GET,
requestCallback,
responseExtractor
);
return ResponseEntity
.ok()
.header(HttpHeaders.CONTENT_DISPOSITION, String.format("attachment; filename=%s", fileName))
.body(response);
}

How to get multipartentity from httpservletrequest

I am trying to invoke a webservice from java spring controller. Below is the code
private void storeImages(MultipartHttpServletRequest multipartRequest) {
DefaultHttpClient httpClient = new DefaultHttpClient();
HttpPost postRequest = new HttpPost(
"http://localhost:8080/dream/storeimages.htm");
MultipartFile multipartFile1 = multipartRequest.getFile("file1");
MultipartEntity multipartEntity = new MultipartEntity(
HttpMultipartMode.BROWSER_COMPATIBLE);
multipartEntity.addPart("file1",
new ByteArrayBody(multipartFile1.getBytes(),
multipartFile1.getContentType(),
multipartFile1.getOriginalFilename()));
postRequest.setEntity(multipartEntity);
HttpResponse response = httpClient.execute(postRequest);
if (response.getStatusLine().getStatusCode() != 201) {
throw new RuntimeException("Failed : HTTP error code : "
+ response.getStatusLine().getStatusCode());
}
}
Above is just partial code. I am trying to determine how to retrieve this on the server side. On the server side i have the following Spring controller code
#RequestMapping(value = "/storeimages.htm", method = RequestMethod.POST)
public ModelAndView postItem(HttpServletRequest request,
HttpServletResponse response) {
logger.info("Inside /secure/additem/postitem.htm");
try {
// How to get the MultipartEntity object here. More specifically i
// want to get back the Byte array from it
} catch (Exception ex) {
ex.printStackTrace();
}
return new ModelAndView("success");
}
I executed this code and my control is going to the server side. But i am stuck on how to get back the byte array from the multipartentity object.
Edited requirement:
Here is the requirement. User uploads the images from website (This is done and working) The control goes to the Spring controller after form submit (This is done and working) In Spring controller I am using Multipart to get the content of the form. (This is done and working) Now i want to call a webservices which will send the image byte array to image server.(This needs to be done) On the image server, i want to receive this webservice request get all the fields from HTTPServlerRequest, store the images and return(This needs to be done)
Finally resolved it. Here is what worked for me.
Client side
private void storeImages(HashMap<String, MultipartFile> imageList) {
try {
DefaultHttpClient httpClient = new DefaultHttpClient();
HttpPost postRequest = new HttpPost("http://localhost:8080/dream/storeimages.htm");
MultipartEntity multipartEntity = new MultipartEntity(HttpMultipartMode.BROWSER_COMPATIBLE);
Set set = imageList.entrySet();
Iterator i = set.iterator();
while(i.hasNext()) {
Map.Entry me = (Map.Entry)i.next();
String fileName = (String)me.getKey();
MultipartFile multipartFile = (MultipartFile)me.getValue();
multipartEntity.addPart(fileName, new ByteArrayBody(multipartFile.getBytes(),
multipartFile.getContentType(), multipartFile.getOriginalFilename()));
}
postRequest.setEntity(multipartEntity);
HttpResponse response = httpClient.execute(postRequest);
if (response.getStatusLine().getStatusCode() != 200) {
throw new RuntimeException("Failed : HTTP error code : "
+ response.getStatusLine().getStatusCode());
}
BufferedReader br = new BufferedReader(new InputStreamReader((response.getEntity().getContent())));
String output;
while ((output = br.readLine()) != null) {
logger.info("Webservices output - " + output);
}
httpClient.getConnectionManager().shutdown();
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
Server side
#RequestMapping(value = "/storeimages.htm", method = RequestMethod.POST)
public void storeimages(HttpServletRequest request, HttpServletResponse response)
{
logger.info("Inside /secure/additem/postitem.htm");
try
{
//List<Part> formData = new ArrayList(request.getParts());
//Part part = formData.get(0);
//Part part = request.getPart("file1");
//String parameterName = part.getName();
//logger.info("STORC IMAGES - " + parameterName);
MultipartHttpServletRequest multipartRequest = (MultipartHttpServletRequest) request;
Set set = multipartRequest.getFileMap().entrySet();
Iterator i = set.iterator();
while(i.hasNext()) {
Map.Entry me = (Map.Entry)i.next();
String fileName = (String)me.getKey();
MultipartFile multipartFile = (MultipartFile)me.getValue();
logger.info("Original fileName - " + multipartFile.getOriginalFilename());
logger.info("fileName - " + fileName);
writeToDisk(fileName, multipartFile);
}
}
catch(Exception ex)
{
ex.printStackTrace();
}
}
public void writeToDisk(String filename, MultipartFile multipartFile)
{
try
{
String fullFileName = Configuration.getProperty("ImageDirectory") + filename;
FileOutputStream fos = new FileOutputStream(fullFileName);
fos.write(multipartFile.getBytes());
fos.close();
}
catch (Exception ex)
{
ex.printStackTrace();
}
}
In my project, we used to use MultipartParser from com.oreilly.servlets to handle HttpServletRequests corresponding to multipart requests, as follows:
// Should be able to handle multipart requests upto 1GB size.
MultipartParser parser = new MultipartParser(aReq, 1024 * 1024 * 1024);
// If the content type is not multipart/form-data, this will be null.
if (parser != null) {
Part part;
while ((part = parser.readNextPart()) != null) {
if (part instanceof FilePart) {
// This is an attachment or an uploaded file.
}
else if (part instanceof ParamPart) {
// This is request parameter from the query string
}
}
}
Hope this helps.
Instead of doing all that by hand, you can use Springs Mutlipart support
The controller can work like this (This example use a command object to store additional user inputs -- (this is an example from an working project)).
#RequestMapping(method = RequestMethod.POST)
public ModelAndView create(#Valid final DocumentCreateCommand documentCreateCommand,
final BindingResult bindingResult) throws IOException {
if (bindingResult.hasErrors()) {
return new ModelAndView("documents/create", "documentCreateCommand", documentCreateCommand);
} else {
Document document = this.documentService.storeDocument(
documentCreateCommand.getContent().getBytes(),
StringUtils.getFilename(StringUtils.cleanPath(documentCreateCommand.getContent().getOriginalFilename())));
//org.springframework.util.StringUtils
return redirectToShow(document);
}
}
#ScriptAssert(script = "_this.content.size>0", lang = "javascript", message = "{validation.Document.message.notDefined}")
public class DocumentCreateCommand {
#NotNull private org.springframework.web.multipart.MultipartFile content;
Getter/Setter
}
To enable Spring Multipart support you need to configure some stuff:
web.xml (Add org.springframework.web.multipart.support.MultipartFilter after CharacterEncodingFilter and before HttpMethodFilter)
<filter>
<filter-name>MultipartFilter</filter-name>
<filter-class>org.springframework.web.multipart.support.MultipartFilter</filter-class>
<!-- uses the bean: filterMultipartResolver -->
</filter>
<filter-mapping>
<filter-name>MultipartFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
In your Spring Configuration for the CORE (not MVC Servlet) of your application add this
<!-- allows for integration of file upload functionality, used by an filter configured in the web.xml -->
<bean class="org.springframework.web.multipart.commons.CommonsMultipartResolver" id="filterMultipartResolver" name="filterMultipartResolver">
<property name="maxUploadSize" value="100000000"/>
</bean>
Then you also need the commons fileupload libary, because the Spring MultipartFile is just some kind of Addapter
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>1.2.1</version>
</dependency>
For some more Details:
#See Spring Reference, Chapter 15.8 Spring's multipart (fileupload) support
to deal with spring files to the controller. you need to indicate, in your app-config.xml as follows:
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver"/>
and treat code as follows
MultipartEntityBuilder paramsBuilder = MultipartEntityBuilder.create();
Charset chars = Charset.forName("UTF-8");
paramsBuilder.setCharset(chars);
if (null != obj.getFile()){
FileBody fb = new FileBody(obj.getFile());
paramsBuilder.addPart("file", fb);
}
and this for red multipart
private File getFile(MultipartFile file) {
try {
File fichero = new File(file.getOriginalFilename());
fichero.createNewFile();
FileOutputStream fos = new FileOutputStream(fichero);
fos.write(file.getBytes());
fos.close();
return fichero;
} catch (Exception e) {
return null;
}
}
I hope this helps.

Categories

Resources