Upload file to Jersey web services with spring MultipartFile - java

I have a 3 step process to upload a file on a server:
Using EXT.JS form, I upload a file to a controler.
In the controler, the method gets the MultipartFile, builds a rest call using rest template and send it to the server.
On the server, the specified method should receive the multipart data and process the file.
Here is the method at the step 2 that get the file from the UI side (EXT.JS):
#RequestMapping("/customerUploadFile/upload")
#ResponseBody
public JsonResponse uploadFile(CustomerUploadBean bean,
#RequestParam("filePath") MultipartFile filePath) throws IOException {
long fileSize = filePath.getSize();
HttpEntity<CustomerUploadBean> httpEntity = getHttpEntity(bean);
byte[] byteArr = filePath.getBytes();
MultiValueMap<String, Object> parameters = new LinkedMultiValueMap<String, Object>();
parameters.add("userId", httpEntity.getHeaders().get("userId"));
parameters.add("file", byteArr);
// to set content type of header
org.springframework.http.HttpHeaders headers = new org.springframework.http.HttpHeaders();
headers.setContentType(MediaType.MULTIPART_FORM_DATA);
RestTemplate restTemplate = new RestTemplate();
ResponseEntity<JsonResponse> jsonResponse = restTemplate.exchange(uri, HttpMethod.POST,
new HttpEntity<MultiValueMap<String, Object>>(parameters, headers),
new ParameterizedTypeReference<JsonResponse>() {
});
JsonResponse response = jsonResponse.getBody();
if (jsonResponse.getStatusCode() == HttpStatus.OK) {
response.setSuccess(true);
} else {
response.setSuccess(false);
}
return response;
}
I've verified, the filePath object have the file and contains information about the file.
At the step 3, here is the method in the controller on the server that awaits for the file to process it:
public Response importUserProfileCSV(
#ApiParam(value = "Service Name", required = true) #PathParam("service") String service,
#ApiParam(value = "CSV file to upload.", required = true) #FormDataParam("file") InputStream uploadedInputStream,
#ApiParam(value = "CSV file detail", required = true) #FormDataParam("file") FormDataContentDisposition fileDetail) {
return delegate.importUserProfileCSV(uploadedInputStream, fileDetail,
service, "user");
}
The problem here is that at the step 3, in the method right above, the fileDetail object contains only null values... How can I adapt the method of step 2 (spring framework) to the method of step 3 (jersey).

Related

When trying to invoke a rest api to upload multipart file Getting error No serializer found for class java.io.ByteArrayInputStream?

I am trying to consume a rest api to upload a Multipart file. I have set MultipartFile in UploadFIleObject and I am sending the same to rest api. However when trying to invoke a rest API as below, I am getting error No serializer found for class java.io.ByteArrayInputStream
public class UploadFileObject implements Serializable{
MultipartFile file;
//getters and setters
}
public void uploadFile() {
Path path = Paths.get("C:/Accounts.txt");
byte[] content = null;
try{
content = Files.readAllBytes(path);
} catch(final IOException e){
}
MultipartFile file = new MockMultipartFile("ABC.txt","ABC.txt","text/plain", content);
UploadFileObject obj = new UploadFileObject();
obj.setFile(file)
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.MULTIPART_FORM_DATA);
headers.set(MediaType.MULTIPART_FORM_DATA);
headers.setContentType("Accept", Mediatype.APPLICATION_JSON_VALUE);
headers.setContentType("Content-type", Mediatype.APPLICATION_JSON_VALUE);
HttpEntity<?> requestEntity = new HttpEntity<>(obj, headers);
String result = getRestTemplate().postForEntity("url", requestEntity, String.class);
}
in application.yml
I have set
spring.serialization.fail-on-empty-beans: false
and in pom.xml I have below of version 2.12.3
jackson-annotation
jackson-core
jackson-databind
jackson-dataformat
jackson-dataformat-xml
}

Rest template read response as stream and pass to spring controller(Get InputStream with rest Template)

