Spring MVC map controller with trailing string of url - java

Is it possible to map a spring mvc controller by trailing keyword of a url. e.g, lets suppose I have following urls:
example.com/{cityName}
example.com/{cityName}/{categoryName}
example.com/{cityName}/ping
example.com/{cityName}/{categoryName}/ping
I want to have 3 controller methods. 1st url should be handled by controller "X", 2nd url should be handled by method "Y" and 3rd, 4th url should be handled by single method "Z". This means that any url ending by /ping should be handled by method "Z" only. No matter what is leading content of that url.
Is this feasible in Spring MVC?

Is it possible to map a spring mvc controller by trailing keyword of a
url?
Yes, you can use Ant-style path patterns. Following controller will handle any request to URLs ending with /ping, with arbitrary number of levels:
#RequestMapping(path = "**/ping")
public String Z(HttpServletRequest request) {
return request.getRequestURI();
}
In order to extract those Path Variables, e.g. cityName and categoryName, you should inject the HttpServletRequest to the method handler.
In addition to URI templates, the #RequestMapping annotation also supports Ant-style path patterns. You can read more on Spring Documentation.

It looks like you're asking to match a slash as part of the controller mapping. This isn't supported in Spring MVC, and the maintainers have no plans to add it. As a special case, if you are limited to only two levels of "directories", you can just specify the mappings explicitly as above.

Related

SpringMVC - Naming strategy for #RequestParam

I would like all my APIs to use lower-case request parameters, but I would still like to use camel-case in my Java code.
For example, consider the following code:
#GetMapping("/ping")
public String ping(
String responseMessage)
{
return "PONG " + responseMessage;
}
To contact this endpoint and supply a response message, I would have to call: localhost:8080/ping?responseMessage=Hello. However, I would like spring to automatically bind the variable name responseMessage to a request parameter named responsemessage. I specifically do not want to manually write #RequestParam(name="responsemessage") in my controller, but rather configure a global naming strategy for request parameters. Is this possible?
There are a couple of other threads on SO that talks about making the request parameters or url mappings case-insensitive:
RequestParam value in spring MVC to be case insensitive
Is there any way we make PathVariable name case insensitive in Spring?
Spring mvc. case insensitive get parameters mapping
Making a request parameter binding case insensitive
However, the answers in these questions strikes me as quite hacky or requires manual codeing. Is there no simple setting for the behaviour I am after? I know this is possible when using JSON bodies, by configuring the Jackson propertyNamingStrategy. Is there an equivalent for request parameters?

Can Resteasy look into parameter's type for JAX-RS methods?

We were using Resteasy 3.0.9 for our JAX-RS webservices, and recently switched to 3.0.19, where we started to see a lot of RESTEASY002142: Multiple resource methods match request warnings.
For example, we have methods like:
#Path("/{id}")
public String getSome(UUID id)
#Path("/{id}")
public String getSome(int id)
I'm not sure how it worked in 3.0.9, probably, we just were very lucky as Resteasy seems to select first method from all candidates (and 3.0.19 sorts candidate methods).
One solution is to explicitly specify regex: #Path("/{id : [0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}}")
But is there a way to somehow tell Resteasy to look into method parameters and construct appropriate regex automatically?
As far as I know, RESTEasy won't take the method parameter type into consideration when matching a request. According the JSR-339 (that RESTEasy implements), this is how the request matching process works:
A request is matched to the corresponding resource method or sub-resource method by comparing the normalized
request URI, the media type of any request entity, and the requested response
entity format to the metadata annotations on the resource classes and their methods. If no matching resource
method or sub-resource method can be found then an appropriate error response is returned. [...]
The JAX-RS implementations must match the requested URI with the #Path annotation values. In the #Path annotation value you can define variables, that are denoted by braces ({ and }).
As part of the request matching, the JAX-RS implementation will replace each URI template variable with the specified regular expression or ([ˆ/]+?) if no regular expression is specified.
To address the situation you mentioned in your question, you should specify a regex to match UUIDs on one resource method:
#Path("{id : [0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}}")
And you also may consider a regex to match integers on the other resource method:
#Path("{id : \\d+}")

Spring MVC RequestMapping ParamRequest collection/array

I have a #Controller with a #RequestMapping functions that accept collections.
Imagine something like:
requestHandler(Collection<Long> param){
...
}
This mapping only matches when I send requests such as:
http://www.domain.com/mapping/funct?param=1&param=2&param=3
I'd like to match it as well when I send a comma sepparated value:
http://www.domain.com/mapping/funct?param=1,2,3
Is there a way without using .split ? I'd like it to be automatically parsed to a collection.
You would have to write a custom Converter and register it in your Spring MVC context.
It is better to access all query parameters and parse according to your needs in this type of scenarios
You should have access to the requests query string via request.getQueryString().
In addition to getQueryString, the query parameters can also be retrieved from request.getParameterMap() as a Map.

Handling special characters in post parameters for Spring-mvc

