I came across MultiActionController today, and I'm not sure I understand what it is used for... on the Spring documentation, it says
Controller implementation that allows multiple request types to be handled by the same class. Subclasses of this class can handle several different types of request with methods of the form
On another site, they said
It aggregates multiple request handling methods into single controller, so related functionality can be kept together easily.
I'm still not understanding how is extending MultiActionController better or different than the following? Or is MultiActionController more a legacy from older versions of Spring? I feel I have some basic misunderstanding...
#Controller
public class MyController {
#RequestMapping("/SomePage.html")
public ModelAndView epdReview(
#RequestParam(value="sessionID", required=true) String sessionId,
MyFormData form,
HttpSession session,
HttpServletRequest request){
//....
}
#RequestMapping(value = "/newData.json", method = RequestMethod.POST)
public #ResponseBody ValidationResponse process(Model model,
#Valid SomeData formData, BindingResult result,
HttpSession session) {
//....
}
}
Yes, that is from the Spring 2.0 MVC API, as is anything that implements the old Controller Interface. I can't find anything around the web from a Spring Developer regarding why this one was not deprecated when all of its cousins were.
I could offer 100% pure speculation that it could be because people could have totally valid custom-implementations of the MethodNameResolver that are impossible to replace with the behaviour of DefaultAnnotationMethodHandlerAdapter. Therefore annotation based config does not provide a 100% alternative to every legitimate use of this class.
Spring offers a multi-action controller with which multiple actions can be aggregated into one controller, grouping functionality together. The multi-action controller is capable of mapping requests to method names and then invoking the right method name. Using the multi-action controller is especially handy when you have a lot of common functionality in one controller, but want to have multiple entry points to the controller
The hole point of using Annotated Controllers - like your later example- is support for request handling without depending on inheritance or framework specific classes (like four first example). In Spring Documentation you can find this:
Spring 2.5 introduces an annotation-based programming model for MVC
controllers, using annotations such as #RequestMapping, #RequestParam,
#ModelAttribute, etc. This annotation support is available for both
Servlet MVC and Portlet MVC. Controllers implemented in this style do
not have to extend specific base classes or implement specific
interfaces.
So, if you're already using Annotated Controllers there's no point in extending Spring built-in Controllers like MultiActionController.
Spring MultiActionController is used to map similar actions to single controller. So If you use MultiActionController class, you do not need to create new controller class for each action.
For example: When we login to internet banking, there is an option to add and delete payee. So we can use single PayeeController to perform similar actions such as add and delete.
Quoted from mkyong.com:
In Spring MVC application, MultiActionController is used to group related actions into a single controller, the method handler have to follow below signature :
public (ModelAndView | Map | String | void) actionName(
HttpServletRequest, HttpServletResponse [,HttpSession] [,CommandObject]);
example
package com.vitthal.common.controller;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.multiaction.MultiActionController;
public class CustomerController extends MultiActionController{
public ModelAndView add(HttpServletRequest request,
HttpServletResponse response) throws Exception {
return new ModelAndView("CustomerPage", "msg","add() method");
}
public ModelAndView delete(HttpServletRequest request,
HttpServletResponse response) throws Exception {
return new ModelAndView("CustomerPage", "msg","delete() method");
}
public ModelAndView update(HttpServletRequest request,
HttpServletResponse response) throws Exception {
return new ModelAndView("CustomerPage", "msg","update() method");
}
public ModelAndView list(HttpServletRequest request,
HttpServletResponse response) throws Exception {
return new ModelAndView("CustomerPage", "msg","list() method");
}
}
With ControllerClassNameHandlerMapping configured.
<beans ...>
<bean
class="org.springframework.web.servlet.mvc.support.ControllerClassNameHandlerMapping" />
<bean class="com.mkyong.common.controller.CustomerController" />
</beans>
Mapping Examples
Now, the requested URL will map to the method name in the following patterns :
CustomerController –> /customer/*
/customer/add.htm –> add()
/customer/delete.htm –> delete()
/customer/update.htm –> update()
/customer/list.htm –> list()
InternalPathMethodNameResolver
The InternalPathMethodNameResolver is the default MultiActionController implementation to map URL to method name. But, you are still allow to add prefix or suffix to the method name :
<beans ...>
<bean
class="org.springframework.web.servlet.mvc.support.ControllerClassNameHandlerMapping" />
<bean class="com.vitthal.common.controller.CustomerController">
<property name="methodNameResolver">
<bean class="org.springframework.web.servlet.mvc.multiaction.InternalPathMethodNameResolver">
<property name="prefix" value="test" />
<property name="suffix" value="Customer" />
</bean>
</property>
</bean>
</beans>
Now, the URL will map to the method name in the following pattern :
CustomerController –> /customer/*
/customer/add.htm –> testaddCustomer()
/customer/delete.htm –> testdeleteCustomer()
/customer/update.htm –> testupdateCustomer()
/customer/list.htm –> testlistCustomer()
Note
With annotation, the MultiActionController is more easy to configure
Related
Looking to create a custom implementation to authorize requests.
I am evaluating options to avoid using annotations on every method in the controller.
Instead, I am exploring the possibility centralizing this feature via a filter that checks if the logged in user has the required permission for the URL
We are using Spring 3.2.5.RELEASE
I intend to create a database table that has a mapping between a permission and the relevant URL.
I am looking for a way to get the request mapping information for the current URL.
For E-g :
In my database, I have:
URL=/view/{id} , permission=VIEW_USER
If the current URL is :
/app/user/view/1
, a method annotated with
#RequestMapping(value = "/view/{id}", method = RequestMethod.GET)
will be invoked. But before this happens, I need to verify if the logged in user has the permission to view user details.
In my filter, I can get the current URL (/app/user/view/1) , how do I get the corresponding mapping (/view/{id}) ? Is there a mechanism to match a URL to its corresponding MVC request mapping ?
I have looked/am looking at related posts on SO and also looked at Spring code but am yet to find a way.
If you want to do it that way, you could register MVC interceptor instead of servlet filter.
Create a class that extends HandlerInterceptorAdapter and in preHandle method you will have access to controller's method and it's annotation. Prehandle method of your interceptor could look something like this:
#Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
if (handler instanceof HandlerMethod) {
HandlerMethod method = (HandlerMethod) handler;
if (method.getMethod().isAnnotationPresent(RequestMapping.class)) {
RequestMapping rqm = method.getMethodAnnotation(RequestMapping.class);
String[] urlMappings = rqm.value();
//do security logic
}
}
...
}
Then you need to register the interceptor. If you use xml config it's done like this:
<mvc:interceptors>
<bean class="com.example.MySecurityInterceptor" />
...
</mvc:interceptors>
Please note that your approach will be difficult, you'll need to handle all the request mapping cases that spring supports. For example, #RequestMapping that's annotated on class level. Or #RequestMapping annotated on parent class of the controller etc..
I am working on my simple REST API prototype written in Spring 3.2. I have read Spring Security documentation and many tutorials on the internet but nothing make sense to me how to secure my REST API.
My requirements are very simple - upon on value of one parameter from HTTP headers I need to allow or disallow client to consume the particular resource. I have a service that can be injected as a bean and this bean can process this task for me. What I need to know is where to place this "check" bean and how to tell to Spring to use it as a filter before the resource is consumed (I configure my application programmatically via Java class and I don't use applicationContext.xml).
I would be appreciate for some simple example - Spring configuration and filter class.
As Bart said, You can very well make use of interceptor. You can do like
#Component
public class SecurityFilter extends HandlerInterceptorAdapter{
#Override
public boolean preHandle(HttpServletRequest request,
HttpServletResponse response, Object handler) throws Exception {
/*you can do this way. set the response content type as
* 'application/json'.get the PrintWriter from response and print
* the Json object
*/
response.setContentType("application/json");
PrintWriter out = response.getWriter();
/*jsonObject can be either be a String form of json. example:
*"{ key1:'value1', key2: 'value2' }" or JSON object created
*using JSON libraries like json.org or Gson package
*/
out.print(jsonObject);
out.flush();
return false;
}
}
You have to also configure in your spring configuration file.
<mvc:interceptors>
<mvc:interceptor>
<!-- map the url path to the appropriate filter -->
<mvc:mapping path="/**" />
<bean class="com.keerthi.filter.SecurityFilter" />
</mvc:interceptor>
</mvc:interceptors>
Please read the documentation of HandlerInterceptorAdapter API. This will help you
I have a sidebar almost in all my pages, which needs some methods and queries to get executed (say a list of cities and events in them). So basically, now I call the method and then model.setAttribute("mylist",list) almost in all my controllers.
A good solution for me would be if I could call a Controller or Service for that sidebar subpage when I include it in JSP but well its not possible in View layer. What I could do would be putting Java snippet codes in that JSP subpage being included in all pages, well which is bad.
Right now I'm adding those method calls and setting the result attributes in all my Controllers, which is a lot of repeated code. What is a good design solution for these cases?
In Summery: I want to have some method calls in almost all my controllers because in Apache Tiles I'm using a sidebar sub page which needs those method calls to be done in controller/service layer.
Another option is to add an interceptor to your MVC configuration. For example, this interceptor retrieves the number of unread conversations a user has in order to display it in his navbar and stores it in the HttpServletRequest as an attribute with request scope. It could have been added to the ModelAndView as well:
public class PageModelInterceptor extends HandlerInterceptorAdapter {
private MessagingService mailboxService;
public PageModelInterceptor() {
}
#Override
public void postHandle(final HttpServletRequest request, final HttpServletResponse response, final Object handler, final ModelAndView modelAndView) {
addNbConversationUpdates(request);
}
private void addNbConversationUpdates(final HttpServletRequest request) {
if (XSecurity.principal() != null) {
final int nbUpdatedConversations = mailboxService.getUpdatedConversations(XSecurity.principal().getId()).size();
request.setAttribute("nbConversationUpdates", nbUpdatedConversations);
}
}
public void setMailboxService(final MessagingService mailboxService) {
this.mailboxService = mailboxService;
}
}
This needs to be added to your dispatcher-servlet.xml or whatever file your web application context is declared in.
<mvc:interceptor>
<mvc:mapping path="/ui/**" />
<bean class="com.xyz.project.web.PageModelInterceptor">
<property name="mailboxService" ref="mailboxService" />
</bean>
</mvc:interceptor>
As you can see you can declare a path pattern and so exclude the URLs for which this isn't necessary.
If what you need is additional model attributes in most of your views i would go for the #ControllerAdvice annotation. There you can declare methods annotated with #ModelAttribute and this will be called on each controller call.
This can lead to some overhead so keep it simple and fast ;)
If I got your Question properly, you need some list object whose values you need to get displayed in all view pages at left/right side.
If that list values(table from where list is getting populated) is not changing frequently then you can hit Query once and get your list ready only once, then you can set that list as Session Variable, So that you can fetch it directly at View Layer.
Based on you correct requirement, you can go some similar requirement if this doesn't work.
I recently started working on a spring MVC project which uses spring security.
I had to do some pre-checks before user's request gets to the controller.
This is what I want to achieve, like I have worked a lot in struts and in struts we can extend all the action classes to a superclass let's say BaseAction and then write some validation here so that they gets called before calling the sub class methods.
I would like to achieve same thing here but don't know how to start.
I cannot use filters as i need to make database calls and web-service calls in pre checks.
I just need the pointers .
You can implement an interceptor using HandlerInterceptorAdapter.
http://static.springsource.org/spring/docs/3.0.x/reference/mvc.html#mvc-handlermapping-interceptor
Configuring the applicationContext in XML.
<mvc:interceptors>
<bean class="my.package.MyInterceptor" />
</mvc:interceptors>
The interceptor.
public class MyInterceptor extends HandlerInterceptorAdapter {
public boolean preHandle(
HttpServletRequest request,
HttpServletResponse response, Object handler) {
// your logic
return true;
}
}
Returns true if the execution chain should proceed with the next interceptor or the handler itself. Else, DispatcherServlet assumes that this interceptor has already dealt with the response itself.
I am using Java with Spring framework. Given the following url:
www.mydomain.com/contentitem/234
I need to map all requests that come to /contentitem/{numeric value} mapped to a given controller with the "numeric value" passed as a parameter to the controller.
Right now in my servlet container xml I have simple mappings similar to the following:
...
<entry key="/index.html">
<ref bean="homeController" />
</entry>
...
I am just wondering what I need to add to the mapping in order to achieve what I described?
Edit: I unaccepted the answer temporarily because I can't seem to figure out how to do the mapping in my web.xml (I am using annotations as described in axtavt's answer below). How do I add a proper <url-pattern>..</url-pattern> in my <servlet-mapping> so that the request for "/contentitem/{numeric_value}" gets properly picked up? Thanks!
It can be done using annotation-based controller configuration (see 15.3 Implementing Controllers):
#Controller
public class ContentItemController {
#RequestMapping("/contentitem/{id}")
public ModelAndView contentItem(#PathVariable("id") int id) {
...
}
}
try to use #RequestMapping and #PathVariable
#RequestMapping(value="/contentitem/{value}", method=RequestMethod.GET)
public String demo(#PathVariable(value="nvalue") String name, ModelMap map) {
int intValue = Integer.parseInt(nvalue);
// Do manipulation
return "something"; // Forward to something.jsp
}
Watch this Spring MVC Framework Tutorial
You must import org.springframework.stereotype.Controller.