拦截器会对处理器进行拦截,拦截的目的就是做一些预处理,以此来增强处理器的功能。
常见的拦截器使用场景:
下面以登录请求为例,简单使用拦截器,来实现登录拦截。
比如一个XX后台管理系统,首先需要登录:
假设路径为: http://localhost:8080/login
输入账号信息登录后进入XX后台管理系统主页: http://localhost:8080/index
那如果直接访问http://localhost:8080/index呢?还是会返回主页,那这登录有啥意义呢?
而使用拦截器的话,浏览器请求http://localhost:8080/index时,拦截器可做预处理,判断会话对象Session中是否存在用户信息,不存在则跳转登录界面。
使用前端使用thymeleaf模板引擎,浏览器GET请求/login和/index返回对应的html,还有一个/login的POST请求用于登录。
和之前没有登录拦截的区别:多了个HttpSession httpSession参数,前端请求不用管,登录成功后将用户名保存至Session中:
httpSession.setAttribute("loginUser",username);//将登陆成功的用户名添加至Session中
完整如下:
@Controller
public class TestController {
Map<String, Object> result;
@GetMapping("/login")
public String login() {
return "login";
}
@PostMapping("/login")
@ResponseBody
public Map<String, Object> login(@RequestParam("username") String username,
@RequestParam("password") String password,
HttpSession httpSession) {
result = new HashMap<>();
if (username.equals("123") && "123".equals(password)) {
httpSession.setAttribute("loginUser",username);//将登陆成功的用户名添加至Session中
result.put("resultCode", 200);
return result;//登陆成功,前端根据resultCode跳转主页面
} else {//登录失败
result.put("resultCode", 500);
return result;
}
}
@GetMapping("/index")
public String index() {
return "index";
}
}
使用@Component标注该拦截器类,将其添加至IOC容器
实现HandlerInterceptor接口中的三个方法preHandle/postHandle/afterCompletion
这三个方法分别在DispatcherServlet之前执行/之后执行/结果返回给客户端之前执行,我们如果需要拦截登录,当然是在DispatcherServlet之前执行,也就是前端发送了我们指定拦截的请求路径后,我们先执行这个方法,再处理请求。
具体到登录拦截,判断上述添加至session中的loginUser是否存在,存在的话说明已经登录过,可放行请求,session中的loginUser为空的话,说明没有登录过,则返回至登录界面。
详情可看注释:
@Component
public class LoginInterceptor implements HandlerInterceptor {
//在DispatcherServlet之前执行
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println("1.我是在DispatcherServlet之前执行的方法");
Object loginUser = request.getSession().getAttribute("loginUser");//获取已登录的用户名
if (loginUser == null) {
//未登录,返回登陆页面
request.setAttribute("msg", "请先登录");
request.getRequestDispatcher("/login").forward(request, response);//前端可获取request中的msg,来提示用户“请先登录”
return false;
} else {
//已登录,放行请求
return true;
}
}
//在DispatcherServlet之后执行
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
System.out.println("2.在controller执行之后的DispatcherServlet之后执行");
}
//在页面渲染完成返回给客户端之前执行
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
System.out.println("3.在页面渲染完成返回给客户端之前执行");
}
}
项目中一般都会有配置类,即实现WebMvcConfigurer接口的类:
只需重写addInterceptors方法即可,使用回调参数InterceptorRegistry对象中的这三个方法:
@Configuration
public class MyConfig implements WebMvcConfigurer {
@Resource
private LoginInterceptor loginInterceptor;
//注册拦截器,springboot已经做好静态资源(js/css等)的映射,无需额外配置
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(loginInterceptor)//增加过滤的方法类
.addPathPatterns("/**")//定义过滤的范围,拦截/下所有请求
.excludePathPatterns("/login");//排除某些请求,这些请求无需拦截
}
//其他配置...
}
效果就是直接访问index管理界面会被拦截,自动跳转至登录界面。正常登录跳转还是和以前一样。