FileSystemResource to MultipartFile - spring

I want to send my image from my storage using the path like this:
MultiValueMap<String, Object> image = new LinkedMultiValueMap<String, Object>();
image.add("image", new FileSystemResource("C:\\xx\\xx\\xx\\xx\\xx\\xx\\xx\\img\\xx.jpg"));
so I call the object using the code below:
MultiValueMap<String, Object> body = new LinkedMultiValueMap<String,Object>();
body.add("image", image);
Then, I get this error:
Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is org.springframework.http.converter.HttpMessageConversionException: Type definition error: [simple type, class sun.nio.ch.ChannelInputStream]; nested exception is com.fasterxml.jackson.databind.exc.InvalidDefinitionException: No serializer found for class sun.nio.ch.ChannelInputStream and no properties discovered to create BeanSerializer (to avoid exception, disable SerializationFeature.FAIL_ON_EMPTY_BEANS) (through reference chain: org.springframework.util.LinkedMultiValueMap["image"]->java.util.LinkedList[0]->org.springframework.core.io.FileSystemResource["inputStream"])] with root cause
com.fasterxml.jackson.databind.exc.InvalidDefinitionException: No serializer found for class sun.nio.ch.ChannelInputStream and no properties discovered to create BeanSerializer (to avoid exception, disable SerializationFeature.FAIL_ON_EMPTY_BEANS) (through reference chain: org.springframework.util.LinkedMultiValueMap["image"]->java.util.LinkedList[0]->org.springframework.core.io.FileSystemResource["inputStream"])
I am using the Rest Template of spring boot, which requires me to send by POST Method the MultipartFile object. Now, I do not know how to convert into the MultipartFile type,
so the Rest Template can accept my request post.
Note: I want to use the body.add("image", image.getResource()); but It did not show up in selection since image wasn't of MultipartFile type.

This worked for me.
#GetMapping(path = "/copy", produces = MediaType.TEXT_PLAIN_VALUE)
public ResponseEntity<String> copyFile() {
MultiValueMap<String, Object> body
= new LinkedMultiValueMap<>();
body.add("image", new FileSystemResource("test.jpg"));
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.MULTIPART_FORM_DATA);
HttpEntity<MultiValueMap<String, Object>> requestEntity
= new HttpEntity<>(body, headers);
String serverUrl = "http://localhost:8080/upload";
RestTemplate restTemplate = new RestTemplate();
ResponseEntity<String> response = restTemplate
.postForEntity(serverUrl, requestEntity, String.class);
return response;
}
#PostMapping(path = "/upload", produces = MediaType.TEXT_PLAIN_VALUE)
public String uploadFile(#RequestParam("image") MultipartFile file) {
try {
byte[] bytes = file.getBytes();
Path path = Paths.get("./uploadedImages/" + file.getOriginalFilename());
Files.write(path, bytes);
} catch (IOException e) {
e.printStackTrace();
return "Error";
}
return "File Uploaded";
}

Related

When trying to invoke rest API throws httpmediatypenotsupportedexception content type 'application/x-www-form-urlencoded' not supported

