SpringBoot的Jackson最全使用详解

SpringBoot的Jackson最全使用详解

在Spring Boot项目中,Jackson是默认的JSON处理库,用于对象与JSON之间的序列化和反序列化。本文将详细介绍Jackson在Spring Boot下的各种使用方法,包括基本配置、注解使用、自定义序列化器和反序列化器、以及处理复杂数据类型等。

1. 导入依赖

在Spring Boot项目中,通常不需要手动导入Jackson的依赖,因为spring-boot-starter-web已经包含了这些依赖。但如果你需要单独引入,可以在pom.xml文件中添加以下依赖:

<!-- Jackson核心库 -->
<dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-databind</artifactId>
    <version>2.13.3</version>
</dependency>

2. 全局配置

application.propertiesapplication.yml文件中,可以对Jackson进行全局配置,例如设置日期格式、时区等。

application.yml
spring:
  jackson:
    # 设置日期格式
    date-format: yyyy-MM-dd HH:mm:ss
    # 设置时区
    time-zone: Asia/Shanghai
    # 设置默认属性包含方式,例如非空
    default-property-inclusion: non_null
    serialization:
      # 设置序列化时是否格式化输出
      indent-output: true
    deserialization:
      # 设置反序列化时是否忽略未知属性
      fail-on-unknown-properties: false
    parser:
      # 设置解析器是否允许未转义的控制字符
      allow-unquoted-control-chars: true
      # 设置解析器是否允许单引号
      allow-single-quotes: true

3. 自定义配置

除了通过配置文件进行全局配置外,还可以通过代码自定义配置Jackson的ObjectMapper

import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.converter.json.Jackson2ObjectMapperBuilder;

import java.text.SimpleDateFormat;
import java.util.TimeZone;

@Configuration
public class JacksonConfig {

    @Bean
    @Primary
    public ObjectMapper objectMapper(Jackson2ObjectMapperBuilder builder) {
        ObjectMapper objectMapper = builder.build();

        // 设置日期格式
        objectMapper.setDateFormat(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"));

        // 设置时区
        objectMapper.setTimeZone(TimeZone.getTimeZone("Asia/Shanghai"));

        // 设置序列化时是否格式化输出
        objectMapper.configure(SerializationFeature.INDENT_OUTPUT, true);

        // 设置反序列化时是否忽略未知属性
        objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);

        // 设置解析器是否允许未转义的控制字符
        objectMapper.configure(JsonParser.Feature.ALLOW_UNQUOTED_CONTROL_CHARS, true);

        // 设置解析器是否允许单引号
        objectMapper.configure(JsonParser.Feature.ALLOW_SINGLE_QUOTES, true);

        // 添加Java 8时间模块支持
        objectMapper.registerModule(new JavaTimeModule());

        return objectMapper;
    }
}

4. 注解使用

Jackson提供了多种注解来控制序列化和反序列化的行为,以下是一些常用的注解及其用法。

  • @JsonIgnore:忽略字段的序列化和反序列化。
  • @JsonProperty:指定字段的JSON键名。
  • @JsonFormat:指定日期格式。
  • @JsonInclude:控制字段的序列化条件。
  • @JsonView:控制视图。
  • @JsonAlias:为反序列化期间要接受的属性定义一个或多个替代名称。
  • @JsonPropertyOrder:指定字段的序列化顺序。
  • @JsonRawValue:将字段值作为原始JSON字符串处理。
  • @JsonAnyGetter@JsonAnySetter:处理动态属性。

示例实体类

import com.fasterxml.jackson.annotation.JsonFormat;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.annotation.JsonPropertyOrder;
import com.fasterxml.jackson.annotation.JsonInclude;

import java.util.Date;

@JsonInclude(JsonInclude.Include.NON_NULL) // 忽略值为null的属性
@JsonPropertyOrder({"name", "age", "email"}) // 控制属性的序列化顺序
public class User {

    @JsonProperty("user_name") // 设置属性的JSON名称
    private String name;

    private int age;

    @JsonIgnore // 忽略此属性的序列化和反序列化
    private String password;

    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "Asia/Shanghai") // 设置日期格式和时区
    private Date createdDate;

    @JsonProperty("user_email") // 设置属性的JSON名称
    private String email;

    @JsonInclude(JsonInclude.Include.NON_NULL) // 控制字段的序列化条件
    private String email;
    
    @JsonRawValue // 将字段值作为原始JSON字符串处理
    private String rawJson;
    
    private Map<String, Object> additionalProperties;
    
    @JsonAnyGetter
    public Map<String, Object> any() {
        return additionalProperties;
    }
    
    @JsonAnySetter
    public void set(String name, Object value) {
        if (additionalProperties == null) {
            additionalProperties = new HashMap<>();
        }
        additionalProperties.put(name, value);
    }

    // 其他构造函数、getter和setter省略
}

5. 序列化和反序列化

