拦截器的概念无需赘述,在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过滤器