springboot jackson
阅读数:198 评论数:0
跳转到新版页面分类
python/Java
正文
一、概述
SpringMVC默认使用的是Jackson,Jackson是spring-boot-starter-json依赖中的一部分,spring-boot-starter-web中包含spring-boot-starter-json。也就是说,当项目中引入spring-boot-starter-web后会自动引入spring-boot-starter-json。
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
如果只是简单的Java代码,不使用Spring Boot的话,直接引入Jackson。
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.13.1</version>
</dependency>
二、ObjectMapper
ObjectMapper是jackson-databind包中的一个类,提供读写JSON的功能,可以方便的进行对象和JSON转换。
如果是使用Spring项目,则自动注入ObjectMapper。
@Autowired
private ObjectMapper objectMapper;
如果是普通Java项目,则new一个ObjectMapper。
private ObjectMapper mapper = new ObjectMapper();
// Java对象 转 JSON
Student student = getStudent();
String studentStr = mapper.writeValueAsString(student);
//Java List 转 JSON
List<Student> studentList= getStudentList();
String studentListStr = mapper.writeValueAsString(studentList);
// Java Map 转 JSON
Map<String, Object> studentMap = new HashMap<>();
studentMap.put("id", "1");
studentMap.put("name", "亚瑟");
studentMap.put("age", 33);
String studentJsonStr = mapper.writeValueAsString(studentMap);
//美化输出格式
String studentStr = mapper.writerWithDefaultPrettyPrinter().writeValueAsString(student);
//序列化结果写文件
mapper.writeValue(new File(OBJECT_FILE_PATH_FOR_WRITE_FROM_SRC), student);
自定义序列化
public class CarSerializer extends StdSerializer<Car> {
protected CarSerializer(Class<Car> t) {
super(t);
}
public void serialize(Car car, JsonGenerator jsonGenerator,
SerializerProvider serializerProvider)
throws IOException {
jsonGenerator.writeStartObject();
jsonGenerator.writeStringField("producer", car.getBrand());
jsonGenerator.writeNumberField("doorCount", car.getDoors());
jsonGenerator.writeEndObject();
}
}
CarSerializer carSerializer = new CarSerializer(Car.class);
ObjectMapper objectMapper = new ObjectMapper();
SimpleModule module =
new SimpleModule("CarSerializer", new Version(2, 1, 3, null, null, null));
module.addSerializer(Car.class, carSerializer);
objectMapper.registerModule(module);
Car car = new Car();
car.setBrand("Mercedes");
car.setDoors(5);
String carJson = objectMapper.writeValueAsString(car);
//JSON 转 Java对象
String studentStr = getStudentString();
Student student = mapper.readValue(studentStr, Student.class);
// JSON 转 Java List
List<Student> studentList1 = mapper.readValue(studentListStr , new TypeReference<>() {});
//或者
List<Student> studentList2 = Arrays.asList(mapper.readValue(studentListStr, Student[].class));
//JSON 转 Java Map
HashMap studentMap = mapper.readValue(studentStr, HashMap.class);
//JSON File 转 Java对象
File file = new File(OBJECT_FILE_PATH_FROM_SRC);
Student student = mapper.readValue(file, Student.class);
//JSON Reader 转 Java对象
File file = new File(OBJECT_FILE_PATH_FROM_SRC);
Reader reader = new java.io.FileReader(file);
Student student = mapper.readValue(reader, Student.class);
// JSON InputStream 转 Java对象
InputStream inputStream = new FileInputStream(OBJECT_FILE_PATH_FROM_SRC);
Student student = mapper.readValue(inputStream, Student.class);
// JSON Byte Array 转 Java对象
Student student = mapper.readValue(studentStr.getBytes(StandardCharsets.UTF_8), Student.class);
// JSON via URL 转 Java对象
URL url = new URL("file:" + OBJECT_FILE_PATH_FROM_SRC);
Student student6 = mapper.readValue(url, Student.class);
自定义反序列化
public class CarDeserializer extends StdDeserializer<Car> {
public CarDeserializer(Class<?> vc) {
super(vc);
}
@Override
public Car deserialize(JsonParser parser, DeserializationContext deserializer) throws IOException {
Car car = new Car();
while(!parser.isClosed()){
JsonToken jsonToken = parser.nextToken();
if(JsonToken.FIELD_NAME.equals(jsonToken)){
String fieldName = parser.getCurrentName();
System.out.println(fieldName);
jsonToken = parser.nextToken();
if("brand".equals(fieldName)){
car.setBrand(parser.getValueAsString());
} else if ("doors".equals(fieldName)){
car.setDoors(parser.getValueAsInt());
}
}
}
return car;
}
}
String json = "{ \"brand\" : \"Ford\", \"doors\" : 6 }";
SimpleModule module =
new SimpleModule("CarDeserializer", new Version(3, 1, 8, null, null, null));
module.addDeserializer(Car.class, new CarDeserializer(Car.class));
ObjectMapper mapper = new ObjectMapper();
mapper.registerModule(module);
Car car = mapper.readValue(json, Car.class);
@Configuration
public class JacksonConfig {
@Bean
public ObjectMapper jacksonObjectMapper(){
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.configure(JsonGenerator.Feature.IGNORE_UNKNOWN, true);
objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES,false);
objectMapper.configure(MapperFeature.ACCEPT_CASE_INSENSITIVE_PROPERTIES,true);
return objectMapper;
}
}
ObjectMapper objectMapper = new ObjectMapper();
//去掉默认的时间戳格式
objectMapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);
//设置为东八区
objectMapper.setTimeZone(TimeZone.getTimeZone("GMT+8"));
// 设置输入:禁止把POJO中值为null的字段映射到json字符串中
objectMapper.configure(SerializationFeature.WRITE_NULL_MAP_VALUES, false);
//空值不序列化
objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
//反序列化时,属性不存在的兼容处理
objectMapper.getDeserializationConfig().withoutFeatures(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
//序列化时,日期的统一格式
objectMapper.setDateFormat(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"));
//序列化日期时以timestamps输出,默认true
objectMapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);
//序列化枚举是以toString()来输出,默认false,即默认以name()来输出
objectMapper.configure(SerializationFeature.WRITE_ENUMS_USING_TO_STRING,true);
//序列化枚举是以ordinal()来输出,默认false
objectMapper.configure(SerializationFeature.WRITE_ENUMS_USING_INDEX,false);
//类为空时,不要抛异常
objectMapper.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false);
//反序列化时,遇到未知属性时是否引起结果失败
objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
//单引号处理
objectMapper.configure(JsonParser.Feature.ALLOW_SINGLE_QUOTES, true);
//解析器支持解析结束符
objectMapper.configure(JsonParser.Feature.ALLOW_UNQUOTED_CONTROL_CHARS, true);
三、注解
无论序列化还是反序列化,Jackson都会忽略这个属性。
@JsonIgnoreProperties的作用和@JsonIgnore类似,但是@JsonIgnoreProperties修饰在Java类上,它可设置忽略多个属性,且可以设置ignoreUnknown = true,反序列化时,忽略在JSON中存在,但在Java类中不存在的字段,而不报异常。
@Data
@AllArgsConstructor
@NoArgsConstructor
@JsonIgnoreProperties(value = {"id", "age"}, ignoreUnknown = true)
public class StudentTestForJsonIgnoreProperties {
private String id;
private String name;
private Integer age;
}
当该注解作用于类时,其它类中该注解类属性将被忽略。
@Data
@AllArgsConstructor
@NoArgsConstructor
public class StudentTestForJsonIgnoreType {
private String id;
private String name;
private EnglishName englishName;
private Integer age;
}
@Data
@NoArgsConstructor
@AllArgsConstructor
@JsonIgnoreType
public class EnglishName {
public String firstName;
public String lastName;
}
如果JSON中字段名和Java类中的属性名不一致时,可以用@JsonProperty修饰在属性上。
@Data
@AllArgsConstructor
@NoArgsConstructor
public class StudentTestForJsonProperty {
private String id;
@JsonProperty("studentName")
private String name;
private Integer age;
}
(5)@JsonAnyGetter/@JsonAnySetter
@Data
@AllArgsConstructor
@NoArgsConstructor
public class StudentTestForJsonGetSet {
private String id;
private String name;
private Integer age;
private Map<String, Object> otherAttributes = new HashMap<>();
@JsonAnyGetter
public Map<String, Object> getOtherAttributes() {
return this.otherAttributes;
}
@JsonAnySetter
public void setOtherAttributes(String name, Object value) {
this.otherAttributes.put(name, value);
}
}
public static void main(String[] args) throws JsonProcessingException {
ObjectMapper mapper = new ObjectMapper();
Map<String, Object> otherAttributes = new HashMap<>();
otherAttributes.put("what", "1");
StudentTestForJsonGetSet stu = new StudentTestForJsonGetSet("1", "亚瑟", 30, otherAttributes);
//序列化
String stuStr = mapper.writeValueAsString(stu);
System.out.println(stuStr);
//反序列化
String stuFullStr = "{\"id\":\"1\",\"studentName\":\"亚瑟\",\"age\":30,\"what\":\"1\"}";
StudentTestForJsonGetSet stu2 = mapper.readValue(stuFullStr, StudentTestForJsonGetSet.class);
System.out.println(stu2.toString());
}
{"id":"1","name":"亚瑟","age":30,"what":"1"}
StudentTestForJsonGetSet(id=1, name=null, age=30, otherAttributes={what=1, studentName=亚瑟})
@JsonAnyGetter |
用在非静态方法上,没有入参,返回值是Map类型 一个类中只能有一处此注解 序列化时json字段的key就是map的key,value就是map的value |
@JsonAnySetter |
用在非静态方法上,注解的方法必须有两个参数,第一个是json字段中的key,第二个是value。 也可以用在Map对象属性上面 反序列化的时候将对应不上的字段全部放到Map里面 |
在序列化日期/时间值时指定格式。
@Data
@AllArgsConstructor
@NoArgsConstructor
public class StudentTestForJsonFormat {
private String id;
private String name;
private Integer age;
//默认情况下,Date序列化为自1970年1月1日以来的毫秒数(long类型)
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
private Date time;
}
它可以修饰在类名上或者属性上,但是一般为了更加细粒度的控制,都修饰在属性上。
ALWAYS | 这个是默认值,无论属性值是否为空,都参加序列化 |
NON_NULL | 属性值不是NULL,才参加序列化 |
NON_ABSENT | NON_NULL的增强版,Optional类型不是null,且isPresent()为true,才参加序列化。 实际开发中并不建议在实体类定义Optional类型的属性,如果你非要用,一定要赋默认值,比如Optional.empty()。 |
NON_EMPTY | 属性值不是NULL,也不是"",如果是集合则isEmpty() = false,才参加序列化 |
NON_DEFAULT | 属性值为缺省值时不序列化,比如int类型=0,String类型=null,这样不参加序列化。 实际开发中不要在实体类中用基础类型(如int,float),要用Integer代替int |
CUSTOM | 结合注解JsonInclude.valueFilter和JsonInclude.contentFilter使用,这两个注解会指定一个Class,然后默认调用这个Class的空参构造方法,返回的对象eques属性值的话,序列化时就忽略。 |
@Data
@AllArgsConstructor
@NoArgsConstructor
public class StudentTestForJsonInclude {
//哪怕是null,也会参与序列化
@JsonInclude
private String id;
//非NULL
@JsonInclude(JsonInclude.Include.NON_NULL)
private String name;
//非NULL,非Optional.empty()
@JsonInclude(JsonInclude.Include.NON_ABSENT)
private Optional<String> nickName;
@JsonInclude(JsonInclude.Include.NON_ABSENT)
private Optional<String> nickName2;
//非NULL,非“”,
@JsonInclude(JsonInclude.Include.NON_EMPTY)
private String englishName;
//非NULL,集合isEmpty() = false
@JsonInclude(JsonInclude.Include.NON_EMPTY)
private List<CourseScore> courseScores;
//属性值为缺省值时,不序列化
@JsonInclude(JsonInclude.Include.NON_DEFAULT)
private Integer age = 0;
}
在序列化的时候自定义属性输出顺序
@Data
@AllArgsConstructor
@NoArgsConstructor
@JsonPropertyOrder(value = {"age", "studentName", "id"})
public class StudentTestForJsonPropertyOrder {
private String id;
@JsonProperty("studentName")
private String name;
private Integer age;
}
@JsonView是Jackson的一个很实用的注解,比如一个类的对象,要根据当前登录人的权限来分别序列化成他只能看到的字段。
public class Views {
public static class NameOnly{};
//NameAndAge 继承了 NameOnly
public static class NameAndAge extends NameOnly{};
}
@Data
@AllArgsConstructor
@NoArgsConstructor
public class StudentTestForJsonView {
private String id;
@JsonView(Views.NameOnly.class)
private String name;
@JsonView(Views.NameAndAge.class)
private Integer age;
}
StudentTestForJsonView stu = new StudentTestForJsonView("1", "亚瑟", 30);
//序列化-NameOnly
String stuNameOnly = mapper.writerWithView(Views.NameOnly.class).writeValueAsString(stu);
System.out.println(stuNameOnly);
//序列化-NameAndAge
String stuNameAndAge = mapper.writerWithView(Views.NameAndAge.class).writeValueAsString(stu);
System.out.println(stuNameAndAge);
完全按照原样序列化属性的值
public class RawBean {
public String name;
@JsonRawValue
public String json;
}
//
RawBean bean = new RawBean("My bean", "{\"attr\":false}");
//打印序列化结果
{
"name":"My bean",
"json":{
"attr":false
}
}
// 而不是
{
"name":"My bean",
"json":"{\"attr\":false}"
}
四、application.yml相关配置
spring:
jackson:
# 设置属性命名策略,对应jackson下PropertyNamingStrategy中的常量值
# SNAKE_CASE-返回的json驼峰式转下划线,json body下划线传到后端自动转驼峰式
property-naming-strategy: SNAKE_CASE
# 全局设置@JsonFormat的格式pattern
date-format: yyyy-MM-dd HH:mm:ss
# 当地时区
locale: zh
# 设置全局时区
time-zone: GMT+8
# 常用,全局设置pojo或被@JsonInclude注解的属性的序列化方式
default-property-inclusion: NON_NULL #不为空的属性才会序列化
serialization:
# 返回的java.util.date转换成timestamp
WRITE_DATES_AS_TIMESTAMPS: true
# 对象为空时是否报错,默认true
FAIL_ON_EMPTY_BEANS: true
deserialization:
# 常用,json中含pojo不存在属性时是否失败报错,默认true
FAIL_ON_UNKNOWN_PROPERTIES: false
mapper:
# 使用getter取代setter探测属性
# 如类中含getName()但不包含name属性与setName()
# 传输的vo json格式模板中依旧含name属性
USE_GETTERS_AS_SETTERS: true #默认false
parser:
ALLOW_SINGLE_QUOTES: true # 是否允许出现单引号,默认false