文章目录
项目的配置
/webapp/WEN-INF/web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://java.sun.com/xml/ns/javaee"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
id="WebApp_ID" version="3.0">
<display-name>Archetype Created Web Application</display-name>
<servlet>
<servlet-name>springmvc</servlet-name>
<servlet-class>
org.springframework.web.servlet.DispatcherServlet
</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:springmvc-config.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>springmvc</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
</web-app>
maven - pom.xml的依赖
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.2.9.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>5.2.4.RELEASE</version>
</dependency>
springmvc-config.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
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.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
<!-- 定义组件扫描器,指定需要扫描的包 -->
<context:component-scan base-package="com.hlq.*" />
<!-- 定义视图解析器 -->
<bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<!-- 设置前缀 -->
<property name="prefix" value="/WEB-INF/jsp/" />
<!-- 设置后缀 -->
<property name="suffix" value=".jsp" />
</bean>
</beans>
数据绑定介绍
什么是数据绑定, SpringMVC是怎样完成数据绑定的?
- 在执行程序时,Spring MVC会根据客户端请求参数的不同,将请求消息中的信息以一定的方式转换并绑定到控制器类的方法参数中
- 这种将请求消息数据与后台方法参数建立连接的过程就是Spring MVC中的数据绑定
- 在数据绑定过程中,Spring MVC框架会通过数据绑定组件(DataBinder)将请求参数串的内容进行类型转换,然后将转换后的值赋给控制器类中方法的形参这样后台方法就可以正确绑定并获取客户端请求携带的参数了
数据绑定的流程
- Spring MVC将ServletRequest对象传递给DataBinder
- 将处理方法的入参对象传递给DataBinder;
- DataBinder调用ConversionService组件进行数据类型转换、数据格式化等工作,并将ServletRequest对象中的消息填充到参数对象中
- 调用Validator组件对已经绑定了请求消息数据的参数对象进行数据合法性校验
- 校验完成后会生成数据绑定结果BindingResult对象,Spring MVC会将BindingResult对象中的内容赋给处理方法的相应参数
简单的数据绑定
- 当前端请求的参数比较简单时,可以在后台方法的形参中直接使用Spring MVC提供的默认参数类型进行数据绑定
- HttpServletRequest:通过request对象获取请求信息
- HttpServletResponse:通过response处理响应信息
- HttpSession:通过session对象得到session中存放的对象
- Model/ModelMap:Model是一个接口,ModelMap是一个接口实现,作用是将model数据填充到request域
绑定到 HttpServletRequest
@Controller
public class UserController {
@RequestMapping("/selectUser")
public String selectUser(HttpServletRequest request, HttpServletResponse response, Model model) {
String id = request.getParameter("id");
System.out.println("id = " + id);
return "success";
}
}
http://localhost:8080/CH13-SpringMVCDataBinder/selectUser?id=1
请求的页面:
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
OK
${msg}
</body>
</html>
绑定到一般的数据类型
@RequestMapping("/selectUserByInteger")
public String selectUserByInteger(Integer id, Model model) {
model.addAttribute("msg", id);
return "success";
}
http://localhost:8080/CH13-SpringMVCDataBinder/selectUserByInteger?id=1
前端请求中参数名和后台控制器类方法中的形参名不一致的解决
- 使用Spring MVC提供的@RequestParam注解类型来进行间接数据绑定
- @RequestParam注解的属性声明如下
案例:
@RequestMapping("/selectUserByRequestParam")
public String selectUserByRequestParam(@RequestParam(value="user_id")Integer id, Model model) {
model.addAttribute("msg", id);
return "success";
}
http://localhost:8080/CH13-SpringMVCDataBinder/selectUserByRequestParam?user_id=1
绑定POJO类
- 客户端请求可能会传递多个不同类型的参数数据,如果还使用简单数据类型进行绑定,那么就需要手动编写多个不同类型的参数,这种操作显然比较繁琐
- 针对多类型、多参数的请求,可以使用POJO类型进行数据绑定
- POJO类型的数据绑定就是将所有关联的请求参数封装在一个POJO类中,然后在方法中直接使用该POJO作为形参来完成数据绑定
- POJO类需要时JavaBean
- 编写注册页面, 注意跳转使用相对类路径
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
<form action="/CH13-SpringMVCDataBinder/registerUser" method="post">
ID: <input type="text" name="id" required /><br>
用户名:<input type="text" name="username" required /><br />
密 码:<input type="text" name="password" required /><br />
<input type="submit" value="注册"/>
</form>
</body>
</html>
- 控制类
@RequestMapping("/register")
public String register() {
return "register";
}
@RequestMapping("/registerUser")
public String registerUser(User user) {
System.out.println(user);
return "success";
}
绑定包装的POJO类
- 在用户查询订单时,页面传递的参数可能包括:订单编号、用户名称等信息,这就包含了订单和用户两个对象的信息
- 谓的包装POJO,就是在一个POJO中包含另一个简单POJO。例如,在订单对象中包含用户对象。这样在使用时,就可以通过订单查询到用户信息
- 要访问的html页面
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
<form action="findOrdersWithUser" method="post">
订单编号:<input type="text" name="ordersId" /><br />
所属用户:<input type="text" name="user.username" /><br />
<input type="submit" value="查询" />
</form>
</body>
</html>
- Controller 控制层
@Controller
public class OrdersController {
@RequestMapping("/findOrders")
public String findOrders() {
return "findOrders";
}
@RequestMapping("/findOrdersWithUser")
public String findOrdersWithUser(Orders orders) {
System.out.println(orders); // 简单输出
return "ok";
}
}
自定义数据绑定
- 有些特殊类型的参数是无法在后台进行直接转换的,但也有特殊数据类型无法直接进行数据绑定
- 必须先经过数据转换,例如日期数据
- 针对特殊数据类型,就需要开发者自定义转换器(Converter)或格式化(Formatter)来进行数据绑定
- Spring框架提供了一个Converter用于将一种类型的对象转换为另一种类型的对象
/**
* 自定义日期转换器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(
"无效的日期格式,请使用这种格式:"+datePattern);
}
}
}
将转化类添加到配置文件中: 即 springmvc-config.xml
注意<mvc:annotation>
的命名空间
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
<!-- 定义组件扫描器,指定需要扫描的包 -->
<context:component-scan base-package="com.hlq.*" />
<!-- 定义视图解析器 -->
<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.hlq.ch13.util.DateConverter" />
</set>
</property>
</bean>
</beans>
编写控制类
/**
* 日期控制器类
*/
@Controller
public class DateController {
/**
* 使用自定义类型数据绑定日期数据
*/
@RequestMapping("/customDate")
public String CustomDate(Date date) {
System.out.println("date=" + date);
return "success";
}
- Formatter与Converter的作用相同,只是Formatter的源类型必须是一个String类型,而Converter可以是任意类型
- 使用Formatter自定义转换器类需要实现org.springframework.format.Formatter接口
- public interface Formatter extends Printer, Parser {}
复杂数据类型
绑定数组
- 简单数据绑定后,已经能够完成实际开发中多数的数据绑定问题,但仍可能遇到一些比较复杂的数据绑定问题,比如数组的绑定、集合的绑定
- 实际开发时,可能会遇到前端请求需要传递到后台一个或多个相同名称参数的情况(如批量删除),此种情况采用前面讲解的简单数据绑定的方式显然是不合适的
- name属性的名称 与 数组的名字相同
<body>
<form action="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>
//...省略向用户列表页面跳转方法
@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";
}
绑定集合
- 如果批量修改用户操作,前端请求传递过来的数据可能就会批量包含各种类型的数据,如Integer,String
- 使用集合数据绑定。即在包装类中定义一个包含用户信息类的集合,然后在接收方法中将参数类型定义为该包装类的集合
- 前端页面
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
<form action="editUsers" method="post" id='formid'>
<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="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>
</body>
</html>
- POJO类
public class UserVO {
private List<User> users;
public List<User> getUsers() {
return users;
}
public void setUsers(List<User> users) {
this.users = users;
}
}
- 控制层Java代码
/**
* 向用户批量修改页面跳转
*/
@RequestMapping("/toUserEdit")
public String toUserEdit() {
return "user_edit";
}
/**
* 接收批量修改用户的方法
*/
@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";
}