Announcement Announcement Module
Collapse
No announcement yet.
merge form controller and multiAction controller Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • merge form controller and multiAction controller

    Hello all,

    I am a newbie to Spring and just migrating to it. so please bear with me.

    I would like to put all the CRUD operations for a domain object into one controller. in this case my controller will be able to handle form and list related operations. But the required functions are spreaded in two main classes. Anybody combined these functionalties into one class before? the simplest way might be copy the multiaction controller and derive the new one from a formcontroller. the other way around would be harder since it spreaded into several classes.

    then, ask a more generic question. why the multiaction controller does not support form submission/resubmission mecanism? Looks like to me, there should be a new class like FormProcessor that will take some parameters (eg, request, command object etc) , and then do the bind to populate the domain object. return a result Wrapper that has command, binderrors etc.

    then developer take this wrapper and decide to resubmission with this wrapper ( a base class function) or keep moving ahead.

    Of course, the I <sprint:bind> will lookup from this wrapper.

    If we implement this way, we further separated the form and controller architecturely and any actions in a controller can process forms to support multiple form in one controller. Actuay, the Pagelisthholder is more or less implemented this way.

    Thanks a lot.

    jfd

  • #2
    I have found this to be an issue too; in fact it is one of the only major uglinesses I see in the Spring Web MVC (the other is the fact that FormController supports only one command object). I have taken a couple different approaches to tackeling this, none of which have completely satisfied me, including one base controller with the logic for common stuff, and then seperate controllers for each CRUD operation; alteratively you can put all code into one FormController and then implement you own logic to process the different operations. If anyone has a better approach I'd very much like to know it, so please do post it.

    Comment


    • #3
      I faced a similar issue and created a subclass of SimpleFormController that does method based dispatching like the MultiActionController.

      I wish Spring supported a MultiActionFormController out of the box.

      Sanjiv

      Comment


      • #4
        a lot of people seem to be interested in this and there was a discussion at
        http://forum.springframework.org/showthread.php?t=11086

        To summarise though the MultiActionController will handle binds to a command object but doesnt really help with the error handling.

        i have written a couple of classes for doing some similar stuff. Although this may not be what you are after hope this can help you develop something that works for you
        Code:
        public class SubmitParameterPropertiesMethodNameResolver implements
        		MethodNameResolver {
        
        	private String defaultMethodName;
        	
        	private Properties mappings;
        
        	/**
        	 * Set URL to method name mappings from a Properties object.
        	 * @param mappings properties with URL as key and method name as value
        	 */
        	public void setMappings(Properties mappings) {
        		this.mappings = mappings;
        	}
        	
        	/**
        	 * @param defaultMethodName The defaultMethodName to set.
        	 */
        	public void setDefaultMethodName(String defaultMethodName) {
        		this.defaultMethodName = defaultMethodName;
        	}
        	
        	public void afterPropertiesSet() {
        		if (this.mappings == null || this.mappings.isEmpty()) {
        			throw new IllegalArgumentException("'mappings' property is required");
        		}
        	}
        
        	public String getHandlerMethodName(HttpServletRequest request)
        			throws NoSuchRequestHandlingMethodException {
        	
        		for (Iterator it = this.mappings.keySet().iterator(); it.hasNext();) {
        			String submitParamter = (String) it.next();
        			if (WebUtils.hasSubmitParameter(request, submitParamter)) {
        				return (String) this.mappings.get(submitParamter);
        			}
        		}
        		return defaultMethodName;
        	}
        and
        Code:
        public abstract class SimpleMultiActionFormController extends SimpleFormController {
        	
        	private MethodNameResolver methodNameResolver = new SubmitParameterPropertiesMethodNameResolver();
        	
        	public final void setMethodNameResolver(MethodNameResolver methodNameResolver) {
        		this.methodNameResolver = methodNameResolver;
        	}
        	
        	public final MethodNameResolver getMethodNameResolver() {
        		return this.methodNameResolver;
        	}
        	
        	protected ModelAndView processFormSubmission(HttpServletRequest request,
        			HttpServletResponse response, Object command, BindException errors)
        			throws Exception {
        		
        		if (errors.hasErrors() || isFormChangeRequest(request)) {
        			if (logger.isDebugEnabled()) {
        				logger.debug("Data binding errors: " + errors.getErrorCount());
        			}
        			return showForm(request, response, errors);
        		}
        		else {
        			String methodName = this.methodNameResolver.getHandlerMethodName(request);
        			
        			Method m = (Method) this.getClass().getMethod(methodName,
        					new Class[] {HttpServletRequest.class,
        								 Object.class,
        								 BindException.class});
        			if (m == null) {
        				throw new NoSuchRequestHandlingMethodException(methodName, getClass());
        			}
        			
        
        			List params = new ArrayList(3);
        			params.add(request);
        			params.add(command);
        			params.add(errors);
        			
        			return (ModelAndView) m.invoke(this, params.toArray(new Object[params.size()]));
        		}
        		
        	}
        
        }
        an example is


        Code:
        	<bean id="submitActionParamResolver" class="com.codebitches.springframework.web.servlet.mvc.multiaction.SubmitParameterPropertiesMethodNameResolver">
               <property name="mappings">
                  <props>
                    <prop key="_addSubject">addSubject</prop>
                    <prop key="_finish">finalSubmit</prop>
                 </props>
               </property>
               <property name="defaultMethodName"><value>finalSubmit</value></property>
           </bean>
        
           <bean id="createEditItemFormController" class="com.codebitches.springxmldb.examples.tilesnews.web.spring.CreateEditItemFormController">
              <property name="methodNameResolver"><ref bean="submitActionParamResolver"/></property>
              <property name="sessionForm"><value>true</value></property>
              <property name="successView"><value>createEditItemConfirmation</value></property>
              <property name="commandName"><value>item</value></property>
              <property name="formView"><value>createEditItemForm</value></property>
           </bean>
        Code:
        public class CreateEditItemFormController extends SimpleMultiActionFormController {
        
        	private ITilesNewsCMS cms;
        	
        	private static Log log = LogFactory.getLog(CreateEditItemFormController.class);
        
        	/**
        	 * @param cms The cms to set.
        	 */
        	public void setCms(ITilesNewsCMS cms) {
        		this.cms = cms;
        	}
        	
        	public CreateEditItemFormController() {
        	}
        
        
        	protected Object formBackingObject(HttpServletRequest request) throws ModelAndViewDefiningException {
        		String id = request.getParameter("itemId");
        		
        		Item item = new Item();
        		
        		if (id != null && !id.equals("")) {
        			item = cms.getItem(id);
        		}
        		
        		return item;
        	}
        	
        	public ModelAndView addSubject(HttpServletRequest request, Object command, BindException errors) throws Exception {
        		Item item = (Item) command;
        		
        		Collection subs = item.getMetadata().getSubjects();
        		subs.add(new ItemSubject());
        		
        		
        		return this.showForm(request, errors, getFormView());
        	}
        	
        	public ModelAndView finalSubmit(HttpServletRequest request, Object command, BindException errors) throws Exception {
        		Item item = (Item) command;
        		
        		item = cms.createOrUpdateItem(item);
        		
        		Map model = new HashMap();
        		model.put("item", item);
        		
        		return new ModelAndView(getSuccessView(), model);
        	}
        
        	/* (non-Javadoc)
        	 * @see org.springframework.web.servlet.mvc.SimpleFormController#referenceData(javax.servlet.http.HttpServletRequest)
        	 */
        	protected Map referenceData(HttpServletRequest request) throws Exception {
        		return super.referenceData(request);
        	}
        Last edited by robyn; May 14th, 2006, 06:22 PM.

        Comment


        • #5
          Thanks. I had a similar version to suit my requirements.

          Minor point : The Class#getMethods() method throws NoSuchMethodException if a method does not exist as opposed to returning 'null'.


          Code:
                   String methodName = this.methodNameResolver.getHandlerMethodName&#40;request&#41;; 
                    
                   Method m = &#40;Method&#41; this.getClass&#40;&#41;.getMethod&#40;methodName, 
                         new Class&#91;&#93; &#123;HttpServletRequest.class, 
                                   Object.class, 
                                   BindException.class&#125;&#41;; 
                   if &#40;m == null&#41; &#123; 
                      throw new NoSuchRequestHandlingMethodException&#40;methodName, getClass&#40;&#41;&#41;; 
                   &#125;

          Comment


          • #6
            Has anyone taken this further? Something like this should really be integrated into Spring MVC. I like the concept of abstracting the form processing out into another class so we can simply work with a MultiActionController and optionally do form validation with it.

            I'm going to poke around a bit and possibly submit a Jira ticket if I don't find anything.

            Comment


            • #7
              http://opensource.atlassian.com/proj...rowse/SPR-1606

              Comment

              Working...
              X