I am trying to invoke rest API below which consumes a multi-part file. First paramter is a MultipartFile and second is s String. and this functions processes some business logic
#PostMapping( value="/uploadFile", consumes = MediaType.MULTIPART_FORM_DATE_VALUE)
public ResponseEntity<String> upload(#RequestPart("file") MultipartFile file,
#RequestParam("path") String path){
//businness logic
}
Invoking above API from code below. But it throws
httpmediatypenotsupportedexception content type
'application/x-www-form-urlencoded' not supported. I have also tried
added header "Content-type", MediaType.MULTIPART_FORM_DATA_VALUE OR
"Content-Type", "multipart/form-data" OR "Accept",
"multipart/form-data" in the headers below, but that has not helped
either
public void uploadFile() {
Path path = Paths.get("C:/ABC.txt");
byte[] content = null;
try{
content = Files.readAllBytes(path); // All file is read in content variable
} catch(final IOException e){
}
MultipartFile file = new MockMultipartFile("ABC.txt",content);
UriComponentsBuilder urlBuilder = UriComponentsBuilder.fromHttpUrl(oauthURL);
urlBuilder.queryParam("file", file);
urlBuilder.queryParam("path", "/temp);
HttpHeaders headers = new HttpHeaders();
HttpEntity<String> response = null;
HttpEntity<?> entity = new HttpEntity<>(headers);
try{
response = restTemplate.exchange(urlBuilder.build().encode().toUri(), HttpMethod.POST, entity. String.class);
}
catch (Exception e){
}
}
}
Your server accepts (consumes) "multipart/form-data" however you are sending the file and path in the URL. This will always result in a "application/x-www-form-urlencoded".
So you need to change the server to accept it as you send them or send the file and path as the body (within the entity)
EDIT (some code to show how):
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.MULTIPART_FORM_DATA);
MultiValueMap<String, Object> body = new LinkedMultiValueMap<>();
body.add("file", file);
body.add("path","/temp");
HttpEntity<MultiValueMap<String, Object>> requestEntity = new HttpEntity<>(body, headers);
response = restTemplate.postForEntity(serverUrl, requestEntity, String.class);

HttpClientErrorException$BadRequest: 400 : [no body] when calling restTemplate.postForObject

I am calling a POST service getOrder3 written in SpringBoot which is working fine (tested in Postman), but getting error when called via restTemplate.postForObject from another service. I tried 2 versions of the client service getOrderClient and getOrderClient2, but both are giving same error :
HttpClientErrorException$BadRequest: 400 : [no body]
Please find the details below. Any help is appreciated.
getOrder3
#PostMapping(value="/getOrder3/{month}",produces="application/json")
public ResponseEntity<OrderResponse> getOrder3(
#PathVariable("month") String month,
#RequestParam String parmRequestSource,
#RequestParam(required=false) String parmAudienceType,
#RequestBody OrderRequestForm orderRequestForm) {
OrderResponse orderResponse = new OrderResponse();
log.info("In getOrder3...parmRequestSource = " + parmRequestSource + " parmAudienceType = " + parmAudienceType);
try {
//validate JSON schema
//orderService.validateMessageAgainstJSONSchema(orderRequestForm);
//process order
orderResponse = orderService.processOrder(orderRequestForm);
orderResponse.setParmRequestSource(parmRequestSource);
orderResponse.setParmAudienceType(parmAudienceType);
orderResponse.setMonth(month);
}catch (Exception e) {
throw new OrderException("101", e.getMessage(), HttpStatus.BAD_REQUEST);
}
return new ResponseEntity<>(orderResponse,HttpStatus.OK);
}
The service is working fine , tested in postman
Now when I try to call via another microservice via restTemplate.postForObject, I get the error. Tried 2 versions of the client as below, getOrderClient and getOrderClient2
getOrderClient
#PostMapping(value="/getOrderClient/{month}",produces="application/json")
public OrderResponse getOrderClient(
#PathVariable("month") String month,
#RequestParam String parmRequestSource,
#RequestParam String parmAudienceType,
#RequestBody OrderRequestForm orderRequestForm) throws URISyntaxException, JsonProcessingException {
RestTemplate restTemplate = new RestTemplate();
URI uri = new URI("http://localhost:51001/orders/v1/getOrder/"+month+"?parmRequestSource="+parmRequestSource+"&parmAudienceType="+parmAudienceType);
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
String requestJson = new ObjectMapper().writeValueAsString(orderRequestForm);
HttpEntity<String> httpEntity = new HttpEntity<String>(requestJson,headers);
String response = restTemplate.postForObject(uri, httpEntity, String.class);
return new ObjectMapper().readValue(response, OrderResponse.class);
}
getOrderClient2
#PostMapping(value="/getOrderClient2/{month}",produces="application/json")
public OrderResponse getOrderClient2(
#PathVariable("month") String month,
#RequestParam String parmRequestSource,
#RequestParam String parmAudienceType,
#RequestBody OrderRequestForm orderRequestForm) throws URISyntaxException, JsonProcessingException {
RestTemplate restTemplate = new RestTemplate();
URI uri = new URI("http://localhost:51001/orders/v1/getOrder/"+month+"?parmRequestSource="+parmRequestSource+"&parmAudienceType="+parmAudienceType);
return restTemplate.postForObject(uri, orderRequestForm, OrderResponse.class);
}
Both are giving same error :
HttpClientErrorException$BadRequest: 400 : [no body]
Please suggest.
To improve the visibility of the solution, #astar fixed the issue by annotating the model object's properties with #JsonProperty.

