之前学习了SpringMVC数据绑定的基本知识和简单数据绑定以及POJO类型数据的绑定。接下来总结剩下的一些数据类型的绑定
1. 绑定包装POJO
所谓的包装POJO,就是在一个POJO中包含另一个简单POJO。
例如,在订单对象中包含用户对象。这样在使用时,就可以通过订单查询到用户信息。
在po包下新建一个OrdersPOJO:
public class Orders {
private Integer ordersId; //订单id
private User user; //用户POJO
//省略setter和getter方法
}
新建一个OrdersController,编写以下两个方法:
@Controller
public class OrdersController {
/**
* 跳转到查询页面
* @return
*/
@RequestMapping("/tofindOrdersWithUser")
public String tofindOrdersWithUser() {
return "orders";
}
/**
* 查询订单和用户信息
* @param orders
* @return
*/
@RequestMapping("/findOrdersWithUser")
public String findOrdersWithUser(Orders orders) {
Integer ordersId = orders.getOrdersId();
User user = orders.getUser();
String username = user.getUsername();
System.out.println("ordersId=" + ordersId + " username" + username);
return "success";
}
}
新建一个查询页面orders.jsp:
<form action="${pageContext.request.contextPath}/findOrdersWithUser" method="post">
订单编号:<input type="text" name="ordersId"/><br/>
所属用户:<input type="text" name="user.username"/><br/>
<input type="submit" value="查询"/>
</form>
在使用包装POJO类型数据绑定时,前端请求的参数名编写必须符合以下两种情况。
1.如果查询条件参数是包装类的直接基本属性,则参数名直接用对应的属性名,如上面代码中的ordersId。
2.如果查询条件是包装类型中POJO的子属性,则参数名必须为[对象.属性],其中[对象]要和包装POJO中的对象属性名称一致,[属性]要和包装POJO中的对象子属性一致,如上述代码中的user.username。
测试运行结果
2.自定义数据绑定
一般情况下,使用基本数据类型和POJO类型的参数数据已经能够满足需求,然而有些特殊类型的参数是无法在后台进行直接转换的,但也有特殊数据类型无法直接进行数据绑定,必须先经过数据转换,例如日期数据。
针对前面提到的特殊数据类型,就需要开发者自定义转换器(Converter)或格式化(Formatter)来进行数据绑定。
2.1 Converter
Spring框架提供了一个Converter用于将一种类型的对象转换为另一种类型的对象。
自定义Converter类需要实现org.springframework.core.convert.converter.Converter接口。
接口代码如下:
public interface Converter<S, T> {
T convert(S source);
}
上述代码中,泛型中的S表示源类型,T表示目标类型,而convert(S source)表示接口中的方法。
在项目中创建一个convert的包,并创建一个日期转换类DateConverter,用于将String类型转换成Date类型,代码如下所示:
/**
* @Package com.ma.converter
* @Description: 自定义日期转换器
* @auther MZ
* @create 2017/11/5 10:21
*/
public class DateConverter implements Converter<String, Date> {
//自定义日期格式
private String datePattern = "yyyy-MM-dd HH:mm:ss";
@Override
public Date convert(String s) {
//格式化日期
SimpleDateFormat simpleDateFormat = new SimpleDateFormat(datePattern);
try {
return simpleDateFormat.parse(s);
} catch (ParseException e) {
throw new IllegalArgumentException("无效的日期格式,请使用这种格式:"+datePattern);
}
}
}
修改springmvc-config.xml文件,添加id为conversionService的Bean。
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-4.3.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc-4.3.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-4.3.xsd">
<!--定义组件扫描,指定需要扫描的包-->
<context:component-scan base-package="com.ma.controller"/>
<!--视图解析器-->
<bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/jsp/"/>
<property name="suffix" value=".jsp"/>
</bean>
<!-- 显示的装配自定义类型转换器 -->
<mvc:annotation-driven conversion-service="conversionService"/>
<!-- 自定义类型转换器配置 -->
<bean id="conversionService" class="org.springframework.context.support.ConversionServiceFactoryBean">
<property name="converters">
<set>
<bean class="com.ma.converter.DateConverter"/>
</set>
</property>
</bean>
</beans>
在controller包中新建一个日期控制器类DateConroller
/**
* @Package com.ma.controller
* @Description: 日期控制器类
* @auther MZ
* @create 2017/11/5 10:32
*/
@Controller
public class DateController {
@RequestMapping("/customeDate")
public String customeDate(Date date) {
System.out.println("date="+date);
return "success";
}
}
测试结果:
2.2 Formatter
Formatter与Converter的作用相同,只是Formatter的源类型必须是一个String类型,而Converter可以是任意类型。
使用Formatter自定义转换器类需要实现org.springframework.format.Formatter接口。接口代码如下:
public interface Formatter<T> extends Printer<T>, Parser<T> {}
Formatter接口继承了Printer和Parser接口,其泛型T表示输入字符串要转换的目标类型。在Printer和Parser接口中,分别包含一个print()和parse()方法,所有的实现类必须覆盖这两个方法。
在converter包中新建一个日期转换类DateFormatter,代码如下:
/**
* @Package com.ma.converter
* @Description: 使用Formatter自定义日期转换器
* @auther MZ
* @create 2017/11/5 10:53
*/
public class DateFormatter implements Formatter<Date> {
//定义日期格式
private String datePattern = "yyyy-MM-dd HH:mm:ss";
//声明SimpleDateFormat对象
SimpleDateFormat simpleDateFormat;
@Override
public Date parse(String s, Locale locale) throws ParseException {
simpleDateFormat = new SimpleDateFormat(datePattern);
return simpleDateFormat.parse(s);
}
@Override
public String print(Date date, Locale locale) {
return new SimpleDateFormat().format(date);
}
}
在配置文件中注册
<!-- 自定义类型格式化转换器配置 -->
<bean id="conversionService" class="org.springframework.format.support.FormattingConversionServiceFactoryBean">
<property name="formatters">
<set>
<bean class="com.itheima.convert.DateFormatter" />
</set>
</property>
</bean>
测试结果和Converter的结果一样。
3. 复杂数据绑定
3.1 绑定数组
在实际开发时,可能会遇到前端请求需要传递到后台一个或多个相同名称参数的情况(如批量删除),此种情况采用前面讲解的简单数据绑定的方式显然是不合适的。
针对上述这种情况,如果将所有同种类型的请求参数封装到一个数组中,后台就可以进行绑定接收了。
接下来,以一个批量删除用户的例子来详细讲解绑定数组的操作使用:
新建一个user.jsp页面
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>用户列表</title>
</head>
<body>
<form action="${pageContext.request.contextPath}/deleteUsers" method="post">
<table width="20%" border="1">
<tr>
<td>选择</td>
<td>用户名</td>
</tr>
<tr>
<td>
<input name="ids" value="1" type="checkbox">
</td>
<td>tom</td>
</tr>
<tr>
<td>
<input name="ids" value="2" type="checkbox">
</td>
<td>jack</td>
</tr>
<tr>
<td>
<input name="ids" value="3" type="checkbox">
</td>
<td>lucy</td>
</tr>
</table>
<input type="submit" value="删除"/>
</form>
</body>
</html>
在UserController中添加方法
/**
* 跳转到用户列表
* @return
*/
@RequestMapping("/toUser")
public String selectUsers() {
return "user";
}
/**
* 接收批量删除的方法
* @param ids
* @return
*/
@RequestMapping("/deleteUsers")
public String deleteUsers(Integer[] ids) {
if (ids != null) {
for (Integer id : ids) {
System.out.println("删除了id为"+ id + "的用户");
}
} else {
System.out.println("ids = null");
}
return "success";
}
测试运行:
3.2 绑定集合
在批量删除用户的操作中,前端请求传递的都是同名参数的用户id,只要在后台使用同一种数组类型的参数绑定接收,就可以在方法中通过循环数组参数的方式来完成删除操作。
但如果是批量修改用户操作的话,前端请求传递过来的数据可能就会批量包含各种类型的数据,如Integer,String等。
针对上述这种情况,就可以使用集合数据绑定。即在包装类中定义一个包含用户信息类的集合,然后在接收方法中将参数类型定义为该包装类的集合。
新那一个包vo,并创建UserVO来封装用户集合的属性,代码如下:
/**
* @Package com.ma.vo
* @Description: 用户包装类
* @auther MZ
* @create 2017/11/5 15:21
*/
public class UserVO {
private List<User> users;
public List<User> getUsers() {
return users;
}
public void setUsers(List<User> users) {
this.users = users;
}
}
在UserController中添加方法:
/**
* 跳转到用户编辑页面
* @return
*/
@RequestMapping("/toUserEdit")
public String toUserEdit() {
return "user_edit";
}
/**
* 接收批量修改用户
* @param userList
* @return
*/
@RequestMapping("/editUsers")
public String editUsers(UserVO userList) {
//将所有用户数据封装到集合中
List<User> users = userList.getUsers();
//循环输出用户信息
for (User user : users) {
//如果接收的用户id不为空,则表示对该用户进行了修改
if (user.getId() != null) {
System.out.println("修改了id为"+ user.getId() +"用户名为:"+user.getUsername());
}
}
return "success";
}
在使用集合数据绑定时,后台方法中不支持直接使用集合形参进行数据绑定,所以需要使用包装POJO作为形参,然后在包装POJO中包装一个集合属性
新建一个user_edit.jsp页面
<form action="${pageContext.request.contextPath}/editUsers" method="post" id='formid'>
<table width="20%" border="1">
<tr>
<td>选择</td>
<td>用户名</td>
</tr>
<tr>
<td>
<input name="users[0].id" value="1" type="checkbox">
</td>
<td>
<input name="users[0].username" value="tome" type="text">
</td>
</tr>
<tr>
<td>
<input name="users[1].id" value="2" type="checkbox">
</td>
<td><input name="users[1].username" value="jack" type="text"></td>
</tr>
</table>
<input type="submit" value="修改"/>
</form>
测试结果:
小结
以上就是有关数据绑定的知识,最后的项目目录如下所示: