浅谈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 后,内置的不可扩展性。