三、用户登录功能的实现
用户登录
功能分析
用户进入登陆页面,输入用户名和密码,点击登录按钮,向后台程序发送请求,后台根据用户信息在数据库中进行查找,如果用户名和密码均正确,则会跳转到对应的主页面,即index.html
持久层
规划要执行的SQL语句
分析:一般逻辑是根据用户名查询数据库返回用户记录给业务层,由于密码存储一般是经过加密后的数据,数据库中与用户输入一般不一致,所以密码等其他信息的校验一般放在业务层去进行
1 | select * from t_user where username=?; |
相关持久层的功能在用户注册模块已经实现
业务层
规划异常
密码错误异常
用户名正确,密码错误引发的异常,PasswordNotMatchException
1 | package com.bang.store.service.ex; |
用户名不存在异常
用户名数据库中不存在所引发的异常,UsernameNotFoundException
1 | package com.bang.store.service.ex; |
设计接口和抽象方法
直接在IUserService
接口中编写登录方法login(String username,String password)
如果登录成功,将用户数据对象需要作为方法返回值返回
状态管理:将相关数据保存在cookie或者session中,可以避免重复度很好的数据多次频繁操作数据库获取
1 | /** |
接口实现类
1 | public User login(String username, String password) { |
控制层
处理异常
根据业务层抛出异常,在统一异常处理基类中做出对应的处理
1 | else if (e instanceof UsernameNotFoundException) { |
设计请求
1 | 请求路径:/user/login |
处理请求
在UserController
类中编写对应的请求处理方法
1 |
|
前端页面
在login.html
页面中找到对应表单,在表单中找到登录按钮,将登录按钮与指定时间绑定,按钮点击,向后端指定程序发送请求
1 | <script> |
用户会话Session
session对象主要存储在服务器端,可以用于保存服务器的临时数据,其在整个项目中都可以被访问,可以在不同模块之间进行数据共享。
对于用户登录功能,可以将用户当前首次登录输入的信息数据存储在session对象中,供整个会话期间,其他模块共用。
1 | //session对象存储数据 |
可能在一个项目中,多次用到session对象存储数据或者从session对象中读取数据,为了减少代码冗余,应该将这两个操作封装到函数中
可以封装到工具类,但是由于这两个操作只会在控制层使用,而本项目控制层存在基类,所以将该方法定义在控制层基类BaseController
中
由于存储操作要视具体情况而定,所以只封装从session对象读取数据功能
1 | /** |
相关位置将数据存取到session对象中
在UserController
类中的login
函数中将相关数据存取到session对象
1 |
|
用户登录拦截器
拦截器
会首先将用户所有请求统一拦截到拦截器中进行处理,所以可以到拦截器中自定义过滤规则,达到拦截请求、过滤响应的目的
比如:对于当前项目(商城系统),访问其他页面会全部拦截到拦截器,判断用户是否登录,如果没有则统一会打开login.html
用户登录页面,打开其他页面,可以使用重定向或者请求转发技术来完成
推荐使用重定向技术,如果两个模块不在同一个服务器上,转发可能会出现错误
SpringBoot中如何拦截器的使用
SpringMVC提供了一个HandleInterceptor
接口,用于表示拦截器
使用步骤
自定义一个类,实现
HandleInterceptor
接口,项目一般会将所有拦截器统一放在一个目录下,本项目中统一放在com.bang.store.interceptor
包下1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50package com.bang.store.interceptor;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
/**
* 定义用户登录拦截器
*/
public class LoginInterceptor implements HandlerInterceptor {
//在所有请求处理方法之前被调用执行,即在请求到达Dispatcher中央处理器之前
//拦截器的重点关注位置
/**
* 功能:检测session对象中是否含有uid数据,如果有则放行请求,否则重定向到用户登录界面
* @param request 请求对象
* @param response 响应对象
* @param handler 处理器
* @return 如果返回值为true,正常放行;如果为false,则表示拦截,不放行,
* @throws Exception
*/
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
//获取session对象
HttpSession session = request.getSession();
//获取uid数据
Object uid = session.getAttribute("uid");
if(uid==null){ //表明用户没有登录
response.sendRedirect("/web/login.html"); //重定向到登录页面
return false; //拦截请求
}
return true; //用户登录后则直接放行
}
//请求执行后被调用
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
HandlerInterceptor.super.postHandle(request, response, handler, modelAndView);
}
//所有关联操作完成之后调用
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
HandlerInterceptor.super.afterCompletion(request, response, handler, ex);
}
}注册拦截器
添加白名单与黑名单,即当前拦截器只对那些请求起作用、对哪些请求不起作用
比如:注册、登录页面不能够被拦截,否则任何界面都无法进入,造成死循环
拦截器注册操作
借助
WebMVCConfigure
接口,可以将用户定义的拦截器进行注册,才能使拦截器生效1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35package com.bang.store.configure;
import com.bang.store.interceptor.LoginInterceptor;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import java.util.ArrayList;
import java.util.List;
//注解,让SpringBoot识别
public class LoginInterceptorConfigure implements WebMvcConfigurer {
/**
* 添加拦截器
* @param registry
*/
public void addInterceptors(InterceptorRegistry registry) {
//实例化自定义拦截器
HandlerInterceptor loginInterceptor = new LoginInterceptor();
//配置白名单
List<String> whiteList = new ArrayList<String>();
whiteList.add("/web/login.html");
whiteList.add("/web/register.html");
whiteList.add("/web/product.html");
whiteList.add("/index.html");
//注册拦截器
registry.addInterceptor(loginInterceptor)
.addPathPatterns("/web/**") //配置黑名单,即拦截器要拦截的路径
.excludePathPatterns(whiteList); //配置白名单,即拦截器不拦截的路径
}
}