需求
前台有日期字符串的数据,提交到后台。后台实体类使用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<String, String> datePatternMap = new LinkedHashMap<>();
// 日期格式List
private static final List<String> dateFormatList = new ArrayList<>();
// 使用静态代码块,可以保证只初始化一次
static {
Class<DateFormatPart> 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<String, String> 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 {
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();
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);
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(前台向后台传数据)forma
t方法用来将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);
}
@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 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格式了
五. 总结
方式一中的1种方法和方式二中的3种方法,共计4中方法都可以实现全局日期格式转换器。
要点就是自定义日期转换的工具类用来处理各种可能的日期格式,并且将此工具类放到Jackson
中的ObjectMapper
对象中,上述4中方法的本质都是如此。
到此这篇关于SpringBoot JSON全局日期格式转换器的文章就介绍到这了,更多相关SpringBoot JSON日期格式转换内容请搜索编程网以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程网!