springboot自定义拦截器简单使用及举例
杀死一只知更鸟debug 人气:01. 自定义拦截器
在springboot中,使用自定义拦截器,只需要将类实现HandlerIntercepter
接口(与原生的filter也基本差不多)。
HandlerIntercepeter源码:
package org.springframework.web.servlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.springframework.lang.Nullable; import org.springframework.web.method.HandlerMethod; public interface HandlerInterceptor { default boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { return true; } default void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable ModelAndView modelAndView) throws Exception { } default void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable Exception ex) throws Exception { } }
preHandle():当某个 url 已经匹配到对应的 Controller 中的某个方法,且在这个方法执行之前 去执行。返回 true 则放行,返回 false 则不会向后执行。
postHandle():当某个 url 已经匹配到对应的 Controller 中的某个方法,且在执行完了该方法,但是在 DispatcherServlet视图渲染之前。所以在这个方法中有个 ModelAndView 参数,可以在此做一些修改动作。
afterCompletion():在整个请求处理完成后(包括视图渲染)执行,这时做一些资源的清理工作,这个方法只有在 preHandle(……) 被成功执行后并且返回 true才会被执行。
2. 拦截器登录验证的小demo
只有当用户正确登录以后,才允许用户去访问网站的其他页面和资源,即初始时拦截掉所有请求,除了登录页面的请求,登录成功以后放行访问其他页面。
目录结构如下:
2.1 配置pom.xml
配置pom.xml
<dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-thymeleaf</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-devtools</artifactId> <scope>runtime</scope> <optional>true</optional> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-configuration-processor</artifactId> <optional>true</optional> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <optional>true</optional> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> <configuration> <excludes> <exclude> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> </exclude> </excludes> </configuration> </plugin> </plugins> </build>
2.2 创建User的bean组件
使用lombok,来快速生成有参无参构造器,以及get ,set方法和toString()方法
package com.robin.boot.bean; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; import lombok.ToString; @ToString @NoArgsConstructor @AllArgsConstructor @Data public class User { private String userName; private String password; }
2.3 创建需要的表单页面以及登录成功的页面
index.html:
<!DOCTYPE html> <html lang="en" xmlns:th="http://www.thymeleaf.org"> <head> <meta charset="UTF-8"> <title>登录页面</title> </head> <body> <h3 th:text="${msg}">title</h3> <form action="/login" method="post"> <input type="text" name="userName"><br> <input type="password" name="password"><br> <input type="submit" value="登录"> </form> </body> </html>
show.html:
<!DOCTYPE html> <html lang="en" xmlns:th="http://www.thymeleaf.org"> <head> <meta charset="UTF-8"> <title>显示页面</title> </head> <body> <h3 th:text="${msg}">title</h3> 账号:<p th:text="${loginUser.userName}">账号xxx</p> 密码:<p th:text="${loginUser.password}">密码xxx</p> </body> </html>
2.4 编写controller映射关系
package com.robin.boot.controller; import com.robin.boot.bean.User; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PostMapping; @Controller public class LoginController { @PostMapping("/login") public String login(User user, Model model){ System.out.println(user); if ("robin".equals(user.getUserName())&&"123456".equals(user.getPassword())){ model.addAttribute("loginUser",user); return "show"; }else{ model.addAttribute("msg","登录失败,请检查账号密码信息.."); return "index"; } } }
2.5 自定义拦截器类,实现intercepetor接口
package com.robin.boot.interceptor; 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; import javax.servlet.http.HttpSession; @Slf4j public class LoginInterceptor implements HandlerInterceptor { // 目标方法执行之前 @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { // 拦截请求输出 String requestURI = request.getRequestURI(); log.info("拦截了请求{}",requestURI); // 登录检查逻辑,是否登录,登录成功以后放行资源,未登录则拦截资源 HttpSession session = request.getSession(); Object loginUser = session.getAttribute("loginUser"); if (loginUser!=null){ // 登录成功放行资源 return true; }else{ // 提示错误信息 request.setAttribute("msg","请先登录!"); // 请求转发 request.getRequestDispatcher("/").forward(request,response); // 未登录拦截资源 return false; } } // 目标方法执行完毕 @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); } }
2.6注册添加拦截器,自定义springboot配置类
通过addInterceptors(InterceptorRegistry registry)
方法,使用registry.addInterceptor()
将自定义拦截器注册。
并且通过InterceptorRegistration.addPathPatterns()
方法添加拦截的请求,InterceptorRegistration.excludePathPatterns()
方法放行请求。
package com.robin.boot.config; import com.robin.boot.interceptor.LoginInterceptor; import org.springframework.context.annotation.Configuration; import org.springframework.web.servlet.config.annotation.InterceptorRegistry; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; // 自定义springboot配置类 @Configuration public class MyWebConfig implements WebMvcConfigurer { // 添加注册拦截器 @Override public void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(new LoginInterceptor()) .addPathPatterns("/**") // 拦截所有请求 .excludePathPatterns("/","/login"); // 放行 / 和 /login请求, // 因为例子写的比较简单 // .excludePathPatterns("/","/login","/css/**","/js/**","/fonts/**","/images/**"); 平常可以写这样 } }
2.7 运行测试
访问首页:
输入错误的账号信息:
直接通过地址栏访问show.html,http://localhost:8080/show.html
,拦截器发送提示信息并请求转发到index.html
,因为是请求转发,所有地址栏不会发生改变。
输入正确的账号信息,成功访问:
总结
加载全部内容