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

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;

Related

Spring Boot 2.2.5. How to retrieve a PathVariable parameter inside a Spring Filter

The problem I want to solve.
I need to apply a specific logic to all restful endpoints where the url belongs to a specific sub path: let's say "/api/employee/{id}". This means all the links which start with this path should apply a logic based on the employee ID, which I am trying to apply directly in Spring Boot filter in order to avoid to spread the logic everywhere.
The problem I face.
I am able to get the query parameters from the ServletRequest, but the PathVariables are not available in the Filter.
Any idea how this could be parsed?
Would be much appreciated :)
The PathVariables are simply the URI. You cann call getRequestURI()
From the docs:
java.lang.String getRequestURI()
Returns the part of this request's URL from the protocol name up to the query string in the first line of the HTTP request. The web container does not decode this String. For example:
First line of HTTP request Returned Value
POST /some/path.html HTTP/1.1 /some/path.html
GET http://foo.bar/a.html HTTP/1.0 /a.html
HEAD /xyz?a=b HTTP/1.1 /xyz
https://docs.oracle.com/javaee/7/api/javax/servlet/http/HttpServletRequest.html#getRequestURI--

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:

Mapping of missing URI variables to Request Mapping

I've developed a Spring API /getFileData, which accepts three URI parameters viz. businessDate/fileName/recordId. It is possible to have any of them can be passed as null. But I still want my API to be working in this case also. How can I achieve this?
I've tried using #GetMapping("getFileData/{businessDate}/{fileName}/{recordId}", "getFileData/{businessDate}//", "getFileData/{businessDate}/{fileName}/")..so on like this for all possible combinations.
#RequestMapping(value = "/getFileData/{businessDate}/{fileName}/{recordId}", method = RequestMethod.GET)
I want this API to be working for all the combination of URI parameters if something get missed out. for example someone requested,
/getFileData///22 or
/getFileData/22Dec2018/ or
/getFileData//treasure/22
You can do that with a #RequestParam of type java.util.Map.
With your design, you will have various #PathVariable params in the controller method as well as the order of path variables /{var1}/{var2}... constructs the url so I don't think it would be possible to skip a path variable in the url and still call the same controller method.

How to call the WebApi,Implemented with AttributeRouting for each action methods,calling it from my client and passing the Query parameters in url?

I have implemented attribute routing for each of action methods in My Webapi.
Example of action method is:-
[Route("api/DocumentApi/DeleteDocument/{fileInfoId}/{customerAccountName}")]
[HttpDelete]
public HttpResponseMessage DeleteDocument(int fileInfoId, string customerAccountName)
{
//***
//*** Some body contents
//***
}
Now i want to call the above action method from the client example( Fiddler Web debugger),or browser and want to pass the Url request in the below pattern:-
http://{localhost:9791}/api/DocumentApi/DeleteDocument?fileInfoId=12&customerAccountName="Manish"
Currently i am not able to hit the above action method by the above specified url request.
But if i use the url pattern like below:-
http://{localhost:9791}/api/DocumentApi/DeleteDocument/12/Manish
I am able to hit the above action method.But for my project requirement,I need to use the Url with query parameters only.
Please suggest me the approach,how to achieve this?
Any response will be greatly appreciated.
Route templates in Web API do not support specifying query string parameters. For your scenario, do not define fileInfoId and customerAccountName as part of your route template as doing so makes Web API to strictly look for 5 segments(the text between the / characters in your route template) in your request url...so just modify your route template to [Route("api/DocumentApi/DeleteDocument")] and keep the parameters on the actions as it is...
Use like following code :
[Route("api/DocumentApi/DeleteDocument/{fileInfoId}/{customerAccountName}")]
public HttpResponseMessage TestAction(string fileInfoId,string customerAccountName)
{

need the query string from the request to use with the input attribute of the action mapping

I am using struts 1.3.10. I need the query string from the request to use with the input attribute of the action mapping so that when validation fails, the forward goes to correct page without any null pointer exceptions. how can I do this? I do have the entire forward(myAction.do?foo="bar") as a form property posted throught he jsp. Plesae let me know if I am not clear on the problem definition.
Have you tried request.getQueryString()?
Example:
String queryString = request.getQueryString(); //where "request" is "HttpServletRequest"

Resources