# 1、问题描述

我在使用 StringRedisTemplate 来存储对象信息的时候,我使用的是 hash 结构,在运行的同时报错:

java.lang.ClassCastException: java.lang.Long cannot be cast to java.lang.String
at org.springframework.data.redis.serializer.StringRedisSerializer.serialize(StringRedisSerializer.java:36) ~[spring-data-redis-2.7.12.jar:2.7.12]
at org.springframework.data.redis.core.AbstractOperations.rawHashValue(AbstractOperations.java:186) ~[spring-data-redis-2.7.12.jar:2.7.12]
at org.springframework.data.redis.core.DefaultHashOperations.putAll(DefaultHashOperations.java:209) ~[spring-data-redis-2.7.12.jar:2.7.12]
at com.hmdp.service.impl.UserServiceImpl.login(UserServiceImpl.java:97) ~[classes/:na]
at com.hmdp.service.impl.UserServiceImpl$$FastClassBySpringCGLIB$$9cac0aa5.invoke(<generated>) ~[classes/:na]
at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:218) ~[spring-core-5.3.27.jar:5.3.27]
at org.springframework.aop.framework.CglibAopProxy.invokeMethod(CglibAopProxy.java:386) ~[spring-aop-5.3.27.jar:5.3.27]
at org.springframework.aop.framework.CglibAopProxy.access$000(CglibAopProxy.java:85) ~[spring-aop-5.3.27.jar:5.3.27]
at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:704) ~[spring-aop-5.3.27.jar:5.3.27]
at com.hmdp.service.impl.UserServiceImpl$$EnhancerBySpringCGLIB$$c7a7fed4.login(<generated>) ~[classes/:na]

意思是无法将 Long 类型转换为 String 类型,这是为什么呢?

# 2、出错原因:

image.png

# 3、如何解决?

# 方案一:可以不使用 StringRedisTemplate。使用 RedisTemplate<key,value>。

# 方案二:不使用 hutool 工具包,自己创建新的 Map,类型都是 String 类型。

# 方案三:继续使用 hutool 工具包,并转换一下类型。

image.png 在 CopyOptions 中有个方法用于转换类型的:

image.png

修改后的代码:

@Override
    public Result login(LoginFormDTO loginForm, HttpSession session) {
        // 1、校验手机号、验证码
        if (!isPhoneInvalid(loginForm.getPhone())) {
            return Result.fail("手机号格式不正确");
        }
        String code = stringRedisTemplate.opsForValue().get(LOGIN_CODE_KEY + loginForm.getPhone());
        if (code == null || !code.equals(loginForm.getCode())) {
            return Result.fail("验证码不正确");
        }
        // 2、 根据手机号查询用户
        User user = getOne(new LambdaQueryWrapper<User>().eq(User::getPhone, loginForm.getPhone()));
        // 2.1 用户是否存在,不存在则创建新用户
        if (user == null) {
            user = createUserWithPhone(loginForm.getPhone());
        }
        // 3. 生成 token
        String token = UUID.randomUUID().toString(true);
        //4. 保存用户信息到 redis
        //4.1 将用户转为 hash 格式
        UserDTO userDTO = BeanUtil.copyProperties(user, UserDTO.class);
        //4.2 存储 ,转换为 map 的时候 stringRedisTemplate 要求必须全部都是 String 类型的
        Map<String, Object> userMap = BeanUtil.beanToMap(userDTO, new HashMap<>(),
                CopyOptions.create()
                        .setIgnoreNullValue(true)
                        .setFieldValueEditor((filedName, filedValue) -> filedValue.toString()));
        String tokenKey = LOGIN_USER_KEY + token;
        stringRedisTemplate.opsForHash().putAll(tokenKey, userMap); // 存 map 是不允许存有效期的,我需要先存后设置有效期 StringRedisTemplate 要求存储的值必须都是 String 类型的
        // 设置有效期
        stringRedisTemplate.expire(tokenKey, LOGIN_USER_TTL, TimeUnit.MINUTES);
        //5、返回 token
        return Result.ok(token);
    }