本文主要介绍 SpringMVC 中拦截器的使用和一个登录拦截的小案例
Spring拦截器是一种基于 AOP 的技术,本质也是使用一种代理技术,它主要作用于接口请求中的控制器,也就是Controller。因此它可以用于对接口进行权限验证控制。
拦截器的实现分为以下两个步骤:
- 创建自定义拦截器,实现 HandlerInterceptor 接口的 preHandle(执行具体方法之前的预处理) 方法。
- 将自定义拦截器加入 WebMvcConfigurer 的 addInterceptors 方法中。
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;
}
}
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()");
}
}
其中:
说明:以上拦截规则可以拦截此项目中的使用 URL,包括静态文件(图片文件、JS 和 CSS 等文件)。
登陆界面不拦截,其他界面拦截
当登陆成功后,拦截的页面可正常访问
说明:此拦截器可以实现访问页面判断用户是否登录,未登录直接重定向的功能
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;
}
}
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 是例外
}
}
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 "其他页面";
}
}