Okhttp create MultipartBody with spring MultipartFile and json object

I have a controller like so that accepts a MultipartFile and json object:
#PostMapping(value = "/v1/submit")
public ResponseEntity submit(
#RequestParam(value="myFile", required = true) MultipartFile myFile
, #Valid #RequestPart(value="fileMeta", required=true) FileMeta fileMeta
){
I need to forward this to a new url using an okhttpclient post with a Multipartbody containing both myFile and fileMeta objects:
OkHttpClient client = new OkHttpClient();
MultipartBody requestBody = new MultipartBody.Builder()
.setType(MultipartBody.FORM)
.addFormDataPart("myFile", myFile.getName(), okhttp3.RequestBody.create(file, MediaType.parse("pdf"))
.addFormDataPart("fileMeta", fileMeta)
.build();
I am getting following error:
Cannot resolve method 'create(org.springframework.web.multipart.MultipartFile, okhttp3.MediaType)'
The method definition of OkHttp's RequestBody create is the following: create(MediaType contentType, byte[] content). It expects the first the MediaType and second the payload (either as byte[], File or other formats).
So you first have to switch the order of the method arguments and second convert the MultipartFile from Spring to a proper format that the create() method accepts, e.g. byte[] or File:
OkHttpClient client = new OkHttpClient();
MultipartBody requestBody = new MultipartBody.Builder()
.setType(MultipartBody.FORM)
.addFormDataPart("myFile", myFile.getName(), RequestBody.create(MediaType.parse("pdf"), file)
.addFormDataPart("fileMeta", fileMeta)
.build();
There are already multiple solutions available on StackOverflow to convert MultipartFile to File: How to convert a multipart file to File?
UPDATE: Example for using RestTemplate
#RestController
public class FileSendingController {
#PostMapping("/files")
public void streamFile(#RequestParam("file") MultipartFile file) {
MultiValueMap<String, Object> body = new LinkedMultiValueMap<>();
body.add("file", file);
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.MULTIPART_FORM_DATA);
HttpEntity<MultiValueMap<String, Object>> requestEntity = new HttpEntity<>(body, headers);
RestTemplate restTemplate = new RestTemplate();
restTemplate.postForEntity("http://upload.to", requestEntity, String.class);
}
}

Passing RequestParam data to Spring RestController

I am using restTemplate.exchangemethod to invoke one service from another service.My request url does accept a request parameter.
url is of the formhttp://localhost:8035/sgapp/student/fetchDeptNo?sid
In the conttroller it is written as
#RestController
#RequestMapping(value="/sgapp/student")
public class SiController{
#GetMapping(value = "/fetchDeptNo",consumes = "application/x-www-form-urlencoded")
public ResponseEntity<String> getSid(#RequestParam(name = "sid")String sid){
String sid = myRepo.getSidCode(sid);
System.out.println("sid received from DB::"+sid);
return new ResponseEntity<String>(sid,HttpStatus.OK);
}
}
In the caller application I am invoking it as
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
HttpEntity<?> entity = new HttpEntity<>(headers);
Map paramMap = new HashMap<String, String>();
paramMap.put("sid", sidData);
HttpEntity<String> sidRespnse = restTemplate.exchange(
"http://localhost:8035/sgapp/student/fetchDeptNo", HttpMethod.GET, entity, String.class,
paramMap);
But I'm getting folllowing exception:
org.springframework.web.client.HttpClientErrorException: 400 null
at org.springframework.web.client.DefaultResponseErrorHandler.handleError(DefaultResponseErrorHandler.java:94) ~[spring-web-5.0.6.RELEASE.jar:5.0.6.RELEASE]
at org.springframework.web.client.DefaultResponseErrorHandler.handleError(DefaultResponseErrorHandler.java:79) ~[spring-web-5.0.6.RELEASE.jar:5.0.6.RELEASE]
Can anyone provide any suitable solution to this???
That particular exchange method is used to substitute variables into the path.
If you want to pass query parameters, use UriComponentsBuilder to create the URL with query params:
UriComponentsBuilder builder =
UriComponentsBuilder
.fromHttpUrl(rootUri)
.queryParam("sid", sidData);
Then you can use RestTemplate as follows:
restTemplate.exchange(
builder.toUriString(),
HttpMethod.GET,
entity,
String.class);

Getting values from JSON using REST client

My api is working fine and I did get back JSON result when tested in POSTMAN. I have problem retrieving the JSON value through a controller using a REST client. I am using spring and hibernate.
#RequestMapping(value = "/viewForm/{id}")
public String viewForm(#Valid #PathVariable("id") String id, Model model) {
RestTemplate restTemplate = new RestTemplate();
String fooResourceUrl
= "http://localhost:8080/api/delivery/searchDanceform/"+ id;
System.out.println(fooResourceUrl);
ResponseEntity<DanceApplicationForm> rateResponse =
restTemplate.exchange(fooResourceUrl,
HttpMethod.GET, null, DanceApplicationForm.class);
DanceApplicationForm response = rateResponse.getBody();
System.out.println(response);
logger.info("result = {}", response);
return VIEW_PATH + "dance-profile";
}
I got this error,
SEVERE: Servlet.service() for servlet [dispatcher] in context with path [/intranet-web] threw exception [Request processing failed; nested exception is org.springframework.web.client.HttpClientErrorException: 404 null] with root cause
org.springframework.web.client.HttpClientErrorException: 404 null
at org.springframework.web.client.DefaultResponseErrorHandler.handleError(DefaultResponseErrorHandler.java:78)
at org.springframework.web.client.RestTemplate.handleResponse(RestTemplate.java:700)
at org.springframework.web.client.RestTemplate.doExecute(RestTemplate.java:653)
at org.springframework.web.client.RestTemplate.execute(RestTemplate.java:613)
at org.springframework.web.client.RestTemplate.exchange(RestTemplate.java:531)
at sg.com.ctc.intranet.web.training.controller.DanceController.viewDanceApplicationForm(DanceController.java:239)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
I have also tried this way.
String response = restTemplate.getForObject(fooResourceUrl, String.class);
but is still not working.
You are passing null value in exchange method, actually in place of null you have to pass entity refrence.
HttpHeaders headers = new HttpHeaders();
headers.set("Accept", "application/json");
HttpEntity entity = new HttpEntity(headers);
ResponseEntity<DanceApplicationForm> rateResponse = restTemplate.exchange(url, HttpMethod.GET, entity, DanceApplicationForm.class);
I place it in the answer section because I am not too sure where I can reply with my code.
#RequestMapping(value = "/viewDanceApplication/{id}")
public String viewDanceApplicationForm(#Valid #PathVariable("id") String id, Model model) {
RestTemplate restTemplate = new RestTemplate();
String fooResourceUrl
= "http://localhost:8080/api/delivery/searchDanceform/"+ id;
HttpHeaders headers = new HttpHeaders();
headers.set("Accept", "application/json");
HttpEntity entity = new HttpEntity(headers);
ResponseEntity<DanceApplicationForm> rateResponse = restTemplate.exchange(fooResourceUrl, HttpMethod.GET, entity, DanceApplicationForm.class);
logger.info("result = {}", rateResponse);
model.addAttribute("showProfile",rateResponse);
return VIEW_PATH + "dance-profile";
}
This is your handler controller of
http://localhost:8080/api/delivery/searchDanceform/
#RequestMapping(value = "/searchDanceform/{id}")
public String searchDanceform(#Valid #PathVariable("id") String id, Model model) {
// do your code and return response
}

Resources