I have a url which download the large size zip file.It returns the response as stream.though file size is large first it returns 200(HTTPSTATUK.OK) and continues download.
I have to implement a new spring controller which call the above url through rest template.I have to read the response returned by rest template and pass to controller.initially I have implemented in below way
#GetMapping("/export/downloadFile")
public ResponseEntity<byte[]> downloadData(Model model,
#ModelAttribute(EXCEPTION_COLLECTOR) ExceptionCollector exceptionCollector,
#RequestParam("userName") String userName,
#RequestParam("startDate") Date startDate,
#RequestParam("endDate") Date endDate,
#RequestParam("reason") String reason) {
URI uri = /building url here/;
return restTemplate.exchange(uri, HttpMethod.GET, new HttpEntity<>(httpHeaders), byte[].class);
}
since I am using ResponseEntity<byte[]> , rest template waits till entire file loaded into memory.so very frequently I am getting socket timeout issue.
Do we have way to read the response as stream and return to controller.
I found few things about restTemplate.execute .
restTemplate.execute(uri,HttpMethod.GET,requestCallBack,clientHttpResponse -> {
File ret = File.createTempFile("download", ".zip",new File("/Users/bokkavijay/Desktop"));
StreamUtils.copy(clientHttpResponse.getBody(), new FileOutputStream(ret));
return ret;
});
above snippet can copy the file to our local with out time out but this is not what I need.
how can we pipe the stream in clientHttpResponse to controller ?
I found the working implementation
Controller
#GetMapping("/readResponseAsStream")
public ResponseEntity<StreamingResponseBody> downloadAsStream(Model model,HttpServletResponse response) {
HttpHeaders httpHeaders=new HttpHeaders();
httpHeaders.add("Transfer-Encoding","chunked");
httpHeaders.add("Content-Type","x-zip-compressed");
httpHeaders.add("Content-Disposition", "attachment;filename=sample.zip");
ServletOutputStream servletOutputStream=response.getOutputStream();
StreamingResponseBody downloadFile = out -> {
RequestCallback requestCallBack=request->{
request.getHeaders().add(//Add headers here);
};
ResponseExtractor<ServletOutputStream> responseExtractor = clientHttpResponse -> {
//code snippet if you want to write response stream to HttpServletResponse
byte[] buff = new byte[800000];
int bytesRead = 0;
while ((bytesRead = clientHttpResponse.getBody().read(buff)) != -1) {
servletOutputStream.write(buff, 0, bytesRead);
}
return servletOutputStream;
//Incase if you want to copy file to you local
File ret = File.createTempFile("download", ".zip",new File("Add Local system directory address here"));
StreamUtils.copy(clientHttpResponse.getBody(), new FileOutputStream(ret));
//You can copy the the clientHttpResponse.getBody() to ByteArrayInputStream and return
// Don't return clientHttpResponse.getBody() directly because rest template will close the inputStream(clientHttpResponse.getBody()) after .execute completed
//if you want to write restTemplate.execute in dao layer , pass servletOutputStream as a argument to method
};
restTemplate.execute(URL_ADDRESS,HttpMethod.GET,requestCallBack,responseExtractor);
};
return new ResponseEntity(downloadFile,httpHeaders,HttpStatus.OK);
}
If you write the response directly to HttpServletResponse , controller download the file when we access in browser

Sending Multipart files with RestTemplate

I have two servers, where server A is sending files to server B. On server B i have an endpoint which recieves files of given category. This is signature of endpoint i need to send files to:
#PostMapping("/uploadMultipleFiles/{projectId}")
public List<UploadFileResponseDts> uploadMultipleFiles(#RequestParam("files") MultipartFile[] files, #RequestParam("categoryId") Long categoryId, #PathVariable("projectId") Long projectId) {
return uploadMulitpleFiles(files, categoryId, projectId);
}
Now im having trouble creating such request with RestTemplate exchange. On Server A i'm trying to send files one by one (endpoint on server B needs to accept multipart array since its used somewhere else as well). This is what i tried:
public Optional<String> uploadFile(File file, Long projectId) throws Exception {
String authToken = getAccessToken();
String projectFileUploadEndpoint = fileUploadEndpoint + SEPARATOR + projectId;
FileInputStream input = new FileInputStream(file);
byte[] bytes = IOUtils.toByteArray(input);
MultiValueMap<String, Object> parts =
new LinkedMultiValueMap<>();
parts.add("files", new ByteArrayResource(bytes));
parts.add("categoryId", 0L);
RestTemplate restTemplate = new RestTemplate();
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.MULTIPART_FORM_DATA);
headers.set("Authorization", authToken);
HttpEntity<MultiValueMap<String, Object>> requestEntity =
new HttpEntity<>(parts, headers);
ResponseEntity<String> response =
restTemplate.exchange(projectFileUploadEndpoint ,
HttpMethod.POST, requestEntity, String.class);
return Optional.empty();
}
this almost works, the only issue is that on server B files from #RequestParam("files") MultipartFile[] files is always null. I assume that the issue is with the way im assembling parts in on my server A, however i cant find my mistake. Could you point it out?
in your controller all is fine, the problem is about your client code.
Basically you should use FileSystemResource object instead of ByteArrayResource.
The basic motivation is about file metadata. Using FileSystemResource spring is able to rebuild the required MultipartFile info, therefore the your code may be like below
#Test
public void contextLoads()
{
File file = new File("test.txt");
FileSystemResource fileSystemResource = new FileSystemResource(file);
MultiValueMap<String, Object> parts = new LinkedMultiValueMap<>();
parts.add("categoryId", 0L);
parts.add("files", fileSystemResource);
String serviceUrl = "http://localhost:8080/uploadMultipleFiles/0";
RequestEntity<MultiValueMap<String, Object>> requestEntity = post(fromPath(serviceUrl).build().toUri())
.contentType(MediaType.MULTIPART_FORM_DATA)
.body(parts);
RestTemplate restTemplate = new RestTemplate();
restTemplate.setErrorHandler(new ResponseErrorHandler()
{
#Override
public boolean hasError(ClientHttpResponse response) throws IOException
{
return false;
}
#Override
public void handleError(ClientHttpResponse response) throws IOException
{
System.out.println(response);
}
});
ResponseEntity<String> response = restTemplate.exchange(serviceUrl, HttpMethod.POST, requestEntity, String.class);
assertThat(200, Is.is(response.getStatusCode()));
}
I hope that this test case can help you to solve the problem

