使用Hutool工具类中的BeanUtil.fillBeanWithMap方法报错`DateException`

使用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!

    使用Hutool工具类中的BeanUtil.fillBeanWithMap方法报错`DateException`_第1张图片

    使用Hutool工具类中的BeanUtil.fillBeanWithMap方法报错`DateException`_第2张图片

  • 问题原因

    原因很简单,BeanUtil.fillBeanWithMap底层对于时间类型的格式转换,默认是采用yyyy-MM-dd HH:mm:ss,而我存入Redis的时间格式直接采用了EEE MMM d HH:mm:ss zzz yyyy

    使用Hutool工具类中的BeanUtil.fillBeanWithMap方法报错`DateException`_第3张图片

    这就导致在执行BeanUtil.fillBeanWithMap这行代码时,Hutool底层对日期类型的数据进行格式化,导致格式化失败,从而抛出DateException异常

  • 问题解决

    通过上面的原因分析,我们可以得出这个问题就是日期格式化的问题,既然原因我们知道了,那么解决起来就会很简单了

    • 方案一:从数据写入角度,我们可以在写入Redis的时候,对所有的日期类型的数据进行一个格式化,将EEE MMM d HH:mm:ss zzz yyyy格式化yyyy-MM-dd HH:mm:ss类型,这样在将Map转Bean就不报DateException错误了

      具体实现措施:

      1. 在Redis的配置类中配置一个全局的日期格式化类,所有写入Redis的Date数据在序列化的时候都会格式化为yyyy-MM-dd HH:mm:ss类型(相关具体步骤可以参考文末给出的链接)

      2. 在Bean转Map的时候,手动编码格式化日期(我所使用的,能够成功解决)。上面那种措施我试了,发现不行,因为我是先将Bean转成Map,这样在序列化的时候,无法识别到当前数据类型是Date,因为都变成了Object,所以在直接在Bean转Map的时候手动格式化,具体代码如下:

            /**
             * 将Bean转成Map
             *
             * @param object 目标Bean
             * @param 
             * @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,成功解决,

使用Hutool工具类中的BeanUtil.fillBeanWithMap方法报错`DateException`_第4张图片

使用Hutool工具类中的BeanUtil.fillBeanWithMap方法报错`DateException`_第5张图片

参考文章

  • Redis序列化存储及日期格式的问题处理

你可能感兴趣的:(Bug记录,bug,java)