How to use Spring`s RestTemplate to POST an array of strings - java

I am trying to post a simple array of strings using the spring`s restTemplate. Did anyone succeed with that ?
The client:
public void save(){
String company = "12345";
String productId = "10";
String[] colors = {"A","B","C","D","E"};
String convertUrl = "http://localhost:8080/cool-web/save";
MultiValueMap<String, Object> convertVars = new LinkedMultiValueMap<String, Object>();
convertVars.add("companyID", StringUtils.trimToEmpty(company));
convertVars.add("productId", StringUtils.trimToEmpty(productId));
convertVars.add("disclaimer", StringUtils.trimToEmpty("ffs"));
convertVars.add("colorsArray", colors);
restTemplate.postForObject(convertUrl, null, String.class, convertVars);
}
The Service is:
#RequestMapping(value = "/save", method = RequestMethod.POST)
#ResponseStatus(value = HttpStatus.OK)
public void save(#RequestParam("colorsArray[]") String[] colors,
#RequestParam("disclaimer") String disclaimer,
#RequestParam("companyID") String companyID,
#RequestParam("productId") String productId) {
resourceService.save(colors, disclaimer, companyID, productId);
}
I got 400 Bad Request.
What am I doing wrong ?
I am using the default messageConverters.
Do I need to implement custom messageConverter for a simple array of Strings ?

Here is the solution:
public void save(){
String company = "12345";
String productId = "10";
String[] colors = {"A","B","C","D","E"};
String convertUrl = "http://localhost:8080/cool-web/save";
MultiValueMap<String, Object> convertVars = new LinkedMultiValueMap<String, Object>();
convertVars.add("companyID", StringUtils.trimToEmpty(company));
convertVars.add("productId", StringUtils.trimToEmpty(productId));
convertVars.add("disclaimer", StringUtils.trimToEmpty("ffs"));
for(String color:colors){
convertVars.add("colorsArray[]", color);
}
restTemplate.postForObject(convertUrl, convertVars , String.class);
}

If you are trying POST MultiValueMap, use Map.class instead of String.class in the code:
restTemplate.postForObject(convertUrl, null, Map.class, convertVars);
And your service method is wrong I guess. Because you are posting MultiValueMap and in save method you are trying to get all the internal variables as method parameters i.e. RequestParam.
That's not going to happen. You will have to accept only MultiValueMap there and take things out of it for use.
public void save(#RequestParam("colorsArray[]") MultiValueMap<String, Object> convertVars ) {
resourceService.save(convertVars.getColors(), .... );
}

#RequestParam(value) value - "The name of the request parameter to bind to." So #RequestParam("colorsArray[]") String[] colors trying to find param with name "colorsArray[]" but u put parameter with name "colorsArray". May be that is the reason.

Related

What's the best way to encode and decode parameter in springboot?

I use #RequestParam to get the parameter value,but I find the if I pass the value like 'name=abc&def&id=123',I will get the name value 'abc' instead of 'abc&def'. I find the encode and decode the parameter value can solve my problem.But I have to write the encode and decode mehtod in every controller method,Do spring have the global mehtod that decode every #RequestParam value?When using #RequestParam, is it necessary to encode and decode every value?
Here is my code:
#PostMapping("/getStudent")
public Student getStudent(
#RequestParam String name,
#RequestParam String id) {
name= URLDecoder.decode(name, "UTF-8");
//searchStudent
return Student;
}
#PostMapping("/getTeacher")
public teacher getTeacher(
#RequestParam String name,
#RequestParam String teacherNo) {
name= URLDecoder.decode(name, "UTF-8");
//searchTeacher
return teacher;
}
Somebody say the the Spring will have already done this,but I have try,the result is not right.Only use curl cmd is ok,but java code is not ok.
#PostMapping(value = "/example")
public String handleUrlDecode1(#RequestParam String param) {
//print ello%26test
System.out.println("/example?param received: " + param);
return "success";
}
#GetMapping(value = "/request")
public String request() {
String url = "http://127.0.0.1:8080/example?param=ello%26test";
System.out.println(url);
RestTemplate restTemplate = new RestTemplate();
return restTemplate.postForObject(url, null, String.class);
}
You must create an HTTP entity and send the headers and parameter in body.
#GetMapping(value = "/request")
public String request() {
String url = "http://127.0.0.1:8080/example";
System.out.println(url);
RestTemplate restTemplate = new RestTemplate();
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
MultiValueMap<String, String> map= new LinkedMultiValueMap<String, String>();
map.add("param","ello&test");
map.add("id","ab&c=def");
HttpEntity<MultiValueMap<String, String>> request = new HttpEntity<MultiValueMap<String, String>>(map, headers);
return restTemplate.postForObject(url, request, String.class);
}
As you can read here, the escape character for & is %26.
So you should use the following
name=abc%26def&id=123
If you don't use an escape character according to URL standards, Spring will try to use what follows & and try to match it as a new query parameter.
No need to manually use URLDecoder, SpringBoot controllers will handle it for you.
#RestController
public class UrlDecodeController {
#GetMapping(value = "/example")
public String handleUrlDecode(#RequestParam String param) {
System.out.println("/example?param received: " + param);
return "success";
}
#PostMapping(value = "/example2")
public String handleUrlDecodeInPostRequest(#RequestParam String param1, ExamplePayload payload) {
System.out.println("/example2?param1 received: " + param1);
System.out.println("request body - value1: " + payload.getValue1());
return "success";
}
#GetMapping(value = "/request")
public String request() {
String url = "http://localhost:8080/example2?param1=test1&test2";
System.out.println(url);
RestTemplate restTemplate = new RestTemplate();
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
MultiValueMap<String, String> map = new LinkedMultiValueMap<String, String>();
map.add("value1","test1&test2");
HttpEntity<MultiValueMap<String, String>> request = new HttpEntity<MultiValueMap<String, String>>(map, headers);
return restTemplate.postForObject(url, request, String.class);
}
class ExamplePayload{
private String value1;
private String value2;
//getters and setters
public ExamplePayload() {
}
}
}
Call with GET /example?param=hello%26test and the System.out.println outputs:
/example?param received: hello&test
Call the POST using curl as an example:
curl -X POST "http://localhost:8080/example2?param1=test1%26test2" -d "value1=test3%26test4"
Prints:
/example2?param1 received: test1&test2
request body - value1: test3&test4
Added GET /request to show using RestTemplate with the application/x-www-form-urlencoded Content-Type. Note that RestTemplate will automatically url encode any values passed as request parameters or in the request body. If you pass a String value of "%26" it will pass it as is, this is what you are seeing in your example. If you pass "&" it will url encode it to "%26" for you, and the Controller decodes it automatically on the other side.

