Spring Boot拦截器
Spring MVC 中提供了拦截器功能,可以根据 URL 对请求进行拦截,主要应用于登陆校验、权限验证、乱码解决、性能监控和异常处理等功能上。Spring Boot 同样提供了拦截器功能。
而在 Spring Boot 项目中,使用拦截器功能需要以下 3 步即可:
- 定义拦截器;
- 注册拦截器;
- 指定拦截规则(如果是拦截所有,静态资源也会被拦截)
一、定义拦截器
在 Spring Boot 中定义拦截器比较简单,只需要创建一个拦截器类,并实现 HandlerInterceptor 接口即可。HandlerInterceptor 接口中定义以下 3 个方法,如下表。
| 返回值类型 | 方法声明 | 描述 |
|---|---|---|
| boolean | preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) | 该方法在控制器处理请求方法前执行,其返回值表示是否中断后续操作,返回 true 表示继续向下执行,返回 false 表示中断后续操作。 |
| void | postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) | 该方法在控制器处理请求方法调用之后、解析视图之前执行,可以通过此方法对请求域中的模型和视图做进一步修改。 |
| void | afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) | 该方法在视图渲染结束后执行,可以通过此方法实现资源清理、记录日志信息等工作。 |
以 springboot08 项目为例,在 com.augus.interceptors中创建一个名为 LoginInterceptor 的拦截器类,对登陆进行拦截,代码如下。
package com.augus.interceptors; import lombok.extern.slf4j.Slf4j; import org.springframework.web.servlet.HandlerInterceptor; import org.springframework.web.servlet.ModelAndView; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; @Slf4j //创建拦截器类 public class LoginInterceptor implements HandlerInterceptor { @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { //获取session域中登录的用户对象 Object loginUser = request.getSession().getAttribute("loginUser"); //如果为空,则表示未登录 if(loginUser == null){ //未登录,则返回登录页面 request.setAttribute("msg","您没有权限进行此操作,请先登录"); /*request.getRequestDispatcher("/toLogin").forward(request, response); * 1、属于转发,也是服务器跳转,相当于方法调用,在执行当前文件的过程中转向执行目标文件,两个文件(当前文件和目标文件)属于同一次请求,前后页共用一个request,可以通过此来传递一些数据或者session信息,request.setAttribute()和request.getAttribute()。 * 2、在前后两次执行后,地址栏不变,仍是当前文件的地址。 * 3、不能转向到本web应用之外的页面和网站,所以转向的速度要快。 * 4、URL中所包含的“/”表示应用程序(项目)的路径。 * */ request.getRequestDispatcher("/user/login").forward(request, response); return false; }else{ //登录后的就放行 return true; } } @Override public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { log.info("postHandle执行{}", modelAndView); } @Override public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { log.info("afterCompletion执行异常{}", ex); } }
二、注册拦截器
在com.augus.interceptors包下创建一个实现了 WebMvcConfigurer 接口的配置类(使用了 @Configuration 注解的类),重写 addInterceptors() 方法,并在该方法中调用 registry.addInterceptor() 方法将自定义的拦截器注册到容器中。
package com.augus.interceptors; import org.springframework.context.annotation.Configuration; import org.springframework.web.servlet.config.annotation.InterceptorRegistration; import org.springframework.web.servlet.config.annotation.InterceptorRegistry; import org.springframework.web.servlet.config.annotation.ViewControllerRegistry; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; @Configuration public class MyMvcConfig implements WebMvcConfigurer { @Override public void addInterceptors(InterceptorRegistry registry) { /* addPathPatterns("/**") :表示拦截所有的请求,包括静态资源的请求 addPathPatterns("/**") */ //注册拦截器 registry.addInterceptor(new LoginInterceptor()).addPathPatterns("/**") .excludePathPatterns("/", "/login", "/user/main", "/user/login", "/user/doLogin","/css/**", "/images/**", "/js/**", "/fonts/**"); } @Override public void addViewControllers(ViewControllerRegistry registry) { //当访问 “/” 时,直接跳转到登陆页面 registry.addViewController("/").setViewName("/user/login"); } }
三、指定拦截规则
修改 MyMvcConfig 配置类中 addInterceptors() 方法的代码,继续指定拦截器的拦截规则,代码如下。
package com.augus.interceptors; import org.springframework.context.annotation.Configuration; import org.springframework.web.servlet.config.annotation.InterceptorRegistry; import org.springframework.web.servlet.config.annotation.ViewControllerRegistry; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; @Configuration public class MyMvcConfig implements WebMvcConfigurer { @Override public void addInterceptors(InterceptorRegistry registry) { /* addPathPatterns("/**") :表示拦截所有的请求,包括静态资源的请求 addPathPatterns("/**") */ //注册拦截器 registry.addInterceptor(new LoginInterceptor()).addPathPatterns("/**") .excludePathPatterns("/", "/login", "/user/login", "/user/doLogin","/css/**", "/images/**", "/js/**", "/fonts/**"); } @Override public void addViewControllers(ViewControllerRegistry registry) { //当访问 “/” 时,直接跳转到登陆页面 registry.addViewController("/").setViewName("/user/login"); } }
在指定拦截器拦截规则时,调用了两个方法,这两个方法的说明如下:
- addPathPatterns:该方法用于指定拦截路径,例如拦截路径为“/**”,表示拦截所有请求,包括对静态资源的请求。
- excludePathPatterns:该方法用于排除拦截路径,即指定不需要被拦截器拦截的请求。
四、案例解析:拦截器实现登录功能验证
1.需求说明
从表中查询出来数据,进行登录操作的拦截

2.搭建springboot项目
我这里就是基于之前测试打包的那个springboot08模块实现的,使用 thymeleaf 模板技术实现,利用上面实现的拦截器完成
3.在com.augus.pojo包中创建User表实体类
package com.augus.pojo; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; import java.io.Serializable; @AllArgsConstructor @NoArgsConstructor @Data public class User implements Serializable { private Integer uid; private String username; private String password; }
4.在resources目录中的mybatis包中创建 UserMapper.xml,内容如下:
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <mapper namespace="com.augus.mapper.UserMapper"> <!--查询所有的员工信息--> <select id="findByUserName" resultType="user"> select * from user where username = #{username} </select> </mapper>
5.在com.augus.mapper包中创建 UserMapper接口,内容如下:
package com.augus.mapper; import com.augus.pojo.User; import org.apache.ibatis.annotations.Mapper; @Mapper public interface UserMapper { User findByUserName(String username); }
6.在com.augus.service包
创建接口 UserService,内容如下:
package com.augus.service; import com.augus.pojo.User; public interface UserService { User findByUserName(String username); }
在service包下创建impl包,存放实体类:
package com.augus.service.impl; import com.augus.mapper.UserMapper; import com.augus.pojo.User; import com.augus.service.UserService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; @Service public class UserServiceImpl implements UserService { @Autowired private UserMapper userMapper; @Override public User findByUserName(String username) { return userMapper.findByUserName(username); } }
7.在com.augus.controller包下创建 LoginController 控制器
package com.augus.controller; import com.augus.pojo.User; import com.augus.service.UserService; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; import javax.servlet.http.HttpSession; import java.util.Map; @Slf4j @Controller @RequestMapping("/user") public class LoginController { @Autowired private UserService userService; @RequestMapping("/login") public String userLogin(){ return "login"; } @RequestMapping("/doLogin") public String doLogin(User user, Map<String,Object> map, HttpSession session){ //根据用户用户名查询用户信息 User userQuery = userService.findByUserName(user.getUsername()); if(userQuery != null && userQuery.getPassword().equals(user.getPassword())){ //将登录的用户信息方到session域中 session.setAttribute("loginUser", user); log.info("登陆成功,用户名:" + user.getUsername()); //防止重复提交使用重定向 return "redirect:/user/main"; }else { map.put("msg", "用户名或密码错误"); log.error("登录失败"); return "login"; } } @RequestMapping("/main") public String main(){ return "main"; } }
8.在resources下的templates下创建前端页面
8.1.创建login.html,代码为:
<!DOCTYPE html> <html lang="en" xmlns:th="http://www.thymeleaf.org"> <head> <meta charset="UTF-8"> <title>hi</title> </head> <body> <form th:action="@{/user/doLogin}" method="post"> <table style="margin: auto"> <tr> <td th:if="${not #strings.isEmpty(msg)}" colspan="2" align="center"> <p style="color: red;margin: auto" th:text="${msg}"></p> </td> </tr> <tr> <td>用户名:</td> <td><input type="text" name="username" required><br></td> </tr> <tr> <td>密码:</td> <td><input type="password" name="password" required><br></td> </tr> <tr> <td colspan="2" align="center"> <input type="submit" value="登陆"> <input type="reset" value="重置"> </td> </tr> </table> </form> </body> </body> </html>
8.1.创建main.html,代码为:
<!DOCTYPE html> <html lang="en" xmlns:th="http://www.thymeleaf.org"> <head> <meta charset="UTF-8"> <title>系统主页</title> </head> <body> <h1 th:text="'欢迎您:'+${session.loginUser.getUsername()}" th:if="${not #strings.isEmpty(session.loginUser)}"></h1> </body> </html>
9.启动项目
通过浏览器访问登录后的主页(http://localhost:8080/springboot08/user/main ),会提示无权限,需要登录才行

在登陆页用户名和密码输入框内分别输入 “zhangsan”和“132123” 错误的账户或者密码,点击下方的登陆按钮,结果如下图。

在登陆页用户名和密码输入框内分别输入 “zhangsan”和“123456”,点击下方的登陆按钮,结果如下图。


浙公网安备 33010602011771号