当前位置:

首页 > 编程开发 > SpringBoot JSON全局日期格式转换器如何实现

SpringBoot JSON全局日期格式转换器如何实现

需求前台有日期字符串的数据,提交到后台。后台实体类使用Date属性接收。日期字符串有多种格式,需要用一个转换器将合法的日期字符串格式转换为Date类型。分析当前台的提交数据的Content-Type为application/json;charset=utf-8,后台使用@RequestBody来接收数据的时候,使用此转换方式。一.前期准备1.1日期正则注解用来标记日期字符串所对应的正则表达式importjava.lang.annotation.*;@Documented@Retention(Retenti

本文目录

      需求

      前台有日期字符串的数据,提交到后台。后台实体类使用Date属性接收。
      日期字符串有多种格式,需要用一个转换器将合法的日期字符串格式转换为Date类型。

      分析

      当前台的提交数据的Content-Type为application/json;charset=utf-8,后台使用@RequestBody来接收数据的时候,使用此转换方式。

      一. 前期准备

      1.1 日期正则注解

      用来标记日期字符串所对应的正则表达式

      import java.lang.annotation.*;
      
      @Documented
      @Retention(RetentionPolicy.RUNTIME)
      @Target({ElementType.FIELD})
      public @interface DatePattern {
      	
          String value();
      }

      1.2 日期格式定数

      指定所有支持的日期格式

      public final class DateFormatPart {
      
      	@DatePattern("^\\d{4}$")
      	public static final String YYYY = "yyyy";
      
      	@DatePattern("^\\d{4}\\d{2}$")
      	public static final String YYYYMM = "yyyyMM";
      
      	@DatePattern("^\\d{4}/\\d{2}$")
      	public static final String YYYYMM_SLASH = "yyyy/MM";
      
      	@DatePattern("^\\d{4}\\d{1,2}\\d{1,2}$")
      	public static final String YYYYMMDD = "yyyyMMdd";
      
      	@DatePattern("^\\d{4}/\\d{2}/\\d{2}$")
      	public static final String YYYYMMDD_SLASH = "yyyy/MM/dd";
      
      	@DatePattern("[0-9]+\\u5e74[0-9]+\\u6708[0-9]+\\u65e5$")
      	public static final String YYYYMMDD_JP = "yyyy年MM月dd日";
      
          @DatePattern("^\\d{4}\\d{1,2}\\d{1,2} \\d{1,2}:\\d{1,2}:\\d{1,2}$")
      	public static final String YYYYMMDD_HHMMSS = "yyyyMMdd HH:mm:ss";
      
          @DatePattern("^\\d{4}/\\d{2}/\\d{2} \\d{1,2}:\\d{1,2}:\\d{1,2}$")
      	public static final String YYYYMMDD_HHMMSS_SLASH = "yyyy/MM/dd HH:mm:ss";
      }

      1.3 日期转换工具类

      • 从日期格式定数类中获取所有的属性值和该属性上所标记的正则注解,通过反射来映射为map。

      • 如果有需要增删的日期格式的话,只需要修改日期格式定数即可,便于维护。

      import org.springframework.util.ObjectUtils;
      import org.springframework.util.ReflectionUtils;
      
      import java.lang.reflect.Field;
      import java.text.ParseException;
      import java.text.SimpleDateFormat;
      import java.util.*;
      
      public final class DateUtil {
      
          // 日期格式 <==> 正则的map,使用LinkedHashMap可以避免按照顺序匹配正则表达式
          private static final Map datePatternMap = new LinkedHashMap<>();
      
          // 日期格式List
          private static final List dateFormatList = new ArrayList<>();
      
          // 使用静态代码块,可以保证只初始化一次
          static {
      
              Class dateFormatClass = DateFormatPart.class;
              // 获取所有的属性
              Field[] fields = dateFormatClass.getFields();
              for (Field field : fields) {
      
                  // 获取属性上的注解
                  DatePattern annotation = field.getAnnotation(DatePattern.class);
                  if (ObjectUtils.isEmpty(annotation)) {
                      continue;
                  }
      
                  //  强制让属性可以访问
                  ReflectionUtils.makeAccessible(field);
      
                  // 日期格式化字符串
                  String dateFormatStr = "";
                  try {
                      // 获取当前属性所对应的属性值
                      dateFormatStr = (String)field.get(dateFormatClass);
                  } catch (IllegalAccessException e) {
                      e.printStackTrace();
                  }
      
                  dateFormatList.add(dateFormatStr);
      
                  // 将该属性的属性值和属性上的正则表达式放到map中
                  datePatternMap.put(dateFormatStr, annotation.value());
              }
          }
      	
      	// 用所有可能支持的格式将日期字符串转换为Date格式
          public static Date formatDateStrToDateAllFormat(String dateStr) {
      
              if (ObjectUtils.isEmpty(dateStr)) {
                  return null;
              }
      
              try {
                  for (Map.Entry mapEntry : datePatternMap.entrySet()) {
      				
      				// 如果当前日期字符串不符合当前正则的话
                      if (!dateStr.matches(mapEntry.getValue())) {
                          continue;
                      }
      
                      return DateUtil.formatStringToDate(dateStr, mapEntry.getKey());
                  }
              } catch (ParseException e) {
                  return null;
              }
      
              return null;
          }
      	
      	// 通过指定的格式将日期字符串转换为Date类型
          public static Date formatStringToDate(String dateStr, String format) throws ParseException {
      
              if (ObjectUtils.isEmpty(dateStr) || !dateFormatList.contains(format)) {
                  return null;
              }
      
              SimpleDateFormat time = new SimpleDateFormat(format);
              return time.parse(dateStr);
          }
      }

      二. 方式1-继承DateDeserializer类,重写_parseDate方法

      • 该方式的要点是通过继承DateDeserializer类,然后重写_parseDate方法实现转换功能

      • 自定义的GlobalDateDeserializer类需要添加到自定义的SimpleModule模块中,然后将模块添加到ObjectMapper中,通过jackson来实现转换。

      • 通过设置ObjectMapper对象的setDateFormat方法来实现后台数据返回到前台时的Date转String的默认格式。

      import com.fasterxml.jackson.core.JsonParser;
      import com.fasterxml.jackson.core.json.PackageVersion;
      import com.fasterxml.jackson.databind.DeserializationContext;
      import com.fasterxml.jackson.databind.DeserializationFeature;
      import com.fasterxml.jackson.databind.ObjectMapper;
      import com.fasterxml.jackson.databind.SerializationFeature;
      import com.fasterxml.jackson.databind.deser.std.DateDeserializers.DateDeserializer;
      import com.fasterxml.jackson.databind.module.SimpleModule;
      import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
      import org.springframework.context.annotation.Bean;
      import org.springframework.context.annotation.Configuration;
      import org.springframework.context.annotation.Primary;
      import org.springframework.http.converter.json.Jackson2ObjectMapperBuilder;
      
      import java.io.IOException;
      import java.text.DateFormat;
      import java.text.SimpleDateFormat;
      import java.util.Date;
      
      @Configuration
      public class CustomConfig {
      
          /*
           * 自定义的全局的日期转换解析类,需要继承jackson包中的DateDeserializer
           * 因为此类不会在别的地方使用了,因此直接使用内部类聚合到自定义的配置文件中
           */
          private static final class GlobalDateDeserializer extends DateDeserializer {
      
              @Override
              protected Date _parseDate(JsonParser jp, DeserializationContext context) throws IOException {
      
                  return DateUtil.formatDateStrToDateAllFormat(jp.getText());
              }
          }
      
          @Bean("objectMapper")
          @Primary
          @ConditionalOnMissingBean
          public ObjectMapper jacksonObjectMapper(Jackson2ObjectMapperBuilder builder) {
      
              // 创建jackson对象
              ObjectMapper jackson = builder.createXmlMapper(false).build();
      
              /*
               * DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES
               * 在进行序列化或者反序列化的时候,
               * JSON字符串中有一个字段,但是我们的对象没有这个字段的时候,该怎么处理
               * 设置为true的时候,会抛出异常
               * 设置为false,忽略异常继续处理
               */
              jackson.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
              // 禁用默认的「yyyy-MM-dd'T'HH:mm:ss.SSS」UTC类型
              jackson.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);
      
               /*
               * 设置序列化时的默认格式,即后台返回数据到前台的时候,
               * Date类型数据需要转换为的字符串格式
               * 如果不进行指定的话,默认使用 yyyy-MM-dd'T'HH:mm:ss.SSS 格式
               */
              DateFormat dateFormat = new SimpleDateFormat(DateFormatPart.YYYYMMDD_HHMMSS_SLASH);
              jackson.setDateFormat(dateFormat);
      
              // 创建一个模块,指定该模块是用来解析 Date.class 类型数据的
              SimpleModule newModule = new SimpleModule("GlobalDateDeserializer", PackageVersion.VERSION);
              // 将我们创建的全局日期转换类添加到模块中,指定转换Date类型
              newModule.addDeserializer(Date.class, new CustomConfig.GlobalDateDeserializer());
              // 将该模块添加到jackson中
              jackson.registerModule(newModule);
      
              return jackson;
          }
      }

      三. 方式2-继承StdDateFormat类,重写方法

      • parse方法用来将日期字符串转换为Date(前台向后台传数据)

      • format方法用来将Date格式的数据转换为指定格式的字符串(后台向前台传数据)。

      import java.text.FieldPosition;
      import java.text.ParsePosition;
      import java.text.SimpleDateFormat;
      import java.util.Date;
      
      import com.fasterxml.jackson.databind.util.StdDateFormat;
      
      public class GlobalJsonDateConvert extends StdDateFormat {
      
          // 静态初始化final,共享
          public static final GlobalJsonDateConvert instance = new GlobalJsonDateConvert();
      
          // 日期字符串解析为日期
          @Override
          public Date parse(String dateStr, ParsePosition pos) {
              return getDate(dateStr);
          }
      
          @Override
          public Date parse(String dateStr) {
              return getDate(dateStr);
          }
      	
      	// 使用自定义的日期转换工具类将所有可能支持的日期字符串转换为Date格式
          private Date getDate(String dateStr) {
              return DateUtil.formatDateStrToDateAllFormat(dateStr);
          }
          
      	/*
         	 * 设置序列化时的默认格式,即后台返回数据到前台的时候,
           * Date类型数据需要转换为的字符串格式
           * 如果不进行指定的话,默认使用 yyyy-MM-dd'T'HH:mm:ss.SSS 格式
           */
          @Override
          public StringBuffer format(Date date, StringBuffer toAppendTo, FieldPosition fieldPosition){
              SimpleDateFormat sdf = new SimpleDateFormat(DateFormatPart.YYYYMMDD_HHMMSS_SLASH);
              return sdf.format(date, toAppendTo, fieldPosition);
          }
      
          @Override
          public GlobalJsonDateConvert clone() {
              super.clone();
              return new GlobalJsonDateConvert();
          }
      }

      3.1 MappingJackson2HttpMessageConverter方式

      import org.springframework.context.annotation.Bean;
      import org.springframework.context.annotation.Configuration;
      import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
      
      @Configuration
      public class CustomConfig {
      
          // JSON格式 全局日期转换器配置
          @Bean
          public MappingJackson2HttpMessageConverter createMappingJackson2HttpMessageConverter() {
      
              /*
               * 通过MappingJackson2HttpMessageConverter得到的ObjectMapper,
               * 已经默认把 DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES 给关闭了
               */
              MappingJackson2HttpMessageConverter jacksonConverter = new MappingJackson2HttpMessageConverter();
              jacksonConverter.getObjectMapper().setDateFormat(GlobalJsonDateConvert.instance);
      
              return jacksonConverter;
          }
      }

      3.2 ObjectMapper方式

      通过Jackson2ObjectMapperBuilder创建ObjectMapper对象,然后将我们定义的转换器GlobalJsonDateConvert放到ObjectMapper对象中

      import com.fasterxml.jackson.databind.ObjectMapper;
      import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
      import org.springframework.context.annotation.Bean;
      import org.springframework.context.annotation.Configuration;
      import org.springframework.context.annotation.Primary;
      import org.springframework.http.converter.json.Jackson2ObjectMapperBuilder;
      
      @Configuration
      public class CustomConfig {
      
          @Bean("objectMapper")
          @Primary
          @ConditionalOnMissingBean
          public ObjectMapper objectMapper(Jackson2ObjectMapperBuilder builder) {
      		
              ObjectMapper objectMapper = builder.build();
              objectMapper.setDateFormat(GlobalJsonDateConvert.instance);
              return objectMapper;
          }
      }

      3.3 Jackson2ObjectMapperBuilder方式

      将我们定义的转换器GlobalJsonDateConvert放到Jackson2ObjectMapperBuilder对象中

      import org.springframework.context.annotation.Bean;
      import org.springframework.context.annotation.Configuration;
      import org.springframework.http.converter.json.Jackson2ObjectMapperBuilder;
      
      @Configuration
      public class CustomConfig {
      
          @Bean
          public Jackson2ObjectMapperBuilder objectMapper() {
      
              Jackson2ObjectMapperBuilder jackson2ObjectMapperBuilder = new Jackson2ObjectMapperBuilder();
              jackson2ObjectMapperBuilder.dateFormat(GlobalJsonDateConvert.instance);
              return jackson2ObjectMapperBuilder;
          }
      }

      四. 效果

      ⏹前台JS

      // 向后台传输的json数据
      const jsonData = {
      	// ????待处理的日期字符串数据
          birthday: '2027年12月12日',
          nameAA: 'jiafeitian',
          hobby: '吃饭'
      };
      
      $.ajax({
          url: url,
          type: 'POST',
          // 对象转换为json字符串
          data: JSON.stringify(jsonData),
          contentType: "application/json;charset=utf-8",
          success: function (data, status, xhr) {
              console.log(data);
          }
      });

      ⏹后台Form

      import lombok.Data;
      import java.util.Date;
      
      @Data
      public class Test15Form {
      
          private String name;
      
          private String hobby;
      
          private String address;
      	
      	// 用来接收的Date类型的数据
          private Date birthday;
      }

      可以看到前台提交的日期字符串被转换为Date格式了

      SpringBoot JSON全局日期格式转换器如何实现

      本站声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系bd@zhengruan.com
      作者最新文章
      编程开发 JSON
      相关文章 更多
      Java发送post请求发送json数据的实现方法与代码示例
      Java发送post请求发送json数据的实现方法与代码示例

      深入解析Java发送JSON格式POST请求的实现机制,对比原生API与第三方库的代码差异,提供可复制的代码示例,并探讨超时设置、编码处理及微服务场景下的例外情况。

      抖音官网入口网页
      抖音官网入口网页

      抖音官网入口的正确打开方式 如果你在寻找抖音网页版的入口,那么直接访问 https://www.douyin.com 就是了。这不仅是通往海量短视频世界的门户,更是一个功能越来越专业的媒体素材库和创作工具箱。为什么这么说?看看它最近在功能上的深度拓展就知道了。 简单一个网址背后,其实是一个日益精密的

      在小说搜搜找不到想看的小说怎么办?小说搜搜换源功能使用详解【必学】
      在小说搜搜找不到想看的小说怎么办?小说搜搜换源功能使用详解【必学】

      小说搜搜搜索不到结果?五种实用解决方法帮你搞定 在小说搜搜里搜不到想看的书?这事儿其实挺常见。问题多半出在书源上——要么是默认的书源还没来得及收录,要么是原先的源数据失效了,更新没跟上。别急,下面这五条解决路径,基本能覆盖绝大多数情况,操作起来也不复杂。 一、通过阅读页调出换源入口手动切换 这个方法

      蓝海搜书搜书攻略及入口指南免费分享
      蓝海搜书搜书攻略及入口指南免费分享

      蓝海搜书提供超三百万部小说资源,覆盖十余类题材;具备毫秒级搜索响应、四套主题引擎、跨端加密同步及全文索引等核心功能,入口为lanhaizw.com。 关于蓝海搜书的免费资源入口和核心功能,一直是许多读者关注的焦点。今天,我们就来深入拆解一下这个平台,看看它在资源、体验和功能上究竟有哪些门道。 官方入

      Java中JSONassert,JsonUnit和Jackson三方比对
      Java中JSONassert,JsonUnit和Jackson三方比对

      断言工具专为测试场景设计,支持宽松模式并精准定位差异;单元工具基于断言工具和杰克逊库封装,提供更友好的断言接口;杰克逊库作为主流处理库,可通过节点树模型自定义比对逻辑,适用于业务开发中精细控制差异的场景。

      百度编辑器从Json对象中取值,完成初次渲染,在编辑器内画表格
      百度编辑器从Json对象中取值,完成初次渲染,在编辑器内画表格

      通过AJAX异步请求服务器获取JSON格式的表格数据,解析JSON对象后遍历数据条目,动态拼接成包含表格标签的HTML字符串,最后调用编辑器实例的setContent()方法将HTML写入编辑器,完成表格在编辑器内的初次渲染。

      1024编程
      1024编程

      面向8-18岁青少年,采用计算机硕士以上师资,以Scratch、Python、C++、CSP-J/S和NOIP五个阶段系统化循序渐进推进,避免冗余理论,注重实战,紧密对标竞赛与升学需求,形成高效衔接、直通信息学奥赛的课程体系,着力培养计算思维,助力学生冲刺升学。

      能编程与会编程
      能编程与会编程

      能编程与会编程的区别在于前者仅是技术实现,后者包含情绪管理、坚持探索、主动负责、追求完善及知识体系构建等综合能力。编程之外的能力决定了解决问题的深度与广度。

      c++如何解析GeoJSON中的FeatureCollection地理要素集【实战】
      c++如何解析GeoJSON中的FeatureCollection地理要素集【实战】

      使用nlohmann/json库解析GeoJSONFeatureCollection,需逐层防御性访问features、geometry和properties,坐标数组维度不确定,需判断。坐标系和精度问题在解析层无法解决,应暴露原始坐标数组供上层处理。性能敏感时避免重复解析和深拷贝,可缓存并视口裁剪。

      Pandas如何解析JSON数据为表_利用json_normalize函数扁平化数据
      Pandas如何解析JSON数据为表_利用json_normalize函数扁平化数据

      pandas.json_normalize 这个函数,说起来挺有意思的——很多人以为它能一键把嵌套 JSON 拍扁成表格,结果往往发现列名变成了一串带点的“火车”(比如 profile.address.city),真正棘手的问题却一个都没解决。字段缺失怎么办?列表嵌套怎么炸开?多层结构怎么拆?答案其

      查看更多
      精品专题 更多
      装机必备
      装机必备

      正软商城装机必备专区,精选办公、浏览器、安全防护、影音播放、压缩解压、设计创作和系统工具等电脑常用正版软件,帮助用户快速完成新电脑软件配置。

      Windows
      Windows

      正软商城Windows软件专区,汇集适用于Windows电脑的办公、设计、安全防护、影音播放、开发工具和系统优化软件,提供软件介绍、系统要求、正版授权及购买下载服务。

      PDF教程
      PDF教程

      正软商城PDF教程频道提供PDF编辑、转换、合并、拆分、压缩及格式处理方法,同时介绍常用PDF软件和工具的使用技巧。

      Mac软件 更多
      讯飞智作 网页版
      讯飞智作 网页版
      Windows/ macOS/ Linux

      讯飞智作是一款基于语音合成技术、虚拟人驱动技术与数字人形象声音构建能力的 AI 数字人音视频创作平台。

      火山引擎 网页版
      火山引擎 网页版
      Windows/ macOS/ Linux

      火山引擎是字节跳动旗下企业级云与AI服务平台。聚焦大模型核心能力,依托字节自研豆包多模态大模型,凭借火山方舟一站式平台,提供模型精调、推理部署、智能应用搭建等全链路服务,结合高性能AI算力,助力各行业快速落地大模型数字化与智能化应用。

      Aperty macOS版
      Aperty macOS版
      macOS

      Aperty 是 Skylum 推出的 AI 人像修图软件,支持自然肤质修饰、瑕疵处理、面部与身体调整、预设及批量同步。

      WINDOWS 更多
      讯飞智作 网页版
      讯飞智作 网页版
      Windows/ macOS/ Linux

      讯飞智作是一款基于语音合成技术、虚拟人驱动技术与数字人形象声音构建能力的 AI 数字人音视频创作平台。

      火山引擎 网页版
      火山引擎 网页版
      Windows/ macOS/ Linux

      火山引擎是字节跳动旗下企业级云与AI服务平台。聚焦大模型核心能力,依托字节自研豆包多模态大模型,凭借火山方舟一站式平台,提供模型精调、推理部署、智能应用搭建等全链路服务,结合高性能AI算力,助力各行业快速落地大模型数字化与智能化应用。

      PixTV 网页版
      PixTV 网页版
      Windows

      PixTV 是一款在浏览器中使用的 AI 视觉内容创作平台,提供图片、视频、音频、文字生成、AI 分镜、局部重绘、提示词反推和无限画布等工具,适合短剧、漫剧、广告及社交媒体内容制作。