您好,欢迎访问一九零五行业门户网

Spring Boot日期时间如何处理

get请求及post表单日期时间字符串格式转换这种情况要和时间作为json字符串时区别对待,因为前端json转后端pojo底层使用的是json序列化jackson工具(httpmessgeconverter);而时间字符串作为普通请求参数传入时,转换用的是converter,两者在处理方式上是有区别。
使用自定义参数转换器(converter)实现 org.springframework.core.convert.converter.converter,自定义参数转换器,如下:
@configurationpublic class dateconverterconfig { @bean public converter<string, localdate> localdateconverter() { return new converter<string, localdate>() { @override public localdate convert(string source) { return localdate.parse(source, datetimeformatter.ofpattern("yyyy-mm-dd")); } }; } @bean public converter<string, localdatetime> localdatetimeconverter() { return new converter<string, localdatetime>() { @override public localdatetime convert(string source) { return localdatetime.parse(source, datetimeformatter.ofpattern("yyyy-mm-dd hh:mm:ss")); } }; }}
点评:以上两个bean会注入到spring mvc的参数解析器(好像叫做parameterconversionservice),当传入的字符串要转为localdatetime类时,spring会调用该converter对这个入参进行转换。
注意:关于自定义的参数转换器 converter,这有个坑,若将上面匿名内部类的写法精简成lambda表达式的方式:
@bean @conditionalonbean(name = "requestmappinghandleradapter") public converter<string, localdate> localdateconverter() { return source -> localdate.parse(source, datetimeformatter.ofpattern(default_date_format)); }
当再次启动项目时会出现异常:
caused by: java.lang.illegalargumentexception: unable to determine source type <s> and target type <t> for your converter [com.example.demo126.config.mappingconverteradapter$$lambda$522/817994751]; does the class parameterize those types?
是由于:
web项目启动注册requestmappinghandleradapter的时候会初始化webbindinginitializer
adapter.setwebbindinginitializer(getconfigurablewebbindinginitializer());
而configurablewebbindinginitializer需要formattingconversionservice, 而formattingconversionservice会将所有的converter添加进来,添加的时候需要获取泛型信息:
@overridepublic void addformatters(formatterregistry registry) { for (converter<?, ?> converter : getbeansoftype(converter.class)) { registry.addconverter(converter); } for (genericconverter converter : getbeansoftype(genericconverter.class)) { registry.addconverter(converter); } for (formatter<?> formatter : getbeansoftype(formatter.class)) { registry.addformatter(formatter); }}
添加converter.class 一般是通过接口获取两个泛型的具体类型
public resolvabletype as(class<?> type) { if (this == none) { return none; } class<?> resolved = resolve(); if (resolved == null || resolved == type) { return this; } for (resolvabletype interfacetype : getinterfaces()) { resolvabletype interfaceastype = interfacetype.as(type); if (interfaceastype != none) { return interfaceastype; } } return getsupertype().as(type);}
lambda表达式的接口是converter,并不能得到具体的类型,既然如此,那解决办法:
最简单的方法就是不适用lambda表达式,还使用匿名内部类,这样就不会存在上述问题
就是等requestmappinghandleradapterbean注册完成之后再添加自己的converter就不会注册到formattingconversionservice中
@bean@conditionalonbean(name = "requestmappinghandleradapter")public converter<string, localdatetime> localdatetimeconverter() { return source -> localdatetime.parse(source, datetimeutils.default_formatter);}
还可以对前端传递的string进行正则匹配,如yyyy-mm-dd hh:mm:ss、yyyy-mm-dd、 hh:mm:ss等,进行匹配。以适应多种场景。
@componentpublic class dateconverter implements converter<string, date> { @override public date convert(string value) { /** * 可对value进行正则匹配,支持日期、时间等多种类型转换 * 这里在匹配date日期格式时直接使用了 hutool 为我们已经写好的解析工具类,这里就不重复造轮子了 * cn.hutool.core.date.dateutil * @param value * @return */ return dateutil.parse(value.trim()); }}
注:这里在匹配date日期格式时直接使用了 hutool 为我们已经写好的解析工具类,这里就不重复造轮子了,下面的方法同样使用了该工具类,想要在自己的项目中使用该工具类也很简单,在项目pom文件中引入hutool的依赖就可以了,如下:
<!--hu tool 工具类--><dependency> <groupid>cn.hutool</groupid> <artifactid>hutool-all</artifactid> <version>5.1.3</version></dependency>
使用spring注解使用spring自带注解@datetimeformat(pattern = "yyyy-mm-dd"),如下:
@datetimeformat(pattern = "yyyy-mm-dd")private date startdate;
如果使用了自定义参数转化器,spring会优先使用该方式进行处理,即spring注解不生效。
使用controlleradvice配合initbinder@controlleradvicepublic class globalexceptionhandler { @initbinder protected void initbinder(webdatabinder binder) { binder.registercustomeditor(localdate.class, new propertyeditorsupport() { @override public void setastext(string text) throws illegalargumentexception { setvalue(localdate.parse(text, datetimeformatter.ofpattern("yyyy-mm-dd"))); } }); binder.registercustomeditor(localdatetime.class, new propertyeditorsupport() { @override public void setastext(string text) throws illegalargumentexception { setvalue(localdatetime.parse(text, datetimeformatter.ofpattern("yyyy-mm-dd hh:mm:ss"))); } }); binder.registercustomeditor(localtime.class, new propertyeditorsupport() { @override public void setastext(string text) throws illegalargumentexception { setvalue(localtime.parse(text, datetimeformatter.ofpattern("hh:mm:ss"))); } }); }}
从名字就可以看出来,这是在controller做环切(这里面还可以全局异常捕获),在参数进入handler之前进行转换;转换为我们相应的对象。
json入参及返回值全局处理请求类型为:post,content-type=application/json, 后台用@requestbody接收,默认接收及返回值格式为: yyyy-mm-dd hh:mm:ss
修改 application.yml 文件在application.propertities文件中增加如下内容:
spring:
jackson:
date-format: yyyy-mm-dd hh:mm:ss
time-zone: gmt+8
支持(content-type=application/json)请求中格式为 yyyy-mm-dd hh:mm:ss的字符串,后台用@requestbody接收,及返回值date转为yyyy-mm-dd hh:mm:ss格式string;
不支持(content-type=application/json)请求中yyyy-mm-dd等类型的字符串转为date; 不支持java8日期api;
利用jackson的json序列化和反序列化@configurationpublic class jacksonconfig { /** 默认日期时间格式 */ public static final string default_date_time_format = "yyyy-mm-dd hh:mm:ss"; /** 默认日期格式 */ public static final string default_date_format = "yyyy-mm-dd"; /** 默认时间格式 */ public static final string default_time_format = "hh:mm:ss"; @bean public mappingjackson2httpmessageconverter mappingjackson2httpmessageconverter() { mappingjackson2httpmessageconverter converter = new mappingjackson2httpmessageconverter(); objectmapper objectmapper = new objectmapper(); // 忽略json字符串中不识别的属性 objectmapper.configure(deserializationfeature.fail_on_unknown_properties, false); // 忽略无法转换的对象 objectmapper.configure(serializationfeature.fail_on_empty_beans, false); // prettyprinter 格式化输出 objectmapper.configure(serializationfeature.indent_output, true); // null不参与序列化 objectmapper.setserializationinclusion(jsoninclude.include.non_null); // 指定时区 objectmapper.settimezone(timezone.gettimezone("gmt+8:00")); // 日期类型字符串处理 objectmapper.setdateformat(new simpledateformat(default_date_time_format)); // java8日期日期处理 javatimemodule javatimemodule = new javatimemodule(); javatimemodule.addserializer(localdatetime.class, new localdatetimeserializer(datetimeformatter.ofpattern(default_date_time_format))); javatimemodule.addserializer(localdate.class, new localdateserializer(datetimeformatter.ofpattern(default_date_format))); javatimemodule.addserializer(localtime.class, new localtimeserializer(datetimeformatter.ofpattern(default_time_format))); javatimemodule.adddeserializer(localdatetime.class, new localdatetimedeserializer(datetimeformatter.ofpattern(default_date_time_format))); javatimemodule.adddeserializer(localdate.class, new localdatedeserializer(datetimeformatter.ofpattern(default_date_format))); javatimemodule.adddeserializer(localtime.class, new localtimedeserializer(datetimeformatter.ofpattern(default_time_format))); objectmapper.registermodule(javatimemodule); converter.setobjectmapper(objectmapper); return converter; }}
以上就是spring boot日期时间如何处理的详细内容。
其它类似信息

推荐信息