目录
1、后台登录和退出功能开发
1.1、需求开发
1.2、代码开发
2、完善登录功能(在未登录或其他特定情况拦截某些登录请求)
2.1、问题分析
2.2、代码开发
--数据模型(创建数据库表)
--登录页面为(http://localhost:8080/backend/page/login/login.html),浏览器打开此页面之后f12(检查)查看登录的请求头等信息
--创建实体类Employee,和employee表进行映射
--创建EmployeeMapper、EmployeeService及其实现类,EmployeeController控制器
--返回结果类R,此类是一个通用结果类,服务端响应的所有结果最终都会包装成此种类型返回给前端页面
--导入静态资源(resources中,static中时不需要配置)需创建其配置类,设置静态资源映射,此配置类需要继承WebMvcConfigurationSupport
--编写EmployeeController
核心代码(登录和退出)
@PostMapping("/login")
public R login(HttpServletRequest request, @RequestBody Employee employee){
//1、将页面提交的密码password进行md5加密处理
String password = employee.getPassword();
password = DigestUtils.md5DigestAsHex(password.getBytes());
//2、根据页面提交的用户名username查询数据库
LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.eq(Employee::getUsername,employee.getUsername());
Employee emp = employeeService.getOne(queryWrapper);
//3、如果没有查询到则返回登录失败结果
if (emp == null){
return R.error("无该用户,登录失败");
}
//4、密码比对,如果不一致则返回登录失败结果
if (!emp.getPassword().equals(password)){
return R.error("密码错误,登录失败");
}
//5、查看员工状态,如果为已禁用状态,则返回员工已禁用结果
if (emp.getStatus() == 0){
return R.error("该用户被禁用,登录失败");
}
//6、登录成功,将员工id存入Session并返回登录成功结果
request.getSession().setAttribute("employee",emp.getId());
return R.success(emp);
}
@PostMapping("/logout")
public R logout(HttpServletRequest request){
request.getSession().removeAttribute("employee");
return R.success("退出成功");
}
--用户如果不登录,直接访问系统首页面,照样可以正常访问。这种设计并不合理,我们希望看到的效果应该是,只有登录成功后才可以访问系统中的页面,如果没有登录则跳转到登录页面。
--解决方案使用过滤器或者拦截器,在过滤器或者拦截器中判断用户是否已经完成登录,如果没有登录则跳转到登录页面
思路:
--创建自定义过滤器LoginCheckFilter
--在启动类上加入注解@ServletComponentScan(保证启动时能够扫描的到过滤器)
-- 过滤器具体的处理逻辑如下:
1、获取本次请求的URI
2、判断本次请求是否需要处理
3、如果不需要处理,则直接放行
4、判断登录状态,如果已登录,则直接放行
5、如果未登录则返回未登录结果
转换如下流程图:
/**
* 设置过滤名称:filterName = "LoginCheckFilter"
* 设置过滤路径:urlPatterns = "/*"
* 检查用户是否已经完成登录
*/
@Slf4j
@WebFilter(filterName = "LoginCheckFilter",urlPatterns = "/*")
public class LoginCheckFilter implements Filter { //自定义过滤器需要实现Filter
//路径匹配器,支持通配符,后面需要用到这个判断两次路径是否相同
public static final AntPathMatcher PATH_MATCHER = new AntPathMatcher();
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
//强制类型转换
HttpServletRequest request = (HttpServletRequest) servletRequest;
HttpServletResponse response = (HttpServletResponse)servletResponse;
//1、获取本次请求的URI
String requestURI = request.getRequestURI();
//定义不需要处理的请求路径
String[] urls = new String[]{
"/employee/login",
"/employee/logout",
"/backend/**",
"/front/**"
};
//2、判断本次请求是否需要处理
boolean check = check(urls, requestURI);
//3、如果不需要处理,则直接放行
if (check){
log.info("不需要处理,直接放行{}",requestURI);
//利用filterChain进行放行
filterChain.doFilter(request,response);
return;
}
//4、判断登录状态,如果已登录,则直接放行
if (request.getSession().getAttribute("employee")!=null){
log.info("用户已登录,id为{}",request.getSession().getAttribute("employee"));
filterChain.doFilter(request,response);
return;
}
//5、如果未登录则返回未登录结果,通过输出流方式向客户端页面响应数据
log.info("用户未登录");
//此返回至客户端的数据NOTLOGIN需要跟前端保持一致,利用这个在前端实现页面跳转
response.getWriter().write(JSON.toJSONString(R.error("NOTLOGIN")));
return;
}
/**
* 利用路径匹配器判断两次路径是否相同
* @param urls
* @param requestURI
* @return
*/
public boolean check(String[] urls,String requestURI){
//利用for循环遍历urls中的数据到url中,然后用PATH_MATCHER判断url和客户端请求路径是否一致
for (String url : urls) {
boolean match = PATH_MATCHER.match(url, requestURI);
if (match){
return true;
}
}
return false;
}
}