SpringMVC数据绑定

1.数据绑定概述

数据绑定的目的是将请求中的数据传递给处理器的参数,因此,数据绑定需要在处理器适配器调用处理器方法前完成。

数据绑定需要从ServletRequest请求对象中提取数据,通过反射机制解析处理器的形参列表,依次完成类型转换、校验等操作,最终完成处理器的参数赋值。

j5j112hgo4l.png

2.简单数据绑定

2.1 处理参数

数据绑定的目的是将ServletRequest对象中的数据赋给处理器的入参,ServletRequest对象中的数据是以“key-value”形式的Map数据格式表示。绑定时按入参名与Key是否相同,作为绑定的依据,与入参的顺序无关,Spring MVC也支持入参名与key名不同的情形,但要通过@RequestParam注解标注。

属性名 描述
value 必选属性,也是默认属性。用于指定请求域中被绑定数据的key。
required 可选属性。取true时,表示请求域必须包含该参数名,否则抛出异常。默认为true。
defaultValue 可选属性。用于设置请求参数的默认值。若设置了该值,则required属性值自动变为false。

一般只有单个参数需要处理时,value可以省略不写。

2.2 默认类型参数绑定

默认类型是指Web容器中内置对象类型及Spring MVC提供的类型,当处理器参数中出现默认类型时,Spring MVC能够识别这些默认类型,自动为其准备相应的实例,再赋值给处理器入参,在上一节中,我们使用到的一个类似的用例:

创建一个实体对象

1
2
3
4
5
6
7
8
9
10
11
12
public class Book {
private int bookId;
private String bookName;
private String isbn;
private float price;
private String pubDate;
private String warehousingDate;
private String author;
private int inventory;
private int pubId;
//省略get、set方法
}

创建控制器Controller

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
@Controller
@RequestMapping(value = "/book")
public class BookController {
@GetMapping("to_add_book")
public String toAddbook(){
return "book/add_book";
}
@PostMapping("add_book_binding_default")
public String addBookBindingDefault(HttpServletRequest request, Model model){
Book book = new Book();
book.setBookId(Integer.parseInt(request.getParameter("book_id")));
book.setBookName(request.getParameter("book_name"));
book.setIsbn(request.getParameter("isbn"));
book.setPrice(Float.parseFloat(request.getParameter("price")));
book.setPubDate(request.getParameter("pub_date"));
book.setWarehousingDate(request.getParameter("warehousing_date"));
book.setAuthor(request.getParameter("author"));
book.setInventory(Integer.parseInt(request.getParameter("inventory")));
book.setPubId(Integer.parseInt(request.getParameter("pub_id")));
model.addAttribute("book", book);
return "book/book_info";
}
}

这里我们使用HttpServletRequest中的request对象中的getParameter来获取form表单中提交的name属性对应的值并且通过类型转换将其赋值给book对象,最后通过model.addAttribute(“book”, book);将book对象封装到一个key为book,value为book对象的键值对中return给下一个页面。

2.3 基础数据类型绑定

采用默认类型数据绑定,虽然可以将请求域中的数据传进处理器,但从HttpServletRequest对象中取数据比较麻烦。Spring MVC支持基本类型数据绑定,即使用基本类型作为处理器的参数,自动接收来自HttpServletRequest对象中的数据。在上一个Controller中添加一个映射方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
@PostMapping("/add_book_binding_basic")
public String addBookBindingBasic(@RequestParam("book_id") int bookId,
@RequestParam("book_name") String bookName, String isbn, float price,
@RequestParam("pub_date") String pubDate,
@RequestParam("warehousing_date") String warehousingDate,
String author, int inventory, @RequestParam("pub_id") int pubId, Model model){
Book book = new Book();
book.setBookId(bookId);
book.setBookName(bookName);
book.setIsbn(isbn);
book.setPrice(price);
book.setPubDate(pubDate);
book.setWarehousingDate(warehousingDate);
book.setAuthor(author);
book.setInventory(inventory);
book.setPubId(pubId);
model.addAttribute("book", book);
return "book/book_info";
}

