How to dynamically specify Spring Restful WebService URL? - java

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
}

Related

Customize Path to REST params in Pageable

I am using spring to build a REST api with PageAble, to get numberofPages,itens...
first, i did a mapping like this
public ResponseEntity<Data> findByName(#PathVariable(value="name",required=true) String name, #RequestParam(value="page", defaultValue="0") Integer page, #RequestParam(value="qtd", defaultValue="10") Integer linesPerPage, #RequestParam(value="sort", defaultValue="nome") String sort, #RequestParam(value="direction", defaultValue="ASC") String direction)
So in my url i get for example "url?name=erick&direction=asc" but i need to change to "url?name=erick!asc"
How can i change it?
You can do this. Look at page 3 of https://www.ietf.org/rfc/rfc1738.txt
In you case,you should use #RequestParam("name") instead of #PathVariable.Then the request url will be like "url?name=erick&direction=asc"
Spring has three kinds of Annotation.
#PathVariable
This annotation means the variable is on the url.For example:
#RequestMapping("/{id}")
public void pathVariable(#PathVariable("id") Long id){}
The variable was put between the brace at the url.
#RequestParam
This annotation means the variable is part of the quest param,the request url looks like
stackoverflow.com?name=hhhh
For example:
#RequestMapping("/")
public void requestParam(#RequestParam("id")Long id){}
#RequestBody
This annotation means you will receive some data from request body.And some kind of converter,like jackson,will convert it into a properly object.For example:
#PostMapping("/")
public void requestBody(#RequestBody Example example){}

How to acces to the query parameter

My client would send a request corresponding to:
GET http://example.com/services/rs/calendar/origin/destination/outwardDate/returnDate?nbPax=&typo=&card
I do this:
#Path("/service/rs") public class MyServiceImpl {
public MyServiceImpl() {
super();
}
#GET
#Path("/{origin}/{destination}/{goDate}/{returnDate}")
public Response getCalendar(#PathParam("origin") String origin, #PathParam("destination") String destination, #PathParam("goDate") String goDate, #PathParam("returnDate") String returnDate, #QueryParam("nbPax") String nbPax, #QueryParam("typo") String typo, #QueryParam("card") String card) {
//print my parameters
return Response.ok("Success").build();
}
}
there cannot map my query parameter, fails with 404, why ?
You need to correct the signature of your method and add the placeholders inside the #Path annotation to map the path parts to those #PathParam-annotated arguments. The parts that are query params should use the #QueryParam annotation.
#GET
#Path("/calendar/{origin}/{destination}/{outwardDate}/{returnDate}")
public Response getInfo(#PathParam("origin") String origin,
#PathParam("destination") String destination,
#PathParam("outwardDate") String outwardDate,
#PathParam("returnDate") String returnDate,
#QueryParam("nbPax") String nbPax,
#QueryParam("typo") String typo,
#QueryParam("card") String card) {
Also, be aware that if you web application is rooted at some context path (this is typical for applications deployed inside Servlet containers like Tomcat or JBoss), the context path will be part of the URL, e.g.
http://[server host]/[app context path]/[class' #Path]/[method's #Path]
This is the address
http://example.com/services/rs/calendar/
and you are calling
http://example.com/services/rs/calendar/origin/destination/outwardDate/returnDate
where you are treating word "origin" (and the rest) as parameter, while its actually part of address, I believe you have no REST service attached to:
http://example.com/services/rs/calendar/origin/destination/outwardDate/returnDate
Thats why you are getting 404.
Those words you are trying to pull are of type #PathParam, #QueryParam is what you have after ? sign

Spring MVC #Path variable with { } braces

Am developing an application using spring boot. In REST controller i prefer to use path variable(#PathVariabale annotation). My code fetching the path variable but it contatins { } braces as it is in the url. Please any one suggest me to solve this issue
#RequestMapping(value = "/user/item/{loginName}", method = RequestMethod.GET)
public void getSourceDetails(#PathVariable String loginName) {
try {
System.out.println(loginName);
// it print like this {john}
} catch (Exception e) {
LOG.error(e);
}
}
URL
http://localhost:8080/user/item/{john}
Out put in controller
{john}
Use http://localhost:8080/user/item/john to submit your request instead.
You give Spring a value of "{john}" to the path variable loginName, so Spring get it with the "{}"
Web MVC framework states that
URI Template Patterns
URI templates can be used for convenient access to selected parts of a
URL in a #RequestMapping method.
A URI Template is a URI-like string, containing one or more variable
names. When you substitute values for these variables, the template
becomes a URI. The proposed RFC for URI Templates defines how a URI is
parameterized. For example, the URI Template
http://www.example.com/users/{userId} contains the variable userId.
Assigning the value fred to the variable yields
http://www.example.com/users/fred.
In Spring MVC you can use the #PathVariable annotation on a method
argument to bind it to the value of a URI template variable:
#RequestMapping(value="/owners/{ownerId}", method=RequestMethod.GET)
public String findOwner(#PathVariable String ownerId, Model model) {
Owner owner = ownerService.findOwner(ownerId);
model.addAttribute("owner", owner);
return "displayOwner";
}
The URI Template " /owners/{ownerId}" specifies the variable name
ownerId. When the controller handles this request, the value of
ownerId is set to the value found in the appropriate part of the URI.
For example, when a request comes in for /owners/fred, the value of
ownerId is fred.

How to exclude url mappings from #RequestMapping in Spring?

I've a request mapping that handles any string after the context e.g. www.example.com/anystring
I'm handling it as follows:
#RequestMapping(value="/{str}", method = RequestMethod.GET)
public String getApp(#PathVariable("str") String anyString, ModelMap model) {
//Do something
}
The problem is I've 2-3 URLs in my app where the URL is as follows: www.example.com/about, www.example.com/contact etc.
I wrote Request Mappings for them as follows:
#RequestMapping("/about")
public String getAboutPage() {
return "about";
}
But obviously, since I've already declared that any string should be handled by the getApp(), the getAboutPage() never gets executed.
How can I exclude /about, /contact etc from getApp() mapping.
We can obviously add another keyword to the URL string, but that's not possible in my app use case.
Kindly help. :(
EDIT:
Should I just handle /about, /contact inside getApp() like:
#RequestMapping(value="/{str}", method = RequestMethod.GET)
public String getApp(#PathVariable("str") String anyString, ModelMap model) {
if(anyString.equals("about")){
//do about related stuff
}
if(anyString.equals("contact")){
//do contact related stuff
}
//Do something
}
Is there a better way?
Specifying the HTTP request method in the "catch-all" mapping is probably making the path matcher consider it to be more specific than the absolute path mappings.
Specify the request method on the absolute paths, and the mapping comparator should order the absolute matches before the one containing the path variable.
eg.
#RequestMapping("/about", method = RequestMethod.GET)
Alternatively, you could remove the method specification on the catch-all:
#RequestMapping("/{str}")
It is entirely dependent upon your url structure and whether or not any of those paths will accept different http request methods.

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