spring boot全局日期格式化配置

简介: spring boot全局日期格式化配置

前言


前端请求的日期格式的参数,你还在挨个配置@DateTimeFormat注解进行接受吗?

后端返回给前端的json响应中的时间格式,你还在挨个用@JsonFormat配置时间格式化吗?

本文教大家如何在spring boot下进行全局的日期格式化配置。


一、全局属性配置


#json格式化全局配置
spring.jackson.time-zone=GMT+8
spring.jackson.date-format=yyyy-MM-dd HH:mm:ss
spring.jackson.default-property-inclusion=NON_NULL
spring.mvc.date-format=yyyy-MM-dd HH:mm:ss

说明:

spring.jackson.time-zone 指定将响应结果进行json序列化时采用的默认时区

spring.jackson.date-format 指定json序列化时 时间格式化采用的默认格式

spring.jackson.default-property-inclusion 指定默认包含的熟悉,NON_NULL表示只序列化非空属性

spring.mvc.date-format

指定前端请求参数中日期格式参数和后端时间类型字段绑定时默认的格式,相当于@DateTimeFormat的全局配置


注意⚠️:

这里的spring.jackson.time-zone指定的时区一定要和mysql数据库连接中时区保持一致。


二、自定义全局格式化配置


经过上面的全局配置,已经能满足大部分场景,个别特殊的时间格式化的场景,我们可以单独采用@JsonFormat和@DateTimeFormat的实体中的日期字段进行配置。


如果用户希望自定义控制json格式化,可参考如下配置:


1、自定义格式化类CustomDateFormat

/**
 * @Description JSON形式的全局时间类型转换器
 * 自定义的格式化类一定要继承SimpleDateFormat
 */
public class CustomDateFormat extends SimpleDateFormat {
    private static final long serialVersionUID = -3201781773655300201L;
    public String defaultDateFormat;
    public String defaultTimeZone;
    public CustomDateFormat(String pattern,String defaultTimeZone){
        this.defaultDateFormat = pattern;
        this.defaultTimeZone = defaultTimeZone;
    }
    /**
     * 只要覆盖parse(String)这个方法即可
     */
    @Override
    public Date parse(String dateStr, ParsePosition pos) {
        return getDate(dateStr, pos);
    }
    /**
     * 前端传的日期字符串转Date
     * @param dateStr
     * @return
     */
    @Override
    public Date parse(String dateStr) {
        ParsePosition pos = new ParsePosition(0);
        return getDate(dateStr, pos);
    }
    //可以根据前端传递的时间格式自动匹配格式化
    private Date getDate(String dateStr, ParsePosition pos) {
        SimpleDateFormat sdf = null;
        if (StringUtils.isBlank(dateStr)) {
            return null;
        } else if (dateStr.matches("^\\d{4}-\\d{1,2}$")) {
            sdf = new SimpleDateFormat("yyyy-MM");
            return sdf.parse(dateStr, pos);
        } else if (dateStr.matches("^\\d{4}-\\d{1,2}-\\d{1,2}$")) {
            sdf = new SimpleDateFormat("yyyy-MM-dd");
            return sdf.parse(dateStr, pos);
        } else if (dateStr.matches("^\\d{4}-\\d{1,2}-\\d{1,2} {1}\\d{1,2}:\\d{1,2}$")) {
            sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm");
            return sdf.parse(dateStr, pos);
        } else if (dateStr.matches("^\\d{4}-\\d{1,2}-\\d{1,2} {1}\\d{1,2}:\\d{1,2}:\\d{1,2}$")) {
            sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
            return sdf.parse(dateStr, pos);
        } else if (dateStr.length() == 23) {
            sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");
            return sdf.parse(dateStr, pos);
        }
        return super.parse(dateStr, pos);
    }
    /**
     * 后端返回的日期格式化指定字符串
     * @param date
     * @param toAppendTo
     * @param fieldPosition
     * @return
     */
    @Override
    public StringBuffer format(Date date, StringBuffer toAppendTo, FieldPosition fieldPosition){
        return new StringBuffer(DateFormatUtils.format(date, defaultDateFormat, TimeZone.getTimeZone(defaultTimeZone)));
    }
}


2、自定义表单日期转化器

/**
 * @Description 表单形式的全局时间类型转换器
 */
