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"
}
Related
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 = //...
}
What is the difference between #RequestParam and #PathVariable while handling special characters?
+ was accepted by #RequestParam as space.
In the case of #PathVariable, + was accepted as +.
#PathVariable is to obtain some placeholder from the URI (Spring call it an URI Template)
— see Spring Reference Chapter 16.3.2.2 URI Template Patterns
#RequestParam is to obtain a parameter from the URI as well — see Spring Reference Chapter 16.3.3.3 Binding request parameters to method parameters with #RequestParam
If the URL http://localhost:8080/MyApp/user/1234/invoices?date=12-05-2013 gets the invoices for user 1234 on December 5th, 2013, the controller method would look like:
#RequestMapping(value="/user/{userId}/invoices", method = RequestMethod.GET)
public List<Invoice> listUsersInvoices(
#PathVariable("userId") int user,
#RequestParam(value = "date", required = false) Date dateOrNull) {
...
}
Also, request parameters can be optional, and as of Spring 4.3.3 path variables can be optional as well. Beware though, this might change the URL path hierarchy and introduce request mapping conflicts. For example, would /user/invoices provide the invoices for user null or details about a user with ID "invoices"?
#RequestParam annotation used for accessing the query parameter values from the request. Look at the following request URL:
http://localhost:8080/springmvc/hello/101?param1=10¶m2=20
In the above URL request, the values for param1 and param2 can be accessed as below:
public String getDetails(
#RequestParam(value="param1", required=true) String param1,
#RequestParam(value="param2", required=false) String param2){
...
}
The following are the list of parameters supported by the #RequestParam annotation:
defaultValue – This is the default value as a fallback mechanism if request is not having the value or it is empty.
name – Name of the parameter to bind
required – Whether the parameter is mandatory or not. If it is true, failing to send that parameter will fail.
value – This is an alias for the name attribute
#PathVariable
#PathVariable identifies the pattern that is used in the URI for the incoming request. Let’s look at the below request URL:
http://localhost:8080/springmvc/hello/101?param1=10¶m2=20
The above URL request can be written in your Spring MVC as below:
#RequestMapping("/hello/{id}") public String getDetails(#PathVariable(value="id") String id,
#RequestParam(value="param1", required=true) String param1,
#RequestParam(value="param2", required=false) String param2){
.......
}
The #PathVariable annotation has only one attribute value for binding the request URI template. It is allowed to use the multiple #PathVariable annotation in the single method. But, ensure that no more than one method has the same pattern.
Also there is one more interesting annotation:
#MatrixVariable
http://localhost:8080/spring_3_2/matrixvars/stocks;BT.A=276.70,+10.40,+3.91;AZN=236.00,+103.00,+3.29;SBRY=375.50,+7.60,+2.07
And the Controller method for it
#RequestMapping(value = "/{stocks}", method = RequestMethod.GET)
public String showPortfolioValues(#MatrixVariable Map<String, List<String>> matrixVars, Model model) {
logger.info("Storing {} Values which are: {}", new Object[] { matrixVars.size(), matrixVars });
List<List<String>> outlist = map2List(matrixVars);
model.addAttribute("stocks", outlist);
return "stocks";
}
But you must enable:
<mvc:annotation-driven enableMatrixVariables="true" >
#RequestParam is use for query parameter(static values) like: http://localhost:8080/calculation/pow?base=2&ext=4
#PathVariable is use for dynamic values like : http://localhost:8080/calculation/sqrt/8
#RequestMapping(value="/pow", method=RequestMethod.GET)
public int pow(#RequestParam(value="base") int base1, #RequestParam(value="ext") int ext1){
int pow = (int) Math.pow(base1, ext1);
return pow;
}
#RequestMapping("/sqrt/{num}")
public double sqrt(#PathVariable(value="num") int num1){
double sqrtnum=Math.sqrt(num1);
return sqrtnum;
}
1) #RequestParam is used to extract query parameters
http://localhost:3000/api/group/test?id=4
#GetMapping("/group/test")
public ResponseEntity<?> test(#RequestParam Long id) {
System.out.println("This is test");
return ResponseEntity.ok().body(id);
}
while #PathVariable is used to extract data right from the URI:
http://localhost:3000/api/group/test/4
#GetMapping("/group/test/{id}")
public ResponseEntity<?> test(#PathVariable Long id) {
System.out.println("This is test");
return ResponseEntity.ok().body(id);
}
2) #RequestParam is more useful on a traditional web application where data is mostly passed in the query parameters while #PathVariable is more suitable for RESTful web services where URL contains values.
3) #RequestParam annotation can specify default values if a query parameter is not present or empty by using a defaultValue attribute, provided the required attribute is false:
#RestController
#RequestMapping("/home")
public class IndexController {
#RequestMapping(value = "/name")
String getName(#RequestParam(value = "person", defaultValue = "John") String personName) {
return "Required element of request param";
}
}
it may be that the application/x-www-form-urlencoded midia type convert space to +, and the reciever will decode the data by converting the + to space.check the url for more info.http://www.w3.org/TR/html401/interact/forms.html#h-17.13.4.1
#PathVariable - must be placed in the endpoint uri and access the query parameter value from the request
#RequestParam - must be passed as method parameter (optional based on the required property)
http://localhost:8080/employee/call/7865467
#RequestMapping(value=“/call/{callId}", method = RequestMethod.GET)
public List<Calls> getAgentCallById(
#PathVariable(“callId") int callId,
#RequestParam(value = “status", required = false) String callStatus) {
}
http://localhost:8080/app/call/7865467?status=Cancelled
#RequestMapping(value=“/call/{callId}", method = RequestMethod.GET)
public List<Calls> getAgentCallById(
#PathVariable(“callId") int callId,
#RequestParam(value = “status", required = true) String callStatus) {
}
Both the annotations behave exactly in same manner.
Only 2 special characters '!' and '#' are accepted by the annotations #PathVariable and #RequestParam.
To check and confirm the behavior I have created a spring boot application that contains only 1 controller.
#RestController
public class Controller
{
#GetMapping("/pvar/{pdata}")
public #ResponseBody String testPathVariable(#PathVariable(name="pdata") String pathdata)
{
return pathdata;
}
#GetMapping("/rpvar")
public #ResponseBody String testRequestParam(#RequestParam("param") String paramdata)
{
return paramdata;
}
}
Hitting following Requests I got the same response:
localhost:7000/pvar/!##$%^&*()_+-=[]{}|;':",./<>?
localhost:7000/rpvar?param=!##$%^&*()_+-=[]{}|;':",./<>?
!# was received as response in both the requests
#RequestParam:We can say it is query param like a key value pair
#PathVariable:-It is came from URI
Is it possible to differenciate those two request URIs in one controller handler :
http://my-uri/
http://my-uri/?with_empty_param
HttpServletRequest object has a ParameterMap object that maps parameter name and its value.
With this map we can check if a parameter was passed in servlet request.
// Check if with_empty_param parameter exists
if (request.getParameterMap().containsKey("with_empty_param ")) {
String with_empty_param = request.getParameter("with_empty_param ");
}
If you want to use Spring way you could do:
#RequestMapping(value = {"/init"}, method = RequestMethod.GET)
public String methodName(
#RequestParam Map<String,String> allParams, ModelMap model) {
if (allParams.containsKey("with_empty_param ")) {
...
}
The #RequestMapping annotation has a params argument which you can use for that.
#RequestMapping
public void method1() {}
And with a check on the param.
#RequestMapping(params={"param"})
public void method2() {}
You can also use the ! to negate the check, so if that param isn't present.
#RequestMapping(params={"!param"})
public void method3() {}
I've created a POJO like this.
public class Param(){
#NotNull
private Sring paraA;
#NotNull
private Sring paraB;
//Setter and getter
}
And I want to use JSR303 to check it.
#RequestMapping(value = "/test/{paraA}/{paraB}")
#ResponseBody
public BaseJsonRsp test(#PathVariable #Valid Param param) {
//doSomething
}
But this code it doesn't work and I've got following error
HTTP Status 500 - Missing URI template variable 'value' for method parameter of type PatchValue!
Why? How to fix it? Thanks.
Have a look at the Spring Refererence Docs on #PathVariable:
A #PathVariable argument can be of any simple type such as int, long, Date, etc.
If you want to use your Param type as the controller method argument, you won't be able to do so using #PathVariable.
Alternatively, you can map your parameters to individual String variables (using #PathVariable), and then manually construct your Param after that. Note that #PathVariable assumes that the placeholder in your URL is the same as the variable name by default. If your variable name doesn't match, you'd do something like
#RequestMapping(value = "/test/{paraA}/{paraB}")
#ResponseBody
public BaseJsonRsp test(#PathVariable("paraA") String myParam,
#PathVariable("paraB") String otherParam) {
//doSomething
}
You need to explicity set the variable values from the URL into the Param object.
#RequestMapping(value = "/test/{paraA}/{paraB}")
#ResponseBody
public BaseJsonRsp test(#PathVariable("paraA") String paramA, #PathVariable("paraB") String paramB) {
Param param = new Param(paramA, paramB);
}
#PathVariable assumes that the placeholder in your URL is the same as the variable name by default. You need to do this
#RequestMapping(value = "/test/{paraA}/{paraB}")
#ResponseBody
public BaseJsonRsp test(#PathVariable("paraA") String paramA,
#PathVariable("paraB") String otherparam) {
Param param = new Param(paramA, paramB);
}
I want to dynamically enter my spring restful url, how to do this?
first of all, before i trying to create dynamical url, i create the static one. Here is what i do :
#RequestMapping(value = "/insert/{id}/{name}/{address}", method = RequestMethod.GET,headers="Accept=application/json")
public void insertsoheaderdinamis(#PathVariable String id, #PathVariable String name, #PathVariable String address) throws ParseException {
}
above is my static url code. in the future, what i need is, i need a new pathvariable like this localhost:8080/SpringServiceJsonSample/service/updatepool/insert/{here goes id}/{here goes name}/{here goes address}/{new variable goes phone number}/{here goes age}.
i don't want to change my code, so i decided to create a dynamic url. While i read around internet.
i trying to do this :
#RequestMapping(value = "/insert/{path}/**", method = RequestMethod.GET,headers="Accept=application/json")
public void insertdynamicurl(#PathVariable("path") String path, HttpServletRequest request) throws ParseException {
}
but this won't do, even i can't get into my function while debuging it. It always give me "noHandlerFound" in my console log. How to do the dynamically url for springrestful service properly?
You can have a look at URI Template Patterns with Regular Expressions which suggests on using regular expressions in #RequestMapping annotations.
The #RequestMapping annotation supports the use of regular expressions in URI template variables. The syntax is {varName:regex} where the first part defines the variable name and the second - the regular expression. For example:
#RequestMapping("/spring-web/{symbolicName:[a-z-]+}-{version:\d\.\d\.\d}.{extension:\.[a-z]}")
public void handle(#PathVariable String version, #PathVariable String extension) {
// ...
}
}
In addition to this, you can match rest of the URL string using request attribute name HandlerMapping.PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE, as shown below.
#RequestMapping("/{id}/**")
public void foo(#PathVariable("id") int id, HttpServletRequest request) {
String restOfTheUrl = (String) request.getAttribute(
HandlerMapping.PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE);
...
}
Shishir's approach is good, but even the regular expression will match the value only up to a first forward slash, because the default AntPathMatcher uses a forward slash as a delimiter for path variables.
This means that you'll always have to statically list the mappings with all the possible path variable combinations. However, on the side of function arguments you don't have to list all the path variables, as you can use a map that will catch all the path variables regardless of the count, and this you can use to achieve a level of generality, something like
#RequestMapping(value = {"/insert/{id}/{name}/{address}", "/insert/{id}/{name}/{address}/{phoneNumber}", "/insert/{id}/{name}/{address}/{phoneNumber}/{age}"} , method = RequestMethod.GET,headers="Accept=application/json")
public void insertsoheaderdinamis(
#PathVariable Map<String, String> pathVariables) {
// to access the values of your path variables do something like
if (pathVariables.containsKey("id")) {
String id= pathVariables.get("id");
}
// do your stuff
}