1. 发送邮件
- 邮箱设置
- 启用客户端SMTP服务
- Spring Email
- 导入 jar 包
- 邮箱参数配置
- 使用 JavaMailSender 发送邮件(MailClient类)
模板引擎
访问注册页面
- 点击顶部区域内的链接,打开注册页面。
- 提交注册数据
- 通过表单提交数据。
- 服务端验证账号是否已存在、邮箱是否已注册。
- 服务端发送激活邮件。(用户表中有激活码)
- 激活注册账号
- 点击邮件中的链接,访问服务端的激活服务。(先判断状态,再对比激活码)
3. 会话管理
- HTTP的基本性质
- HTTP是简单的
- HTTP是可扩展的
- HTTP是无状态的,有会话的
- 它不对之前发生过的请求和响应的状态进行管理。即,无法根据之前的状态进行本次的请求处理。
- Cookie
- 通过在请求和响应报文中写入Cookie信息来控制客户端的状态。
- 其会根据从服务器端发送的响应报文内的一个叫做Set-Cookie的首部字段信息,通知客户端保存Cookie。当下次客户端再往该服务器发送请求时,客户端会自动在请求报文中加入Cookie值后发送出去。
- 服务端接受客户端发送过来的Cookie后,会去检查 究竟是从一个客户端发来的连接请求,然后对比服务器上的记录,最后得到之前的状态信息。
Session
- 是JavaEE的标准,用于在服务端记录客户端信息。
- 数据存放在服务端更加安全,但是也会增加服务端的内存压力。
- 分布式部署使用session存在问题:各个服务器中的session不同步,浏览器第一次访问的session在另一台服务器上没有存储
Kaptcha
访问登录页面
- 点击顶部区域内的链接,打开登录页面。
- 登录LoginController
- 验证账号、密码、验证码。
- 验证码从session中通过属性名称获得
- 成功时,生成登录凭证,发放给客户端。
- 登录表中有用户id,登录状态和令牌以及过期时间
- 通过用户表验证密码,登录状态后,生成登录表所需的数据插入到登录表
- 将当前的令牌和过期时间放入cookie,并设置cookie的有效路径
- 失败时,跳转回登录页。
- 验证账号、密码、验证码。
退出
登录状态和非登录状态,同一个页面所展示的内容可能是不一样的。
- 拦截器示例
- 定义拦截器LoginTicketInterceptor,实现HandlerInterceptor
- 配置拦截器WebMvcConfig,为它指定拦截、排除的路径
- 拦截器应用LoginTicketInterceptor类
- 在请求开始时(preHandle方法的作用)查询登录用户(到Cookie中通过令牌查询),并将用户存入HostHolder类中,类似于session的功能(解决第5节只更改页面和数据库登录状态的情况)
- 在本次请求中持有用户数据HostHolder类,通过ThreadLocal实现线程隔离
- 为什么要使用ThreadLocal?
- 利用ThreadLocal管理登录用户信息实现随用随取
- Java中的ThreadLocal通常是在什么情况下使用的? - Java3y的回答 - 知乎
- 总结:通过session存储->service层、dao层不好通过Servlet api获得用户信息->采用ThreadLocal实现->切换线程会导致ThreadLocal中没有用户信息->HandleInterceptor类的preHandle方式实现登录时,从redis获取相应的用户信息进行存储
- 通常在项目中,用户登录后,我们会将用户的信息存到session,如果想在其它地方获取session中的用户信息,我们需要先获取HttpServletRequest,再通过request.getSession得到HttpSession,从而获取到我们想要的用户信息。
- 通常在一个大型项目中,service层和dao层都是和web层分离开来,都是单独的工程,不依赖servlet api,大家也不会为了在service层或者dao层获取登录用户信息而这么做
- 采取一种新的方法来存储用户信息——ThreadLocal。ThreadLocal就是本地线程,它是本地线程局部变量的意思,我们每个请求都会对应一个线程,这个ThreadLocal就是这个线程使用过程中的一个变量,该变量为其所属线程所有,各个线程互不影响。在一个请求中,所有调用的方法都在同一个线程中去处理,这样就实现了在任何地方都可以获取到用户信息了
- treadLocal为各个线程所私有,各线程间不共享,也互不影响,那么问题来了,我们只是在登录的时候,查询用户信息并将其放进当前线程的ThreadLocal,而后续其它请求一旦切换到别的线程,我们的功能就玩不转了,所以我们需要借助一个方法来拦截所有的后台请求(排除非必须登录才能访问的url)
- 在springMVC中,我们可以通过HandlerInterceptor来实现,定义一个类去实现这个HandlerInterceptor接口,在preHandle中去调用SessionLocal中的setUser(user)来设置用户信息
- 为什么要使用ThreadLocal?
- 在模板视图上显示用户数据
- 在请求结束时(即视图渲染完毕后)清理用户数据
7. 账号设置
- 上传文件
- 请求:必须是POST请求
- 表单:enctype=“multipart/form-data”
- Spring MVC:通过 MultipartFile 处理上传文件
- 开发步骤UserController类
- 访问账号设置页面
- 上传头像,需要修改用户表中的头像地址
- 获取头像:通过读取当前user的请求图片路径获取图片,因此在Controller层需要定义一个get请求,实现图片的回显
- 修改密码
- 请求:POST请求
- 需要实现登录拦截
开发步骤
使用拦截器
- 在方法前标注自定义注解LoginRequired注解
- 拦截所有请求,只处理带有该注解的方法LoginRequiredInterceptor类
- 在preHandle层获取到带有自定义注解的方法(通过反射),判断有没有登录,没有登录需要重定向到登录
- 配置拦截器WebMvcConfig
- 自定义注解
- 常用的元注解: @Target、@Retention、@Document、@Inherited
- 如何判断方法有该注解:(通过反射获取)
- Method.getDeclaredAnnotations ()
- Method.getAnnotation (Class annotationClass)