使用Hutool工具类中的BeanUtil.fillBeanWithMap方法报错DateException
-
问题背景
在实现登录功能时,我先将用户信息存入Redis中,然后再获取用户信息的时候,又取出来。我存入Redis的用户信息是Hash格式的,所以取出来的时候,需要通过Map转Bean的方式进行转换,但是在转换的过程中发生了报错:
org.springframework.web.util.NestedServletException: Request processing failed; nested exception is cn.hutool.core.date.DateException: Parse ["Sat Jun 10 20:26:54 CST 2023"] with format [EEE MMM dd HH:mm:ss zzz yyyy] error!
-
问题原因
原因很简单,BeanUtil.fillBeanWithMap底层对于时间类型的格式转换,默认是采用
yyyy-MM-dd HH:mm:ss
,而我存入Redis的时间格式直接采用了EEE MMM d HH:mm:ss zzz yyyy
这就导致在执行
BeanUtil.fillBeanWithMap
这行代码时,Hutool底层对日期类型的数据进行格式化,导致格式化失败,从而抛出DateException
异常 -
问题解决
通过上面的原因分析,我们可以得出这个问题就是日期格式化的问题,既然原因我们知道了,那么解决起来就会很简单了
-
方案一:从数据写入角度,我们可以在写入Redis的时候,对所有的日期类型的数据进行一个格式化,将
EEE MMM d HH:mm:ss zzz yyyy
格式化yyyy-MM-dd HH:mm:ss
类型,这样在将Map转Bean就不报DateException
错误了具体实现措施:
-
在Redis的配置类中配置一个全局的日期格式化类,所有写入Redis的Date数据在序列化的时候都会格式化为
yyyy-MM-dd HH:mm:ss
类型(相关具体步骤可以参考文末给出的链接) -
在Bean转Map的时候,手动编码格式化日期(我所使用的,能够成功解决)。上面那种措施我试了,发现不行,因为我是先将Bean转成Map<Object,Object>,这样在序列化的时候,无法识别到当前数据类型是Date,因为都变成了Object,所以在直接在Bean转Map的时候手动格式化,具体代码如下:
/** * 将Bean转成Map<String, Object> * * @param object 目标Bean * @param <T> * @return */ public static <T> Map<String, Object> beanToMap(T object) { return BeanUtil.beanToMap(object, new HashMap<>(), CopyOptions.create().setIgnoreNullValue(true) .setFieldValueEditor((fieldName, fieldValue) -> Optional.ofNullable(fieldValue) .map(value -> { if (value instanceof Date) { // 如果是Date类型,就格式化为 yyyy-MM-dd HH:mm:ss return DateUtil.formatDateTime((Date) value); } return value.toString(); }) .orElse(null))); }
如果你存入Redis的数据类型是String不是Hash就可以尝试使用措施一
-
-
方案二:从数据读取角度,我们通过从Redis中读取数据,然后直接使用
BeanUtil.fillBeanWithMap
将读取到的Map转成Bean,问题核心是fillBeanWithMap
不支持格式化EEE MMM d HH:mm:ss zzz yyyy
,既然你不支持,那我就自己写一个工具类,用于将Map转成Bean,同时支持EEE MMM d HH:mm:ss zzz yyyy
格式的日期。这种方式理论上肯定是可行的,我也让GPT写了个工具类,并成功测试成功了,但是结果不太理想
-
我采用方案一的措施2,成功解决,
参考文章:
- Redis序列化存储及日期格式的问题处理