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.
Related
I have question about controllers. Always when i working with controller im start to declare #RequestMapping for example if have UserController then is #RequestMapping("/user");
What if i want to declare another path in this same controller? For example im have #GetMapping("/info") and i will get info about user, but what if i want to declare on this same controller path localhost:8080/topic/blablabla? Is another solution than delete #RequestMapping from controller and make on every Get/PostMapping another path?
Defining a #RequestMapping at the controller level; it means narrowing it down to your criteria.
You can use the #RequestMapping annotation to map requests to controllers methods. It has various attributes to match by URL, HTTP method, request parameters, headers, and media types. You can use it at the class level to express shared mappings or at the method level to narrow down to a specific endpoint mapping. Read More
It is good you want to do, sometimes I need it too but as far as I research it is not supported now.
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).
I am using Spring Boot application. In that i have used Spring MVC at front end. I have a requirement to download various reports like pdf, xls. As i understand, Spring Boot, internally uses ContentNegotiatingViewResolver, BeanNameViewResolver, ViewResolverComposite and InternalResourceViewResolver. I am not overriding any beans in code and using default configurations as provided
Currently to test, i am using below url
http://localhost:8080/SearchCustomers.xls
Properties in application.properties file are
spring.mvc.media-types.pdf=application/pdf
spring.mvc.media-types.xls=application/vnd.ms-excel
In my code, i have created a view class which extends from AbstractPdfView.It is a spring bean and it's id is "SearchCustomers".Controller code returns "SearchCustomers" as a view name.
Whenever i execute above code, ContentNegotiatingViewResolver doesn't returns any view.ContentNegotiatingViewResolver internally uses BeanNameViewResolver, ViewResolverComposite and InteralResourceViewRsolver to resolve view names.In our case, the bean name matches with view but its media type doesn't as it matches the path extension internally along with the bean content type.This is a correct Behavior?
However DispatcherServlet reiterates through all view resolvers and which is causing an issue.
In the second iteration, BeanNameViewResolver matches the bean id with returned view name from controller and it invokes the pdf view,which i believe is incorrect.
Is there any workaround for this?
I found out the solution
If you want just one controller method to handle all type of requests..then in that case your view should be given id in below format
id - viewname + path extension
Ex
My controller method returns view name as "SearchCustomers" for all type of request..
I have created different views for different requests like
#Component("SearchCustomers.pdf")
class MyPdfView extends from AbstractPdfView
#Component("SearchCustomer.xls")
class MyExcelView extends from AbstractExcelView
Interanally, CNVR searches for these beans. and then it matches the mediatype/contenttype which returns the correct 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
I am trying to share data between two controllers in a Spring mvc application.
In Controller A I have annotated the class with #SessionAttributes({"mymodel1"}) and in the method which receives the first GET request I add it to the ModelMap:
model.addAttribute("mymodel1", MyModel1);
I now want to read myModel1 from Controller B.
In this Controller I have the following method which intercepts the POST requests and already has a different model in its parameters:
public String processSubmit(#ModelAttribute("mymodel2") MyModel2 mymodel2, BindingResult result, SessionStatus status, HttpServletRequest httpRequest)
Up to this point everything works fine and I am able to read mymodel2 from processSubmit however if I now want to add another #ModelAttribute("mymodel1") MyModel1 mymodel1 to this method signature I would have expected to be able to read the value I was setting in Controller A however I'm getting exceptions that the first model is no longer recognised.
So my question is: how can I read mymodel2 from Controller B?
You can't do that with #SessionAttributes :
Session attributes as indicated using this annotation correspond to a specific handlers model attributes, getting transparently stored in a conversational session. Those attributes will be removed once the handler indicates completion of its conversational session. Therefore, use this facility for such conversational attributes which are supposed to be stored in the session temporarily during the course of a specific handlers conversation.
For example I use this annotation when I want to validate elements with Hibernate validation, and after I submit the page and SOME elements are invalid I want the rest to be still on the page, but this is not your case. I think that the only way to do it would be with:
HttpSession.getAttribute()
The javadoc excerpt above is the most typical way #SessionAttributes is used. However, what Joly is describing should also work. Session attributes are stored via DefaultSessionAttributeStore, which by default does not prefix attribute names when it stores them in the session. That means if ControllerA and ControllerB both list an attribute called "mymodel1", they're actually referring to the same session attribute. You'll need to provide a little more information on the error you're getting and the actual controller code.