springboot 多了8小时_详解SpringBoot时间参数处理完整解决方案

在JavaWeb程序的开发过程中,接口是前后端对接的主要窗口,而接口参数的接收有时候是一个令人头疼的事情,这其中最困扰程序猿的,应该是时间参数的接收。

比如:设置一个用户的过期时间,前端到底以什么格式传递参数呢?时间戳?还是2019-12-01 22:13:00这种格式?还是其他格式?

今天我就来总结一下SpringBoot Web应用接口接收时间类型参数的问题解决方案。

注:目前我对Spring源码的掌握还不是很好,所以这一篇仅仅总结一下解决方法,后面感悟多了会重写一下!

经过简单的测试,我们知道:

不使用@RequestBody注解的情况下,所有时间类型参数都会引起报错;

使用@RequestBody,前端传递时间戳或2019-11-22形式正常,传递2019-11-22 11:22:22报错,其他格式同样报错。

之前有接触过类似的解决办法,在类的属性上加上@DateFormat注解,解决单个时间参数问题。

但是局限较多。

理想的解决方案是:一次配置,全局通用,多种格式,自动转换(朗朗上口嗷)

一、源码简要分析

首先我们来简单分析一下源码:

深入的就不解释了(我现在也不懂🤦‍♂️)

简单来说,接口接收的参数,首先被HandlerMethodArgumentResolver的实现类处理了一遍,将其转换为我们需要的格式。

这里主要分为两种情况:

使用了@RequestBody的参数,一般是对象接收,前端传递的通常是JSON形式

其他接收参数的方式,比如@RequestAttribute,@RequestParam,或者默认形式,前端传递的通常是表单参数、请求URL后缀参数等

二、解决方法

默认形式,或使用@RequestAttribute,或使用@RequestParam,这样的参数,通过配置converter来解决问题

使用@RequestBody解析的参数,通过在ObjectMapper中配置序列化和反序列化规则来处理

2.1 自定义converter

针对第一种情况,我们需要配置converter,这里介绍两种方法:

@ControllerAdvice + @InitBinder

直接使用@Bean定义converter类

首先我们这里需要一个DateConverter类,这个类实现了Converter接口,重写了其中的convert方法,将String转成Date类型:

我们这里定义了三种处理格式:

/**

* 日期转换类

* 将标准日期、标准日期时间、时间戳转换成Date类型

*/

/*@Deprecated*/

public class DateConverter implements Converter {

private Logger logger = LoggerFactory.getLogger(DateConverter.class);

private static final String dateFormat = "yyyy-MM-dd HH:mm:ss";

private static final String shortDateFormat = "yyyy-MM-dd";

private static final String timeStampFormat = "^\\d+$";

@Override

public Date convert(String value) {

logger.info("转换日期:" + value);

if(value == null || value.trim().equals("") || value.equalsIgnoreCase("null")) {

return null;

}

value = value.trim();

try {

if (value.contains("-")) {

SimpleDateFormat formatter;

if (value.contains(":")) {

formatter = new SimpleDateFormat(dateFormat);

} else {

formatter = new SimpleDateFormat(shortDateFormat);

}

return formatter.parse(value);

} else if (value.matches(timeStampFormat)) {

Long lDate = new Long(value);

return new Date(lDate);

}

} catch (Exception e) {

throw new RuntimeException(String.format("parser %s to Date fail", value));

}

throw new RuntimeException(String.format("parser %s to Date fail", value));

}

}

注:这个DateConverter类在下面都会用到。

import com.aegis.yqmanagecenter.config.date.DateConverter;

import com.aegis.yqmanagecenter.model.bean.common.JsonResult;

import org.slf4j.Logger;

import org.slf4j.LoggerFactory;

import org.springframework.beans.propertyeditors.CustomDateEditor;

import org.springframework.core.convert.support.GenericConversionService;

import org.springframework.http.HttpStatus;

import org.springframework.web.bind.WebDataBinder;

import org.springframework.web.bind.annotation.*;

import java.beans.PropertyEditorSupport;

import java.text.DateFormat;

import java.text.SimpleDateFormat;

import java.util.Date;

@ControllerAdvice

public class ControllerHandler {

private Logger logger = LoggerFactory.getLogger(ControllerHandler.class);

@InitBinder

public void initBinder(WebDataBinder binder) {

// 方法1,注册converter

GenericConversionService genericConversionService = (GenericConversionService) binder.getConversionService();

if (genericConversionService != null) {

genericConversionService.addConverter(new DateConverter());

}

// 方法2,定义单格式的日期转换,可以通过替换格式,定义多个dateEditor,代码不够简洁

DateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

CustomDateEditor dateEditor = new CustomDateEditor(df, true);

binder.registerCustomEditor(Date.class, dateEditor);

// 方法3,同样注册converter

binder.registerCustomEditor(Date.class, new PropertyEditorSupport() {

@Override

public void setAsText(String text) throws IllegalArgumentException {

setValue(new DateConverter().convert(text));

}

});

}

}

注:上面的三个方法都是利用@ControllerAdvice+@InitBinder来设置时间参数处理的,其中1和3都可以设置DateConverter,而方法2只能一个一个手动设置格式。

这里需要注意,上述配置方法都无法解决Json格式数据中的时间参数接收问题。下面我们直接看完整的解决方案——将DateConverter注册为组件,并使用ObjectMapper来配置时间参数的序列化(接口返回值)和反序列化形式(接口接收参数)。

2.2 配置ObjectMapper以及完整解决方案

完整的解决方案:

/**

* 日期转换配置

* 解决@RequestAttribute、@RequestParam和@RequestBody三种类型的时间类型参数接收与转换问题

*/

@Configuration

public class DateConfig {

/**

* 默认日期时间格式

*/

public static final String DEFAULT_DATE_TIME_FORMAT = "yyyy-MM-dd HH:mm:ss";

/**

* Date转换器,用于转换RequestParam和PathVariable参数

*/

@Bean

public Converter dateConverter() {

return new DateConverter();

}

/**

* Json序列化和反序列化转换器,用于转换Post请求体中的json以及将我们的对象序列化为返回响应的json

* 使用@RequestBody注解的对象中的Date类型将从这里被转换

*/

@Bean

public ObjectMapper objectMapper(){

ObjectMapper objectMapper = new ObjectMapper();

objectMapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);

objectMapper.disable(DeserializationFeature.ADJUST_DATES_TO_CONTEXT_TIME_ZONE);

JavaTimeModule javaTimeModule = new JavaTimeModule();

//Date序列化和反序列化

javaTimeModule.addSerializer(Date.class, new JsonSerializer() {

@Override

public void serialize(Date date, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) throws IOException {

SimpleDateFormat formatter = new SimpleDateFormat(DEFAULT_DATE_TIME_FORMAT);

String formattedDate = formatter.format(date);

jsonGenerator.writeString(formattedDate);

}

});

javaTimeModule.addDeserializer(Date.class, new JsonDeserializer() {

@Override

public Date deserialize(JsonParser jsonParser, DeserializationContext deserializationContext) throws IOException, JsonProcessingException {

return new DateConverter().convert(jsonParser.getText());

}

});

objectMapper.registerModule(javaTimeModule);

return objectMapper;

}

}

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持脚本之家。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值