Using BodyInserters to pass parameter with webClient

There is my code.
public Mono<RespDto> function(TransReqDto1 reqDto1, TransReqDto2 reqDto2, String token) {
MultipartBodyBuilder builder = new MultipartBodyBuilder();
builder.part("TransReqDto1", reqDto1);
builder.part("TransReqDto2", reqDto2);
MultiValueMap<String, HttpEntity<?>> parts = builder.build();
LinkedMultiValueMap map = new LinkedMultiValueMap();
map.add("TransReqDto1", reqDto1);
map.add("TransReqDto2", reqDto2);
return
client.post()
.uri("/api")
.body(BodyInserters.fromValue(reqDto1))
.headers(h -> h.setBearerAuth(token.split(" ")[1]))
.retrieve()
.bodyToMono(RespDto.class);
}
My probelm is that I need to send both reqDto1 & reqDto2. I've successfully sent reqDto1 with the code above but I can't figure out a way to send two objects.
Tried MultipartBodybuild and MultiValueMap but both are returning error from the target API. Please give me some hints!! Thank you
Here is the API I am trying to call!
#PostMapping("")
#ApiOperation(value = "test", notes = "test")
public Mono<?> transPost(#Valid #RequestBody TransReqDto1 reqDto1,
#Valid #RequestBody TransReqDto2 reqDto2) {
return testService.function(reqDto1, reqDto2);
}
You cannot use two #RequestBody. It can bind to a single object only. The expected way to do that is to create a wrapper DTO containing all the relevant data:
public class TransReqDto {
private TransReqDto1 transReqDto1;
private TransReqDto2 transReqDto2;
//...
}

Spring RestTemplate: How to serialize java.util.Collection

I need to call a RESTful webservice from a Java program and pass it to a DateTime Collection.
So, my code is like the following:
RestTemplate restTemplate = new RestTemplate();
try {
String scheme = request.getScheme();
String userInfo = request.getRemoteUser();
String host = request.getLocalAddr();
int port = request.getLocalPort();
String path = "/myapp/common/myapi";
MultiValueMap<String, Object> requestParams = new LinkedMultiValueMap<String, Object>();
requestParams.add("aId", objA.getId());
requestParams.add("bIb", objB.getId());
for (DateTime date : dates) {
requestParams.add("dates", date);
}
URI apiUri = new URI(scheme, userInfo, host, port, path, null, null);
result = restTemplate.postForObject(apiUri.toString(), request, BigDecimal.class,
requestParams);
} catch (URISyntaxException e) {
logger.error(e.getMessage());
} catch (DataAccessException e) {
logger.error(e.getMessage());
}
And the webservice's signature is like:
#RequestMapping(value = "myapi", method = RequestMethod.POST)
public #ResponseBody BigDecimal myApi(
#RequestParam("dates") final List<DateTime> dates,
#RequestParam("aId") final Integer aId, #RequestParam("bId") final Integer bId) {
[...]
return result;
}
But I get the error:
org.springframework.http.converter.HttpMessageNotWritableException: Could not write JSON: No serializer found for class java.util.Collections$3 and no properties discovered to create BeanSerializer (to avoid exception, disable SerializationConfig.Feature.FAIL_ON_EMPTY_BEANS) )
I understand that the problem is the serialization of the collection, but I do not know how to solve it.
Updated
I also tried with a Command class, so something like:
public class CalcolaGiorniResiduiCommand implements Serializable {
private List<DateTime> dates;
//[...]
}
Changed the controller:
#RequestMapping(value = "myapi", method = RequestMethod.POST)
public #ResponseBody BigDecimal myApi(
#RequestParam("command") final MyCommand command) {
And finally:
MyCommand command = MyCommand.build(1, 1, dates); //dates is a DateTime Collection
restTemplate.postForObject(apiUri.toString(), request, BigDecimal.class, command);
But I get the same error.
Any help, please?
I think you have to pass a list of dateTime object rather than adding it multiple time. Can you please try with the below snippet.
List<DateTime> dates = new ArrayList<>();
for (DateTime date : dates) {
dates.add(date);
}
requestParams.add("dates", dates);
From the documentation, the request parameter is the Object to be POSTed, so the command object have to be passed as second parameter instead of the object request.
So the code should be changed from:
restTemplate.postForObject(apiUri.toString(), request, BigDecimal.class, command);
to:
restTemplate.postForObject(apiUri.toString(), command, BigDecimal.class);

