SpringBoot中处理日期的两种方式(消息转换器)

在Spring Boot中,我们通常会使用Jackson来序列化和反序列化Java对象到JSON。在进行日期序列化时,我们需要指定日期格式,否则Jackson会使用默认格式,这可能不是我们想要的。要指定日期格式,有两种方式:

如果没有处理按照默认的结果如下图: 所以我们需要通过一些手段来对日期进行处理.这里通过两个方式来解决.

方式一: 使用注解 (不推荐)

我们可以在实体类日期属性上添加@JsonFormat(),并且通过参数pattern,来格式化我们的想要的格式实例如下:

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

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

此时前端就会按照我们设置的格式显示

在这里插入图片描述

对于上面的方法,需要我们对每一个向前端显示的日期都加上@JSONFormat这个注解,所以十分的麻烦,于是就有了方式二.通过全局异常处理.

方式二 自定义消息转换器

首先介绍Jackson包中的ObjectMapper.

ObjectMapper是Jackson库中的一个类,它的主要作用是:

  1. 将Java对象序列化为JSON/XML等格式;
  2. 将JSON/XML等格式的数据反序列化为Java对象。

所以,它是实现对象与JSON/XML互相转换的关键。

那么我们可以在这个类中做一点文章,

  • (1)在构造器中自定义日期转换的格式. ----也就相当于改变他的属性的初始化值.

  • (2)通过配置让SpringMVC在调用的时候不再调用Jackson自定义的ObjectMapper,使用我们自定的格式

下面我们就通过这两步实现.

第一步: 继承ObjectMapper,重写构造方法,自定义序列化方式

import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.module.SimpleModule;
import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateDeserializer;
import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateTimeDeserializer;
import com.fasterxml.jackson.datatype.jsr310.deser.LocalTimeDeserializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateSerializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateTimeSerializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalTimeSerializer;

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;

import static com.fasterxml.jackson.databind.DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES;

/**
 * 对象映射器:基于jackson将Java对象转为json,或者将json转为Java对象
 * 将JSON解析为Java对象的过程称为 [从JSON反序列化Java对象]
 * 从Java对象生成JSON的过程称为 [序列化Java对象到JSON]
 */
public class JacksonObjectMapper extends ObjectMapper {

    public static final String DEFAULT_DATE_FORMAT = "yyyy-MM-dd";
    //public static final String DEFAULT_DATE_TIME_FORMAT = "yyyy-MM-dd HH:mm:ss";
    public static final String DEFAULT_DATE_TIME_FORMAT = "yyyy-MM-dd HH:mm:ss";
    public static final String DEFAULT_TIME_FORMAT = "HH:mm:ss";

    public JacksonObjectMapper() {
        super();
        //收到未知属性时不报异常
        this.configure(FAIL_ON_UNKNOWN_PROPERTIES, false);

        //反序列化时,属性不存在的兼容处理
        this.getDeserializationConfig().withoutFeatures(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);

        SimpleModule simpleModule = new SimpleModule()
                .addDeserializer(LocalDateTime.class, new LocalDateTimeDeserializer(DateTimeFormatter.ofPattern(DEFAULT_DATE_TIME_FORMAT)))
                .addDeserializer(LocalDate.class, new LocalDateDeserializer(DateTimeFormatter.ofPattern(DEFAULT_DATE_FORMAT)))
                .addDeserializer(LocalTime.class, new LocalTimeDeserializer(DateTimeFormatter.ofPattern(DEFAULT_TIME_FORMAT)))
                .addSerializer(LocalDateTime.class, new LocalDateTimeSerializer(DateTimeFormatter.ofPattern(DEFAULT_DATE_TIME_FORMAT)))
                .addSerializer(LocalDate.class, new LocalDateSerializer(DateTimeFormatter.ofPattern(DEFAULT_DATE_FORMAT)))
                .addSerializer(LocalTime.class, new LocalTimeSerializer(DateTimeFormatter.ofPattern(DEFAULT_TIME_FORMAT)));
        //注册功能模块 例如,可以添加自定义序列化器和反序列化器
        this.registerModule(simpleModule);
    }
}

第二步: 让Spring使用我们的自定的消息转换器

这里我们就要想了,我们应该怎么处理呢?在哪配置?配置文件? 配置类?

首先我们可以想到,系统中少不了的是拦截器,而拦截器的是不是有一个配置拦截规则的配置类.那么我们能不能再这里配置.

binggo,就是这里. 我们在配置拦截器的配置类的时候我们会发现, WebMvcConfigurationSupport 这个类有很多方法,

有我们常用的protected void addInterceptors(InterceptorRegistry registry) { ... } 配置拦截规则

public void addResourceHandlers(ResourceHandlerRegistry registry) {... } 配置资源处理

等等有很多配置方法.而我们的消息转换器也在其中