I have an application using spring-mvc 3.0.
The controllers are configured like this:
#RequestMapping(value = "/update", method = RequestMethod.POST)
public ModelAndView updateValues(
#RequestParam("einvoiceId") String id){
...}
When posting an id that contains special characters (in this case pipe |), url-encoded with UTF-8 (id=000025D26A01%7C2014174) the string id will contain %7C. I was expecting spring-mvc to url decode the parameter. I am aware that I can solve this by using
java.net.URLDecoder.decode()
but since I have a large number of controllers, I would like this to be done automatically by the framework.
I have configured the Tomcat connector with URIEncoding="UTF-8" and configured a CharacterEncodingFilter, but as I understand it this will only affect GET requests.
Any ideas on how I can make spring-mvc url decode my post parameters?
http://wiki.apache.org/tomcat/FAQ/CharacterEncoding#Q3
This page says CharacterEncodingFilter can change POST parameters
I believe you encounter the same issue as I did.
Try using #PathVariable instead #RequestParam.
#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
If you do, you have to change your url and don't provide parameter 'id'.
Just "/update/000025D26A01%7C2014174".
More information can be found where I found the solution for my problem #RequestParam vs #PathVariable

Can I find the URL for a spring mvc controller in the view layer?

I think what I need is called reverse url resolution in Django. Lets say I have an AddUserController that goes something like this:
#Controller
#RequestMapping("/create-user")
public class AddUserController{ ... }
What I want is some way to dynamically find the url to this controller or form a url with parameters to it from the view (JSP), so I don't have to hardcode urls to controllers all over the place. Is this possible in Spring MVC?
Since Spring 4 you can use MvcUriComponentsBuilder.
For the most type-safe method:
String url = fromMethodCall(on(MyController.class).action("param")).toUriString();
Note this example requires that the method returns a proxyable type - e.g. ModelAndView, not String nor void.
Since 4.2, the fromMappingName method is registered as a JSP function called mvcUrl:
Login
This method does not have the proxy restriction.
Have you considered having a bean that aggregates all of the controller URLs you need into a HashMap and then adding this controller/URL Map to any model that requires it? Each Spring controller has the ability to call an init() method, you could have each controller add it's name and URL to the controller/URL map in the init() methods so it would be ready to use when the controllers go live.
Can solve with Java Reflection API. By Creating Custom Tag library. methods looks like this
Class c = Class.forName("Your Controller");
for(Method m :c.getMethods()){
if(m.getName()=="Your Method"){
Annotation cc = m.getAnnotation(RequestMapping.class);
RequestMapping rm = (RequestMapping)cc;
for(String s:rm.value()){
System.out.println(s);
}
}
}
Possible Problem You Can Face is
1.Path Variable > Like this /pet/show/{id} so set of path name & value should be support then replace this String.replace() before return url
2.Method Overriding > only one method is no problem. if Method override Need to give support sequence of Parameter Type That you really want like Method.getParametersType()
3.Multiple Url to Single Method> like #RequestMapping(value={"/", "welcome"}). so easy rule is pick first one.
4.Ant Like Style Url > Like this *.do to solve this is use multiple url by placing ant like style in last eg. #RequestMapping(value={"/pet","/pet/*.do"})
So Possible link tag style is
<my:link controller="com.sample.web.PetController" method="show" params="java.lang.Integer">
<my:path name="id" value="1" />
</my:link>
Where parmas attribute is optional if there is no method override.
May be I left to think about some problem. :)
I would probably try to build a taglib which inspects the annotations you're using in order to find a suitable match:
<x:url controller="myController">
<x:param name="action" value="myAction"/>
</x:url>
Taglib code might be something roughly like
Ask Spring for configured beans with the #Controller annotation
Iterate in some suitable order looking for some suitable match on the controller class or bean name
If the #RequestMapping includes params, then substitute them
Return the string
That might work for your specific case (#RequestMapping style) but it'll likely get a bit hairy when you have multiple mappings. Perhaps a custom annotation would make it easier.
Edit:
AbstractUrlHandlerMapping::getHandlerMap, which is inherited by the DefaultAnnotationHandlerMapping you're most likely using, returns a Map of URL to Handler
Return the registered handlers as an
unmodifiable Map, with the registered
path as key and the handler object (or
handler bean name in case of a
lazy-init handler) as value.
So you could iterate over that looking for a suitable match, where "suitable match" is whatever you want.
You can get access to the request object in any JSP file without having to manually wire in or manage the object into the JSP. so that means you can get the url path off the request object, have a google into JSP implicit objects.
Here is a page to get you started http://www.exforsys.com/tutorials/jsp/jsp-implicit-and-session-objects.html
The problem with this is that there's no central router in SpringMVC where all routes are registered and ordered. Then reverse routing is not a static process and route resolution in the view layer can be hard to integrate.
Check out this project for a centralized router (like rails) and reverse routing in the view layer.

Categories