spring绑定参数的过程
从客户端请求key/value数据,经过参数绑定,将key/value数据绑定到controller方法的形参上。springmvc中,接收页面提交的数据是通过方法形参来接收,而不是在controller类定义成员变更接收!
默认支持的类型
直接在controller方法形参上定义下边类型的对象,就可以使用这些对象,在参数绑定过程中,如果遇到下边类型直接进行绑定。
- HttpServletRequest,通过request对象获取请求信息
- HttpServletResponse,通过response处理响应信息
- HttpSession,通过session对象得到session中存放的对象
- Model/ModelMap,model是一个接口,modelMap是一个接口实现 。作用是将model数据填充到request域。
简单类型
当参数类型是java的基本数据类型时,提交到controller的name和接收方法的形参名称一致就接收到数据。如:
@RequestMapping(value="/addItems", method={RequestMethod.POST, RequestMethod.GET})
public String addItems(HttpServletRequest request, Model model, String itemsName) throws Exception {
System.out.println("商品名称:" + itemsName);
return "forward:queryItems";
}
这时候在浏览器输入http://localhost:8080/ssm/items/addItmes?itemsName='Java编程思想',或者请求页面中的链接为:
<a href="items/addItems?itemsName='Thinking In Java'">参数传递</a><br />
后台就会接收到商品名为《Java编程思想》的商品名。其中那个RequesMapping的属性value是对应的url,method是规定该方法接收的请求类型,这里既运行使用post请求,同事也允许get请求。
如果request传入的参数和形参的名称不一致,需要使用@RequestParam进行绑定才能映射成功。
@RequestMapping(value="/addItems", method={RequestMethod.POST, RequestMethod.GET})
public String addItems(HttpServletRequest request, Model model, @RequestParam(value="bookName", required=false) String itemsName) throws Exception {
System.out.println("商品名称:" + itemsName);
return null;
}
<a href="items/addItems?bookName='Thinking In Java'">参数传递</a><br />
可以看到请求的参数名称叫做:bookName,而方法的形参名称叫做:itemsName,但是加上这一句@RequestParam(value="bookName", required=false)之后,请求参数可以参观的映射到形参。
如果不使用@RequestParam,要求request传入参数名称和controller方法的形参名称一致,方可绑定成功;如果使用@RequestParam,不用限制request传入参数名称和controller方法的形参名称一致。通过required属性指定参数是否必须要传入,如果设置为true,没有传入参数,报下边错误:
pojo绑定
当页面中input的name和controller的pojo形参中的属性名称一致,将页面中数据绑定到pojo。
我的pojo定义如下:
public class Items {
private Integer id;
private String name;
private Float price;
private String pic;
private Date createtime;
private String detail;
//getter/setter
}
jsp:页面定义:
<form action="items/addItems" method="post">
<table width="50%" border="1px">
<tbody>
<tr>
<td>商品名称</td>
<td><input type="text" name="name"/></td>
</tr>
<tr>
<td>商品价格</td>
<td><input type="text" name="price" /></td>
</tr>
<tr>
<td colspan="2"><input type="submit" value="添加" /></td>
</tr>
</tbody>
</table>
</form>
先测一测简单的数据类型,商品名和商品价格,因为这两种类型都是简单的数据类型,Date类型接下来再解决。
controller的接收方法
@RequestMapping("/addItems")
public String addItems(HttpServletRequest request, Model model, Items items) throws Exception {
System.out.println("商品名:" + items.getName());
System.out.println("商品价格:" + items.getPrice());
return null;
}
这里可以看到,添加商品的jsp页面中,商品的input的name="name",这个值将映射成为items对象的name属性,input的name="price"商品价格的值会映射到items对象的price这个属性里边。
再来测试另外几种数据类型,再定义一个java bean:Student。
public class Student {
/*
* id
*/
private int id;
/**
* 姓名
*/
private String name;
/**
* 是否成年
*/
private boolean adaut;
/**
* 生日
*/
private Date birthday;
/**
* 身高
*/
private float hight;
//getter/setter
}
提交表单的jsp页面如下:
<form action="items/addStudent" method="post">
<table width="50%" border="1px">
<tbody>
<tr>
<td>id</td>
<td><input type="text" name="id"/></td>
</tr>
<tr>
<td>姓名</td>
<td><input type="text" name="name" /></td>
</tr>
<tr>
<td>是否成年</td>
<td>
<input type="radio" name="adaut" value="true" checked>是
<input type="radio" name="adaut" value="false">否
</td>
</tr>
<tr>
<td>生日</td>
<td><input type="text" name="birthday" /></td>
</tr>
<tr>
<td>身高</td>
<td><input type="text" name="hight" /></td>
</tr>
<tr>
<td colspan="2"><input type="submit" value="添加" /></td>
</tr>
</tbody>
</table>
</form>
在这个JavaBean的属性中有日期类型,需要自定义参数绑定。将请求日期数据串传成 日期类型,要转换的日期类型和pojo中日期属性的类型保持一致,需要向处理器适配器中注入自定义的参数绑定组件。
自定义日期类型绑定
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import org.springframework.core.convert.converter.Converter;
public class CustomDateConverter implements Converter<String, Date> {
public Date convert(String source) {
//实现将日期串转成日期类型(格式是yyyy-MM-dd HH:mm:ss)
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
try {
return sdf.parse(source);
} catch (ParseException e) {
e.printStackTrace();
}
return null;
}
}
在配置文件中配置:
<mvc:annotation-driven conversion-service="conversionService" />
<!-- 自定义参数绑定 -->
<bean id="conversionService" class="org.springframework.format.support.FormattingConversionServiceFactoryBean">
<!-- 转换器 -->
<property name="converters">
<list>
<!-- 日期转换类型 -->
<bean class="com.shizongger.ssm.model.CustomDateConverter" />
</list>
</property>
</bean>
如此这般,jsp页面的input输入框中,日期格式如:2016-12-12 21:59:00的字符串变会转换成Date的日期格式。是否成年的boolean值也会传递到adaut属性中。
包装类型pojo参数绑定
需求:
商品查询controller方法中实现商品查询条件传入。
实现方法:
- 在形参中 添加HttpServletRequest request参数,通过request接收查询条件参数。
- 在形参中让包装类型的pojo接收查询条件参数。
分析:
页面传参数的特点:复杂,多样性。条件包括 :用户账号、商品编号、订单信息。如果将用户账号、商品编号、订单信息等放在简单pojo(属性是简单类型)中,pojo类属性比较多,比较乱。建议使用包装类型的pojo,pojo中属性是pojo。
定义一个查询的java bean QueryVo,所有将要查询的条件都将由这个vo接收。
public class QueryVo {
private Items items;
private Student student;
public Items getItems() {
return items;
}
public void setItems(Items items) {
this.items = items;
}
public Student getStudent() {
return student;
}
public void setStudent(Student student) {
this.student = student;
}
}
Items和Student定义如上所述,这个vo定义了两个属性items商品和student用户(里面student就是用户),两者都有一个共同的属性名:name,items商品中有一个属性名name代表商品名称,student有一个属性名name代表用户名称,这个案例将展示如果分别向这个不同的name属性传递值。
jsp页面代码:
<form action="queryItems" method="post">
<table border="1px" width="80%">
<tr>
<td>商品名:<input type="text" name="items.name" /></td>
<td>商品价格:<input type="text" name="items.price" /></td>
<td>商品详情:<input type="text" name="items.detail" /></td>
<td>下单用户:<input type="text" name="student.name" /></td>
<td><input type="submit" value="查询" /></td>
</tr>
</table>
</form>
controller代码:
//商品查询
@RequestMapping("/queryItems")
public ModelAndView queryItems(HttpServletRequest request, QueryVo queryVo) throws Exception{
if(null != queryVo && null != queryVo.getItems() && null != queryVo.getStudent()) {
System.out.println("前端传递过来的查询条件:");
System.out.println("商品名称:" + queryVo.getItems().getName() + " 商品价格:"
+ queryVo.getItems().getPrice() + " 商品详情:"
+ queryVo.getItems().getDetail() + " 下单用户:"
+ queryVo.getStudent().getName() );
}
}
在input的name属性中,name值与queryVo属性的属性名对应,才能映射成功。
集合类型的绑定
数组类型绑定
需求:
商品批量删除,用户在页面选择多个商品,批量删除。
分析:
在批量删除需求中,如果能够一次性拿到jsp页面中复选框选中的内容那好办了。所以我们可以将页面选择(多选)的商品id,传到controller方法的形参,方法形参使用数组接收页面请求的多个商品id。
controller方法定义:
@RequestMapping("/deleteItems")
public String deleteItems(HttpServletRequest request, Integer[] itemsIds) {
for(int i = 0; i < itemsIds.length; i++) {
System.out.println("要删除的id:" + itemsIds[i]);
}
return null;
}
jsp页面定义:
<form id="itemsTalbe">
<table border="1px" width="80%">
<thead>
<tr><td>删除</td><th>序列</th><th>商品名称</th><th>商品详情</th><th>商品价格</th><th>订单创建时间</th><th>修改</th></tr>
</thead>
<tbody>
<c:forEach items="${itemsList }" var="items" varStatus="status">
<tr>
<td><input type="checkbox" name="itemsIds" value="${items.id }" /></td>
<td>${status.count }</td>
<td>${items.name }</td>
<td>${items.detail }</td>
<td>${items.price }</td>
<td>${items.createtime }</td>
<td><a href="editItems?id=${items.id }">修改</a></td>
</tr>
</c:forEach>
<tr>
<td colspan="7"><input type="submit" value="批量删除" onclick="batchDelete()"/></td>
</tr>
</tbody>
</table>
</form>
js代码:
function batchDelete() {
var form = document.getElementById("itemsTalbe");
form.action ="${pageContext.servletContext.contextPath }/items/deleteItems";
form.submit();
}
在jsp页面中,用jstl迭代输出表格中每一行的记录内容。最重要的是每一行的第一个td的内容:
<td><input type="checkbox" name="itemsIds" value="${items.id }" /></td>
name属性等于itemsIds正是controller接收参数Interger数组的名称。
list绑定
通常在需要批量提交数据时,将提交的数据绑定到list< pojo>中,比如:成绩录入(录入多门课成绩,批量提交),本例子需求:
批量商品修改,在页面输入多个商品信息,将多个商品信息提交到controller方法中。
在上诉的请求vo中,再添加属性:
private List<Items> itemsList;
完整的vo如下:
public class QueryVo {
private Items items;
private Student student;
private List<Items> itemsList;
public List<Items> getItemsList() {
return itemsList;
}
public void setItemsList(List<Items> itemsList) {
this.itemsList = itemsList;
}
public Items getItems() {
return items;
}
public void setItems(Items items) {
this.items = items;
}
public Student getStudent() {
return student;
}
public void setStudent(Student student) {
this.student = student;
}
}
jsp页面:
springmvc和struts2的区别
springmvc基于方法开发的,struts2基于类开发的。springmvc将url和controller方法映射。映射成功后springmvc生成一个Handler对象,对象中只包括了一个method。方法执行结束,形参数据销毁。springmvc的controller开发类似service开发。
springmvc可以进行单例开发,并且建议使用单例开发,struts2通过类的成员变量接收参数,无法使用单例,只能使用多例。
经过实际测试,struts2速度慢,在于使用struts标签,如果使用struts建议使用jstl。
参考资料:<传智播客_Springmvc+Mybatis由浅入深之spring mvc>