protected void extendMessageConverters(List<HttpMessageConverter<?>> converters) {...}

通过在这个方法中配置相关信息,即可改变Spring默认指定的规则,而使用我们自己定义的规则(组件)

代码如下:

@Override
protected void extendMessageConverters(List<HttpMessageConverter<?>> converters) {
    log.info("扩展消息转换器...");
    //创建一个消息转换器对象,注意不要导错包是Jackson2Http
    MappingJackson2HttpMessageConverter converter =  new MappingJackson2HttpMessageConverter();
    //需要为消息转换器设置一个对象转换器,对象转换器可以将Java对象序列化为json数据
    converter.setObjectMapper(new JacksonObjectMapper());
    //将自己的消息转化器加入容器中
    converters.add(0, converter);
}
  1. 创建了一个MappingJackson2HttpMessageConverter,这是Spring MVC集成Jackson的消息转换器,可以将Java对象序列化/反序列化为JSON。
  2. 为消息转换器指定使用我们的JacksonObjectMapper, 用来将Java对象序列化/反序列化为JSON。
  3. 将刚才创建的MappingJackson2HttpMessageConverter对象加入到消息转换器列表converters中,并且加入到第一个位置,让其优先使用

由于我们重写了extendMessageConverters()方法,Spring MVC会调用这个方法并使用我们添加的消息转换器。所以,我们添加的MappingJackson2HttpMessageConverter会生效,并使用我们自定义的JacksonObjectMapper(),用来处理对象与JSON之间的序列化和反序列化。
因为我们的消息转换器是第一个消息转换器,如果客户端要求返回JSON数据Spring MVC会选择我们的这个消息转换器进行对象序列化。

从而实现了对系统所有的日期按照我们要求的格式进行序列化.

此时前端数据也就是我们设置的格式.不在是Jackson默认的格式.


既然提到了日期,与之类似的还有一个对敏感信息的处理:
我们在返回前端数据的时候可能会因为实体类的设计,或者不想让前端能够看到该数据,此时就需要通过一些手段对数据进行一些处理, 还是两种方式.

  1. 在返回之前对数据的值进行替换, 调用set方法设置为 垃圾信息, 比如 setPassword(“******”)
  2. 是在实体类中使用Jackson提供的 @JsonIgnore 注解也可以解决,作用是忽略字段的序列化和反序列化。

做一个记录以后好直接用

喜欢钻牛角尖很烦,但是知道了原因后很释怀.加油


  • 5
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
您好,这是一个 Java 代码片段,可以通过扩展 Jackson 库的 SimpleModule 类来实现全局 Long 类型转换为 String 类型,同时排除 IPage 类属性不转换。具体实现如下: ```java import com.baomidou.mybatisplus.core.metadata.IPage; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.fasterxml.jackson.core.JsonGenerator; import com.fasterxml.jackson.databind.JsonSerializer; import com.fasterxml.jackson.databind.SerializerProvider; import com.fasterxml.jackson.databind.module.SimpleModule; import java.io.IOException; public class LongToStringModule extends SimpleModule { public LongToStringModule() { addSerializer(Long.class, new LongToStringSerializer()); addSerializer(Long.TYPE, new LongToStringSerializer()); } private static class LongToStringSerializer extends JsonSerializer<Long> { @Override public void serialize(Long value, JsonGenerator gen, SerializerProvider serializers) throws IOException { gen.writeString(String.valueOf(value)); } } @Override public void setupModule(SetupContext context) { super.setupModule(context); context.addSerializers(new LongToStringSerializer()); context.addBeanSerializerModifier(new LongToStringBeanSerializerModifier()); } private static class LongToStringBeanSerializerModifier extends SimpleBeanPropertyFilter { @Override public void serializeAsField(Object pojo, JsonGenerator gen, SerializerProvider provider, PropertyWriter writer) throws Exception { if (pojo instanceof IPage && writer.getName().equals("records")) { // 排除 IPage 类的 records 属性 return; } Object value = writer.get(pojo); if (value instanceof Long) { gen.writeStringField(writer.getName(), String.valueOf(value)); } else { super.serializeAsField(pojo, gen, provider, writer); } } } } ``` 上述代码,我们定义了一个 LongToStringModule 类,并继承了 Jackson 库的 SimpleModule 类。在构造方法,我们添加了一个 LongToStringSerializer 类型的序列化器,用于将 Long 类型的数据转换为 String 类型。在 setupModule 方法,我们添加了 LongToStringSerializer 序列化器和 LongToStringBeanSerializerModifier 类型的序列化器修改器。其,LongToStringBeanSerializerModifier 类型的序列化器修改器用于对 IPage 类的 records 属性进行排除。最后,您可以在项目启动时将 LongToStringModule 注册到 ObjectMapper 即可全局生效。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

yfs1024

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值