Multipart files http request with Spring Rest Template arrives without the files

I have this client for sending multipart file http requests with Rest Template
#Component
public class RestTemplatePost {
#Bean
public RestTemplate restTemplate() {
return new RestTemplate();
}
#PostConstruct
public void prepareMessage() throws Exception {
File file = new File("****");
File file2 = new File("****");
HttpHeaders httpHeaders = new HttpHeaders();
httpHeaders.setContentType(MediaType.MULTIPART_FORM_DATA);
MultiValueMap<String, Object> form = new LinkedMultiValueMap<>();
form.add("files", file);
form.add("files", file2);
form.add("usertoken", "test");
form.add("sendTo", "test);
form.add("subject", "test");
form.add("content", "test");
HttpEntity<MultiValueMap<String, Object>> requestEntity = new HttpEntity<>(form, httpHeaders);
String serverUrl = "http://localhost:8080/api/mails/send";
List<HttpMessageConverter<?>> httpMessageConverters = new ArrayList<>();
httpMessageConverters.add(new FormHttpMessageConverter());
httpMessageConverters.add(new MappingJackson2HttpMessageConverter());
restTemplate().setMessageConverters(httpMessageConverters);
restTemplate().postForEntity(serverUrl, requestEntity, String.class);
}
}
Then I have this server side that should receive the request:
#RestController
#RequestMapping("/api")
public class MainConroller {
private static final Logger log = LoggerFactory.getLogger(MainConroller.class);
#Autowired
private MainService mainService;
public MainConroller(MainService mainService) {
this.mainService = mainService;
}
#PostMapping("/mails/send")
public void send(
#RequestParam("usertoken") String usertoken,
#RequestParam("sendTo") String sendTo,
#RequestParam("subject") String subject,
#RequestParam("content") String content,
#RequestParam(required = false, name = "files") List<MultipartFile> multipartFiles) {
log.debug("{}, {}, {}, {}", usertoken, sendTo, subject, content);
mainService.processMessage(usertoken, sendTo, subject, content, multipartFiles);
}
}
When I send this request from the client side, everything arrives on the server side except the files.
The RequestParam files is empty after receiving the request.
Update
Message converters explicitly removed as recommended, nothing changed.
No files are sent because there is no HttpMessageConverter capable of converting a java.io.File.
On the other hand, there is a ResourceHttpMessageConverter which converts all kinds of Resource, including FileSystemResource.
PS FormHttpMessageConverter is added by default when RestTemplate is created and FormHttpMessageConverter also uses it under the hood.

How to pass raw XML into RESTTemplate POST or PUT method without converting it?

I am trying to update or create xml file if not present. Then I use code below to send the file using PUT method of a service.
public void importClusterProperties(RestManPropertyHolder propertyHolder,File file,String id) throws RestManServiceException {
testRestTemplate = new TestRestTemplate(propertyHolder.getSbusUserName(), propertyHolder.getSbusUserPassword());
String sbusUrl = utils.prepareGatewayURI(propertyHolder);
try {
HttpHeaders requestHeaders = new HttpHeaders();
List <MediaType> mediaTypeList = new ArrayList<MediaType>();
mediaTypeList.add(MediaType.APPLICATION_ATOM_XML);
requestHeaders.setAccept(mediaTypeList);
requestHeaders.setContentType(MediaType.APPLICATION_ATOM_XML);
HttpEntity<String> requestEntity = new HttpEntity<String>(requestHeaders);
// Create the HTTP PUT request,
ResponseEntity<String> response = testRestTemplate.exchange(sbusUrl + "/clusterproperty?",HttpMethod.PUT, requestEntity,String.class);
if (null != response) {
System.out.println("RESPONSE::" + response.toString());
}
} catch (RestClientException rce) {
System.out.println("REST EXCEPTION:::" + rce.getMessage());
}
}
How to pass raw xml file into RestTemplate without converting it first into a java object?
enter image description here
Convert file to byte array and send it using ByteArrayHttpMessageConverter.
RestTemplate restTemplate = new RestTemplate();
// Add ByteArrayHttpMessageConverter if not present by default.
restTemplate.getMessageConverters().add(
new ByteArrayHttpMessageConverter());
String fileName = "path + file name";
// FileUtils is from Apache Commons IO
// import org.apache.commons.io.FileUtils;
byte[] requestBody = FileUtils.readFileToByteArray(new File(fileName));
HttpEntity<byte[]> requestEntity = new HttpEntity<byte[]>(requestBody , requestHeaders);
// Create the HTTP PUT request,
ResponseEntity<byte[]> response =
restTemplate.exchange("URL ...." , HttpMethod.PUT ,
requestEntity , byte[].class);

Categories

Resources