SpringBoot2.x系列教程16--SpringBoot中自定义JSON序列化器和反序列化器
SpringBoot2.x系列教程16--SpringBoot中自定义JSON序列化器和反序列化器
前言
在上一章节中给大家介绍了在SpringMVC框架中,我们可以使用HttpMessageConverter转换器类来转换HTTP请求和响应信息,并且可以实现对JSON信息的格式转换。我们知道,JSON是前后端信息传输的主要载体,我们大多数传递的参数都是利用JSON完成的,所以JSON是非常重要和常用的。而JSON信息本身也比较复杂,其中有些细节需要我们注意,比如JSON的序列化和反序列化。
一. 序列化与反序列化简介
1. 概述
HttpMessageConverter在转换http请求和响应的过程中,可以将对象转为JSON,这个过程我们可以称之为序列化;反过来也可以将JSON转为对象,这就是反序列化。
2. @JsonComponent注解
在Spring Boot中,默认是使用Jackson来对JSON信息进行序列化和反序列化的。那么除了可以用默认的之外,我们也可以编写自己的JsonSerializer和JsonDeserializer类来进行自定义操作。
自定义序列化器(serializers)通常是通过Module方式注册到Jackson中,但在Spring Boot中提供了@JsonComponent注解作为替代方案,它能帮我们更为轻松的将序列化器注册到Spring Beans中。
我们可以直接在JsonSerializer 或 JsonDeserializer类上使用 @JsonComponent注解,该注解允许我们将带该注解的类公开为Jackson序列化器或反序列化器,而无需再手动将其添加到ObjectMapper。我们还可以在包含序列化程序/反序列化程序作为内部类的类上使用它,如下例所示:
import java.io.*;
import com.fasterxml.jackson.core.*;
import com.fasterxml.jackson.databind.*;
import org.springframework.boot.jackson.*;
@JsonComponent
public class Example {
public static class Serializer extends JsonSerializer<SomeObject> {
// ...
}
public static class Deserializer extends JsonDeserializer<SomeObject> {
// ...
}
}
ApplicationContext 中的所有 @JsonComponent bean都会自动注册到Jackson,因为 @JsonComponent是用 @Component进行注解的,所以应用通常的组件扫描规则。
SpringBoot还提供了JsonObjectSerializer和JsonObjectDeserializer 基类,它们在序列化对象时为标准的Jackson版本提供了有用的替代方案。
二. 自定义序列化与反序列化
接下来我就带大家创建一个项目,在这里实行JSON的序列化和反序列化。
1. 创建新项目
为了讲解序列化与反序列化的实现,我们创建一个新的工程,创建过程类似于之前,此处略过。最后完整的项目结构如下,各位可以参考创建。
2. 实现JsonSerializer序列化
我们首先创建一个CustomeJackSon类,类上带有@JsonComponent注解。在该类内部编写一个静态内部类,继承JsonSerializer,并重写Serialize()方法。在重写的serialize()方法中实现对JSON信息中Double类型数据的格式化。
/**
*使用@JsonComponent注释会自动被注册到Jackson中.
**/
@JsonComponent
public class CustomeJackSon {
/**
* 自定义序列化器,格式化数值
*/
public static class MySerializer extends JsonSerializer<Double> {
private DecimalFormat df = new DecimalFormat("##.00");
/**
* 序列化操作,继承JsonSerializer,重写Serialize函数
*/
@Override
public void serialize(Double value, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) throws IOException {
jsonGenerator.writeString(df.format(value));
}
}
}
3. 反序列化JsonDeserializer实现
然后我们再编写一个静态内部类,继承JsonDeserializer类,重写deserialize()方法,自定义自己的反序列化逻辑。在这里实现对JSON中日期信息的格式化。
/**
* 使用@JsonComponent注释会自动被注册到Jackson中.
*/
@Slf4j
@JsonComponent
public class CustomeJackSon {
/**
* 自定义反序列化器,格式化时间
*/
public static class MyDeserializer extends JsonDeserializer<Date> {
private SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
@Override
public Date deserialize(JsonParser jsonParser, DeserializationContext deserializationContext) throws IOException {
Date date = null;
try {
date = sdf.parse(jsonParser.getText());
} catch (ParseException e) {
e.printStackTrace();
}
return date;
}
}
}
4. 构建Bean对象
4.1 常用json注解简介
- @JsonIgnoreProperties: 此注解是类注解,作用是在json序列化时将Java bean中的某些属性忽略掉,序列化和反序列化都受影响。
- @JsonIgnore: 此注解用于属性或者方法上(最好是属性上),作用和上面的@JsonIgnoreProperties一样。
- @JsonFormat: 此注解用于属性或者方法上(最好是属性上),可以方便的把Date类型直接转化为我们想要的模式,比如@JsonFormat(pattern = "yyyy-MM-dd HH-mm-ss")
- @JsonSerialize: 此注解用于属性或者getter方法上,用于在序列化时嵌入我们自定义的序列化器,比如序列化一个double时在其后面限制两位小数点。
- @JsonDeserializ: 此注解用于属性或者setter方法上,用于在反序列化时嵌入我们自定义的反序列化器,比如反序列化一个Date类型的时间字符串。
- @JsonCreator与@JsonProperty: 该注解的作用就是指定反序列化时替代无参构造函数,构造方法的参数前面需要加上@JsonProperty注解。
4.2 完整的Java bean实体类
接下来我再创建一个User实体类,注意这个类上的一些关于JSON的注解。
package com.yyg.boot.domain;
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import com.yyg.boot.json.CustomeJackSon;
import lombok.Data;
import lombok.ToString;
import java.util.Date;
/**
* @NoArgsConstructor
* @AllArgsConstructor 表示序列化时忽略的属性
*/
@Data
@ToString
@JsonIgnoreProperties(value = {"word"})
public class User {
/**
* 注意:在进行JSON序列化和反序列化时,要么提供一个无参的构造方法,要么在其他构造方法上添加@JsonCreator注解.
*/
private String name;
private int age;
private boolean sex;
private Date birthday;
private String word;
private double salary;
@JsonCreator
public User(@JsonProperty("name") String name, @JsonProperty("age") int age, @JsonProperty("sex") boolean sex, @JsonProperty("birthday") Date birthday,
@JsonProperty("word") String word, @JsonProperty("salary") double salary) {
super();
this.name = name;
this.age = age;
this.sex = sex;
this.birthday = birthday;
this.word = word;
this.salary = salary;
}
/**
* 反序列化一个固定格式的Date
*/
@JsonDeserialize(using = CustomeJackSon.MyDeserializer.class)
public void setBirthday(Date birthday) {
this.birthday = birthday;
}
/**
* 序列化指定格式的double格式
*/
@JsonSerialize(using = CustomeJackSon.MySerializer.class)
public double getSalary() {
return salary;
}
}
注意:
当json在反序列化时,默认选择类的无参构造函数创建类对象,当没有无参构造函数时则会报错,@JsonCreator注解的作用就是指定反序列化时用的无参构造函数。构造方法的参数前面需要加上@JsonProperty,否则会报错!
例如:
@JsonCreator
public Person(@JsonProperty("id") String id) {
this.id = id;
}
5. 编写Controller
然后我们再编写一个Controller,封装2个Web接口用于测试,接收传递过来的请求参数,并将User实体类转为JSON格式的信息响应到前端。
package com.yyg.boot.web;
import com.yyg.boot.domain.User;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.*;
import java.util.Date;
@Slf4j
@RestController
public class UserController {
/**
* 将对象转为json字符串-->序列化
*/
@GetMapping("/user/{salary}")
public User home(@PathVariable("salary") Long salary) {
return new User("一一哥", 30, true, new Date(), "程序员", salary);
}
/**
* 将一个json转化为对象-->反序列化
*/
@RequestMapping(value = "user")
public String getValue(@RequestBody User user) {
log.warn("user=" + user.toString());
return user.toString();
}
}
6. 编写入口类
最后编写一个项目入口类。
package com.yyg.boot;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
/**
* json的序列化与反序列化
*/
@SpringBootApplication
public class SerializeApplication {
public static void main(String[] args) {
SpringApplication.run(SerializeApplication.class, args);
}
}
7. 运行程序,检查结果
重启项目后,我们进行项目测试。
7.1 序列化测试
我们先来看看序列化的测试结果,会发现JSON中携带的double类型数据后面自动带了2位小数点。
7.2 反序列化测试
因为我们要接受一个JSON参数,所以可以利用postman进行反序列化测试,执行后可以看到返回的JSON数据中,我们的日期信息被转换成了我们规定的格式。
最终我们在SpringBoot项目中实现了自定义的JSON序列化与反序列化操作。
结语
这样通过一些简单配置,我们就把整个项目中所有的JSON序列化和反序列化进行了统一的设置,以后开发时,我们项目中的JSON格式一般都有统一的要求,就可以采用本文中的方法进行序列化和反序列化,你学会了吗?
今日小作业:
增加一个学生注册功能,注册信息中要带有学生体重、学费、生日等信息,对这些信息请做统一处理。