What?
这种将请求消息数据与后台方法参数建立连接的过程就是Spring MVC中的数据绑定。
Spring MVC会根据客户端的请求参数的不同,将请求消息中的信息以一定的方法转换并绑定到控制器类的方法参数中,
过程
Spring Mvc框架通过数据绑定组件(DataBinder)将请求参数串的内容进行类型的转换,然后将转换后的值赋给控制器类中方法的形参,这样后台方法就可以正确的绑定并获取客户端请求携带的参数了,
数据绑定的分类
根据客户端请求参数类型和个数的不同,将数据绑定分为简单数据绑定和复杂数据绑定,
绑定默认数据类型
当前端请求的参数比较简单的时候,可以在后台方法的形参中直接使用Spring MVC提供的默认参数类型进行数据绑定。
- 常用的默认参数类型:
- HttpServletRequest:通过request对象获取请求信息;
- HttpServletResponse:通过response处理响应信息;
- HttpSession:通过session对象得到session中存放的对象。
- Model/ModelMap:Model是一个接口,ModelMap是一个接口实现,作用将model数据填充到request域中。
代码
web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
version="3.1">
<servlet>
<servlet-name>springmvc</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<!--initparam元素存在并且通过其子元素配置了
Spring MVC配置文件的路径,则应用程序在启动时会加载配置路径下的配置文件-->
<!--如果这里面没有通过<init-param>元素配置,则应用程序会默认去WEB-INF目录下寻找
以servletName-servlet.xml方式命名的配置文件,这里的servletName指的下面的springmvc-->
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:springmvc.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>
FirstController
package com.yzb.chapter13;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import javax.servlet.http.HttpServletRequest;
@Controller
public class FirstController {
@RequestMapping("/first")
public String first(HttpServletRequest request){
String id = request.getParameter("id");
System.out.println(id);
return "first";
}
}
springmvc.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-4.3.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-4.3.xsd">
<!--上面引入context的信息-->
<!--指定需要扫描的包-->
<context:component-scan base-package="com.yzb.chapter13"/>
<!--使用注解的时候,程序的运行需要依赖Spring的AOP包,因此需要注入aop的jar包-->
<!--配置视图解析器的前缀和后缀,-->
<bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<!--设置前缀-->
<property name="prefix" value="/WEB-INF/jsp"></property>
<!--设置后缀-->
<property name="suffix" value=".jsp"/>
</bean>
</beans>
first.jxp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
OK
</body>
</html>
简单的数据类型的绑定
指的时Java中集中基本数据类型的绑定,例如String,Double等类型,
@RequestMapping("/second")
public String first(Integer id){
System.out.println(id);
return "first";
}
//将HttpServletRequest请求改为基本请求类型Integer的绑定方式
@RequestParam
如果前端请求中的参数和后台方法中传入的形参名不一样,这就会导致无法接受前台的请求参数,这是就可以使用@RequestParam注解进行间接注解绑定
- @RequestParam注解的属性说明
- value:name属性的别名,这里指参数的名字,即入参的请求参数的名字,如value="item_id"表示请求的参数中名字为item_id的参数的值传入,如果只用value属性,则可以省略value属性名
- name:指定请求绑定的名称
- required:用于指定参数是否必须,默认为true,表示请求中一定要有相应的参数
- defaultValue:默认值,表示如果请求中没有同名参数的默认值。
@RequestMapping("/second")
public String first(@RequestParam(value = "item_id" ,required = true ) Integer id){
System.out.println(id);
return "first";
}
POJO类型的数据绑定
FirstController
package com.yzb.chapter12;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@Controller
public class FirstController {
@RequestMapping("/abc")
public String register(){
return "register";
}
@RequestMapping("/toRegister")
public String first(User user){
String username = user.getUsername();
String password = user.getPassword();
System.out.println(username +"<br/>"+ password);
return "first";
}
}
User
package com.yzb.chapter12;
public class User {
private Integer id;
private String username;
private String password;
@Override
public String toString() {
return "User{" +
"id=" + id +
", username='" + username + '\'' +
", password='" + password + '\'' +
'}';
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
}
register.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<form action="${pageContext.request.contextPath}/toRegister" method="post">
<%--当绑定POJO类型数据时,表单的name的属性名要和pojo类中的属性名保持一直--%>
用户名;<input type="text" name="username"><br/>
密码:<input type="text" name="password"><br/>
<input type="submit" value="注册">
</form>
</body>
</html>
注意在使用POJO类型数据绑定的时,前端请求的参数名必须与pojo类中的属性名一样,这样才能自动将请求数据绑定到POJO对象中,否则后台接受的值为空
解决前台传入参数为乱码
- 加入编码乱码过滤器,在web.xml中加入这个配置文件
<!--配置编码过滤器-->
<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>
包装POJO类型的数据绑定
为了解决一个页面传递的参数包含多个对象的信息,这是就需要对POJO类型进行包装。就是在一个POJO中包含另一个简单POJO,例如在订单对象中包含用户对象,这样就可以在查询订单的时候,查询用户,
Orders
package com.yzb.chapter12;
public class Orders {
private Integer orderId;
private User user;
public Integer getOrderId() {
return orderId;
}
public void setOrderId(Integer orderId) {
this.orderId = orderId;
}
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
}
OrderController
package com.yzb.chapter12;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
@Controller
public class OrderController {
@RequestMapping("toFindOrdersWithUser")
public String toFindOrdersWithUser(){
return "orders";
}
@RequestMapping("findOrdersWithUser")
public String findOrdersWithUser(Orders orders){
Integer orderId = orders.getOrderId();
System.out.println(orderId);
User user = orders.getUser();
String username = user.getUsername();
System.out.println(username);
return "first";
}
}
orders.jsp
注意
在使用包装POJO类型数据绑定时,前端请求的参数名编写要符合两种情况
1:如果查询条件时包装类的直接基本属性,则参数名直接对应属性名,例如orderId;
2:如果查询的条件时包装类中的子属性,则参数名必须为【对象.属性】,其中对象要和包装pojo中的对象属性名称一致,属性要和包装类pojo中的对象子属性一致。例如上面的代码user.username.
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<form action="${pageContext.request.contextPath}/findOrdersWithUser" method="post">
<%--当绑定POJO类型数据时,表单的name的属性名要和pojo类中的属性名保持一直--%>
订单id;<input type="text" name="orderId"><br/>
用户名:<input type="text" name="user.username"><br/>
<input type="submit" value="注册">
</form>
</body>
</html>
自定义数据绑定
对于特殊类型的参数是无法在后台进行直接转换的,但也有特殊数据类型无法直接进行数据绑定,必须经过数据类型的转换,例如日期数据。
自定义转换器Converter
spring提供的Converter用于将一种类型的对象转换为另一种类型的对象。
自定义了Converter类需要实现org.framework.core.convert.vonverter.Converter接口
public interface Converter<S,T>{
T convert(S source);
}
//S 是源类型,T是目标类型
格式化Formatter
作用与Converter的一样,指示Formatter的源类型必须是String类型,而Converter可以是任意类型。
使用Formatter自定义转换器类需要实现org.springframework.format.Formatter接口。
public interface Formatter<T> extends Printer<T>, Parser<T>{}
Converter的代码
DateConverter
定义格式转换类
package com.yzb.chapter12;
import org.springframework.core.convert.converter.Converter;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
/*
* 自定义日期转换器
* */
public class DataConverter 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.xml
告诉spring配置了自定义转换器
<!--显示装配的自定义类型转换器-->
<mvc:annotation-driven conversion-service="conversionService"></mvc:annotation-driven>
<!--自定义类型转换器配置-->
<bean id="conversionService" class="org.springframework.context.support.ConversionServiceFactoryBean">
<property name="converters">
<set>
<bean class="com.yzb.chapter12.DataConverter"/>
</set>
</property>
</bean>
DateController
package com.yzb.chapter12;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import java.util.Date;
/*
* 日期控制类
* */
@Controller
public class DateController {
/*
* 使用自定义类型数据绑定日期数据
* */
@RequestMapping("/customDate")
public String CustomDate(Date date){
System.out.println("date = " + date);
return "first";
}
}
formatter的代码
DateFormatter
package com.yzb.chapter12;
import org.springframework.format.Formatter;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Locale;
public class DateFormatter implements Formatter<Date> {
//定义格式
private String datePattern = "yyyy-MM-dd HH:mm:ss";
//声明SimpleDateFormat对象
private SimpleDateFormat simpleDateFormat;
/*
* 解析字符串文本,生成Date对象
* */
@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);
}
}
springmvc.xml
<!--显示装配的自定义类型转换器-->
<mvc:annotation-driven conversion-service="conversionService"></mvc:annotation-driven>
<!--自定义类型格式化转换器配置-->
<!--class和name的属性必须是这两个-->
<bean id="conversionService" class="org.springframework.format.support.FormattingConversionServiceFactoryBean">
<property name="formatters">
<set>
<bean class="com.yzb.chapter12.DateFormatter"></bean>
</set>
</property>
</bean>
绑定数组
结果图
User.jsp
<%--
Created by IntelliJ IDEA.
User: 岳振彪
Date: 2020/6/30
Time: 14:59
To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<form action="${pageContext.request.contextPath}/deleteUser" method="post">
<table border="1">
<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>rose</td>
</tr>
</table>
<input type="submit" value="删除">
</form>
</body>
</html>
UserController
package com.yzb.chapter12;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
@Controller
public class UserController {
@RequestMapping("delete")
public String toFindOrdersWithUser(){
return "user";
}
@RequestMapping("deleteUser")
public String findOrdersWithUser(Integer[] ids){
if(ids !=null){
for (Integer id : ids) {
System.out.println("删除了id为"+id+"的用户!");
}
}else {
System.out.println("ids = null");
}
return "first";
}
}
集合类的包装
UserVO
package com.yzb.chapter12;
import java.util.List;
public class UserVO {
private List<User> users;
public List<User> getUsers() {
return users;
}
public void setUsers(List<User> users) {
this.users = users;
}
}
EditController
package com.yzb.chapter12;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import java.util.List;
@Controller
public class EditController {
@RequestMapping("edit")
public String toFindOrdersWithUser(){
return "edit";
}
@RequestMapping("editUser")
public String findOrdersWithUser(UserVO list){
List<User> users = list.getUsers();
for (User user : users) {
System.out.println("修改id为"+ user.getId()+"的用户名"+user.getUsername());
}
return "first";
}
}
edit.jsp
<%--
Created by IntelliJ IDEA.
User: 岳振彪
Date: 2020/6/30
Time: 14:59
To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<form action="${pageContext.request.contextPath}/editUser" method="post">
<table 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="jack" type="text"></td>
</tr>
<tr>
<td> <input name="users[2].id" value="3" type="checkbox"></td>
<td><input name="users[2].username" value="rose" type="text"></td>
</tr>
</table>
<input type="submit" value="删除">
</form>
</body>
</html>