# 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、出错原因:

# 3、如何解决?
# 方案一:可以不使用 StringRedisTemplate。使用 RedisTemplate<key,value>。
# 方案二:不使用 hutool 工具包,自己创建新的 Map,类型都是 String 类型。
# 方案三:继续使用 hutool 工具包,并转换一下类型。
在 CopyOptions 中有个方法用于转换类型的:

修改后的代码:
@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); | |
} |