第13章 数据绑定
学习目标
● 了解Spring MVC中的数据绑定的概念
● 熟悉Spring MVC中的几种数据绑定类型
● 掌握Spring MVC数据绑定的使用
13.1 数据绑定介绍
Spring MVC会根据客户端请求参数的不同,将请求消息中的信息以一定的方式转换并绑定到控制器类的方法参数中,将请求消息数据与后台方法参数建立连接的过程就是Spring MVC中的数据绑定。
通过数据绑定组件(DataBinder)将请求参数串的内容进行类型转换,然后将转换后的值赋给控制器类中方法的形参,这样后台方法就可以正确绑定并获取客户端请求携带的参数了。
![](https://img2023.cnblogs.com/blog/2003270/202304/2003270-20230425020000140-1726809017.png)
(1)Spring MVC将ServletRequest对象传递给DataBinder。
(2)将处理方法的入参对象传递给DataBinder。
(3)DataBinder调用ConversionService组件进行数据类型转换、数据格式化等工作,并将ServletRequest对象中的消息填充到参数对象中。
(4)调用Validator组件对已经绑定了请求消息数据的参数对象进行数据合法性校验。
(5)校验完成后会生成数据绑定结果BindingResult对象,Spring MVC会将BindingResult对象中的内容赋给处理方法的相应参数。
13.2 简单数据绑定
13.2.1 绑定默认数据类型
· HttpServletRequest:通过request对象获取请求信息。
· HttpServletResponse:通过response处理响应信息。
· HttpSession:通过session对象得到session中存储的对象。
· Model/ModelMap:Model是一个接口,ModelMap是一个接口实现,作用是将model数据填充到request域。
1.导包
2.配置web.xml前端控制器
3.配置springmvc-config.xml组件扫描器、视图解析器
4.控制器类UserController
@Controller
public class UserController {
@RequestMapping("/selectUser")
public String selectUser(HttpServletRequest request){
String id = request.getParameter("id");
System.out.println("id = " + id);
return "success";
}
}
5.创建jsp页面success.jsp
6.启动tomcat
13.2.2 绑定简单数据类型
指Java中几种基本数据类型的绑定,如int、String、Double等类型
@Controller
public class UserController {
@RequestMapping("/selectUser")
public String selectUser(Integer id){
System.out.println("id = " + id);
return "success";
}
}
13.2.3 绑定POJO类型
POJO类型的数据绑定就是将所有关联的请求参数封装在一个POJO中,然后在方法中直接使用该POJO作为形参来完成数据绑定。
1.pojo类
2.controller类
@RequestMapping("/toRegister")
public String toRegister(){
return "register";
}
@RequestMapping("/registerUser")
public String registerUser(User user){
String username = user.getUsername();
System.out.println("username = " + username);
// Integer id = user.getId();
Integer password = user.getPassword();
System.out.println("password = " + password);
return "success";
}
3.jsp
<body>
<form action="${pageContext.request.contextPath}/registerUser" method="post">
用户名:<input type="text" name="username" /><br/>
密 码:<input type="text" name="password" /><br/>
<input type="submit" value="注册" />
</form>
</body>
4.启动服务器
为了防止前端传入的中文数据出现乱码问题,我们可以使用Spring提供的编码过滤器来统一编码
<! -- 配置编码过滤器 -->
<filter>
<filter-name>CharacterEncodingFilter</filter-name>
<filter-class> org.springframework.web.filter.CharacterEncodingFilter </filter-class>
<init-param>
<param-name>encoding</param-name>
<param-value>UTF-8</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>CharacterEncodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
13.2.4 绑定包装POJO
所谓的包装POJO,就是在一个POJO中包含另一个简单POJO。例如,在订单对象中包含用户对象。
1.pojo类
private Integer ordersId;
private User user;
2.controller类
@RequestMapping("/tofindOrdersWithUser")
public String tofindOrdersWithUser(){
return "orders";
}
@RequestMapping("/findOrdersWithUser")
public String findOrdersWithUser(Orders orders){
Integer ordersId = orders.getOrdersId();
System.out.println("ordersId = " + ordersId);
User user = orders.getUser();
String username = user.getUsername();
System.out.println("username = " + username);
return "success";
}
3.jsp
<body>
<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>
</body>
① 如果查询条件参数是包装类的直接基本属性,则参数名直接用对应的属性名,如上面代码中的ordersId。
② 如果查询条件参数是包装类中POJO的子属性,则参数名必须为【对象.属性】,其中【对象】要和包装POJO中的对象属性名称一致,【属性】要和包装POJO中的对象子属性一致,如上述代码中的user.username。
4.启动服务器
13.2.5 自定义数据绑定
有些特殊类型的参数是无法在后台进行直接转换的,例如日期数据就需要开发者自定义转换器(Converter)或格式化(Formatter)来进行数据绑定。
1.Converter
Spring框架提供了一个Converter用于将一种类型的对象转换为另一种类型的对象。
public interface Converter<S, T> {
T convert(S source);
}
泛型中的S表示源类型,T表示目标类型,而convert(S source)表示接口中的方法。
日期转换类DateConverter
/*
自定义日期转换器
*/
public class DateConverter implements Converter<String, Date> {
// 定义日期格式
private String datePattern = "yyyy-MM-dd HH:mm:ss";
@Override
public Date convert(String source) {
// 格式化日期
SimpleDateFormat sdf = new SimpleDateFormat(datePattern);
try {
return sdf.parse(source);
} catch (ParseException e) {
throw new IllegalArgumentException("illegal date format " +
"please use :"+datePattern);
}
}
}
springmvc-config.xml添加id为conversionService的Bean
<!--添加了3个mvc的schema信息-->
xmlns:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc-4.3.xsd"
<!-- 显示的装配自定义类型转换器-->
<mvc:annotation-driven conversion-service="conversionService"/>
<!-- 自定义类型转化器配置-->
<bean id="conversionService" class="org.springframework.context.support.ConversionServiceFactoryBean">
<!--列出程序中自定义的所有Converter-->
<property name="converters">
<set>
<bean class="com.itheima.convert.DateConverter"/>
</set>
</property>
</bean>
日期控制器类DateController
@Controller
public class DateController {
@RequestMapping("/customerDate")
public String customerDate(Date date){
System.out.println("date = " + date);
return "success";
}
}
启动服务器
![](https://img2023.cnblogs.com/blog/2003270/202304/2003270-20230425020000113-1619455921.png)
2.Formatter
Formatter的源类型必须是一个String类型,而Converter可以是任意类型。
实现org.springframework.format.Formatter接口
public interface Formatter<T> extends Printer<T>, Parser<T> {}
1.DateFormatter
public class DateFormatter implements Formatter<Date> {
String dataPattern = "yyyy-MM-dd HH:mm:ss";
@Override
public Date parse(String source, Locale locale) throws ParseException {
SimpleDateFormat simpleDateFormat = new SimpleDateFormat(dataPattern);
return simpleDateFormat.parse(source);
}
@Override
public String print(Date date, Locale locale) {
return new SimpleDateFormat().format(date);
}
}
2.Controller
@Controller
public class DateController {
@RequestMapping("/customerDate")
public String customerDate(Date date){
System.out.println("date = " + date);
return "success";
}
}
3.springmvc-config.xml
<bean id="conversionService" class="org.springframework.format.support.FormattingConversionServiceFactoryBean">
<property name="formatters">
<set>
<bean class="com.itheima.convert.DateFormatter"/>
</set>
</property>
</bean>
没有<mvc:annotation-driven conversion-service="conversionService"/>
会报如下错:
HTTP Status 500 - Failed to convert value of type 'java.lang.String' to required type 'java.util.Date'; nested exception is java.lang.IllegalStateException: Cannot convert value of type 'java.lang.String' to required type 'java.util.Date': no matching editors or conversion strategy found
13.3 复杂数据绑定
13.3.1 绑定数组
在批量删除用户的操作中,前端请求传递的都是同名参数的用户id,只要在后台使用同一种数组类型的参数绑定接收,就可以在方法中通过循环数组参数的方式来完成删除操作.
1.user.jsp
<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>shu</td>
</tr>
<tr>
<td><input name="ids" value="3" type="checkbox"></td>
<td>xu</td>
</tr>
</table>
<input type="submit" value="删除" />
</form>
</body>
2.UserController
@RequestMapping("/toUser")
public String selectUsers(){
return "user";
}
@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";
}
13.3.2 绑定集合
批量修改用户操作,前端请求传递过来的数据可能就会批量包含各种类型的数据,如Integer、String等。可以使用集合数据绑定。即在包装类中定义一个包含用户信息类的集合,然后在接收方法中将参数类型定义为该包装类的集合。
1.包装类UserVO
public class UserVO {
private List<User> users;
public List<User> getUsers() {
return users;
}
public void setUsers(List<User> users) {
this.users = users;
}
}
2.UserController
@RequestMapping("/toUserEdit")
public String toUserEdit(){
return "user_edit";
}
@RequestMapping("/editUsers")
public String editUsers(UserVO userlist){
List<User> users = userlist.getUsers();
for (User user:users){
if(user.getId()!= null){
System.out.println("修改了id为"+user.getId()+
"的用户名为"+user.getUsername());
}
}
return "success";
}
在使用集合数据绑定时,后台方法中不支持直接使用集合形参进行数据绑定,所以需要使用包装POJO作为形参,然后在包装POJO中包装一个集合属性。
3.user_edit.jsp
<body>
<form action="${pageContext.request.contextPath}/editUsers" method="post">
<table width="30%" 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="tom" type="text"></td>
</tr>
<tr>
<td><input name="users[1].id" value="2" type="checkbox"></td>
<td><input name="users[1].username" value="shu" type="text"></td>
</tr>
</table>
<input type="submit" value="修改">
</form>
</body>
4.启动服务器
【思考题】
1.请简述简单数据类型中的@RequestParam注解及其属性作用。
绑定url地址
value url的值
method 请求方法 post get等
2.请简述包装POJO类型绑定时的注意事项。
包装pojo类型绑定时
需要写一个pojo类型,实现get和set方法
在controller里写一个绑定pojo类型的方法,加上@requestparam注解
把pojo类型作为方法类的参数