UrlMapping Wildcard for #Pathvariable - java

I am trying to Define #PathVariable with wildcard in Web.xml for url-mapping.
Seems it does not work unless I give the full path in the mapping.
Here is my code.
TrackingController .java - PSEUDO Code
#Controller
#RequestMapping(value = "/tracking")
public class JobController implements Runnable {
#RequestMapping(value = "/{countrycode}/{urlID}", method = RequestMethod.GET)
#ResponseBody
public RedirectView refreshcache(#PathVariable("countrycode") String countrycode, #PathVariable("urlID") String urlID){
String Oauthurl="";
System.out.println(countrycode);
System.out.println(urlID);
if (countrycode.equals("India"))
{
Oauthurl ="https://www.google.co.in/";
}
else
{
Oauthurl ="https://www.google.com/";
}
RedirectView redirectView = new RedirectView();
redirectView.setUrl(Oauthurl);
return redirectView;
}
What I have already Tried is putting the full path and the path with wildcard
in the web.xml
Full path- Works
<servlet-name>appServlet</servlet-name>
<url-pattern>/tracking/India/1</url-pattern>
</servlet-mapping>
Wildcard - Does not work
<servlet-name>appServlet</servlet-name>
<url-pattern>/tracking/*</url-pattern>
</servlet-mapping>
Expected Result with wild card is it would redirect to the Url based on the #Pathvariable provided
However it throws 404 Error

You need to specify double (*) in the path url to match any string.
here is the example.
<servlet-name>appServlet</servlet-name>
<url-pattern>/tracking/**</url-pattern>
</servlet-mapping>

Don't use mapping via web.xml. It's already done by #RequestMapping.
Following code should work:
#Controller
#RequestMapping(value = "/tracking")
public class JobController {
#GetMapping("/{countryCode}/{urlID}")//removed #ResponseBody
public RedirectView refreshCache(#PathVariable String countryCode, #PathVariable String urlID) {
String oauthUrl;
System.out.println(countryCode);
System.out.println(urlID);
if ("India".equalsIgnoreCase(countryCode)) {//Avoid NPE
oauthUrl = "https://www.google.co.in/";
} else {
oauthUrl = "https://www.google.com/";
}
return new RedirectView(oauthUrl);
}
}
If don't - check configuration. Spring can't find your controllers. Take a look

Related

Accept multiple params in a single PathVariable

I have a controller method as this:
#PostMapping("/view/{location}")
public ModelAndView view(#PathVariable("location") String location) {
ModelAndView modelAndView = new ModelAndView();
return modelAndView;
}
This method is capable of receiving requests like
"/view/a" or "/view/b" such that pathVariable location becomes a or b.
But I want this same method to receive all the requests having /view in their beginning, such that the pathVariable "location" holds the rest of the data.
for example
for a request as /view/a/b/c, the pathVariable location will become a/b/c.
like a file system hierarchy.
Please let me know if such a thing is possible in Spring MVC, and I am very new at this.
Check out this article
The idea is to map all the paths which start with /view to a single controller method by adding **, but you'll have to use HttpServletRequest instead of #PathVariable.
So, in your case, it'll be something like this:
#PostMapping("/view/**")
public ModelAndView view(HttpServletRequest request) {
String pathVariable = extractId(request);
ModelAndView modelAndView = new ModelAndView();
return modelAndView;
}
private String extractId(HttpServletRequest request) {
String path = (String) request.getAttribute(HandlerMapping.PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE);
String bestMatchPattern = (String) request.getAttribute(HandlerMapping.BEST_MATCHING_PATTERN_ATTRIBUTE);
return new AntPathMatcher().extractPathWithinPattern(bestMatchPattern, path);
}
Also, check out this question
You could go by the approach shared earlier,
#GetMapping(value = "blog/**")
public Blog show(HttpServletRequest request){
String id = (String)
request.getAttribute(HandlerMapping.PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE);
System.out.println(id);
int blogId = Integer.parseInt(id);
return blogMockedData.getBlogById(blogId);
}
Second way is to use RequestParam instead of Path variable.
you will call the api using :
http://localhost:8080/blog?input=nabcd/2/nr/dje/jfir/dye
controller will look like :
#GetMapping(value = "blog")
public Blog show(#RequestParam("input") String input){
If you are certain about the number of slash in your input, you could go with any approach mentioned here help

Path Variable Causing 404

I'm adding a Path variableto receive value sent by URL. And this is my controller.
#Controller
#RequestMapping("/user")
public class UserController {
#RequestMapping(value = "/list/{field}", method = RequestMethod.GET)
public void userList(Model model, #PathVariable("field") String field) {
List<Users> userList = userDAO.searchAll();
System.out.println("Condition "+field);
model.addAttribute("userList", userList);
}
}
But I'm getting a 404 error.
And this is my folder structure for jsp.
Please help me to find out what is wrong here.
Thanks.
Edit : And also is there any chance that I can send empty path variable ex: http://localhost:8080/mvcquick/user/list and return to the same method?
system is looking for mvcquick/WEB-INF/jsp/user/list/n.jsp.
I dont see this file.
Please try this:
#Controller
#RequestMapping("/user")
public class UserController {
#RequestMapping(value = "/list/{field}", method = RequestMethod.GET)
public String userList(Model model, #PathVariable("field") String field) {
List<Users> userList = userDAO.searchAll();
System.out.println("Condition "+field);
model.addAttribute("userList", userList);
return "user/list"; // added line. Alos return type to String
}
Please try with below option.
#PathVariable(name="field",required=true)
Notice the error says n.jsp is not found. It means you're not returning the view name from the controller - I assume it's list.jsp. To change this, give a return value of String pointing to your list.jsp file. So try using
#RequestMapping(value = "/list/{field}", method = RequestMethod.GET)
public String userList(Model model, #PathVariable("field") String field) {
List<Users> userList = userDAO.searchAll();
System.out.println("Condition "+field);
model.addAttribute("userList", userList);
return "jsp/user/list.jsp"; // Path root must be from WEB-INF
}
I think it is looking for n.jsp inside your ".jsp" files. Please make sure that while sending id or attributes you are sending properly.
See this link for sending data(SO)

Spring path params with multiple slash

I have a Spring boot app where I have an API that takes other urls as path params. For example:
host:port/{eid} is my base path and after this I can have URLs like
host:port/{eid}/abc
host:port/{eid}/abc/pqr/
host:port/{eid}/abc/pqr/b=2
host:port/{eid}/abc/pqr/xyz
host:port/{eid}/abc/pqr/xyz?a=1
...and so on...
I would like to define a controller that I can map to all the above URLs and that should work something like
#RequestMapping(value = "/{eid}/{urlParts}", method = RequestMethod.GET)
public ResponseEntity<Object> share(
#PathVariable String eid,
#PathVariable String urlParts) {
......
}
I tried using #PathVariable Map<String, String> path and also #RequestMapping(value = "/{eid}/{urlParts:.+}"
but couldn't get the expected result.
Is there any solution to receive path slash(/) in path param.
Note: I can not URL encode the slash(/) in the URL. That's not an option for me.
I know the query is too old but still it's useful and this answer can help others.
You can get the full url parts using request attribute as below.
#RequestMapping(value = "/{eid}/**", method = RequestMethod.GET)
public ResponseEntity<Object> share(#PathVariable String eid, HttpServletRequest request) {
Object uriObject = request.getAttribute(HandlerMapping.PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE);
if (null != uriObject) {
String urlParts = uriObject.toString().replaceFirst("^/" eid + "/", "");
}
....
}
why don't you try #RequestParam to take url if you working with jsp or other stuff..
#PathVariable means that the annotated method argument should be extracted from the path of the invoked URL. #RequestParam means that the annotated method argument must be extracted from the request parameters. None of these annotations cause the annotated arguments to be put in the request, session or application scope.
so you use your map also...
${username} means "write the value of the username attribute (found in page, or request, or session, or application scope) in the response". Since you didn't include any username attribute in any of those scopes, it doesn't write anything.
The code would work if the method returned a ModelAndView object, and the model contained a username attribute and a studentid attribute.
you can refer below code and link :
First URL : localhost:8080/projectName/test?firstname=john
Second URL :localhost:8080/projectName/test?firstname=john&secondname=roy
#Controller
#RequestMapping("/test")
public class TestController {
#RequestMapping(value = { "/test/{firstname}/test" }, method = { RequestMethod.GET })
public String someMethod(#PathVariable("firstname") String firstname){
return someMethod(firstValue )
}
#RequestMapping(value = { "/test/{firstname}/{otherString}/test" }, method = { RequestMethod.GET })
public String someOtherMethod(#PathVariable("firstname") String firstname, #PathVariable("secondname") String secondValue) {
return someMethod(firstValue + "/" + secondValue)
}
}
so I am not sure if there is a direct spring implementation to doing this however, you could us a mixture of things.
#RequestParam - returns a map of the URL params (succeeding the ?)
#PathVariable - return the eid
HttpServletRequest - use the request to return the URI and strip host:port/{eid} and anything after ? , then use Arrays.asList(str.split("/")); (remember this is a wrapper of an array use new ArrayList<Sting>(Arrays.asList(str.split("/"))) )
#RequestMapping(value = "/{eid}", method = RequestMethod.GET)
public ResponseEntity<Object> share(
#PathVariable String eid,
#RequestParam Map<String,String> allRequestParams,
HttpServletRequest request) {
......
}

Forward request to another controller in Spring MVC

I'd like to know if there is a way I can forward a request from one controller to another without actually changing the URL in the browser.
#RequestMapping(value= {"/myurl"})
public ModelAndView handleMyURL(){
if(somecondition == true)
//forward to another controller but keep the url in the browser as /myurl
}
examples that I found online were redirecting to another url which was causing other controllers to handle that. I don't want to change the URL.
Try to return a String instead of ModelAndView, and the String being the forward url.
#RequestMapping({"/myurl"})
public String handleMyURL(Model model) {
if(somecondition == true)
return "forward:/forwardURL";
}
Instead of forwarding, you may just call the controller method directly after getting a reference to it via autowiring. Controllers are normal spring beans:
#Controller
public class MainController {
#Autowired OtherController otherController;
#RequestMapping("/myurl")
public String handleMyURL(Model model) {
otherController.doStuff();
return ...;
}
}
#Controller
public class OtherController {
#RequestMapping("/doStuff")
public String doStuff(Model model) {
...
}
}
As far as I know "forward" of a request will be done internally by the servlet, so there will not be a second request and hence the URL should remain the same. Try using the following code.
#RequestMapping(value= {"/myurl"})
public ModelAndView handleMyURL(){
if(somecondition == true){
return new ModelAndView("forward:/targetURL");
}
}

RESTful servlet URLs - servlet-mapping in web.xml

I feel like this is a common problem but nothing I've researched has worked yet...
In my web.xml I have a mapping for all REST calls -
<servlet-mapping>
<servlet-name>springmvc</servlet-name>
<url-pattern>/rest/*</url-pattern>
</servlet-mapping>
This works well if the URL is -
GET /rest/people
but fails if it is
GET /rest/people/1
I get a 400 Bad Request error saying The request sent by the client was syntactically incorrect (). I'm not sure it even made it to the Spring servlet to get routed...
How can I wildcard anything that starts with /rest so that it can be handled appropriately?
In other words, I'd like for all of the following to be valid -
GET /rest/people
GET /rest/people/1
GET /rest/people/1/phones
GET /rest/people/1/phones/23
Edit - Controller code as requested
#Controller
#RequestMapping("/people")
public class PeopleController {
#RequestMapping(method=RequestMethod.GET)
public #ResponseBody String getPeople() {
return GsonFactory.getInstance().toJson(LookupDao.getInstance().getPeople());
}
#RequestMapping(value="{id}", method=RequestMethod.GET)
public #ResponseBody String getPerson(#PathVariable String id) {
return GsonFactory.getInstance().toJson(LookupDao.getInstance().getPerson(id));
}
}
Answer
#matsev It didn't seem to matter if I had the / there or not.
While I was transposing the variable names for public view I changed a couple things to make it work.
Original
#RequestMapping(value="{id}", method=RequestMethod.GET)
public #ResponseBody String getPerson(#PathVariable String userId) {
return GsonFactory.getInstance().toJson(LookupDao.getInstance().getPerson(userId));
}
What I posted
#RequestMapping(value="{id}", method=RequestMethod.GET)
public #ResponseBody String getPerson(#PathVariable String id) {
return GsonFactory.getInstance().toJson(LookupDao.getInstance().getPerson(id));
}
The variable name mismatch did me in... I leave this here as a warning to all... match your variable names!
Try add a /before the {id}:
#RequestMapping(value="/{id}", method=RequestMethod.GET)
Without it, the id will be appended directly to the people url, e.g /rest/people1 as opposed to /rest/people/1.

Categories