Spring Boot框架中使用Jackson的处理总结

本文详细介绍了在Spring Boot框架中使用Jackson进行JSON序列化和反序列化的处理,包括统一序列化时间格式、全局配置、各种配置选项以及Jackson常见注解的使用示例。通过注解和全局配置,可以实现时间字段的格式化,同时探讨了Jackson在Spring Boot中的配置选项,如date-format、time-zone、locale等。此外,文章还展示了Jackson常用注解如@JsonAnyGetter、@JsonGetter、@JsonRootName等的使用方法,帮助开发者更好地理解和应用Jackson框架。
摘要由CSDN通过智能技术生成

1.前言

通常我们在使用Spring Boot框架时,如果没有特别指定接口的序列化类型,则会使用Spring Boot框架默认集成的Jackson框架进行处理,通过Jackson框架将服务端响应的数据序列化成JSON格式的数据。

本文主要针对在Spring Boot框架中使用Jackson进行处理的经验进行总结,同时也结合在实际开发场景中碰到的问题以及解决方案进行陈述。

本文涉及到的源码地址:https://gitee.com/dt_research_institute/code-in-action

PS:目前市面上针对JSON序列化的框架很多,比较出名的就是JacksonGsonFastJson。如果开发者对序列化框架没有特别的要求的情况下,个人建议是直接使用Spring Boot框架默认集成的Jackson,没有必要进行更换。

2.统一序列化时间格式

在我们的接口中,针对时间类型的字段序列化是最常见的需求之一,一般前后端开发人员会针对时间字段统一进行约束,这样有助于在编码开发时,统一编码规范。

在Spring Boot框架中,如果使用Jackson处理框架,并且没有任何配置的情况下,Jackson针对不同时间类型字段,序列化的格式也会不尽相同。

先来看一个简单示例,User.java实体类编码如下:

public class User {
   

    private String name;

    private Integer age;

    private LocalDateTime birthday;

    private Date studyDate;

    private LocalDate workDate;
    
    private Calendar firstWorkDate;
    
    public static User buildOne(){
   
        User user=new User();
        LocalDateTime now=LocalDateTime.now();
        user.setWorkDate(now.plusYears(25).toLocalDate());
        user.setStudyDate(Date.from(now.plusYears(5).atZone(ZoneId.systemDefault()).toInstant()));
        user.setName("姓名-"+RandomUtil.randomString(5));
        user.setAge(RandomUtil.randomInt(0,100));
        user.setBirthday(now);
        user.setFirstWorkDate(Calendar.getInstance());
        return user;
    }
    
    //getter and setter...
}

接口代码层也很简单,返回一个User的实体对象即可,代码如下:

@RestController
public class UserApplication {
   


    @GetMapping("/queryOne")
    public ResponseEntity<User> queryOne(){
   
        return ResponseEntity.ok(User.buildOne());
    }
}

如果我们对框架代码没有任何的配置,此时我们通过调用接口/queryOne,拿到的返回结果数据如下图:

image-20210312085839202

Jackson序列化框架针对四个不同的时间类型字段,序列化处理的操作是不同的,如果我们对时间字段有格式化的要求时,我们应该如何处理呢?

2.1 通过@JsonFormat注解

最直接也是最简单的一种方式,是我们通过使用Jackson提供的@JsonFormat注解,对需要格式化处理的时间字段进行标注,在@JsonFormat注解中写上我们的时间格式化字符,User.java代码如下:

public class User {
   

    private String name;

    private Integer age;

    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
    private LocalDateTime birthday;

    private Date studyDate;

    private LocalDate workDate;

    private Calendar firstWorkDate;
    //getter and setter...
}

此时,我们再通过调用接口,拿到的返回结果如下图:

image-20210312090417967

通过对birthday字段标注@JsonFormat注解,最终Jackson框架会将该字段序列化为我们标注的格式类型。

2.2 配置全局application.yml

通过@JsonFormat注解的方式虽然能解决问题,但是我们在实际的开发当中,涉及到的时间字段会非常多,如果全部都用注解的方式对项目中的时间字段进行标注,那开发的工作量也会很大,并且多团队一起协同编码时,难免会存在遗漏的情况,因此,@JsonFormat注解只适用于针对特定的接口,特定的场景下,对序列化响应的时间字段进行约束,而在全局的角度来看,开发者应该考虑通过在application.yml配置文件中进行全局配置

针对Spring Boot框架中Jackson的全局配置,我们在application.yml进行配置时,IDEA等编辑器会给出相应的提示,包含的属性如下图:

image-20210312092003557

开发者可以通过org.springframework.boot.autoconfigure.jackson.JacksonProperties.java查看所有配置的源码信息

配置属性 说明
date-format 日期字段格式化,例如:yyyy-MM-dd HH:mm:ss

针对日期字段的格式化处理,我们只需要使用date-format属性进行配置即可,application.yml配置如下:

spring:
  jackson:
    date-format: yyyy-MM-dd HH:mm:ss

当然,如果有必要的话,还需要配置time-zone时区属性,不过该属性不配置的情况下,Jackson会使用系统默认时区。

我们从Spring Boot的源码中可以看到对Jackson的时间处理逻辑,JacksonAutoConfiguration.java中部分代码如下:

