话说我们讲到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 页面标签使用呢?下一节我希望我能掘开这个问题,如果有了解的童鞋也可以联系我,跟我讲解下,谢谢了。
好了,如果对本页有疑问可以联系我的哦,记得转载要保留出处哦。盗用别人的劳动不说明出处是不健康的呢。