redis_点评详解(03.短信登录—基于Redis实现共享session登录)
1、WvcConfig(SpringMVC拦截器配置类)Configuration public class WvcConfig implements WebMvcConfigurer { Resource private StringRedisTemplate stringRedisTemplate; Override public void addInterceptors(InterceptorRegistry registry) { //registry是拦截器的注册器,在这里面配置拦截器 registry.addInterceptor(new LoginInterceptor(stringRedisTemplate)) .excludePathPatterns( //不应该被拦截的一些功能 ///shop/**指所有shop有关的请求都不用拦截 /shop/**, //...... ); } }一、Configuration所属包org.springframework.context.annotation作用标记当前类为Spring 配置类相当于传统 Spring 的 XML 配置文件。功能Spring 启动时会自动扫描并加载该类完成拦截器、Bean、组件等的注册。场景用于配置拦截器、MVC、数据库、线程池等。二、Resource所属包javax.annotation作用依赖注入注解从 Spring 容器中自动获取已创建好的对象并赋值给当前变量。功能不需要new对象由 Spring 自动注入、管理、初始化。// 省略了自己手动 new 对象省略了管理对象的创建、销毁、自己找依赖、组装对象private StringRedisTemplate stringRedisTemplate new StringRedisTemplate();与 Autowired 区别Spring 只认类型是 StringRedisTemplate不管你变量名叫aaa、bbb、redisTemplate都能自动注入成功。三、那么Autowired 又是什么1、基本定义Autowired 是 Spring 官方的依赖注入注解作用和 Resource 一样自动从 Spring 容器注入 Bean不用手动 new。1、Autowired 按类型装配是什么意思不看变量名只看变量的「数据类型」Spring 会去容器里找有没有这个类型的对象有就直接赋值给你写法 1变量名随便写照样能注入Autowired private StringRedisTemplate aaa;Spring 只认类型是 StringRedisTemplate不管你变量名叫aaa、bbb、redisTemplate都能自动注入成功。四、implements WebMvcConfigurer一、基本介绍WebMvcConfigurer是Spring MVC提供的回调配置接口。包路径org.springframework.web.servlet.config.annotation.WebMvcConfigurer作用用来自定义 SpringMVC 底层配置不破坏 SpringBoot 自动配置只做扩展增强。二、为什么要实现它SpringBoot 已经帮我们默认配好了 MVC 规则如果我们想自己改、自己加配置就需要配置类上加Configuration实现WebMvcConfigurer重写它提供的方法做自定义配置WebMvcConfigurer 是 SpringMVC 扩展配置接口配置类实现它就能自定义拦截器、跨域、静态资源等 MVC 配置。最常用核心方法addInterceptors()注册自定义拦截器你现在登录拦截器就是用这个addCorsMappings()配置跨域请求addResourceHandlers()配置静态资源映射configureMessageConverters()配置消息转换器、统一返回格式五、registry.addInterceptor(拦截器).excludePathPatterns(白名单路径);1、InterceptorRegistry registry 是什么是固定的吗这是SpringMVC 规定死的方法参数不能改名字、不能改类型。完全固定、写死。registry 拦截器注册器可以把它理解成一个专门用来登记、注册拦截器的管理员你要添加拦截器必须通过它。2、registry.addInterceptor(...)是什么固定吗固定写法作用向 SpringMVC 注册一个拦截器。告诉 Spring我要启用这个拦截器3.new LoginInterceptor(stringRedisTemplate)这是自己写的拦截器因为拦截器需要用 Redis 校验登录所以把stringRedisTemplate传给它。4、.excludePathPatterns(...) 是什么固定吗固定写法作用设置白名单 → 这些路径不拦截、直接放行整体三连语法固定死的格式registry.addInterceptor(拦截器).excludePathPatterns(白名单路径);2、ServiceImpl//保存验证码到redis stringRedisTemplate.opsForValue().set(LOGIN_CODE_KEYphone,code,LOGIN_CODE_TTL, TimeUnit.MINUTES);//从redis中获取验证码并校验 get(key)从 Redis 根据 key 获取 value。 String cacheCode stringRedisTemplate.opsForValue().get(LOGIN_CODE_KEYphone);一、stringRedisTemplate.opsForValue().set(key, value, 过期时间, 时间单位);opsForValue()表示操作 Redis 的 String 字符串类型set(...)向 Redis 存数据相当于 Redis 命令set key valueget(key)从 Redis 根据 key 获取 value。//7.存在-保存用户信息到redis中 //7.1生成一个随机token作为登录令牌 String token UUID.randomUUID().toString(true); //7.2将User对象转为Hashmap存储 UserDTO userDTO BeanUtil.copyProperties(user, UserDTO.class); MapString,Object userMapBeanUtil.beanToMap(userDTO,new HashMap(), CopyOptions.create()//作用创建一个 “转换规则” 对象 .setIgnoreNullValue(true)// 忽略空值开启 “忽略 null 值” 功能 .setFieldValueEditor((fieldName,fieldValue) - fieldValue.toString())); // 所有值转字符串 /*第一步User → UserDTO 第二步UserDTO → Map 原因Redis 的 Hash 结构只能存储 Map 格式数据不能直接存 Java 对象*/ //7.3存储 拼接Redis的Key固定前缀 token String tokenKeyLOGIN_USER_KEYtoken; stringRedisTemplate.opsForHash().putAll(tokenKey,userMap); /*putAll()把用户信息 Map一次性写入 Redis*/ //7.4设置token有效期 stringRedisTemplate.expire(tokenKey,LOGIN_USER_TTL,TimeUnit.MINUTES);二、Stringtoken UUID.randomUUID().toString(true);作用生成一个唯一、随机、不可伪造的登录令牌UUID.randomUUID()生成全球唯一的随机字符串toString(true)生成不带横杠的简洁字符串如a1b2c3d4e5f6是Hutool 工具包对 UUID 的增强方法 参数true→ 去掉横杠生成紧凑字符串更简洁、更方便、避免特殊符号引发问题三、UserDTO userDTO BeanUtil.copyProperties(user, UserDTO.class);BeanUtil.copyProperties( 源对象, 目标对象.class );对象属性拷贝把源对象里所有同名属性自动复制到目标对象中。User 里有敏感信息密码、创建时间、更新时间不能直接存入 Redis。UserDTO 只保留id、昵称、手机号、头像实现 数据脱敏 / 安全过滤。为什么UserDTO.class要加 .classUserDTO是类名只是名字UserDTO.class是这个类的「字节码对象 / 类型对象」代表这个类本身的类型。类名只是名称不能作为类型参数加 .class 拿到类的字节码对象用来告诉方法要转换的目标类型。四、BeanUtil.beanToMap (对象目标 Map, 转换规则)CopyOptions.create()创建转换规则配置setIgnoreNullValue(true)忽略null值避免脏数据存入 RedissetFieldValueEditor(...)作用自定义字段值编辑器//上述复杂的一系列方法相当于下面的 MapString, Object userMap new HashMap();// 手动放值 userMap.put(id, userDTO.getId().toString()); userMap.put(nickName, userDTO.getNickName()); // 如果字段不为null才放进去 if (userDTO.getPhone() ! null) { userMap.put(phone, userDTO.getPhone()); }