1、遇到的问题
在项目中,后端接口经常将日期参数定义为Date类型,在与前台或者第三方服务对接时,经常出现一个问题,比如: Date startTime,定义好的参数是基于日期格式的参数,后续复用或者其他原因,后端的对接方,可能传递的参数会改变,但是原先约定的时间格式也会继续使用,例如之前约定是 yyyy-MM-dd HH:mm:ss,后面又增加了yyyy/MM/dd HH:mm:ss,甚至使用long时间戳格式的日期参数。
出了问题,后端背锅,要求马上出解决方案。。。
2、定位问题
既然是日期格式的参数问题适配,解决这一问题,应该在接口请求接收到request参数,设置参数值的时候,统一对Date类型的参数接收值,进行格式化转换,最后将Date参数的值设置到请求参数中,之后就是后端服务处理了。
3、解决方案
maven依赖:
<!-- Apache Lang3 -->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
</dependency>
统一抽象基础处理类:
package com.springcloud.service.web;
import com.springcloud.service.utils.StringUtils;
import org.apache.commons.lang3.time.DateUtils;
import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.bind.annotation.InitBinder;
import java.beans.PropertyEditorSupport;
import java.text.ParseException;
import java.util.Date;
public class BaseController {
private static String[] parsePatterns = {
"yyyy-MM-dd", "yyyy-MM-dd HH:mm:ss", "yyyy-MM-dd HH:mm", "yyyy-MM",
"yyyy/MM/dd", "yyyy/MM/dd HH:mm:ss", "yyyy/MM/dd HH:mm", "yyyy/MM",
"yyyy.MM.dd", "yyyy.MM.dd HH:mm:ss", "yyyy.MM.dd HH:mm", "yyyy.MM"};
/**
* 日期型字符串转化为日期 格式
*/
public static Date parseDate(Object str) {
if (str == null) {
return null;
}
try {
return DateUtils.parseDate(str.toString(), parsePatterns);
} catch (ParseException e) {
return null;
}
}
/**
* 将前台传递过来的日期格式的字符串,自动转化为Date类型
*/
@InitBinder
public void initBinder(WebDataBinder binder) {
// Date 类型转换
binder.registerCustomEditor(Date.class, new PropertyEditorSupport() {
@Override
public void setAsText(String text) {
// 适配:Long转Date
if (StringUtils.isNotEmpty(text) && StringUtils.isInteger(text)) {
setValue(new Date(Long.parseLong(text)));
return;
}
setValue(parseDate(text));
}
});
}
}
工具类(部分):
/**
* 正则匹配是否正整数
*
* @param str
* @return
*/
public static boolean isInteger(String str) {
final Pattern pattern = Pattern.compile("^[-\\+]?[\\d]*$");
return pattern.matcher(str).matches();
}
/**
* * 判断一个字符串是否为空串
*
* @param str String
* @return true:为空 false:非空
*/
public static boolean isEmpty(String str) {
return isNull(str) || NULLSTR.equals(str.trim());
}
controller类继承BaseController类:
public class RequestProviderController extends BaseController
-----------
public class RequestConsumerController extends BaseController
ps: 若不需要适配处理日期,可以重写 public void initBinder(WebDataBinder binder) 方法
@Override
public void initBinder(WebDataBinder binder) {
// TODO
}
4、测试结果
【1】字符串格式请求(yyyy-MM-dd HH:mm:ss)
参数:
http://localhost:5000/consumer/request/get/02?&startTime=2020-12-21 17:03:00&endTime=2020-12-22 17:03:00&message=测试数据02
截图:
【2】字符串格式请求(yyyy/MM/dd HH:mm:ss)
参数:
http://localhost:5000/consumer/request/get/02?&startTime=2020/12/21 17:03:00&endTime=2020/12/22 17:03:00&message=测试数据02
截图:
【3】long格式请求
参数:
http://localhost:5000/consumer/request/get/02?&startTime=1608541380000&endTime=1608627780000&message=测试数据02
截图:
5、总结
http的跨服务之间的Feign调用GET请求,以及服务的接口GET请求,参数中包含Date类型的参数时,因为需要兼容不同调用方的格式不一致,或不同场景的参数格式不一致时,需要对请求参数中的Date数据进行格式化处理,保证接口的正确调用。同理可得,若在实际的业务需要中,若某一类型的参数,多场景下存在这多种不同的格式,需要在接口请求时,对此类型的参数值进行格式化处理,保障不通业务场景下,接口正确调用。
这种解决方案是实际应用中的一种实践,还有许多的方案可以解决此类的问题。