private void configureDateFormat(Jackson2ObjectMapperBuilder builder) {
   
    // We support a fully qualified class name extending DateFormat or a date
    // pattern string value
    String dateFormat = this.jacksonProperties.getDateFormat();
    if (dateFormat != null) {
   
        try {
   
            Class<?> dateFormatClass = ClassUtils.forName(dateFormat, null);
            builder.dateFormat((DateFormat) BeanUtils.instantiateClass(dateFormatClass));
        }
        catch (ClassNotFoundException ex) {
   
            SimpleDateFormat simpleDateFormat = new SimpleDateFormat(dateFormat);
            // Since Jackson 2.6.3 we always need to set a TimeZone (see
            // gh-4170). If none in our properties fallback to the Jackson's
            // default
            TimeZone timeZone = this.jacksonProperties.getTimeZone();
            if (timeZone == null) {
   
                timeZone = new ObjectMapper().getSerializationConfig().getTimeZone();
            }
            simpleDateFormat.setTimeZone(timeZone);
            builder.dateFormat(simpleDateFormat);
        }
    }
}

从上面的代码中,我们可以看到的处理逻辑:

  • 从yml配置文件中拿到dateFormat属性字段
  • 首先通过ClassUtils.forName方法来判断开发者配置的是否是格式化类,如果配置的是格式化类,则直接配置dateFormat属性
  • 类找不到的情况下,捕获ClassNotFoundException异常,默认使用JDK自带的SimpleDateFormat类进行初始化

最终,我们在application.yml配置文件中配置了全局的Jackson针对日期处理的格式化信息,此时我们再看/queryOne接口响应的内容是什么情况呢?如下图:

image-20210312094014588

从图中我们可以发现,除了LocalDate类型的字段,包含时分秒类型的日期类型:LocalDateTimeDateCalendar全部按照我们的要求将日期序列化成了yyyy-MM-dd HH:mm:ss格式,达到了我们的要求。

3.Jackson在Spring Boot框架中的配置选项

在上面的时间字段序列化处理,我们已经知道了如何配置,那么在Spring Boot的框架中,针对Jackson的各个配置项主要包含哪些呢?我们通过IDEA的提示可以看到,配置如下图:

image-20210312092003557

在上面的12个属性中,每个属性的配置都会对Jackson产生不同的效果,接下来,我们逐一详解每个属性配置的作用

3.1 date-format日期格式化

date-format在前面我们已经知道了该属性的作用,主要是针对日期字段的格式化

3.2 time-zone时区

time-zone字段也是和日期字段类型,使用不同的时区,最终日期类型字段响应的结果会不一样

时区的表示方法有两种:

  • 指定时区的名称,例如:Asia/Shanghai,America/Los_Angeles
  • 通过格林威治平时GMT针对时分秒做+或者-自定义操作

通过指定时区的名称,假设我们指定当前的项目是America/Los_Angeles,那么接口响应的数据是什么效果呢?

PS:时区名称如果不是很清楚的话,一般在Linux服务器的/usr/share/zoneinfo目录可以进行查看,如下图:

image-20210312131802521

application.yml:

spring:
  jackson:
    date-format: yyyy-MM-dd HH:mm:ss
    time-zone: America/Los_Angeles

效果图如下:

image-20210312130547087

我们在结合代码来分析:

//User.java
public static User buildOne(){
   
    User user=new User();
    LocalDateTime now=LocalDateTime.now();
    user.setWorkDate(now.plusYears(25).toLocalDate());
    user.setStudyDate(Date.from(now.plusYears(5).atZone(ZoneId.systemDefault()).toInstant()));
    user.setName("姓名-"+RandomUtil.randomString(5));
    user.setAge(RandomUtil.randomInt(0,100));
    user.setBirthday(now);
    user.setFirstWorkDate(Calendar.getInstance());
    return user;
}

由于洛杉矶时区与上海时区相差16个小时,因此,Jackson框架针对日期的序列化时,分别做了不同类型的处理,但我们也能看出差别

  • LocalDateTimeLocalDate类型的字段,Jackson的时区设置不会对该字段产生影响(因为这两个日期类型自带时区属性)
  • DateCalendar类型的字段受Jackson序列化框架的时区设置影响

另外一种方式是通过格林威治平时(GMT)做加减法,主要有两种格式支持:

  • GMT+HHMM或者GMT-HHMM或者GMT+H:其中HH代表的是小时数,MM代表的是分钟数,取值范围是0-9,例如我们常见的GMT+8代表东八区,也就是北京时间
  • GMT+HH:MM或者GMT-HH:MM:其中HH代表的是小时数,MM代表的是分钟数,取值范围是0-9,和上面意思差不多

可以自己写测试代码进行测试,示例如下:

public class TimeTest {
   
    public static void main(String[] args) {
   
        LocalDateTime localDateTime=LocalDateTime.now();
        DateTimeFormatter dateTimeFormatter=DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
        System.out.println(localDateTime.format(dateTimeFormatter));
        System.out.println(LocalDateTime.now(ZoneId.of("GMT+0901")).format(dateTimeFormatter));
        System.out.println(LocalDateTime.now(ZoneId.of("GMT+09:01")).format(dateTimeFormatter));
    }
}

3.3 locale本地化

JSON序列化时Locale的变量设置

3.4 visibility访问级别

Jackson支持从私有字段中读取值,但是默认情况下不这样做,如果我们的项目中存在不同的序列化反序列化需求,那么我们可以在配置文件中对visibility进行配置

我们将上面User.java代码中的name属性的get方法修饰符从public变更为private,其他字段保持不变

代码如下:

public class User {
   

    private String name;

    private Integer age;
    private Date nowDate;

    private LocalDateTime birthday;

    private Date studyDate;

    private LocalDate workDate;

    private Calendar firstWorkDate;

    //getter方法修饰符从public修改为private
    private String getName() {
   
        return name;
    }
    //other setter and getter
}

此时,我们通过调用/queryOne接口响应结果如下:

image-20210314191124147

从结果中我们可以看到,由于我们将name属性的getter方法设置为了private,因此jackson在序列化时,没有拿到该字段

此时,我们再修改application.yml的配

  • 3
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值