@Configuration
public class DateConverter implements Converter<String, Date> {
    private static final List<String> FORMARTS = new ArrayList<String>(4);
    static{
        FORMARTS.add("yyyy-MM");
        FORMARTS.add("yyyy-MM-dd");
        FORMARTS.add("yyyy-MM-dd HH:mm");
        FORMARTS.add("yyyy-MM-dd HH:mm:ss");
    }
    //可以根据前端传递的时间格式自动匹配格式化
    @Override
    public Date convert(String source) {
        String value = source.trim();
        if ("".equals(value)) {
            return null;
        }
        if(source.matches("^\\d{4}-\\d{1,2}$")){
            return parseDate(source, FORMARTS.get(0));
        }else if(source.matches("^\\d{4}-\\d{1,2}-\\d{1,2}$")){
            return parseDate(source, FORMARTS.get(1));
        }else if(source.matches("^\\d{4}-\\d{1,2}-\\d{1,2} {1}\\d{1,2}:\\d{1,2}$")){
            return parseDate(source, FORMARTS.get(2));
        }else if(source.matches("^\\d{4}-\\d{1,2}-\\d{1,2} {1}\\d{1,2}:\\d{1,2}:\\d{1,2}$")){
            return parseDate(source, FORMARTS.get(3));
        }else {
            throw new IllegalArgumentException("Invalid boolean value '" + source + "'");
        }
    }
    /**
     * 功能描述:格式化日期
     * @param dateStr   String 字符型日期
     * @param format    String 格式
     * @return Date 日期
     */
    public  Date parseDate(String dateStr, String format) {
        Date date=null;
        try {
            DateFormat dateFormat = new SimpleDateFormat(format);
            date = (Date) dateFormat.parse(dateStr);
        } catch (Exception e) {
        }
        return date;
    }
}

3、注册自定义的日期转化器

@Slf4j
@Configuration
public class WebMvcConfigurer implements WebMvcConfigurer {
    private static final DateTimeFormatter DATE_TIME_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
    private static final DateTimeFormatter DATE_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd");
    private static final DateTimeFormatter TIME_FORMATTER = DateTimeFormatter.ofPattern("HH:mm:ss");
    @Value("${spring.jackson.date-format:yyyy-MM-dd HH:mm:ss}")
    private String defaultDateFormat;
    @Value("${spring.jackson.time-zone:UTC}")
    private String defaultTimeZone;
    /**
     * JSON全局日期转换器
     */
    public MappingJackson2HttpMessageConverter getMappingJackson2HttpMessageConverter() {
        MappingJackson2HttpMessageConverter mappingJackson2HttpMessageConverter = new MappingJackson2HttpMessageConverter();
        //设置日期格式
        ObjectMapper objectMapper = new ObjectMapper();
        objectMapper.setDateFormat(new CustomDateFormat(defaultDateFormat,defaultTimeZone));
        //支持LocalDateTime、LocalDate、LocalTime的序列化
        JavaTimeModule javaTimeModule = new JavaTimeModule();
        javaTimeModule.addSerializer(LocalDateTime.class, new LocalDateTimeSerializer(DATE_TIME_FORMATTER));
        javaTimeModule.addSerializer(LocalDate.class, new LocalDateSerializer(DATE_FORMATTER));
        javaTimeModule.addSerializer(LocalTime.class, new LocalTimeSerializer(TIME_FORMATTER));
        objectMapper.registerModule(javaTimeModule);
        // 设置时区
        objectMapper.setTimeZone(TimeZone.getTimeZone(defaultTimeZone));
        mappingJackson2HttpMessageConverter.setObjectMapper(objectMapper);
        //忽略不能识别的字段
        objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
        //忽略非空字段
        objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
        //设置中文编码格式
        List<MediaType> list = new ArrayList<MediaType>();
        list.add(MediaType.APPLICATION_JSON);
        mappingJackson2HttpMessageConverter.setSupportedMediaTypes(list);
        return mappingJackson2HttpMessageConverter;
    }
    /**
     *  注册转化器
     *  注意:List<HttpMessageConverter>的转化器是按顺序生效,前面的执行了,后面的就不会执行了
     * @param converters
     */
    @Override
    public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
       //将fastJson添加到视图消息转换器列表内
        converters.add(0,getMappingJackson2HttpMessageConverter());
    }
   /**
    * 表单全局日期转换器
    */
    @Bean
    public ConversionService getConversionService(DateConverter dateConverter){
        ConversionServiceFactoryBean factoryBean = new ConversionServiceFactoryBean();
        Set<Converter> converters = new HashSet<>();
        converters.add(dateConverter);
        factoryBean.setConverters(converters);
        return factoryBean.getObject();
    }
 }


这样采用自定义的方式,主要完成了自动根据时间参数的格式去匹配时间格式化完成Date类型的参数绑定。


四、补充


前端传递到后端的时间,一般会带有时区,这就导致传递的是CST时区,保存到数据库自动转化成了UTC时区。出现传入时间和保存到数据库的时间不一致的问题。

注意:

保证数据库连接的时区也采用GMT+8能解决大部分时间不一致的问题。


解决方案如下:

方案一: (经验证,解决我的问题)

将以下行添加到 application.properties 文件:

spring.jackson.deserialization.ADJUST_DATES_TO_CONTEXT_TIME_ZONE = false


原理主要是不将前端的时区传到后端。


方式二:(参考,待验证)

在 Application.java(带有 main 方法的类)中设置全局时区:

@PostConstruct
void started() {
    TimeZone.setDefault(TimeZone.getTimeZone("Etc/UTC"));
}


总结


本文主要介绍了spring boot项目中,如何进行全局日期格式化的配置。

