一、需求
想要配置全局字符串转日期工具,将Controller中接收的日期字符串转换为Date类型,便于操作。(不在实体内使用注解)
二、使用Converter全局处理
实现SpringMVC提供的Converter接口。注意:此方法适用于大部分情况。但无法处理@RequestBody接收的值。(原因尚未研究,打断点测试,数据并未进入自定义的Converer实体中),此方式可以转换,单独的Date对象,以及使用@RequestParam
简单的日期转换器
@Component
public class DateConverter implements Converter<String,Date> {
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
@Override
public Date convert(String source) {
if (source != null && !"".equals(source)) {
try {
return sdf.parse(source);
} catch (ParseException e) {
e.printStackTrace();
}
}
return null;
}
}
更完整的日期转换器
@Component
public class DateConverter implements Converter<String,Date> {
private static final List<String> formats = new ArrayList<>(4);
static {
formats.add("yyyy-MM");
formats.add("yyyy-MM-dd");
formats.add("yyyy-MM-dd hh:mm");
formats.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, formats.get(0));
} else if (source.matches("^\\d{4}-\\d{1,2}-\\d{1,2}$")) {
return parseDate(source, formats.get(1));
} else if (source.matches("^\\d{4}-\\d{1,2}-\\d{1,2} {1}\\d{1,2}:\\d{1,2}$")) {
return parseDate(source, formats.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, formats.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 = dateFormat.parse(dateStr);
} catch (Exception e) {
}
return date;
}
}
三、解决无法转换@RequestBody接收值的问题
自定义JsonDeserializer反序列化程序
package com.tianqicode.myquickframe.common.utils;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.JsonDeserializer;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.time.DateUtils;
import java.io.IOException;
import java.text.ParseException;
import java.util.Date;
/**
* @author wangtianqi
* @create 2020-09-27 11:53
*/
public class DateJacksonConverter extends JsonDeserializer<Date> {
private static String[] pattern =
new String[]{"yyyy-MM-dd", "yyyy-MM-dd HH:mm", "yyyy-MM-dd HH:mm:ss", "yyyy-MM-dd HH:mm:ss.S",
"yyyy.MM.dd", "yyyy.MM.dd HH:mm", "yyyy.MM.dd HH:mm:ss", "yyyy.MM.dd HH:mm:ss.S",
"yyyy/MM/dd", "yyyy/MM/dd HH:mm", "yyyy/MM/dd HH:mm:ss", "yyyy/MM/dd HH:mm:ss.S"};
@Override
public Date deserialize(JsonParser p, DeserializationContext ctxt) throws IOException, JsonProcessingException {
Date targetDate = null;
String originDate = p.getText();
if (StringUtils.isNotEmpty(originDate)) {
try {
long longDate = Long.valueOf(originDate.trim());
targetDate = new Date(longDate);
} catch (NumberFormatException e) {
try {
targetDate = DateUtils.parseDate(originDate, DateJacksonConverter.pattern);
} catch (ParseException pe) {
throw new IOException(String.format(
"'%s' can not convert to type 'java.util.Date',just support timestamp(type of long) and following date format(%s)",
originDate,
StringUtils.join(pattern, ",")));
}
}
}
return targetDate;
}
@Override
public Class<?> handledType() {
return Date.class;
}
}
创建配置类
package com.tianqicode.myquickframe.framework.config;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.tianqicode.myquickframe.common.utils.DateJacksonConverter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.converter.json.Jackson2ObjectMapperFactoryBean;
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
import java.text.SimpleDateFormat;
/**
* @author wangtianqi
* @create 2020-09-27 11:52
*/
@Configuration
public class DateConverterConfig {
@Bean
// 注册自定义反序列化器实体
public DateJacksonConverter dateJacksonConverter() {
return new DateJacksonConverter();
}
@Bean
// 注册添加自定义反序列化器实体的ObjectMapper工厂实体
public Jackson2ObjectMapperFactoryBean jackson2ObjectMapperFactoryBean(
@Autowired
DateJacksonConverter dateJacksonConverter) {
Jackson2ObjectMapperFactoryBean jackson2ObjectMapperFactoryBean = new Jackson2ObjectMapperFactoryBean();
jackson2ObjectMapperFactoryBean.setDeserializers(dateJacksonConverter);
return jackson2ObjectMapperFactoryBean;
}
@Bean
// 覆盖Springboot默认的HttpMessageConverter配置,添加自定义的ObjectMapper
public MappingJackson2HttpMessageConverter mappingJackson2HttpMessageConverter(
@Autowired
ObjectMapper objectMapper) {
MappingJackson2HttpMessageConverter mappingJackson2HttpMessageConverter =
new MappingJackson2HttpMessageConverter();
objectMapper.setDateFormat(new SimpleDateFormat("yyyy/MM/dd HH:mm:ss"));
mappingJackson2HttpMessageConverter.setObjectMapper(objectMapper);
return mappingJackson2HttpMessageConverter;
}
}
四、使用注解
当然使用注解可以更简便的方式实现自动转换,虽然与我的需求不相符,单也记录一下。
1、使用@JsonFormat
在实体需要转换的属性上添加@JsonFormat(pattern = "定义日期格式")
即可转换定义格式的日期字符串,但这种方式有个缺点:只能接收一种格式的字符串。
2、使用@JsonDeserialize
配合上面自定义的DateJacksonConverter
类,就可以实现接收多种日期格式。同样的在实体需要转换的属性上添加@JsonDeserialize(using = DateJacksonConverter.class)
即可。