Setting multiple parameters in a request - java

I need to form a cache, for regions by id, which are passed in the region_ids parameter, the request looks like this:
localhost:8080/cache/mscache?region_ids=5,19....,23
how is it best to read these several parameters in the program code?

read them a String and the parse that String into whatever you want:
#GetMapping("/cache/mscache)
public String getCache(#RequestParam String listOfRegionIds)
List<String> ids = Arrays.stream(listOfRegiosIds.split(",")).collect(Collectors.toList);
// ...
}
more info at https://www.baeldung.com/spring-request-param

You can use an array or a List
#GetMapping(value = "/test")
public void test(#RequestParam List<String> ids) {
ids.forEach(System.out::println);
}
Make a get request like:
http://localhost:8080/test?ids=1,2,3
Check here for more details.

If the request is a Get request use #RequestParam like sugessted by J Asgarov, if it is soething else you can also use #RequestBody by creating an class containing all of your parameters
for exemple a Post request could look like this :
#PostMapping("...")
public String postCache(#RequestBody RegionIdsRequest regionIds)
// ...
}
public class RegionIdsRequest{
List<int> regionsIds = //...
}

Related

Is there a way to obtain in Spring the list of path variables from the URI?

#RequestMapping(value = "/{ids}", method=RequestMethod.GET)
public String getMethod(#PathVariable List<String> ids){
}
I would like something similar, but I need the request to map to something like: localhost:8080/id1/id2/id3/.../idn
I don’t know the number of path variables (ids) and neither their names.
When you are using a path it essentially adds to the uri . The uri has length limitations.
Related post : Maximum length of HTTP GET request
So it is not advisable to add multiple number of parameters to the uri as path variable, when the number is not restricted.
You could use query params like :
#RequestMapping(value = "/{ids}", method=RequestMethod.GET)
public String getMethod(#RequestParam("myparam") List<String> ids)
{
}
Instead what you could have is convert it to a post request and have a request body with the list of data as an object.
#PostMapping("/")
public ResponseEntity postController(
#RequestBody CustomPojo data) {
exampleService.fakeAuthenticate(data);
return ResponseEntity.ok(HttpStatus.OK);
}
class CustomPoJo {
List<String> ids;
//getter setter etc
}
and the json could look like :
{"custompojo":["id1","id2"]}
It cannot be done since the request will look for endpoint having matching URL and matching method.

Spring MVC populate #RequestParam Map<String, String>

I have the following method in my Spring MVC #Controller :
#RequestMapping(method = RequestMethod.GET)
public String testUrl(#RequestParam(value="test") Map<String, String> test) {
(...)
}
I call it like this :
http://myUrl?test[A]=ABC&test[B]=DEF
However the "test" RequestParam variable is always null
What do I have to do in order to populate "test" variable ?
As detailed here
https://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/web/bind/annotation/RequestParam.html
If the method parameter is Map or MultiValueMap and a parameter name is not specified, then the map parameter is populated with all request parameter names and values.
So you would change your definition like this.
#RequestMapping(method = RequestMethod.GET)
public String testUrl(#RequestParam Map<String, String> parameters)
{
(...)
}
And in your parameters if you called the url http://myUrl?A=ABC&B=DEF
You would have in your method
parameters.get("A");
parameters.get("B");
You can create a new class that contains the map that should be populated by Spring and then use that class as a parameter of your #RequestMapping annotated method.
In your example create a new class
public static class Form {
private Map<String, String> test;
// getters and setters
}
Then you can use Form as a parameter in your method.
#RequestMapping(method = RequestMethod.GET)
public String testUrl(Form form) {
// use values from form.getTest()
}
Spring doesn't have default conversion strategy from multiple parameters with the same name to HashMap. It can, however, convert them easily to List, array or Set.
#RequestMapping(value = "/testset", method = RequestMethod.GET)
public String testSet(#RequestParam(value = "test") Set<String> test) {
return "success";
}
I tested with postman like http://localhost:8080/mappings/testset?test=ABC&test=DEF
You will see set having data, [ABC, DEF]
Your question needs to be considered from different points of view.
first part:
as is mentioned in the title of the question, is how to have Map<String, String> as #RequestParam.
Consider this endpoint:
#GetMapping(value = "/map")
public ResponseEntity getData(#RequestParam Map<String, String> allParams) {
String str = Optional.ofNullable(allParams.get("first")).orElse(null);
return ResponseEntity.ok(str);
}
you can call that via:
http://<ip>:<port>/child/map?first=data1&second=data2
then when you debug your code, you will get these values:
> allParams (size = 2)
> first = data1
> second = data2
and the response of the requested url will be data1.
second part:
as your requested url shows (you have also said that in other answers' comments) ,you need an array to be passed by url.
consider this endpoint:
public ResponseEntity<?> getData (#RequestParam("test") Long[] testId,
#RequestParam("notTest") Long notTestId)
to call this API and pass proper values, you need to pass parameters in this way:
?test=1&test=2&notTest=3
all test values are reachable via test[0] or test[1] in your code.
third part:
have another look on requested url parameters, like: test[B]
putting brackets (or [ ]) into url is not usually possible. you have to put equivalent ASCII code with % sign.
for example [ is equal to %5B and ] is equal to %5D.
as an example, test[0] would be test%5B0%5D.
more ASCII codes on: https://ascii.cl/
I faced a similar situation where the client sends two groups of variable parameters. Let's call these groups foo and bar. A request could look like:
GET /search?page=2&size=10&foo[x]=aaa&foo[y]=bbb&bar[z]=ccc
I wanted to map these parameters to two distinct maps. Something like:
#GetMapping("/search")
public Page<...> search(Pageable pageable,
#RequestParam(...) Map<String, String> foo,
#RequestParam(...) Map<String, String> bar) {
...
}
#RequestParam didn't work for me, too. Instead I created a Model class with two fields of type Map<> matching the query parameter names foo and bar (#Data is lombok.Data).
#Data
public static class FooBar {
Map<String, String> foo;
Map<String, String> bar;
}
My controller code has changed to:
#GetMapping("/search")
public Page<...> search(Pageable pageable, FooBar fooBar) {
...
}
When requesting GET /search?page=2&size=10&foo[x]=aaa&foo[y]=bbb&bar[z]=ccc Spring instantiated the Maps and filled fooBar.getFoo() with keys/values x/aaa and y/bbb and fooBar.getBar() with z/ccc.
you can use MultiValueMap
MultiValueMap<String, String>
#RequestMapping(method = RequestMethod.GET)
public String testUrl(#RequestParam(value="test") MultiValueMap<String, String> test) {
(...)
}
and while testing don't use test[A],test[B]. just use it as stated below.
http://myUrl?test=ABC&test=DEF
test result will be in below format when you print it.
test = {[ABC, DEF]}

passing complex input from jquery to Spring MVC

What I would like to achieve is to pass parameters from jquery to a Spring Controller. I was successful in passing simple parameter (one string) from jquery to Spring bu how can I do the same with complex data?
For example: in Spring I expect a POJO as input parameter and this POJO has a String property and a List property.
POJO:
public class SimplePojo {
private String one;
private List<String> two;
...
}
Spring Controller:
#RequestMapping(value = "/something", method = RequestMethod.POST)
public #ResponseBody String check(#RequestParam(????) SimplePojo input) { ... }
JQuery
jq.post("/something", ????, function(data){ ... });
I put question marks to the places where I have no idea what to write :)
Could you please help me?
Thanks, Viktor
In js :
ajax.get('api/checkout_patron/patron_id='+self.patronId())
In java :
#RequestMapping(method= RequestMethod.GET,value = "/patron_id={patron_id}")
public #ResponseBody
Response getPatron(#PathVariable String patron_id){
}
Here js request I have mapped using :
#Controller
#RequestMapping(value = "/api/checkout_patron")
on before class declaration.
Here I am using knockout js, so I am using this pattern to pass request.
Second Small Example with my technique :
var form={
sourceName : self.sourceName(),
sourceEmail :self.email()
}
ajax.post('api/source',JSON.stringify(form)).done(function(response){
});
Here Get data :
#RequestMapping(method= RequestMethod.POST,consumes = "application/json")
public #ResponseBody
ResponseEntity<IWebApiResponse> addBudget(#RequestBody AddBudgetSourceForm form){
//your code to process data
}
AddBudgetSourceForm class :
public class AddBudgetSourceForm {
private String sourceName;
private String sourceEmail;
// getter and setter
}
Keep one thing in mind that name of form class and in js form data-bind should be same (i.e. left side of parameter in js form that have been stringified).
UPDATE :
You can do something like following :
List<String> var = new ArrayList<>();
var.add(form.getSourcename());
var.add(form.getSourceEmail());
and yes you can send data like that in json.
If you are sending single data for each thing then don't use List.
Instead of that use List<classname> and define all required variable in class with getter-setter.

Spring MVC, deserialize single JSON?

How can I easily separate JSON values that are sent in the same request?
Given that I POST a JSON to my server:
{"first":"A","second":"B"}
If I implement the following method in the Controller:
#RequestMapping(value = "/path", method = RequestMethod.POST, consumes = MediaType.APPLICATION_JSON_VALUE)
public void handleRequest(#RequestBody String input) {
// ...
}
then the input parameter will constitute a String with the entire JSON object, {"first":"A","second":"B"}. What I really want is two separate Strings (or a String and an int whichever is suitable for the particular request) with just the two values (other key / value pairs that the client may send should be ignored).
If the strings were sent as request parameters instead of JSON request body it would be simple:
#RequestMapping(value = "/path", method = RequestMethod.POST)
public void handleRequest(#RequestParam("first") String first,
#RequestParam("second") String second) {
// ...
}
I know that I can create a simple bean class that can be used in conjunction with the #RequestBody annotation that will contain both A and B when used, but it seems like a detour, since they will have different purposes inside the web app.
Dependencies:
org.springframework : spring-web : 3.1.0.RELEASE
org.codehaus.jackson : jackson-mapper-asl : 1.9.3
POJO
public class Input {
private String first;
private String second;
//getters/setters
}
...and then:
public void handleRequest(#RequestBody Input input)
In this case you need Jackson to be available on the CLASSPATH.
Map
public void handleRequest(#RequestBody Map<String, String> input)
I have written a custom WebArgumentResolver that does exactly this, combined with a custom annotation.
I don't have the source available to me now, but basically I annotated my method like this:
#RequestMapping(value = "/path", method = RequestMethod.POST)
public void handleRequest(#JsonField("first") String first, #JsonField("second") String second) {
// ...
}
Then my JsonFieldWebArgumentResolver checks if the method parameter is annotated with JsonField, and if it is it extracts the actual type from the parameter (not quite straight-forward it turns out if you want to handle generic parameters as well, such as List<String> or List<Pojo>), and invokes Jackson's JsonParser manually to create the correct type. It's a shame I can't show you any code, but that's the gist of it.
However, that solution is for Spring MVC 3.0, and if you are using 3.1 I think you will be better off using a custom HandlerMethodArgumentResolver instead. But the idea should be the same.

Get requested value(URL) when using #RequestMapping annotations

When I map multiple values to #RequestMapping(like Multiple Spring #RequestMapping annotations), can I get the requested value(URL)?
Like this:
#RequestMapping(value={"/center", "/left"}, method=RequestMethod.GET)
public String getCenter(Model model) throws Exception {
String requestedValue = getRequestedValue(); // I want this.
// I want to do something like this with requested value.
String result;
if (requestedValue.equals("center")
result = "center";
else if (requestedValue.equals("left")
result = "left";
return result;
}
You can have the Request (HttpServletRequest) itself as an parameter of the handler method. So you can then inspect the request url to get the "value".
#RequestMapping(value={"/center", "/left"}, method=RequestMethod.GET)
public String getCenter(Model model, HttpServletRequest request) throws Exception {
String whatYouCallValue = request.getServletPath();
....
Javadoc: https://docs.oracle.com/javaee/7/api/javax/servlet/http/HttpServletRequest.html#getServletPath--
Btw: if I understand you right, you want to have different urls, not different values.
From Spring 3.1.0, you can use URI Template Patterns with Regular Expressions.
#RequestMapping(value={"/{path:[a-z-]+}"}, method=RequestMethod.GET)
public String getCenter(#PathVariable String path) throws Exception {
// "path" is what I want
}
From Spring 3.1.0, you can use ServletUriComponentsBuilder
#RequestMapping(value={"/center", "/left"}, method=RequestMethod.GET)
public String getCenter(Model model) throws Exception {
UriComponentsBuilder builder = ServletUriComponentsBuilder.fromCurrentRequest();
String requestedValue = builder.buildAndExpand().getPath(); // I want this.
System.out.println(requestedValue);
// I want to do something like this with requested value.
String result="fail";
if (requestedValue.equals("center"))
result = "center";
else if (requestedValue.equals("left"))
result = "left";
return result;
}
Use RequestParam annotation. You can also add a parameter of type HttpServletRequest to your method and then getParameters from that.
Addition to the best answer #Hugh_Lee:
This method will work for all not mapped requests. If you want to use this method just for two (or several) cases only, e.g. "/center" and "/left", you may do following. Rename "center" to "positionCenter", "left" to "positionLeft" (or add another common word). So the code would be like this:
#RequestMapping(value={"/{path:position+[A-Za-z-]+}"}, method=RequestMethod.GET)
public String getCenter(#PathVariable String path) throws Exception {
// "path" is what I want
}
Following regex will make your method to be executed only for the urls /center and /left. And you can get the value with #PathVariable annotation.
#GetMapping("/{path:^center$|^left$}")
public ResponseEntity<?> whatIsThePath(#PathVariable String path){
// path is either "center" or "left"
}

Categories

Resources