周末没项目写,看一下黑马怎么教Redis的
一:短信登录功能
这个功能的实现应该有几个比较重要的点:
1:根据用户的手机号生成验证码,并且发送给用户。 需要注意这个地方用户手机号是否合理,就比如不存在这个手机号,或者是判断输入错误。
用工具类检测手机号是否符合
生成验证码也是用工具类生成即可。
2:生成验证码,并把验证码保存在本地,用于本地登录。所以把验证码存到session里面。
session里面一般是存键值对,一个key和存的code。
什么是session
session在网络应用中称为“会话控制”,是服务器为了保存用户状态而创建的一个特殊的对象。简而言之,session就是一个对象,用于存储信息。
在访问服务器的时候,会存在这样一个流程:先判断这个用户是否有sessionID,如果没有,那么就创建一个sessionID并且给这个用户在Tomcat(服务器)上生成一个session空间。如果有,那么就getSessionID,找到在服务器里面存的那个session空间。(企业里面一般把session放在Redis缓存里面做一个持久化,毕竟每个用户每次登录都会进行这个步骤,还是很频繁的)
而cookie呢,是保存在用户这一端的内容,他是一个小型的文本文件,一般用于存放用户喜好和sessionID,相当于给session起一个保护作用。并附带需要的信息。
3:短信验证码登录、注册。这个要注意的是用户端提供手机号和验证码,然后我们根据手机号和携带的sessionid去空间里面看是否符合预期的验证码,然后判断用户是否存在,存在就登录,不存在就注册。同时把用户保存到session。
传的是用户DTO类和一个session值,session里面可以去查他的验证码。
4:检验登录状态。一些功能需要登录才能使用,用户给的请求cookie里面就携带了sessionID,然后就看看这个是否有权限。而有很多业务都需要这个验证,所以可以中间加一层拦截器,过了拦截器就啥都可以干,然后把拦截通过的信息存放在一个本地缓存里面,黑马里面放在ThreadLocal里面,就是在服务端的session里面查一下这个用户有没有权限,有的话就在客户端本地放一个临时的缓存,存这个用户有权限,之后就不用到服务端去调取查询session也可以访问需要登录的业务了。保存在本地的方法:
添加拦截器后添加拦截路径(可以用通配符)
同时为什么要用本地线程ThreadLocal,这篇文章感觉讲的不错:为什么要使用ThreadLocal
其中说的ThreadLocal可以解决封闭性问题,和HTTP把每次请求都分配一个独立线程相呼应。
同时如果不设置本地缓存,那么每次都要申请查询sessionID就很麻烦了。
5:其中提到的MyBtis的自动单表查询:
继承了这个之后MyBatis会自动根据传入的User对象来解析下一步的查询
然后User对象里面写了表名,嗯,但我们公司好像不是这么干的,我们是自动生成了单表查询的类,Server层好像没有继承,后天去公司在看看。
二:session存在的问题(Redis解决)
分布式环境下的Session失效问题
- 默认Session存储:传统Session数据存储在单机服务器内存中(如Tomcat内存)。当用户请求通过负载均衡器(如Nginx)分发到不同服务器时,后续请求可能落到未存储该Session的服务器上,导致无法获取用户状态
如果每次session都同步到每个Tomcat里面(session拷贝),但这样会导致内存空间浪费,并且拷贝的时候会出现数据不一致的情况(拷贝的时候有人来访问了)
因此引出了需要的解决方案:这个功能需要——1:key-value 2:内存搜索快 3:可以分布式存储(数据共享)
因此用Redis来存:
Redis里面用什么存key和value:
Redis的内存空间是共享的,所以key不能一样,因此要有一个生成token的功能。value在session里面是用String存一个6个数字的String,但是在Redis里面要存一个对象、所以考虑用JSON存String或者用hash:hash里面又是一个kV关系,
hash优点:可以单独改field和value,存的内容比JSON少。所以建议用hash。
而为什么用token,因为之前session里面只携带手机号,但是可以通过sessionID来查询Tomcat里面的session空间,所以要加一个能够让Tomcat识别用户的值,就从携带sessionID变成携带一个token了,这样token既有sessionID的作用还有手机号的作用。
创建token并保存到Redis里面,同时设置过期时间:
有的时候一些类用Resource,一些是用构造方法,这个的区分在于:
一、需要交给Spring容器管理的类
功能类(无状态、可共享)
- 特点:无实例变量或状态信息,方法行为仅依赖参数,生命周期与应用一致。
- 场景:
- Controller(如
OrderController
处理HTTP请求)- Service(如
PaymentService
封装业务逻辑)- DAO/Repository(如
UserRepository
操作数据库)- 注解:
@Controller
、@Service
、@Repository
(语义化派生注解,本质仍是@Component
)- 通用工具类可用
@Component
(如DiscountCalculator
)配置类
- 特点:定义Bean的创建逻辑(如第三方库集成)。
- 场景:
- 数据库连接池配置(
DataSource
)- 线程池配置(
ThreadPoolTaskExecutor
)- 注解:
@Configuration
+@Bean
二、不需要交给容器管理的类
状态类(有状态、不可共享)
- 特点:保存用户或请求特定数据,生命周期短暂。
- 场景:
- 实体类(如
UserInfo
存储用户信息)- DTO/VO(数据传输对象,如
OrderDTO
)静态工具类
- 特点:仅包含静态方法,无需实例化。
- 场景:
- 字符串处理工具类(如
StringUtils
)- 数学计算工具(如
MathHelper
)手动创建的临时对象
- 特点:动态生成,依赖运行时条件。
- 场景:
- 线程局部变量(
ThreadLocal
)- 工厂模式生成的实例
如何刷新:
重新再设置一次就可以了。
到这里基本就写完了一个注册流程。