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类型的参数绑定,

帮助提高日常开发效率。

目录
相关文章
|
16天前
|
Java 开发者 微服务
手写模拟Spring Boot自动配置功能
【11月更文挑战第19天】随着微服务架构的兴起,Spring Boot作为一种快速开发框架,因其简化了Spring应用的初始搭建和开发过程,受到了广大开发者的青睐。自动配置作为Spring Boot的核心特性之一,大大减少了手动配置的工作量,提高了开发效率。
37 0
|
2月前
|
Java API 数据库
构建RESTful API已经成为现代Web开发的标准做法之一。Spring Boot框架因其简洁的配置、快速的启动特性及丰富的功能集而备受开发者青睐。
【10月更文挑战第11天】本文介绍如何使用Spring Boot构建在线图书管理系统的RESTful API。通过创建Spring Boot项目,定义`Book`实体类、`BookRepository`接口和`BookService`服务类,最后实现`BookController`控制器来处理HTTP请求,展示了从基础环境搭建到API测试的完整过程。
48 4
|
2月前
|
Java API 数据库
Spring Boot框架因其简洁的配置、快速的启动特性及丰富的功能集而备受开发者青睐
本文通过在线图书管理系统案例,详细介绍如何使用Spring Boot构建RESTful API。从项目基础环境搭建、实体类与数据访问层定义,到业务逻辑实现和控制器编写,逐步展示了Spring Boot的简洁配置和强大功能。最后,通过Postman测试API,并介绍了如何添加安全性和异常处理,确保API的稳定性和安全性。
38 0
|
2月前
|
Java API Spring
在 Spring 配置文件中配置 Filter 的步骤
【10月更文挑战第21天】在 Spring 配置文件中配置 Filter 是实现请求过滤的重要手段。通过合理的配置,可以灵活地对请求进行处理,满足各种应用需求。还可以根据具体的项目要求和实际情况,进一步深入研究和优化 Filter 的配置,以提高应用的性能和安全性。
|
26天前
|
Java Spring
[Spring]aop的配置与使用
本文介绍了AOP(面向切面编程)的基本概念和核心思想。AOP是Spring框架的核心功能之一,通过动态代理在不修改原代码的情况下注入新功能。文章详细解释了连接点、切入点、通知、切面等关键概念,并列举了前置通知、后置通知、最终通知、异常通知和环绕通知五种通知类型。
30 1
|
2月前
|
Java BI 调度
Java Spring的定时任务的配置和使用
遵循上述步骤,你就可以在Spring应用中轻松地配置和使用定时任务,满足各种定时处理需求。
147 1
|
3月前
|
XML Java 数据格式
Spring IOC—基于XML配置Bean的更多内容和细节(通俗易懂)
Spring 第二节内容补充 关于Bean配置的更多内容和细节 万字详解!
229 18
Spring IOC—基于XML配置Bean的更多内容和细节(通俗易懂)
|
3月前
|
前端开发 Java Spring
关于spring mvc 的 addPathPatterns 拦截配置常见问题
关于spring mvc 的 addPathPatterns 拦截配置常见问题
244 1
|
2月前
|
XML Java 数据格式
手动开发-简单的Spring基于注解配置的程序--源码解析
手动开发-简单的Spring基于注解配置的程序--源码解析
47 0
|
2月前
|
XML Java 数据格式
手动开发-简单的Spring基于XML配置的程序--源码解析
手动开发-简单的Spring基于XML配置的程序--源码解析
82 0