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();

1、序列化

// 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);

2、反序列化

//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);

3、自定义ObjectMapper

@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);

三、注解

1、序列化与反序列化同时生效的注解

(1)@JsonIgnore

无论序列化还是反序列化,Jackson都会忽略这个属性。

(2)@JsonIgnoreProperties

@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;
}

(3)@JsonIgnoreType

当该注解作用于类时,其它类中该注解类属性将被忽略。

@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;
}

(4)@JsonProperty

如果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里面

2、仅序列化生效的注解

(1)@JsonFormat

在序列化日期/时间值时指定格式。

@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;
}

(2)@JsonInclude

它可以修饰在类名上或者属性上,但是一般为了更加细粒度的控制,都修饰在属性上。

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;
}

(3)@JsonPropertyOrder

在序列化的时候自定义属性输出顺序

@Data
@AllArgsConstructor
@NoArgsConstructor
@JsonPropertyOrder(value = {"age", "studentName", "id"})
public class StudentTestForJsonPropertyOrder {

    private String id;

    @JsonProperty("studentName")
    private String name;

    private Integer age;
}

(4)@JsonView

@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);

(5)@JsonRawValue

完全按照原样序列化属性的值

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



相关推荐

当然可以自己写redis的工具类,或者使用第三方开源jar包或代码,这里使用spring boot的集成类。 一、pom依赖 <dependency> <gro

一、概述 1、序列化的作用 个人理解它的主要作用是为了对象可以跨平台存储和进行网络传输,在网络传输的时候,我们需要经过 IO,而 IO 传输支持的就是字节数组这种格式,所以序列化过后可以更好的传输。

一、默认日期序列化 1、fastjson默认使用的序列格式 public static String DEFFAULT_DATE_FORMAT = "yyyy-MM-dd HH:m

一、@JsonFormat  1、作用 约束时间的接收格式和响应格式(接收和响应的都是JSON字符串),用于在JSON和java.util.Date之间约束,注意因为我们在东八区,使用时需要加上时区(

一、消息转换器 在使用SpringMVC框架时,由前端发请求给后端,请求体中的内容就被称为消息。消息转换器就是实现消息与Java对象的相互转换,将请求体中的消息转为Java对象,反过来将Java对象转

一、概述 Spring 中的处理器的实现多变,比如用户的处理器可以实现 Controller 接口或者 HttpRequestHandler 接口,也可以用 @RequestMapping 注解将方法