数据绑定的简单介绍
在执行程序时,Spring MVC会根据客户端请求参数的不同,将请求消息中的信息以一定的方式转换并绑定到控制器类的方法参数中。这种将请求消息数据与后台方法参数建立连接的过程就是Spring MVC中的数据绑定。
数据绑定的完成操作
在数据绑定过程中,Spring MVC框架会通过数据绑定组件(DataBinder)将请求参数串的内容进行类型转换,然后将转换后的值赋给控制器类中方法的形参,这样后台方法就可以正确绑定并获取客户端请求携带的参数了。
简单的数据绑定
在先前的注释实现Spring MVC当中进行修改:参考:Spring MVC 的核心类和注释实现MVC程序
当前端请求的参数比较简单时,可以在后台方法的形参中直接使用Spring MVC提供的默认参数类型进行数据绑定。如下所示:
使用以下代码获取前端的数据
@RequestMapping(value = "/firstController1")
public String SelectUser(HttpServletRequest request) {
String id = request.getParameter("id");
if (id!=null) {
System.out.println(id);
}
return "first";
}
运行项目,打开对应的网址,在后面使用问号传递参数 id=78 http://localhost:8080/DataBanding/hello/firstController1?id=78
,随后在控制台当中查看。可以看到一条输出语句,打印了id的值。
在这里使用的是HttpServletRequest,当然还可以使用其他的对象:HttpServletResponse、HttpSession、Model/ModelMap不一 一列举。
当我们的命名比较同意的话就可以不使用到对象进行获取值,直接获取Integer对象的值:
@RequestMapping(value = "/firstController2")
public String SelectUser1(Integer id) {
if (id!=null) {
System.out.println("firstController2="+id);
}
return "first";
}
相同的。我们重新传递这个值:http://localhost:8080/DataBanding/hello/firstController2?id=78
,很显然这样也是可以的,而且相比之下较为简便。
当使用到的变量名不是特别一致的时候,或者前端请求中参数名和后台控制器类方法中的形参名不一样,那么这样就会导致后台无法正确绑定并接收到前端请求的参数。这要如何实现呢?可以考虑使用Spring MVC提供的@RequestParam注解类型来进行间接数据绑定。@RequestParam注解的属性声明如下:
定义方法,添加@RequestParam即可,如下是给id添加一个别名,user_id
@RequestMapping(value = "/firstController3")
public String SelectUser3( @RequestParam(value="user_id")Integer id) {
if (id!=null) {
System.out.println("firstController3/user_id="+id);
}
return "first";
}
调用这个方法传递参数进行测试:http://localhost:8080/DataBanding/hello/firstController3?user_id=78
传递的参数是user_id=78,随后在控制台查看输出的id:
绑定POJO类型
在使用简单数据类型绑定时,可以很容易的根据具体需求来定义方法中的形参类型和个数,然而在实际应用中,客户端请求可能会传递多个不同类型的参数数据,如果还使用简单数据类型进行绑定,那么就需要手动编写多个不同类型的参数,这种操作显然比较繁琐。 针对多类型、多参数的请求,可以使用POJO类型进行数据绑定。POJO类型的数据绑定就是将所有关联的请求参数封装在一个POJO中,然后在方法中直接使用该POJO作为形参来完成数据绑定。其中 POJO(Plain Ordinary Java Object)是指简单的Java对象,实际就是普通JavaBeans。
.比如:定义一个表单提交,需要提交用户名和密码。register.jsp文件。
<form action="${pageContext.request.contextPath }/hello/registerUser"
method="post">
用户名:<input type="text" name="username" /><br />
密 码:<input type="password" name="password" /><br />
<input type="submit" value="注册" />
</form>
新定义一个com.lzq.po 的包,在下面新建一个User类,把需要传递的数据进行定义,并且getter/setter封装。在使用POJO类型数据绑定时,前端请求的参数名(指如上form表单内各元素的name属性值)必须与要绑定的POJO类中的属性一样,这样才会自动将请求数据绑定到POJO对象中,否则后台接收的参数值为null。
String username;
Integer password;
随后在前文相同的地方定义路由:
@RequestMapping(value = "/toRegister")
public String toRegister() {
return "register";
}
@RequestMapping(value = "/registerUser")
public String toRegisterUser(User user) {
String username = user.getUsername();
Integer password = user.getPassword();
System.out.println("username = " + username + ", password = " + password);
return "register";
}
由toRegister路由进入,先跳到jsp页面进行输入数据,在jsp当中的action这个属性进行再次跳转,到/registerUser路由,进行接收。并且将数据进行打印输出,http://localhost:8080/DataBanding/hello/registerUser
在控制台当中进行查看:
但是在这里,会发现当用户名输入中文的时候会导致乱码。如何修改呢?我们只需要将编码都设置为utf-8即可,在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>/*
上述代码中,通过
元素的配置会拦截前端页面中的所有请求,并交由名称CharacterEncodingFilter 的编码过滤器类进行处理 filter 元素中,首先配置了编码过滤器类org.spring.framework.web.filter.CharacterEncodingFilter
,然后通过初始化参数设置统一的编码为 UTF-8 这样所有的请求信息内容都会以 UTF-8 的编码格式进行解析。再进行测试,输入中文,在控制台进行查看:
绑定包装POJO
在用户查询订单时,页面传递的参数可能包括:订单编号、用户名称等信息,这就包含了订单和用户两个对象的信息,这个时候订单和用户信息混合封装,显得比较混乱。可以使用包装POJO类型绑定。
所谓的包装POJO,就是在一个POJO中包含另一个简单POJO。例如,在订单对象中包含用户对象。这样在使用时,就可以通过订单查询到用户信息。
实现如下:首先在com.lzq.po这个包下面定义一个Orders订单类,订单类和用户类存在关联关系,在订单类当中引用用户类并进行封装(封装的代码省略)。如下代码所示:
private Integer ordersId;
private User user;
这里的orders.jsp页面和user.jsp页面相同,修改跳转的地址即可
<body>
<form action="${pageContext.request.contextPath }/hello/findOrdersWithUser"
method="post">
订单编号:
<input type="text" name="ordersId" /><br />
所属用户:
<input type="text" name="user.username" /><br />
<input type="submit" value="查询" />
</form>
</body>
在java类中获取数据:
@RequestMapping(value = "/tofindOrdersWithUser")
public String tofindOrdersWithUser() {
return "orders";
}
@RequestMapping(value = "/findOrdersWithUser")
public String findOrdersWithUser(Orders orders) {
Integer ordersId = orders.getOrdersId();
User user = orders.getUser();
String username = user.getUsername();
System.out.println("username = " + username + ", ordersId = " + ordersId);
return "orders";
}
最后点开网址进行测试:http://localhost:8080/DataBanding/hello/findOrdersWithUser
点击查询,在控制台当中就会打印出订单编号和所属用户的数据:
自定义数据的绑定
有些特殊类型的参数是无法在后台进行直接转换的,例如日期数据就需要开发者自定义转换器( Converter )或格式化( Formatter )来进行数据绑定。
Converter类
Spring 框架提供了一个 Converter 用于将一种类型的对象转换为另一种类型的对象 例如,用户输入的曰期形式可能是“2020/05/20 10:15:26”的字符串,而要Spring 将输入的日期与后台的 Date 进行绑定,则需要将字符串转换为日期,此时就可以自定义一个 Converter类来进行曰期转换,自定义 Converter 类需要实现 org.springframework.core.convert.converter.Converter
接口。
public intface Convert<S,T>{
T convert(S source)
}
S表示源类型,T表示目标类型。示例如下:
先创建一个com.lzq.convert包。创建一个类实现接口
package com.lzq.convert;
import java.text.SimpleDateFormat;
import java.util.Date;
import org.springframework.core.convert.converter.Converter;
import jdk.nashorn.internal.parser.DateParser;
public class DataConvert 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 (Exception e) {
throw new IllegalArgumentException("无效的日期格式: "+ DatePattern);
}
}
}
在需要使用到这个转换器,在springmvc-config当中需要定义:
首先添加了 mvc schema 信息 ;然后定义了组件扫描器和视图解析器;接下来显示装配了自定义的类型转换器;最后编写了自定义类型转换器的配置,其中 Bean的类名称必须为 org.springframework.context.support.ConversionServiceFactoryBean
,并且Bean 申还需要包含一个 converters 属性,通过该属性列出程序中自定义的所有 Converter。
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">
<property name="converters">
<set>
<bean class="com.lzq.convert.DataConvert"></bean>
</set>
</property>
</bean>
使用测试代码
@RequestMapping(value = "/customDate")
public String CustomDate(Date date) {
System.out.println("data = " + date);
return "success";
}
启动项目输入网址:http://localhost:8080/DataBanding/hello/customDate?date=2020-05-20 10:46:35
在控制台当中查看结果:
Formatter类
Formatter 和 Converter 的作用相同,只是 Formatter 的源类型必须是一个 String 类型,而 Converter 可以是任意类型 。使用 Formatter 自定义转换器类需要实现 org.springframework.format.Formatter
接口,该接口的代码如下所示。
public interface Formatter<T> extends Printer<T>, Parser<T> {}
Formatter 接口继承了 Printer Parser 接口,其泛型 表示输入字符串要转换的目标类型 Printer,Parser 接口中,分别包含一个 print(),parse()方法,所有的实现类必须覆盖这两个方法。在前面的包当中创建一个DateFormatter类。
package com.lzq.convert;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Locale;
import org.springframework.format.Formatter;
public class DateFormatter implements Formatter<Date> {
String DatePattern = "yyyy-MM-dd HH:mm:ss";
private SimpleDateFormat simpledateformat;
@Override
public String print(Date date, Locale locale) {
return new SimpleDateFormat().format(date);
}
@Override
public Date parse(String source, Locale locale) throws ParseException {
simpledateformat = new SimpleDateFormat(DatePattern);
return simpledateformat.parse(source);
}
}
DateFormatter 类实现了 Formatter 接口,并实现了接口中的两个方法其中 print() 方法会返回目标对象的字符串,而 parseO 方法会利用指定的 Locale 将一个 String 析成目标类型,要使用 Formatter 自定义的曰期转换器,同样需要在 Spring MVC 的配置文件中进行注册。修改Convert的bean即可。
<bean id="conversionService" class="org.springframework.format.support.FormattingConversionServiceFactoryBean">
<property name="formatters">
<set>
<bean class="com.lzq.convert.DataFormatter"></bean>
</set>
</property>
</bean>
在使用这个bean的时候,把前面的bean注释一下:使用相同的网址进行测试http://localhost:8080/DataBanding/hello/customDate?date=2020-05-20%2011:11:26
,在控制填查看结果
复杂数据类型的绑定
Spring MVC 的数据绑定(复杂数据绑定——数组与集合)单击前往 ->