序列化对象为JSON字符串
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class UserController {

    @Autowired
    private ObjectMapper objectMapper;

    @GetMapping("/serialize")
    public String serialize() throws Exception {
        // 创建一个Java对象
        User user = new User();
        user.setName("张三");
        user.setAge(30);
        user.setPassword("123456");
        user.setCreatedDate(new Date());
        user.setEmail("zhangsan@example.com");

        // 序列化Java对象为JSON字符串
        String jsonString = objectMapper.writeValueAsString(user);
        return "序列化后的JSON字符串: " + jsonString;
    }
}
反序列化JSON字符串为对象
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class UserController {

    @Autowired
    private ObjectMapper objectMapper;

    @PostMapping("/deserialize")
    public User deserialize(@RequestBody String jsonString) throws Exception {
        // 反序列化JSON字符串为Java对象
        User user = objectMapper.readValue(jsonString, User.class);
        return user;
    }
}

6. 自定义序列化器和反序列化器

有时候默认的序列化和反序列化行为可能不满足需求,可以通过自定义序列化器和反序列化器来实现更复杂的功能。

自定义序列化器
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.SerializerProvider;

import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;

public class CustomDateSerializer extends JsonSerializer<Date> {
    private static final SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

    @Override
    public void serialize(Date date, JsonGenerator gen, SerializerProvider provider) throws IOException {
        String formattedDate = dateFormat.format(date);
        gen.writeString(formattedDate);
    }
}
自定义反序列化器
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.JsonDeserializer;

import java.io.IOException;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;

public class CustomDateDeserializer extends JsonDeserializer<Date> {
    private static final SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

    @Override
    public Date deserialize(JsonParser p, DeserializationContext ctxt) throws IOException {
        try {
            return dateFormat.parse(p.getValueAsString());
        } catch (ParseException e) {
            throw new RuntimeException(e);
        }
    }
}
使用自定义序列化器和反序列化器
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import lombok.Data;

import java.util.Date;

@Data
public class User {
    private String name;
    
    @JsonSerialize(using = CustomDateSerializer.class)
    @JsonDeserialize(using = CustomDateDeserializer.class)
    private Date registerDate;
}

7. 处理复杂数据类型

7.1 List序列化和反序列化
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;

import java.util.Arrays;
import java.util.List;

@RestController
public class UserController {

    @Autowired
    private ObjectMapper objectMapper;

    @GetMapping("/serialize-list")
    public String serializeList() throws Exception {
        // 创建一个Java对象列表
        List<User> users = Arrays.asList(
            new User("张三", 30, "123456", new Date(), "zhangsan@example.com"),
            new User("李四", 25, "654321", new Date(), "lisi@example.com")
        );

        // 序列化Java对象列表为JSON字符串
        String jsonString = objectMapper.writeValueAsString(users);
        return "序列化后的JSON字符串: " + jsonString;
    }

    @PostMapping("/deserialize-list")
    public List<User> deserializeList(@RequestBody String jsonString) throws Exception {
        // 反序列化JSON字符串为Java对象列表
        List<User> users = objectMapper.readValue(jsonString, objectMapper.getTypeFactory().constructCollectionType(List.class, User.class));
        return users;
    }
}
7.2 Map序列化和反序列化
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;

import java.util.HashMap;
import java.util.Map;

@RestController
public class UserController {

    @Autowired
    private ObjectMapper objectMapper;

    @GetMapping("/serialize-map")
    public String serializeMap() throws Exception {
        // 创建一个Map
        Map<String, Object> map = new HashMap<>();
        map.put("name", "张三");
        map.put("age", 30);
        map.put("email", "zhangsan@example.com");

        // 序列化Map为JSON字符串
        String jsonString = objectMapper.writeValueAsString(map);
        return "序列化后的JSON字符串: " + jsonString;
    }

    @PostMapping("/deserialize-map")
    public Map<String, Object> deserializeMap(@RequestBody String jsonString) throws Exception {
        // 反序列化JSON字符串为Map
        Map<String, Object> resultMap = objectMapper.readValue(jsonString, Map.class);
        return resultMap;
    }
}
7.3 枚举类型序列化和反序列化
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonProperty;

public enum Status {
    ACTIVE("active"),
    INACTIVE("inactive");

    private String value;

    Status(String value) {
        this.value = value;
    }

    @JsonCreator
    public static Status fromValue(@JsonProperty("value") String value) {
        for (Status status : values()) {
            if (status.getValue().equals(value)) {
                return status;
            }
        }
        throw new IllegalArgumentException("Unknown enum value: " + value);
    }

    public String getValue() {
        return value;
    }
}
7.3 使用枚举类型
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class UserController {

    @Autowired
    private ObjectMapper objectMapper;

    @GetMapping("/serialize-enum")
    public String serializeEnum() throws Exception {
        // 创建一个包含枚举类型的Java对象
        User user = new User();
        user.setStatus(Status.ACTIVE);

        // 序列化Java对象为JSON字符串
        String jsonString = objectMapper.writeValueAsString(user);
        return "序列化后的JSON字符串: " + jsonString;
    }

    @PostMapping("/deserialize-enum")
    public User deserializeEnum(@RequestBody String jsonString) throws Exception {
        // 反序列化JSON字符串为Java对象
        User user = objectMapper.readValue(jsonString, User.class);
        return user;
    }
}
7.4 处理嵌套对象