How to loop through JSON response in Spring MVC Controller

I will like to use the JSON response inside a controller. I am calling a method that returns the JSON. See my code below. Please how do I loop through the Json object returned inside my controller. I need to use the properties like sending mail to the email addresses from another method inside my controller .
My method that does that returns the JSON :
#ResponseBody
private ResponseEntity<?> queryIsw(String ref, String amt) throws Exception{
String pdtid = "62";
String salt = "D3D1D05AFE42AD50818167EAC73C109168A0F108";
RestTemplate restt = new RestTemplate();
String uri = "https://bestng.com/gettransaction.json";
MultiValueMap<String, String> params = new LinkedMultiValueMap<String, String>();
params.add("productid", pdtid);
params.add("transactionreference", ref);
params.add("amount", amt);
UriComponents uriComponents = UriComponentsBuilder.fromHttpUrl(uri).queryParams(params).build();
URI oro = uriComponents.toUri();
HttpHeaders hea = new HttpHeaders();
String hs = pasher(pdtid, ref, salt);
hea.add("hash", hs);
HttpEntity<String> hent = new HttpEntity<String>(hea);
ResponseEntity<Object> resp = restt.exchange(oro, HttpMethod.GET, hent, Object.class);
return resp;
}
Below is my call to this method above from another method :
ResponseEntity<?> dres = queryIsw(dref,ama);
Kindly explain how I can use properties of 'dres' returned in my controller .
Thanks
Try taking a look at the Jackson JSON to Java mapping tools and specifically the ObjectMapper. It can convert a properly formatted JSON string into an object hierarchy from which you can pull out the data that you need. Jackson is a frequently used tool for this activity. Take a look at the tutorial for more details:
http://www.mkyong.com/java/how-to-convert-java-object-to-from-json-jackson/
If you need more help, do ask.
I am assuming that it will return within the body of the ResponseEntity.
Try:
String body = dres.getBody();
You can use something that can parse that string to a json object. Something like:
JSONObject jObject = new JSONObject(body);
See:
http://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/http/ResponseEntity.html
Java String to JSON conversion

How to have multiple parameters using Spring MVC RequestMapping?

I am using Spring MVC RequestMapping here for GET parameters. Below is my code -
#RequestMapping(value = "index", method = RequestMethod.GET)
public HashMap<String, String> handleRequest(#RequestParam("dc1Servers") String dc1Servers) {
HashMap<String, String> model = new HashMap<String, String>();
String helloWorld = "Hello World!";
model.put("greeting", helloWorld);
System.out.println(dc1Servers);
return model;
}
I am hitting this URL - http://127.0.0.1:8080/dataweb/index?dc1Servers=7 then it goes into the above code and prints out 7 on the console and works fine.
Now I would like to have these two below parameters as well -
dc2Servers=7
dc3Servers=7
So I made a method like this which can take three input parameters -
#RequestMapping(value = "index", method = RequestMethod.GET)
public HashMap<String, String> handleRequest(#RequestParam("dc1Servers") String dc1Servers, #RequestParam("dc2Servers") String dc2Servers, #RequestParam("dc3Servers") String dc3Servers) {
HashMap<String, String> model = new HashMap<String, String>();
String helloWorld = "Hello World!";
model.put("greeting", helloWorld);
System.out.println(dc1Servers);
System.out.println(dc2Servers);
System.out.println(dc3Servers);
return model;
}
Now if I hit the url like this then it doesn't works -
http://127.0.0.1:8080/dataweb/index?dc1Servers=7?dc2Servers=7?dc3Servers=7
And it gives me some error.. Any idea what wrong I am doing here?
This should be
http://127.0.0.1:8080/dataweb/index?dc1Servers=7&dc2Servers=7&dc3Servers=7
change an try again
& works between each parameter
? only works at the begin of the url parameters
Check this example
http://www.example.com/products/women/dresses?sessionid=34567&source=google.com

Categories

Resources