What is the difference between a spring request mapping and url mapping? - spring

I stumbled across this question after reading the log of my spring boot applicaiton in debug mode.
At startup, the While the spring RequestMappingHandlerMapping is "Looking for request mappings in application context" and finds the resquest mappings defined on my controllers. Later the BeanNameUrlHandlerMapping is "Looking for URL mappings in application context" and fails to find one for every bean defined in my context (no URL paths identified)
My question is, what the difference between a request mapping and an url mapping, can someone link a documentation to read what the BeanNameUrlHandlerMapping is looking for?

RequestMappingHandlerMapping
According to the documentation, the RequestMappingHandlerMapping:
Creates RequestMappingInfo instances from type and method-level #RequestMapping annotations in #Controller classes.
A RequestMappingInfo can be instantiated with the constructor:
public RequestMappingInfo(String name,
PatternsRequestCondition patterns,
RequestMethodsRequestCondition methods,
ParamsRequestCondition params,
HeadersRequestCondition headers,
ConsumesRequestCondition consumes,
ProducesRequestCondition produces,
RequestCondition<?> custom)
and represents a request with a set of conditions to be matched.
BeanNameUrlHandlerMapping
The BeanNameUrlHandlerMapping is an:
Implementation of the HandlerMapping interface that map from URLs to beans with names that start with a slash ("/"),
and as a AbstractDetectingUrlHandlerMapping is:
detecting URL mappings for handler beans through introspection of all defined beans in the application context.

RequestMappingHandlerMapping defines all possible URLs you can process in the application. It is not necessary read the URLs from controllers annotation. The mappings could be calculated. E.g. the question provides a solution when request mappings are generated on fly from method names.
RequestMapping should be comlex with e.g. #PathParameter when mapping text is "\user\{userId}"
So step 1 kind of register all URLs we can process.
Then for each the URL we need to find a bean which actually should be invoked to process some URL (to find a method which spring should call).

Related

Mapping url to a single controller with different method with Spring 3

I have to map different url to single controller
e.g.
/test/read
/test1/read
/test2/read
/test/submit
/test1/submit
/test2/submit
So at the class level I use #RequestMapping(values ={"/test/*", "/test1/*","/test2/*"}) and at method level #RequestMapping(read) and for other method #RequestMapping("submit").
This fails and says that read is already mapped.
By default I think RequestMappingHandlerMapping is being used.
How to do this kind of mapping please suggest.

Implication of use <url-pattern> in a Spring application

Someone have a simple explanation about the effects the value of tag <url-pattern> in my web.xml file will have in a Spring application? I ever use *.html without problems, but if I change to / to a more wide scope, I can't reach any page from my application.
If I choose /, how should be my mapping value in my controller, and how I should link to my views in the JSP files?
First, you need to understand what the <url-pattern> mappings are. They are described in the Servlet specification, here in chapter 12.
In the Web application deployment descriptor, the following syntax is
used to define mappings:
A string beginning with a ‘/’ character and ending with a ‘/*’ suffix is used for path mapping.
A string beginning with a ‘*.’ prefix is used as an extension mapping.
The empty string ("") is a special URL pattern that exactly maps to the application's context root, i.e., requests of the form
http://host:port/<contextroot>/. In this case the path info is ’/’ and
the servlet path and context path is empty string (““).
A string containing only the ’/’ character indicates the "default" servlet of the application. In this case the servlet path is the
request URI minus the context path and the path info is null.
All other strings are used for exact matches only.
So [/...]/* is path mapping, anything prefixed with *. is extension mapping, and / is the default match.
The Servlet specification also explains in what order those are checked.
When a request arrives, the Servlet container goes through all your url-pattern elements to find a match and then calls the service(..) method of the corresponding Servlet. In our case, this is DispatcherServlet.
The DispatcherServlet then, typically, uses a RequestMappingHandlerMapping bean to figure out which handler method is the best match to handle the request. Basically it determines which #Controller #RequestMapping method to dispatch to. RequestMappingHandlerMapping has a property called useSuffixPatternMatch (which is true by default) which determines
Whether to use suffix pattern match (".") when matching patterns to
requests. If enabled a method mapped to "/users" also matches to
"/users.".
So if your servlet is mapped to
<url-pattern>*.html</url-pattern>
and the handler method is mapped
#RequestMapping(value = "/test")
then a request to /context/test.html will be handled by that method.
If I choose /, how should be my mapping value in my controller, and
how I should link to my views in the JSP files?
There are a million answers to this. It depends. Just take note of all the information above and decide for yourself.

Default handler mapping for annotation based spring project

I am new to spring framework. Even I dont have any deep concept about annotation.
I am developing a very small application using spring mvc 3 framework and also I used annotation.
I have a confusion. I have one spring-servlet.xml. Here I have not defined any handler mapping. But still it is working. So must be there some default handler mapping. Can you please let me what is this default handler mapping and how I can override it so that I do some customization.
It is all explained in: http://static.springsource.org/spring/docs/3.2.x/spring-framework-reference/html/mvc.html#mvc-config
Also see this question: How to use default-servlet-handler and Where to put default-servlet-handler in Spring MVC configuration
Spring 3.1 and later doesnt need DefaultAnnotationHandlerMapping and AnnotationMethodHandlerAdapter declaration in the [servelt-name]-servlet.xml
These links might help:
Spring Controller to handle all requests not matched by other Controllers
https://dzone.com/articles/using-the-spring-requestmapping-annotation
I had the same problem that I just resolved so I have confirmed the approach below works, although this is with annotations rather than an XML configuration.
You specify URL prefixes at the controller class level and include a request mapping annotation for ** to ensure you match on anything that falls through your other handlers for this class. There's really nothing special or default about this handler other than the fact that you're defining a handler that is guaranteed to match everything under the class level mappings.
Note: This is not magic. Your handlers are still subject to Spring's ordering algorithm regarding the "best match". It would be nice to have an annotation providing for a true default when nothing else matches handler, especially in cases with complex mappings where "**" is useful outside of this catch-all handler. The basic implementation is:
#RestController
#RequestMapping(value={"/path1/","/path2/"})
public class MyRestController {
#RequestMapping("/subpath")
String matchedRequestHandler () {
return "This matches /path1/subpath and /path2/subpath.";
}
#RequestMapping("**")
String unmatchedRequestsHandler () {
return "This matches everything else.";
}
}
In my actual use case, I needed to handle arbitrary paths to resources inside of the URL pattern and therefore needed to support a variable number of directories. Ideally, that would be handled using a pattern such as:
"/base/{optionaldir}/**/{entityName}/{describeVar:describe.json}"
which works fine by itself, but it isn't compatible with a default handler bound to "**" since the "**" mapping is calculated by Spring as a better match for these types of requests.
Instead, I had to add a bunch of separate entries to my request mapping to support the arbitrary paths within the URL pattern, e.g.
value={"/base/{optionaldir}/{entityName}/{describeVar:describe.json}",
"/base/{optionaldir}/*/{entityName}/{describeVar:describe.json}",
"/base/{optionaldir}/*/*/{entityName}/{describeVar:describe.json}",
"/base/{optionaldir}/*/*/*/{entityName}/{describeVar:describe.json}"
}
Alternatively, I could have handled everything with a "**" mapping and parsed the URL myself, but that kind of defeats the purpose of using request mappings with path variables. Hopefully Spring's capabilities will evolve in this area in the future.

