浅谈SpringMVC之数据绑定

Spring MVC 拥有强大的数据绑定数据功能 ,本文介绍一下其对各种数据类型的绑定。

数据绑定 : 将请求中的字段按照 名字匹配 的原则填入模型对象中。

测试可以使用HTTP工具提交,推荐:postman

本 wiki 基于 springboot ,mvc 细节不加赘述,依赖如下:

1
2
3
4
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>

基本类型 & 包装类型 & 数组

对于这种类型的数据,直接使用 名字匹配 即可,不需要特殊处理。

基本类型 & 包装类型

推荐直接使用 包装类型 代替 基本类型

数据类型 传递要求 类型要求
基本类型 (如 int 默认参数必须传,反之 HTTP Status 500 类型必须一致(如 int ),反之 HTTP Status 400
包装类型 (如 Integer 参数可以不传,若如此为 null 类型必须一致(如 int ),反之 HTTP Status 400
1
GET /mvc/bind/boxed?id=1
1
2
3
4
5
6
7
8
9
10
11
@GetMapping(value = "/primitive" )
public String primitiveBind(int id){

return "id: " + id;
}

@GetMapping(value = "/boxed")
public String boxedBind(Integer id){

return "id: " + id;
}

数组

GET 传递数组较困难,一般会传json字符串再解析。

1
GET /mvc/bind/array?name=foo&name=bar
1
2
3
4
5
@GetMapping(value = "/array")
public String arrayBind(@RequestParam("name") String[] names){

return Arrays.toString(names);
}

对象

为了便于讲解,本文模拟使用 get 请求类型,且不进行转义(chrome 会自动转义)。

因为 SpringMVC 是通过类的 setter 进行绑定的,所以当绑定多个对象且具有相同属性时,默认同属性都会被赋值,这时需要特殊处理( @@InitBinder 等),这里不介绍。

1
GET /mvc/bind/object?id=1&name=Foo&attribute.size=M
1
2
3
4
5
@GetMapping(value = "/object")
public String objectGetBind(ObjectParam param) {

return param.toString();
}
1
2
3
4
5
6
7
8
9
POST /mvc/bind/object

{
"id": 1,
"name": "Foo",
"attribute": {
"size": "M"
}
}
1
2
3
4
5
@PostMapping(value = "/object")
public String objectPostBind(@RequestBody ObjectParam param) {

return param.toString();
}

日期

为了最佳兼容,一般不直接使用日期类型,而使用时间戳/字符串等。

1
GET /mvc/bind/date?date=2020-01-01&localDate=2020-01-02
1
2
3
4
5
6
7
8
@GetMapping(value = "/date")
public String dateBind(@DateTimeFormat(iso = DateTimeFormat.ISO.DATE, pattern = "yyyy-MM-dd") Date date,
@RequestParam("localDate") String localDateStr) {

LocalDate localDate = LocalDate.parse(localDateStr);

return StringUtils.join(new Object[]{date, localDate}, " ,");
}

集合

由于 GET 的局限性,集合类型应该使用 POST

List

1
2
3
4
5
6
7
8
9
10
11
POST /mvc/bind/list

[
{
"id": 1,
"name": "Foo",
"attribute": {
"size": "M"
}
}
]
1
2
3
4
5
@PostMapping(value = "/list")
public String listBind(@RequestBody List<ObjectParam> param) {

return param.toString();
}

Set

1
2
3
4
5
6
7
8
9
10
11
12
POST /mvc/bind/set

[
{
"id": 1,
"name": "Foo"
},
{
"id": 1,
"name": "Bar"
}
]
1
2
3
4
5
6
@PostMapping(value = "/set")
public String setBind(@RequestBody Set<ObjectParam> param) {

return param.toString();
// [ObjectParam(id=1, name=Foo, attribute=null)]
}

Map

1
2
3
4
5
6
POST /mvc/bind/map

{
"size": "M",
"color": "white"
}
1
2
3
4
5
@PostMapping(value = "/map")
public String mapBind(@RequestBody Map<String, String> param) {

return param.toString();
}

XML

绑定 xml 数据依赖 spring-oxm

*.xml

1
2
3
4
5
<?xml version="1.0" encoding="UTF-8" ?>
<item>
<id>1</id>
<name>Foo</name>
</item>

*entity.java

需要使用 @XmlRootElement 注解。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
package tk.gushizone.web.bind.controller.dto;

import lombok.Data;

import javax.xml.bind.annotation.XmlRootElement;

@Data
@XmlRootElement(name = "item")
public class XmlParam {

private Integer id;

private String name;
}

*Controller.java

需要使用 @RequestBody 注解。

1
2
3
4
5
@PostMapping(value = "/xml")
public String xmlBind(@RequestBody XmlParam param) {

return param.toString();
}

类型转化器

Spring还提供了一些类型转化接口,借此可以完成复杂的数据绑定。

一般可以通过接口约定避免复杂情况,故这里不加赘述。

类型转化接口 用途 说明
PropertyEditor 作用 局部 ;绑定借助 WebDataBinder Spring3 前,内置的可扩展性。
Formatter 作用局部/全局;自动绑定; 参数为String Spring3 后,内置的可扩展性。
Converter 作用局部/全局;自动绑定;参数为自定义。 Spring3 后,内置的不可扩展性。