第 2~6 行是处理器 addBookBindingBasic0 的入参表,除了最后的 model 参数外,其余都是基本类型参数。当然,基本类型也可以换成对应的引用类型,如 int 和 float 可以换成 Integer 与 Float,其运行结果相同。部分请求参数名与入参名不一致,因此,用到了 @RequestParam 注解标注。由于每个基本类型参数只接收一个数据,因此,当入参很多时,会导致处理器的参数表太长。

2.3 自定义类型转换

Spring MVC提供了org.springframework.core.convert.converter.Converter接口,供开发人员定制类型转换器,同时也可以使用org.springframework.format.Formatter接口实现同样的类型转换功能。

1
2
3
4
package org.springframework.core.convert.converter;
public interface Converter<S, T> {
T convert(S source);
}

例如,我想定制一个类型 转换器实现String到Date类型的转换

1
2
3
4
5
6
7
8
9
10
11
12
public class DateConverter implements Converter<String, Date> {
@Override
public Date convert(String source) {
String pattern = "yyyy-MM-dd";
SimpleDateFormat simpleDateFormat = new SimpleDateFormat(pattern);
try {
return simpleDateFormat.parse(source);
}catch (ParseException e){
throw new IllegalArgumentException("日期格式无效,请使用" + pattern + "格式");
}
}
}

自定义转换器类 DateConverter 实现 Converter<> 接口,重写了 convert0方法。DateConverter类重写 convert0 方法,使自己具备了从 String 到 Date类型转换的能力,实现 Converter<> 接口自己具备了成为类型转换器的资格。接下来通过配置,使 DateConverter类进入型转工作的就绪状态,需要在配置文件 spring-mvc.xml 中添加类型转换器的配置信息:

1
2
3
4
5
6
7
<bean name="converterService"
class="org.springframework.context.support.ConversionServiceFactoryBean">
<property name="converters">
<set><bean class="com.javaee.ex07.converter.DateConverter"/></set>
</property>
</bean>
<mvc:annotation-driven conversion-service="converterService"/>

ConversionServiceFactoryBean 类在实例化后,便具备了处理 Spring MVC 默认类型的转换的能力,其集合属性 converters 中可以通过配置注人多个自定义类型转换器。第7行用于装载自定义类型转换器,为了能够验证 DateConverter 类型转换器的有效性,在 BookController 控制器类中添加一个处理器addBookBindingBasicEx();

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
@PostMapping("/add_book_binding_basic_ex")
public String addBookBindingBasicEx(@RequestParam("book_id") int bookId,
@RequestParam("book_name") String bookName, String isbn, float price,
@RequestParam("pub_date") Date pubDate,
@RequestParam("warehousing_date") Date warehousingDate,
String author, int inventory, @RequestParam("pub_id") int pubId, Model model) {
BookEx book = new BookEx();
book.setBookId(bookId);
book.setBookName(bookName);
book.setIsbn(isbn);
book.setPrice(price);
book.setPubDate(pubDate);
book.setWarehousingDate(warehousingDate);
book.setAuthor(author);
book.setInventory(inventory);
book.setPubId(pubId);
model.addAttribute("book", book);
return "book/book_info";
}

这个代码和上个代码的差异体现19在第 1、4、5行。显然,映射路径的差异是必需的。由于形参pubDate和warehousingDate的类型由原来的String修改成 Date。

3.复杂数据绑定

3.1 pojo绑定

基本数据类型绑定简单,但是当传入的参数数量比较多的时候,形参列表的数量会比较长不利于阅读,为此可以将pojo封装成一个pojo实体类,但是在上面的book类中只包含了pubid一个属性,但是我们需要在book类中添加一个实体类Publisher实体类时。

未完待续。。。。。