并更进一步介绍了通过自定义格式化类,实现自动根据时间参数的格式去匹配时间格式化完成Date类型的参数绑定,

帮助提高日常开发效率。

目录
相关文章
|
1月前
|
负载均衡 监控 Java
Spring Cloud Gateway 全解析:路由配置、断言规则与过滤器实战指南
本文详细介绍了 Spring Cloud Gateway 的核心功能与实践配置。首先讲解了网关模块的创建流程,包括依赖引入(gateway、nacos 服务发现、负载均衡)、端口与服务发现配置,以及路由规则的设置(需注意路径前缀重复与优先级 order)。接着深入解析路由断言,涵盖 After、Before、Path 等 12 种内置断言的参数、作用及配置示例,并说明了自定义断言的实现方法。随后重点阐述过滤器机制,区分路由过滤器(如 AddRequestHeader、RewritePath、RequestRateLimiter 等)与全局过滤器的作用范围与配置方式,提
Spring Cloud Gateway 全解析:路由配置、断言规则与过滤器实战指南
|
27天前
|
Java 关系型数据库 MySQL
Spring Boot自动配置:魔法背后的秘密
Spring Boot 自动配置揭秘:只需简单配置即可启动项目,背后依赖“约定大于配置”与条件化装配。核心在于 `@EnableAutoConfiguration` 注解与 `@Conditional` 系列条件判断,通过 `spring.factories` 或 `AutoConfiguration.imports` 加载配置类,实现按需自动装配 Bean。
|
28天前
|
人工智能 Java 开发者
【Spring】原理解析:Spring Boot 自动配置
Spring Boot通过“约定优于配置”的设计理念,自动检测项目依赖并根据这些依赖自动装配相应的Bean,从而解放开发者从繁琐的配置工作中解脱出来,专注于业务逻辑实现。
|
3月前
|
Java Spring
Spring Boot配置的优先级?
在Spring Boot项目中,配置可通过配置文件和外部配置实现。支持的配置文件包括application.properties、application.yml和application.yaml,优先级依次降低。外部配置常用方式有Java系统属性(如-Dserver.port=9001)和命令行参数(如--server.port=10010),其中命令行参数优先级高于系统属性。整体优先级顺序为:命令行参数 &gt; Java系统属性 &gt; application.properties &gt; application.yml &gt; application.yaml。
606 0
|
21天前
|
缓存 Java 应用服务中间件
Spring Boot配置优化:Tomcat+数据库+缓存+日志,全场景教程
本文详解Spring Boot十大核心配置优化技巧,涵盖Tomcat连接池、数据库连接池、Jackson时区、日志管理、缓存策略、异步线程池等关键配置,结合代码示例与通俗解释,助你轻松掌握高并发场景下的性能调优方法,适用于实际项目落地。
223 4
|
28天前
|
传感器 Java 数据库
探索Spring Boot的@Conditional注解的上下文配置
Spring Boot 的 `@Conditional` 注解可根据不同条件动态控制 Bean 的加载,提升应用的灵活性与可配置性。本文深入解析其用法与优势,并结合实例展示如何通过自定义条件类实现环境适配的智能配置。
探索Spring Boot的@Conditional注解的上下文配置
|
6月前
|
安全 Java API
深入解析 Spring Security 配置中的 CSRF 启用与 requestMatchers 报错问题
本文深入解析了Spring Security配置中CSRF启用与`requestMatchers`报错的常见问题。针对CSRF,指出默认已启用,无需调用`enable()`,只需移除`disable()`即可恢复。对于`requestMatchers`多路径匹配报错,分析了Spring Security 6.x中方法签名的变化,并提供了三种解决方案:分次调用、自定义匹配器及降级使用`antMatchers()`。最后提醒开发者关注版本兼容性,确保升级平稳过渡。
709 2
|
2月前
|
安全 算法 Java
在Spring Boot中应用Jasypt以加密配置信息。
通过以上步骤,可以在Spring Boot应用中有效地利用Jasypt对配置信息进行加密,这样即使配置文件被泄露,其中的敏感信息也不会直接暴露给攻击者。这是一种在不牺牲操作复杂度的情况下提升应用安全性的简便方法。
724 10
|
7月前
|
缓存 Java API
微服务——SpringBoot使用归纳——Spring Boot集成 Swagger2 展现在线接口文档——Swagger2 的配置
本文介绍了在Spring Boot中配置Swagger2的方法。通过创建一个配置类,添加`@Configuration`和`@EnableSwagger2`注解,使用Docket对象定义API文档的详细信息,包括标题、描述、版本和包路径等。配置完成后,访问`localhost:8080/swagger-ui.html`即可查看接口文档。文中还提示了可能因浏览器缓存导致的问题及解决方法。
755 0
微服务——SpringBoot使用归纳——Spring Boot集成 Swagger2 展现在线接口文档——Swagger2 的配置
|
8月前
|
XML Java 测试技术
Spring IOC—基于注解配置和管理Bean 万字详解(通俗易懂)
Spring 第三节 IOC——基于注解配置和管理Bean 万字详解!
527 26