Handling forward slashes spring mvc rest - spring

I have a rest controller setup like below
#RequestMapping(value = {"getDataFromSpaceForType/{gridName}/{spaceName}/{dataType}/{fieldNames}/{criteria}"}, method = GET, produces = "application/json")
public EntriesForTypeName getDataFromSpaceForType(#PathVariable Map<String, String> dataRequestVariables) throws Exception {
The last field criteria can contain multiple forward slashes. I am unable to handle such scenario. It breaks with 404 error
Also i dont know how many slashes might come, so it becomes impossible to create multiple methods.

If you know that your URL may contain slashes, all you have to do is to encode the URL before you send/use it.
If your front-end is angularJS then you can do it like this:
How to generate url encoded anchor links with AngularJS?
Or if you use jquery then:
URL Encode a string in jQuery for an AJAX request

Related

How to handle invalid/extra special characters & = in request url-SpringBoot?

I have a Rest service where get call if I send multiple invalid/extra & and = characters then also my endpoint does not throw any error. I would like to throw back invalid request error if url contains any extra special character like & or =.
for example:
http://localhost:8080/myservice?rollNo=03456789321&school=Myschool //This is Okay for me
http://localhost:8080/myservice?rollNo=03456789321&school= //should throw error as school is not having value
http://localhost:8080/myservice?rollNo=03456789321&&&&school=Myschool
//should throw error as &&&& is multiple where it should only one
http://localhost:8080/myservice?rollNo=03456789321&= //should throw error as &= is there at end having no sence.
Note that , I am hitting these request from postman , and I have doubt that postman do something with these parameters, cause I am not able to find these extra characters in spring boot while debugging.
Any way through which i can get whole request url in my controller so that I can find out for these charecters comming?
Any built in springboot annotation is there to handle such a cases?
I got my problem solved.
After lot of research , and some observation I came to know that when you pass any number of characters among & and = in request url, the rest client tools like postman , or advanced rest client will refine the url before hitting actual server and remove those extra un-necessary characters. SO if you write multiple &&&& or == charecters in url , it will consider each extra & as blank parameter and will ignore while sending final request, only of those characters which has parameter names besides it it will taken as part of refined request.
you can see in screenshot bellow:
You can Use #RequestParam in your Spring Boot rest Controller
Something of the following
#GetMapping(value = "/myservice")
public boolean doSomething(#RequestParam("rollNo") Integer rollNo , #RequestParam("school") String school) {
doValidation(rollNo,school);
// Do Something
return true;
}
#RequestParam will make sure that your Url need to have these Params rollNo & school. Without it it will throw error.
But if you were to pass an empty string like &school= in your second example. The controller will get an empty String.
You can add a basic validation layer right before you do anything in you controller to handle this condition.

How to get the current Request Mapping URL configured at Controller layer when request is executed?

I went through so many links like How to show all controllers and mappings in a view and How to configure a default #RestController URI prefix for all controllers? and so on.
I want to get the Request Mapping URL at Filter interceptor
Ex: This URL I configured at REST controller method, and naturally we will pass /employees/employee-names/John to get the Employee John.
/employees/employee-names/{employee_name}
Now, when somebody hit /employees/employee-names/John I want to get the value of actual mapping url if REST controller /employees/employee-names/{employee_name},
Any pointers how to get that ?
Spring MVC sets the attribute HandlerMapping.BEST_MATCHING_PATTERN_ATTRIBUTE, which you can use to get the pattern that was used to match the incoming request:
String matchingPattern = (String) request.getAttribute(HandlerMapping.BEST_MATCHING_PATTERN_ATTRIBUTE)
That would return /employees/employee-names/{employee_name} in your case.
I was able to solve this issue using below code. AntPathMatcher is the perfect way to identify if the incoming request and URL you configured in the property file matches exactly. This solution works greatly for me.
AntPathMatcher springMatcher = new AntPathMatcher();
Optional<String> antMatch = props.getMapping().stream()
.filter(//Perform Some Filter as per need)
.map(Mapping::getVersion)
.findFirst();
return antMatch.isPresent() ? antMatch.get() : null;

Influencing order of RequestMapping processing

In short this is what I'm searching for: I want to create a RequestMapping that catches all URLs except a small list I don't want to catch.
The minimum to exclude is everything below /webjars/, I also would like to exclude other URLS like /actuator/ and probably more.
Background information
We need to replace an old CMS which has literally thousands of different URLs. All URLs need to be detected and checked against a database and then the users shall be presented with a landing page, this landing page will then redirect the user to the new CMS target URL.
The logic that needs to be applied is too complicated for some Apache / nginx magic, therefore I wrote a Spring Boot application that can accomplish this.
I've created a #RequestMapping(value = "**", method = RequestMethod.GET) that catches all GET requests (these are the one I want to grab and react on) and a #RequestMapping(value = "**") for the other http verbs like POST and DELETE which I simply abort by sending a http error status code.
This works fine and the (simplified) code looks like this:
#RequestMapping(value = "**", method = RequestMethod.GET)
public String catchAccepted(HttpServletRequest request, HttpServletResponse httpServletResponse, Model model) {
model.addAttribute("targetUrl", ua.deriveNewUrl(request));
return "redirect";
}
#RequestMapping(value = "**")
#ResponseBody
public ResponseEntity<Object> catchDenied(HttpServletRequest request, HttpServletResponse httpServletResponse) {
return new ResponseEntity<Object>(HttpStatus.I_AM_A_TEAPOT);
}
The page that gets displayed for all the GET requests is based on a Thymeleaf template which uses Bootstrap in order to do the layout job.
In order to include Bootstrap I use the webjars-locator and org.webjars.bootstrap, the resources are included by specifying <script src="/webjars/bootstrap/js/bootstrap.min.js"></script> in the redirect.html Thymeleaf template.
Problem
The problem is, that my ** mapping on GET also gets applied to the /webjars/... call and instead of the desired js code I get whatever my redirect template returns.
I found no way to tell Spring Boot about the desired order.
First I would like to have Spring Boot handle the webjars mapping, then my other mapping.
Attempts so far
I checked other posts on SO but they only work when I have access to the sourcecode where the mapping is made. And I don't have access to the webjars locator / see no point in changing it just to solve this issue.
I also tried to set up a "anything that is not related to webjars" mapping like this:
#RequestMapping(value = "^(?!webjars$|actuator$).*", method = RequestMethod.GET)
But this doesn't have the desired effect because the RequestMapping only seems to support ant-stlye paths, which doesn't support negations because Ant (in contrast to Spring Boot) has a field for includes and excludes: https://ant.apache.org/manual/dirtasks.html
Negating the mapping seems only to be possible for params, not for the path: Change #RequestMapping order
I didn't yet find a way to influence the order if other mappings come from code I can not incluence.
But I found a way to configure "catch all except of ...":
#RequestMapping(value = { "", "/", "{url:(?!webjars$|actuator$).*}/**" }, method = RequestMethod.GET)
This configures three mappings. The first two are there to handle calls to the root of the webserver. The third configures a path pariable which I could also put into a #PathVariable but in my scenario the value doesn't matter. If you configure a path variable you need to give it a default because the pattern will only be satisfied depending on the value of your URL.
The regex tells Spring Boot only to react if the url doesn't contain webjars or actuator. The regex itself is best explained by using regex101:

Accessing rest of URI as PathVariable [duplicate]

I have a use case. Spring MVC REST Url receive content using the GET method code is as follows:
#RequestMapping("/q/{key}")
public String query(#PathVariable() String key, Model model){
//todo`
}
But the front end of such a request: /q/SiGeC%2FSi%E5%BC%82%E8%B4%A8%E7%BB%93. %2F decoded character /. The controller can not match mapping request.
How should I do?
You can include regular expressions in your path variable as such:
#RequestMapping("/q/{key:.*}")
This will grab EVERYTHING after the /q/. Or you can make it a more specific regex to match the pattern you are actually expecting.
Annotations of # PathVariable may not be able to solve this problem.Last use the workaround is resolved.Code is as follows:
#RequestMapping("/q/**")

Spring 4 #RequestMapping handling REST URL with special characters

How does Spring 4 handle the REST URL with special character, such as #?
For example : http://localhost:8080/#/members/browse?id=1234
The following code seems not working.
Because Spring always discards everything after (including) #, and just returns the response of http://localhost:8080
Could anyone give us some help?
#RequestMapping(value = "/#/members/browse", method = RequestMethod.GET, produces = "application/json")
public String findMembers(#RequestParam(value="id", required=false) {
// some code
}
This is the expected behavior. It's a fragment identifier and it's not meant to be used for routing requests on the server side.
In your browser, clicking on another anchor link like #/members/browse?id=5678 in the same page looks for an anchor within the page and does not send a request to the server.
I think you're probably using a javascript framework such as Ember or Angular, which provide routing components to route those events on the client side and render views. See the router documentation for Ember.

Resources