话说我们讲到spring mvc 四 的时候,是不是已经感觉spring mvc 已经搞的差不多了?一个类多个方法提供外面请求,看上去好像真的已经可以了,已经到了使用的跟struts 的效
果了是吧?其实不然,我们还有一个重要的需求还没有实现呢,那是什么?
答案是表单提交,对头了,这是一个非常重要的需求呢。
呵呵,当然了,如果您是提交几个简单的字段,完全使用 request.getParameter("fieldName") 就万事大吉了。不过我们回头想想,如果大批量的数据提交或者修改的时候,您都
是request.getParameter("fieldName")接收数据,您是不是感觉回到了servlet时代了(当然,其实spring父亲就是servlet)?那我们还用spring干嘛?可能有的童鞋说,我用他一
个类提供多个方法嘛。那您就错了,其实我们Spring mvc 四 里面讲解的配置是不能使用来提交表单的,因为请求是:/abc.htm?method=方法 这样的请求,这种请求应该是不能在提交数据时候用的。现在您是不是感觉到非常失望了?没有关系,接下来我们学习下,既可以提交表单,又不用request.getParameter("fieldName")。
开始吧...... 从那里开始呢..........
1、可能有了解spring mvc 的童鞋认为,这个提交表单很简单啊,用 SimpleFormController 就可以了。对了,这个是一直关注spring 3.0之前的用法,没有错,您确实没有看错,但是,当您升级到3.0之后,您会发现关于 BaseCommandController下面所有的子类都已经被Spring 声明不建议使用了
即 :@Deprecated ,好,废话少说,贴张图上来,有图有真相:
是吧,没有错吧,如果您不信,还可以查询他下面的子类的哦。当然并不是说明 声明不建议就不能用,你要是坚持用,我也咬不了您的,您爱用就用呗。
好了,废话不多说了,我们现在要说明的是SimpleFormController ,行吧,我们先看看对Spring mvc 四的 spring配置文件进行调整吧,以得到更优美的请求地址,如下:
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd"> <beans default-autowire="byName"> <!-- 普通的bean实体 --> <bean name="sampleController" class="com.lap.taobaouse.controller.SampleController" /> <bean name="lapController" class="com.lap.taobaouse.controller.LapController"> <property name="methodNameResolver" ref="propertiesMethodResolver" /> </bean> <!-- 实现一类对多方法的方法参数 --> <bean id="propertiesMethodResolver" class="org.springframework.web.servlet.mvc.multiaction.PropertiesMethodNameResolver"> <property name="mappings"> <props> <prop key="/query_list.htm">queryList</prop> <prop key="/query_byId.htm">queryById</prop> </props> </property> </bean> <!-- url 管理 --> <bean id="simpleUrlHandlerMapping" class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping"> <property name="mappings"> <props> <prop key="/test.htm">sampleController</prop> <prop key="/query_list.htm">lapController</prop> <prop key="/query_byId.htm">lapController</prop> </props> </property> </bean> <!-- 管理视图对象 --> <bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver"> <property name="cache" value="true" /> <property name="prefix" value="/static/template/" /> <property name="suffix" value=".jsp" /> <property name="contentType" value="text/html;charset=utf-8" /> </bean> </beans>
这个时候您就可以打开两个窗口对比 Spring mvc 四 里面的配置文件了,他们的差异是:
<!-- 实现一类对多方法的方法参数 --> <bean id="parameterMethodResolver" class="org.springframework.web.servlet.mvc.multiaction.ParameterMethodNameResolver"> <property name="paramName" value="method" /> </bean>
变成这样了,也就是说,我们用到了Spring mvc 四里面提到的 PropertiesMethodNameResolver配置,这个类是配置请求地址和方法对应的。
<!-- 实现一类对多方法的方法参数 --> <bean id="propertiesMethodResolver" class="org.springframework.web.servlet.mvc.multiaction.PropertiesMethodNameResolver"> <property name="mappings"> <props> <prop key="/query_list.htm">queryList</prop> <prop key="/query_byId.htm">queryById</prop> </props> </property> </bean>
好了,这个时候您要细心的看下配置文件,相信您有一定的收获的哦。
2、接下来,我们看看Java类怎么实现获取页面对象表单吧,如下代码:
/* * Copyright 2013 The JA-SIG Collaborative. All rights reserved. * distributed with this file and available online at * http://www.etong.com/ */ package com.lap.taobaouse.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; /** * <p> * 表单提交对象,并实现了一类多方法功能 * </p> * * @author 劳水生 Exp * @version $FileName: LapFormController.java $Date: 2013-3-21 上午9:49:17 -0400 * 2013 * @since 1.0 * */ public class LapFormController extends MultiActionController { /** * <p> * 进入表单提交页面 * </p> * * @param request * @param response * @return */ public ModelAndView toAdd(HttpServletRequest request, HttpServletResponse response) { return new ModelAndView("addTest"); } /** * <p> * 表单提交 * </p> * * * @param request * @param response * @param testVO * @return */ public ModelAndView saveTest(HttpServletRequest request, HttpServletResponse response, TestVO testVO) { System.out.println(testVO); return new ModelAndView(); } }
大家看了代码,重点是看第二个方法的方法头里面的参数,呵呵,最后一个就是我们要的对象了,不错吧,我们再去看看MultiActionController给我提供的源码方法建议,相信您可能有一定收获,如:
/** * {@link org.springframework.web.servlet.mvc.Controller 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 * * <pre class="code">public (ModelAndView | Map | String | void) actionName(HttpServletRequest request, HttpServletResponse response, [,HttpSession] [,AnyObject]);</pre> * * A Map return value indicates a model that is supposed to be passed to a default view * (determined through a {@link org.springframework.web.servlet.RequestToViewNameTranslator}). * A String return value indicates the name of a view to be rendered without a specific model. * * <p>May take a third parameter (of type {@link HttpSession}) in which an * existing session will be required, or a third parameter of an arbitrary * class that gets treated as the command (that is, an instance of the class * gets created, and request parameters get bound to it) * * <p>These methods can throw any kind of exception, but should only let * propagate those that they consider fatal, or which their class or superclass * is prepared to catch by implementing an exception handler. * * <p>When returning just a {@link Map} instance view name translation will be * used to generate the view name. The configured * {@link org.springframework.web.servlet.RequestToViewNameTranslator} will be * used to determine the view name. * * <p>When returning {@code void} a return value of {@code null} is * assumed meaning that the handler method is responsible for writing the * response directly to the supplied {@link HttpServletResponse}. * * <p>This model allows for rapid coding, but loses the advantage of * compile-time checking. It is similar to a Struts {@code DispatchAction}, * but more sophisticated. Also supports delegation to another object. * * <p>An implementation of the {@link MethodNameResolver} interface defined in * this package should return a method name for a given request, based on any * aspect of the request, such as its URL or an "action" parameter. The actual * strategy can be configured via the "methodNameResolver" bean property, for * each {@code MultiActionController}. * * <p>The default {@code MethodNameResolver} is * {@link InternalPathMethodNameResolver}; further included strategies are * {@link PropertiesMethodNameResolver} and {@link ParameterMethodNameResolver}. * * <p>Subclasses can implement custom exception handler methods with names such * as: * * <pre class="code">public ModelAndView anyMeaningfulName(HttpServletRequest request, HttpServletResponse response, ExceptionClass exception);</pre> * * The third parameter can be any subclass or {@link Exception} or * {@link RuntimeException}. * * <p>There can also be an optional {@code xxxLastModified} method for * handlers, of signature: * * <pre class="code">public long anyMeaningfulNameLastModified(HttpServletRequest request)</pre> * * If such a method is present, it will be invoked. Default return from * {@code getLastModified} is -1, meaning that the content must always be * regenerated. * * <p><b>Note that all handler methods need to be public and that * method overloading is <i>not</i> allowed.</b> * * <p>See also the description of the workflow performed by * {@link AbstractController the superclass} (in that section of the class * level Javadoc entitled 'workflow'). * * <p><b>Note:</b> For maximum data binding flexibility, consider direct usage of a * {@link ServletRequestDataBinder} in your controller method, instead of relying * on a declared command argument. This allows for full control over the entire * binder setup and usage, including the invocation of {@link Validator Validators} * and the subsequent evaluation of binding/validation errors. * * @author Rod Johnson * @author Juergen Hoeller * @author Colin Sampaleanu * @author Rob Harrop * @author Sam Brannen * @see MethodNameResolver * @see InternalPathMethodNameResolver * @see PropertiesMethodNameResolver * @see ParameterMethodNameResolver * @see org.springframework.web.servlet.mvc.LastModified#getLastModified * @see org.springframework.web.bind.ServletRequestDataBinder */ public class MultiActionController extends AbstractController implements LastModified {
....
}
里面的信息我们就不贴出来了,我们是看注释里面给我们说明继承他后的方法,行吧,这里我就不多说了,把 TestVO 对象代码也贴下吧,免得有人问 TestVO 是什么呢,如下:
/* * Copyright 2013 The JA-SIG Collaborative. All rights reserved. * distributed with this file and available online at * http://www.etong.com/ */ package com.lap.taobaouse.controller; import java.io.Serializable; /** * * @author 劳水生 Exp * @version $FileName: TestVO.java $Date: 2013-3-21 上午9:50:36 -0400 2013 * @since 1.0 * */ public class TestVO implements Serializable { private static final long serialVersionUID = 7868977600979801437L; /** * id */ private int id; /** * 用户姓名 */ private String name; /** * 性别 */ private int sex; /** * 动物猫数据对象 */ private CatVO catVO; public int getId() { return id; } public void setId(int id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getSex() { return sex; } public void setSex(int sex) { this.sex = sex; } public CatVO getCatVO() { return catVO; } public void setCatVO(CatVO catVO) { this.catVO = catVO; } }
为了证明类内聚合对象也能提交,我在TestVO 里面还搞了一个 CatVO,这里也贴出来吧,如下:
/* * Copyright 2013 The JA-SIG Collaborative. All rights reserved. * distributed with this file and available online at * http://www.etong.com/ */ package com.lap.taobaouse.controller; import java.io.Serializable; /** * * @author 劳水生 Exp * @version $FileName: CatVO.java $Date: 2013-3-21 下午2:00:54 -0400 2013 * @since 1.0 * */ public class CatVO implements Serializable { private static final long serialVersionUID = 2015266440849396264L; /** * 动物名称 */ private String name; public String getName() { return name; } public void setName(String name) { this.name = name; } }
两个数据对象都非常简单吧,这里就不说明了,呵呵。
3、我们看下页面的代码吧,页面代码还是有比较值的 注意 的细节,特别是对用惯了struts 2的童鞋,相信会写错哦,代码如:
addTest.jsp页面了,提交数据成功后我没有做页面,呵呵
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <title>信息添加页面</title> </head> <body> <form action="save_test.htm"> 姓名<input type="text" name="name" /><br> 男<input type="radio" name="sex" value="1"/> 女<input type="radio" name="sex" value="2"/> <br> 宠物猫名称<input type="text" name="catVO.name" /><br> <input type="submit" value="保存" /> </form> </body> </html>
页面里面我们重点注意的就是html控件里面的 <input type="xx" name="name"/> name,我们发现他并不是我们使用struts2里面的那样,不能写成 <input type="xx" name="testVO.name"/> ,注意哦。
4、可以测试了,按照我们这里写的,请求应该是 :http://localhost:8080/spring-example/add_test.htm.界面大概如下:
有图有真相。做到这里视乎应该完成了吧,但是我一直没有搞清楚一个问题,就是spring 3.0之后的 mvc 都已经声明 SimpleFormController了,那spring 的标签还能用吗?能用是不是只是对
SimpleFormController使用,如果是这样,那 MultiActionController 怎么结合 Spring 页面标签使用呢?下一节我希望我能掘开这个问题,如果有了解的童鞋也可以联系我,跟我讲解下,谢谢了。
好了,如果对本页有疑问可以联系我的哦,记得转载要保留出处哦。盗用别人的劳动不说明出处是不健康的呢。