拦截器的概念无需赘述,在SpringMVC的一篇Blog中我就详细聊过【Spring MVC学习笔记 七】深入理解SpringMVC拦截器原理,所以关于拦截器和过滤器的区别、拦截器的作用等就不再赘述了,这里主要探讨下SpringBoot是如何使用拦截器的。按照如下步骤我们来处理登录拦截这样一个场景,即未登录之前请求都被转发到login.html界面
SpringBoot使用拦截器
在 Spring Boot 中定义拦截器十分的简单,只需要创建一个拦截器类,并实现 HandlerInterceptor 接口即可
接下来我们实践下SpringBoot的拦截器使用过程
1 预置正常的SpringMVC请求
首先我们预置一个正常的MVC请求模型,然后再去看拦截器如何发挥作用
1 定义处理登录请求的Controller
LoginController
package com.example.springboot.controller; import com.example.springboot.model.Person; import com.example.springboot.model.User; import lombok.extern.log4j.Log4j; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Controller; import org.springframework.util.StringUtils; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestMapping; import javax.servlet.http.HttpSession; import java.util.Map; /** * * @Name LoginController * * @Description * * @author tianmaolin * * @Data 2021/10/15 */ @Controller @Slf4j public class LoginController { @PostMapping("/user/login") public String doLogin(User user, Map<String, Object> map, HttpSession session) { if (user != null && StringUtils.hasText(user.getUsername()) && "123456".equals(user.getPassword())) { session.setAttribute("loginUser", user); log.info("登陆成功,用户名:" + user.getUsername()); //防止重复提交使用重定向 return "redirect:/main.html"; } else { map.put("msg", "用户名或密码错误"); log.error("登陆失败"); return "login"; } } }
2 添加要跳转的html页面
在template下添加如下两个html文件:
login.html
<!DOCTYPE html> <html lang="en" xmlns:th="http://www.thymeleaf.org"> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> </head> <body> <div class="login-container" > <p style="color: red" th:text="${msg}" th:if="${not #strings.isEmpty(msg)}"></p> <form action="/user/login" method="post"> <div > <input type="text" name="username" th:placeholder="#{username}" /> </div> </br> <div> <input type="password" name="password" th:placeholder="#{password}" /> </div> </br> <button id="submit" type="submit" th:text="#{loginBtn}"></button> <button type="btn" th:text="#{registerBtn}"></button><br> <!--thymeleaf 模板引擎的参数用()代替 ?--> <a class="btn btn-sm" th:href="@{/login.html(l='zh_CN')}">中文</a>| <a class="btn btn-sm" th:href="@{/login.html(l='en_US')}">English</a> </form> </div> </body> </html>
main.html
<!DOCTYPE html> <html lang="en" xmlns:th="http://www.thymeleaf.org"> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> </head> <body> 恭喜你终于登录成功了,能看到我这个页面,说明你通过了拦截器的考验,成功把用户信息放到了session里,你的用户信息为: <div th:object="${session.loginUser}" > <p th:text="*{username}">username</p> <p th:text="*{password}">password</p> </div> </body> </html>
2 定义拦截器
我们在component文件夹下新增拦截器
LoginInterceptor.java
package com.example.springboot.component; import lombok.extern.slf4j.Slf4j; 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; @Slf4j public class LoginInterceptor implements HandlerInterceptor { /** * 目标方法执行前 * * @param request * @param response * @param handler * @return * @throws Exception */ @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { Object loginUser = request.getSession().getAttribute("loginUser"); if (loginUser == null) { //未登录,返回登陆页 request.setAttribute("msg", "您没有权限进行此操作,请先登陆!"); request.getRequestDispatcher("/login.html").forward(request, response); return false; } else { //放行 log.info("preHandle执行成功"); return true; } } /** * 目标方法执行后 * * @param request * @param response * @param handler * @param modelAndView * @throws Exception */ @Override public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { log.info("postHandle执行{}", modelAndView); } /** * 页面渲染后 * * @param request * @param response * @param handler * @param ex * @throws Exception */ @Override public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { log.info("afterCompletion执行异常{}", ex); } }
3 注册拦截器
定义好后我们需要把拦截器进行注册,使用 registry.addInterceptor() 方法将拦截器注册到容器中后,我们便可以继续指定拦截器的拦截规则了
MyMvcConfig.java
package com.example.springboot.config; import com.example.springboot.component.LoginInterceptor; import com.example.springboot.component.MyLocalResolver; import lombok.extern.slf4j.Slf4j; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.web.servlet.LocaleResolver; import org.springframework.web.servlet.config.annotation.*; @Configuration @Slf4j public class MyMvcConfig implements WebMvcConfigurer { //添加视图控制器 @Override public void addViewControllers(ViewControllerRegistry registry) { //当访问/时会跳转到登录页 registry.addViewController("/").setViewName("login"); registry.addViewController("/login.html").setViewName("login"); //添加视图映射 main.html 指向 main.html registry.addViewController("/main.html").setViewName("main"); } //将自定义的区域信息解析器以组件的形式添加到容器中 @Bean public LocaleResolver localeResolver(){ return new MyLocalResolver(); } @Override public void addInterceptors(InterceptorRegistry registry) { log.info("注册拦截器"); registry.addInterceptor(new LoginInterceptor()).addPathPatterns("/**") //拦截所有请求,包括静态资源文件 .excludePathPatterns("/", "/login","/login.html", "/index.html", "/user/login", "/css/**", "/images/**", "/js/**", "/fonts/**"); //放行登录页,登陆操作,静态资源 } }
在指定拦截器拦截规则时,调用了两个方法,这两个方法的说明如下:
- addPathPatterns:该方法用于指定拦截路径,例如拦截路径为“/**”,表示拦截所有请求,包括对静态资源的请求。
- excludePathPatterns:该方法用于排除拦截路径,即指定不需要被拦截器拦截的请求。
至此,拦截器的基本功能已经完成
4 查看实现效果
我们测试下,访问http://localhost:8080/main.html
然后我们输入错误的密码,显示:
最后我们输入正确用户名和密码:
对比SpringMVC实现方式
其实SpringBoot的拦截器实现和SpringMVC的大同小异,但却把配置干掉了,转而体现在代码里,我们之前的拦截配置是在:
springmvc-servlet.xml
文件,通过该文件注入拦截器以及定义拦截规则
现在我们都通过代码进行配置注入了,本质上没什么区别。有个需要注意的地方:
总结一下
本篇Blog详细介绍了SpringBoot的拦截器实现方式,其实可以发现,和SpringMVC实现方式上本质是一致的,只是拦截器的注入方式不同,通过代码比通过配置确乎好理解很多,之后我们处理相关请求的拦截时也更加方便了,如果想看各种不同拦截器的实现方式,参照我之前的这两篇Blog:【Spring MVC学习笔记 七】深入理解SpringMVC拦截器原理,【Java Web编程 十】深入理解Servlet过滤器