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
}
Related
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.
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";
}
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);
It will call another REST API with a GET request.
#RequestMapping(value = "xxxx/{id}", method = RequestMethod.GET)
public #ResponseBody GetObjet GET( #PathVariable("id") String id,
#RequestHeader(value="X-Auth-Token") String Token) {
RestTemplate restTemplate = new RestTemplate();
HttpHeaders headers = new HttpHeaders();
headers.add("X-Auth-Token", Token);
HttpEntity entity = new HttpEntity(headers);
ResponseEntity<GetObjet> response = restTemplate.exchange(url, HttpMethod.GET, entity, GetObjet.class);
return response.getBody();
}
Always 400 Error. It means that bad request or some errors in the request body. But this is GET so the resquest bodys is always empty. So this way to add header may be not right. Any ideas?
You can obtain the headers including the notation #RequestHeader in your method
public void displayHeaderInfo(#RequestHeader("Accept-Encoding") String encoding,
#RequestHeader("Keep-Alive") long keepAlive) {
}
o
You can read more about the request here
And the other way to abtain the URL is:
#RequestMapping(value = "/restURL")
public String serveRest(#RequestBody String body, #RequestHeader HttpHeaders headers){
//Use headers to get the information about all the request headers
long contentLength = headers.getContentLength();
...
StreamSource source = new StreamSource(new StringReader(body));
YourObject obj = (YourObject) jaxb2Mashaller.unmarshal(source);
...
}
Try using:
RestTemplate.getForEntity(url, GetObject.class);
You have some methods to request data from a rest API, such as getForEntity and getForObject, use the one you needed.
My post method gets called but my Profile is empty. What is wrong with this approach? Must I use #Requestbody to use the RestTemplate?
Profile profile = new Profile();
profile.setEmail(email);
String response = restTemplate.postForObject("http://localhost:8080/user/", profile, String.class);
#RequestMapping(value = "/", method = RequestMethod.POST)
public #ResponseBody
Object postUser(#Valid Profile profile, BindingResult bindingResult, HttpServletResponse response) {
//Profile is null
return profile;
}
You have to build the profile object this way
MultiValueMap<String, Object> parts = new LinkedMultiValueMap<String, Object>();
parts.add("email", email);
Object response = restTemplate.postForObject("http://localhost:8080/user/", parts, String.class);
MultiValueMap was good starting point for me but in my case it still posted empty object to #RestController my solution for entity creation and posting ended up looking like so:
HashedMap requestBody = new HashedMap();
requestBody.put("eventType", "testDeliveryEvent");
requestBody.put("sendType", "SINGLE");
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
// Jackson ObjectMapper to convert requestBody to JSON
String json = new ObjectMapper().writeValueAsString(request);
HttpEntity<String> entity = new HttpEntity<>(json, headers);
restTemplate.postForEntity("/generate", entity, String.class);
My current approach:
final Person person = Person.builder().name("antonio").build();
final ResponseEntity response = restTemplate.postForEntity(
new URL("http://localhost:" + port + "/person/aggregate").toString(),
person, Person.class);