2018-11-22 · Develop

SpringBoot 数据绑定

什么是数据绑定

引用 维基百科 的一段描述:

数据绑定(英语:Data binding)是将“提供器”的数据源与“消费者”绑定并使其同步的一种通用技术。这通常用两种不同语言的数据/信息源完成,如XML数据绑定。在UI数据绑定中,相同语言但不同逻辑功能的数据与信息对象被绑定在一起(例如Java UI元素到Java对象)。

在数据绑定过程中,每个数据更改会由绑定到数据的元素自动反射。术语“数据绑定”也指一个外部数据表示随元素更改产生变化,并且底层数据自动更新以反映此更改。举例来说,对一个文本框的更改可能修改其根源的数据值。

这篇文章使用 SpringBoot 和 lombok 以及 swagger 技术进行演示,如果你对这三种技术不是很清楚的话,可以去搜索引擎上进行搜索或者看我之前写的文章 快速创建一个SpringBoot应用SpringBoot 集成 Swagger2。文章基于 慕课网 精英讲师 Geelly 老师的免费课程 SpringMVC数据绑定入门 的内容进行写作的,你可以直接观看老师的视频进行学习。

基本类型/包装类型的绑定

@RestController
@Api(description = "数据绑定")
public class HelloController {

    @GetMapping("/base")
    @ApiOperation("基本类型")
    public String hello(@RequestParam(value = "user_age") int age) {
        return "result -> " + age;
    }

    @GetMapping("/package")
    @ApiOperation("包装类型")
    public String hello(Integer age) {
        return "result -> " + age;
    }

    @GetMapping("/array")
    @ApiOperation("数组类型")
    public String hello(String[] names) {
        return "result -> " + Arrays.toString(names);
    }
}

基本类型需要注意的几点是:

下面是对这三个接口的一些测试:

curl -X GET "http://localhost:8080/base?user_age=12"  
result -> 12

curl -X GET "http://localhost:8080/base?age=12"
{"timestamp":"2018-11-23T14:51:01.340+0000","status":400,"error":"Bad Request","message":"Required int parameter 'user_age' is not present","path":"/base"}

curl -X GET "http://localhost:8080/base"
{"timestamp":"2018-11-23T14:51:05.906+0000","status":400,"error":"Bad Request","message":"Required int parameter 'user_age' is not present","path":"/base"}

curl -X GET "http://localhost:8080/package"
result -> null

curl -X GET "http://localhost:8080/package?age=12"
result -> 12

curl -X GET "http://localhost:8080/array?names=a&names=b&names=c"
result -> [a, b, c]

简单对象/多层级对象/同属性对象

首先创建两个实体对象,以便后面使用。

@Getter
@Setter
@ToString
public class User {
    private String name;
    private Integer age;
    private ContactInfo contactInfo;
}
@Getter
@Setter
@ToString
public class ContactInfo {
    private String phone;
    private String address;
}

下面进行对象的绑定。

@GetMapping("/object")
@ApiOperation("对象类型")
public String hello(User user) {
    return "result -> " + user.toString();
}
curl -X GET "http://localhost:8080/object?contactInfo.phone=10086&name=ZUOJL&age=18"
result -> User(name=ZUOJL, age=18, contactInfo=ContactInfo(phone=10086, address=null))

我们再创建一个实体类,这个实体类和 User 类很像,应为我们需要解决的是同属性的情况下的解决方案:

@Getter
@Setter
@ToString
public class Admin {
    private String name;
    private Integer age;
}
@GetMapping("/object")
@ApiOperation("同属性对象类型")
public String hello(User user, Admin admin) {
    return "result -> " + user.toString() + ", " + admin.toString();
}

上面这种情况一般可以使用命名规划的方式避免掉,但如果你接手一个遗留项目是这样使用,还是可以通过下面的方式进行解决。

curl -X GET "http://localhost:8080/object?name=ZUOJL&age=18"
result -> User(name=ZUOJL, age=18, contactInfo=null), Admin(name=ZUOJL, age=18)

curl -X GET "http://localhost:8080/object?user.name=ZUOJL&admin.age=18"
result -> User(name=null, age=null, contactInfo=null), Admin(name=null, age=null)

这个时候我们使用 @InitBinder 对数据进行绑定前的处理。 @InitBinder 标识的方法,可以对 WebDataBinder 对象进行初始化。WebDataBinder 是 DataBinder 的子类,用于完成由表单字段到 JavaBean 属性的绑定。
@InitBinder 方法不能有返回值,它必须声明为 void。
@InitBinder 方法的参数通常是是 WebDataBinder。
@InitBinder 方法的作用域是当前 controller。

@InitBinder("user")
public void initUser(WebDataBinder binder) {
    binder.setFieldDefaultPrefix("user.");
}

@InitBinder("admin")
public void initAdmin(WebDataBinder binder) {
    binder.setFieldDefaultPrefix("admin.");
}

再次测试

curl -X GET "http://localhost:8080/object?user.name=ZUOJL&admin.age=18"
result -> User(name=ZUOJL, age=null, contactInfo=null), Admin(name=null, age=18)

由于篇幅问题,下篇文章再讲 集合类型,Json/XML 以及数据格式化的一些问题。