Jackson可以轻松处理嵌套对象的序列化和反序列化。

import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.Data;

@Data
public class Address {
    private String street;
    private String city;
    private String zipCode;
}

@Data
public class User {
    private String name;
    private Address address;
}

public class Main {
    public static void main(String[] args) throws Exception {
        ObjectMapper mapper = new ObjectMapper();
        
        // 创建一个嵌套对象
        Address address = new Address("123 Main St", "Springfield", "12345");
        User user = new User("张三", address);
        
        // 序列化嵌套对象为JSON字符串
        String jsonString = mapper.writeValueAsString(user);
        System.out.println("序列化后的JSON字符串: " + jsonString);
        
        // 反序列化JSON字符串为嵌套对象
        User deserializedUser = mapper.readValue(jsonString, User.class);
        System.out.println("反序列化后的嵌套对象: " + deserializedUser);
    }
}
7.5 处理循环引用

在处理包含循环引用的对象时,可以使用@JsonIdentityInfo注解来避免无限递归。

import com.fasterxml.jackson.annotation.JsonIdentityInfo;
import com.fasterxml.jackson.annotation.ObjectIdGenerators;
import lombok.Data;

@Data
@JsonIdentityInfo(generator = ObjectIdGenerators.PropertyGenerator.class, property = "id")
public class User {
    private Long id;
    private String name;
    private User friend;
}

public class Main {
    public static void main(String[] args) throws Exception {
        ObjectMapper mapper = new ObjectMapper();
        
        // 创建循环引用对象
        User user1 = new User(1L, "张三", null);
        User user2 = new User(2L, "李四", user1);
        user1.setFriend(user2);
        
        // 序列化循环引用对象为JSON字符串
        String jsonString = mapper.writeValueAsString(user1);
        System.out.println("序列化后的JSON字符串: " + jsonString);
        
        // 反序列化JSON字符串为循环引用对象
        User deserializedUser = mapper.readValue(jsonString, User.class);
        System.out.println("反序列化后的循环引用对象: " + deserializedUser);
    }
}
7.6 处理多态类型

Jackson可以通过@JsonTypeInfo@JsonSubTypes注解来处理多态类型。

import com.fasterxml.jackson.annotation.JsonSubTypes;
import com.fasterxml.jackson.annotation.JsonTypeInfo;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.Data;

@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "type")
@JsonSubTypes({
    @JsonSubTypes.Type(value = Dog.class, name = "dog"),
    @JsonSubTypes.Type(value = Cat.class, name = "cat")
})
interface Animal {}

@Data
class Dog implements Animal {
    private String breed;
}

@Data
class Cat implements Animal {
    private String color;
}

public class Main {
    public static void main(String[] args) throws Exception {
        ObjectMapper mapper = new ObjectMapper();
        
        // 创建多态对象
        Animal dog = new Dog("German Shepherd");
        Animal cat = new Cat("Black");
        
        // 序列化多态对象为JSON字符串
        String jsonStringDog = mapper.writeValueAsString(dog);
        String jsonStringCat = mapper.writeValueAsString(cat);
        System.out.println("序列化后的JSON字符串 (Dog): " + jsonStringDog);
        System.out.println("序列化后的JSON字符串 (Cat): " + jsonStringCat);
        
        // 反序列化JSON字符串为多态对象
        Animal deserializedDog = mapper.readValue(jsonStringDog, Animal.class);
        Animal deserializedCat = mapper.readValue(jsonStringCat, Animal.class);
        System.out.println("反序列化后的多态对象 (Dog): " + deserializedDog);
        System.out.println("反序列化后的多态对象 (Cat): " + deserializedCat);
    }
}
7.7 处理异常

在处理JSON数据时,可能会遇到各种异常。可以通过捕获这些异常来处理错误情况。

import com.fasterxml.jackson.databind.JsonMappingException;
import com.fasterxml.jackson.databind.ObjectMapper;

public class Main {
    public static void main(String[] args) {
        ObjectMapper mapper = new ObjectMapper();
        
        // 错误的JSON字符串
        String jsonString = "{\"name\": \"张三\", \"age\": \"not a number\"}";
        
        try {
            // 尝试反序列化JSON字符串为Java对象
            Person person = mapper.readValue(jsonString, Person.class);
            System.out.println("反序列化后的Java对象: " + person);
        } catch (JsonMappingException e) {
            System.out.println("JSON映射异常: " + e.getMessage());
        } catch (Exception e) {
            System.out.println("其他异常: " + e.getMessage());
        }
    }
}

通过本文的介绍,你应该对Spring Boot下Jackson的各种使用方法有了全面的了解。从基础配置到高级功能,Jackson提供了丰富的API和灵活的配置选项,使得开发者可以根据具体需求进行定制。希望本文能帮助你在项目开发中更加高效地利用Jackson进行JSON数据处理。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值