1. 什么是拦截器
Spring拦截器是一种基于 AOP 的技术,本质也是使用一种代理技术,它主要作用于接口请求中的控制器,也就是Controller。因此它可以用于对接口进行权限验证控制。
2. 拦截器的实现
拦截器的实现分为以下两个步骤:
创建自定义拦截器,实现 HandlerInterceptor 接口的 preHandle(执行具体方法之前的预处理) 方法。
将自定义拦截器加入 WebMvcConfigurer 的 addInterceptors 方法中。
2.1 自定义拦截器
import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import org.springframework.web.servlet.HandlerInterceptor; import org.springframework.web.servlet.ModelAndView; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; // 只是定义了一个空白的拦截器类 // 要让拦截器工作起来: // 1. 有个拦截器对象(自己new 或者 交给 Spring) // 2. 需要将对象注册,并且关联到某些 URL(哪些 URL 会应用拦截器),通过 WebConfigurator bean 来注册 @Slf4j @Component public class MyInterceptor implements HandlerInterceptor { @Autowired public MyInterceptor() { log.info("MyInterceptor.MyInterceptor()"); } @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { log.info("MyInterceptor.preHandle()"); response.setCharacterEncoding("utf-8"); response.setContentType("text/plain"); response.getWriter().println("后续页面被拦截,不再执行"); // 返回 true 代表后续继续执行,返回 false 代表后续不执行 return false; } }
2.2 将自定义拦截器加入到配置中
import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Configuration; import org.springframework.web.servlet.config.annotation.InterceptorRegistry; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; /* * Title: * Author: huang * Date: 2022/11/12 16:33 */ // 1. 必须是一个 Spring bean(否则没有机会调用) // 2. 必须实现了 WebMvcConfigurer 接口 @Slf4j @Configuration public class InterceptConfig implements WebMvcConfigurer { private final MyInterceptor myInterceptor; @Autowired public InterceptConfig(MyInterceptor myInterceptor) { this.myInterceptor = myInterceptor; } @Override public void addInterceptors(InterceptorRegistry registry) { // 在这个方法中添加拦截器 // registry.addInterceptor(myInterceptor).addPathPatterns("/first/**"); // 为 first 下的所有 url 添加拦截器 registry.addInterceptor(myInterceptor).addPathPatterns("/**") // 拦截所有接口 .excludePathPatterns("/first/**"); // 排除接口 log.info("WebConfig.addInterceptors()"); } }
其中:
- addPathPatterns:表示需要拦截的 URL,“**”表示拦截任意方法(也就是所有方法)。
- excludePathPatterns:表示需要排除的 URL。
说明:以上拦截规则可以拦截此项目中的使用 URL,包括静态文件(图片文件、JS 和 CSS 等文件)。
3. 登录拦截器的实现
登陆界面不拦截,其他界面拦截
当登陆成功后,拦截的页面可正常访问
说明:此拦截器可以实现访问页面判断用户是否登录,未登录直接重定向的功能
3.1 自定义拦截器
import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Component; import org.springframework.web.servlet.HandlerInterceptor; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; @Slf4j @Component public class LoginInterceptor implements HandlerInterceptor { @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { // 为了方便不创建实体类,直接用 Object Object currentUser = null; HttpSession session = request.getSession(false); if (session != null) { currentUser = session.getAttribute("currentUser"); } if (currentUser == null) { // 说明用户未登录 log.info("LoginInterceptor.preHandle: 用户未登录,重定向到 登录页(/login.html)"); response.sendRedirect("/login.html"); return false; } log.info("LoginInterceptor.preHandle: 用户登录了,继续后续操作。当前用户: {}", currentUser); return true; } }
3.2 将自定义拦截器加入配置中
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Configuration; import org.springframework.web.servlet.config.annotation.InterceptorRegistry; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; @Configuration public class AppConfig implements WebMvcConfigurer { private final LoginInterceptor loginInterceptor; @Autowired public AppConfig(LoginInterceptor loginInterceptor) { this.loginInterceptor = loginInterceptor; } @Override public void addInterceptors(InterceptorRegistry registry) { // 注册拦截器 registry.addInterceptor(loginInterceptor) .addPathPatterns("/**") // 应用到所有 URL 上 .excludePathPatterns("/error") // 只要有错误,都会到这 .excludePathPatterns("/login.do") .excludePathPatterns("/login.html"); // 但是 /login.html 是例外 } }
3.3 Controller 类
import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.ResponseBody; import javax.servlet.http.HttpSession; import java.util.LinkedHashMap; import java.util.Map; @Slf4j @Controller public class LoginDoController { @PostMapping("/login.do") public String login(String username, String password, HttpSession session) { // 为了方便不创建实体类,直接使用 Map 存放用户信息 Map<String, String> user = new LinkedHashMap<>(); user.put("username", username); user.put("password", password); session.setAttribute("currentUser", user); log.info("LoginDoController.login: 登录成功,重定向到首页(/)"); return "redirect:/"; } @GetMapping("/") @ResponseBody public String index() { return "首页"; } @GetMapping("/hello") @ResponseBody public String hello() { return "其他页面"; } }