Accessing Spring Controller Name from View

With Spring, how can i retrieve the following Controller attributes in the view?
Controller name
Controller's #RequestMapping URI
Action method name
Action method's #RequestMapping URI
One approach which i have tried is by creating a subclass of HandlerInterceptorAdapter and overriding postHandle. I register my subclass as an mvc:interceptor for a list of given paths - which is clunky to maintain but was the only way to avoid my interceptor being called for ResourceHandler requests (which i don't want). In my postHandle i can easily add the 2 name attributes, but not the URIs...
Parsing from the HttpRequest object requires constraints on all Controller RequestMappings. I.e. i must always map /Controller/Action or equiv scheme. Quite limiting.
Creating an ApplicationContext and querying that with the requestURI is too long-winded.
I am thinking about dropping the HandlerInterceptorAdapter and instead defining a BaseController for all my controllers to extend.
I wanted to ask before i do this, is there a better approach?
You haven't stated why you need to do this (it sometimes helps to include your motivation, as others can suggest alternative approaches).
But I'm guessing that the Spring 3.1 features loosely termed "end point documentation" may do what you are asking... See RequestMappingHandlerMapping in the Spring documentation which doesn't provide a lot of detail, so this example project is the best place to see it in action:
Spring MVC 3.1 Demo App
example controller
example JSP page

Can i use Spring's #RequestMapping and BeanNameUrlHandlerMapping in conjuntion with each other to map a URL to method?

What I would like to do is have a common Service class which has various methods such as "search" "retriveByID" etc.
Ideally this class would consume the service parameters and populate a request object and hand off to the appropriate data source handler.
I want to instantiated a service class as a Spring bean with different request handlers depending on the domain object being searched. Then using bean BeanNameUrlHandlerMapping invoke a different Service class based on the URL.
<bean name="/sequence/*" class="org.dfci.cccb.services.SearchServiceImpl">
<property name="searchHandler">
....
My problem is that when i try to do this I can't use method level RequestMapping annotations to select the appropriate method of the service class.
#RequestMapping("*/search/")
QueryResult search(...
Alternatively is it possible to inject annotation values through bean definitions?
UPDATE
There is also a Springsource article on this topic:
http://blog.springsource.com/2008/03/23/using-a-hybrid-annotations-xml-approach-for-request-mapping-in-spring-mvc/
Was very surprised to learn that it actually works. Just remove the trailing slash:
#RequestMapping("*/search")
And this works too:
#RequestMapping("search")

Resources