上一节Springboot官网学习(7、Web应用程序【一 Spring Web MVC 之HttpMessageConverters消息转换器】)我们学习了自己定制消息转换器,SpringMVC框架使用HttpMessageConverter转换器类来转换http请求数据和响应数据。如果需要配置的话,通过注解@Bean来返回我们自己配置的消息转换器。HttpMessageConverter在转换http请求和响应的过程中,就需要将java对象转为JSON字符串,也叫做序列化;或者将JSON字符串转为java对象,也叫做反序列化。
那么我们有时候就会遇到一些需求,比如格式化日期格式,比如说格式化double类型保留两位小数,比如字符串转换成日期格式等这些需求在工作中都是会遇到的,难道我们就去对每一个对象修改吗,显然这样是不合理的,所以通过自定义序列化器和反序列化器是非常有必要的。
如果使用Jackson来序列化和反序列化JSON数据,则可能需要编写自己的JsonSerializer和JsonDeserializer类。自定义序列化程序通常是通过模块向Jackson进行注册的,但是Spring Boot提供了另一种@JsonComponent注释,使直接注册Spring Bean更加容易。
这是官网的说法。
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> {
// ...
}
}
这是官网给出的例子。
那么我们就按照这个例子来写一个自己的序列化和反序列化器吧
代码里面有一些注释,如果不懂的,请评论,我会简答。
package com.osy.config;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.JsonDeserializer;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.SerializerProvider;
import org.springframework.boot.jackson.JsonComponent;
import java.io.IOException;
import java.text.DecimalFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
// 使用此注解,让springboot来进行扫描,并且识别他是我们自定义的序列化器和反序列化器
@JsonComponent
public class MyJsonSerializer {
public static class Serializer extends JsonSerializer<Object> {
private DecimalFormat decimalFormat = new DecimalFormat("#.00");
private SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
/**
* 自定义序列化器,这里看他源码是带泛型的,所以这里一定要带上泛型,可以像我一样使用Object类,如果不写,启动就会报错
* Cannot pass `null` as type to register serializer for(血类史:耽搁了我大概十分钟)
* @param o
* @param jsonGenerator
* @param serializerProvider
* @throws IOException
*/
@Override
public void serialize(Object o, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) throws IOException {
System.out.printf("o = " + o);
if(o instanceof Double){
jsonGenerator.writeString(decimalFormat.format(o));
}else if(o instanceof Date){
jsonGenerator.writeString(simpleDateFormat.format(o));
}else{
jsonGenerator.writeObject(o);
}
}
}
public static class Deserializer extends JsonDeserializer<Date> {
private SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
private SimpleDateFormat simpleDateFormatSimple = new SimpleDateFormat("yyyy-MM-dd");
@Override
public Date deserialize(JsonParser jsonParser, DeserializationContext deserializationContext) throws IOException, JsonProcessingException {
Date date = null;
// 检查格式,如果是yyyy-MM-dd",那么就解析,如果不是,就再次解析yyyy-MM-dd HH:mm:ss
try {
date = simpleDateFormatSimple.parse(jsonParser.getText());
} catch (ParseException e) {
try {
date = simpleDateFormat.parse(jsonParser.getText());
}catch (ParseException e1){
e1.printStackTrace();
throw new RuntimeException("时间类型解析错误,请传入正确的日期格式");
}
}
return date;
}
}
}
看完是不是就知道怎么用了,打上@JsonComponent注解springboot就会扫描到并且进行配置,注意,这个类一定要写在启动类下面的包下。如果不明白为什么,请看另一边博客Springboot官网学习(2、Maven构建项目)
那么这里在说一下jackson包给我们提供了一些便捷的注解:
@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注解。
那么我们就要验证一下:
建立实体User类(我这里就之验证一下序列化)
package com.osy.entity;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import com.osy.config.MyJsonSerializer;
import java.util.Date;
public class User {
// 这里一定要指定我们自定义的序列化器,不打注解不生效,我以为他们默认全部生效,后来想了一下,不合理。有些是不需要的
@JsonSerialize(using = MyJsonSerializer.Serializer.class)
private Double price;
@JsonSerialize(using = MyJsonSerializer.Serializer.class)
private Date birthDay;
public double getPrice() {
return price;
}
public void setPrice(double price) {
this.price = price;
}
public Date getBirthDay() {
return birthDay;
}
public void setBirthDay(Date birthDay) {
this.birthDay = birthDay;
}
}
创建启动类和控制器,返回User对象
import com.osy.entity.User;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.Date;
@RestController
@SpringBootApplication
public class Application {
@RequestMapping("/getUser")
public User getUser() {
User user = new User();
user.setPrice(20); // 看结果是否返回20.00
user.setBirthDay(new Date()); // 看结果是否返回我们定义的格式yyyy-MM-dd HH:mm:ss
return user;
}
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
然后访问了一波,看结果:
{“price”:“20.00”,“birthDay”:“2020-06-18 23:29:04”},这就是达到了我们自定义序列化的效果了,这种操作我相信80%的项目应该都有这种需求吧,get到了吗,没有的话评论吧,我会一一回复的