Spring Boot拦截器和过滤器的使用
Spring Boot拦截器和过滤器的使用
文章目录
一、拦截器与过滤器
拦截器与过滤器的区别:
1、过滤器和拦截器触发时机不一样,过滤器是在请求进入容器后,但请求进入servlet之前进行预处理的。请求结束返回也是,是在servlet处理完后,返回给前端之前。
如下图:
2、拦截器可以获取IOC容器中的各个bean,而过滤器就不行,因为拦截器是spring提供并管理的,spring的功能可以被拦截器使用,在拦截器里注入一个service,可以调用业务逻辑。而过滤器是JavaEE标准,只需依赖servlet api ,不需要依赖spring。
过滤器拦截器运行先后步骤:
其中第2步,SpringMVC的机制是由DispaterServlet来分发请求给不同的Controller,其实这一步是在Servlet的service()方法中执行的.
3、过滤器的实现基于回调函数。而拦截器(代理模式)的实现基于反射,代理分静态代理和动态代理,动态代理是拦截器的简单实现。
何时使用拦截器?何时使用过滤器?
-
如果是非spring项目,那么拦截器不能用,只能使用过滤器。
-
如果是处理controller前后,既可以使用拦截器也可以使用过滤器。
-
如果是处理dispaterServlet前后,只能使用过滤器。
servlet和controller的区别?
- controller的前端控制器DispatcherServlet最终是继承了HttpServlet的,只不过springmvc帮助你做好了url和method的映射了(注解实现),不需要你自己在web.xml一个servlet和一个method去配置了
二、springboot中使用过滤器和拦截器
spring boot 使用过滤器
两种方式:
1、使用spring boot提供的FilterRegistrationBean注册Filter
2、使用原生servlet注解定义Filter
两种方式的本质都是一样的,都是去FilterRegistrationBean注册自定义Filter
方式一:
①、先定义Filter:
package com.hwm.filter;
import javax.servlet.*;
import java.io.IOException;
public class MyFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
// do something 处理request 或response
System.out.println("filter1");
// 调用filter链中的下一个filter
filterChain.doFilter(servletRequest,servletResponse);
}
@Override
public void destroy() {
}
}
②、注册自定义Filter
@Configuration
public class FilterConfig {
@Bean
public FilterRegistrationBean registrationBean() {
FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean(new MyFilter());
filterRegistrationBean.addUrlPatterns("/*");
return filterRegistrationBean;
}
}
方式二:
// 注入spring容器
@Component
// 定义filterName 和过滤的url
@WebFilter(filterName = "my2Filter" ,urlPatterns = "/*")
public class My2Filter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
System.out.println("filter2");
}
@Override
public void destroy() {
}
}
Spring boot拦截器的使用:
①、定义拦截器:
public class MyInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println("preHandle");
return true;
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable ModelAndView modelAndView) throws Exception {
System.out.println("postHandle");
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable Exception ex) throws Exception {
System.out.println("afterCompletion");
}
}
②、配置拦截器:
@Configuration
public class InterceptorConfig implements WebMvcConfigurer {
@Override
public void addInterceptors(InterceptorRegistry registry) {
//注册自定义拦截器,添加拦截路径和排除拦截路径
registry.addInterceptor(new MyInterceptor()).addPathPatterns("/**").excludePathPatterns("/loginPage","/login");
}
}
addPathPatterns//这个是添加拦截路径,excludePathPatterns这个是排除拦截的路径多个路径中间用逗号隔开,
③Controller演示:
@RestController
public class UController {
@GetMapping("/home")
public String home(){
System.out.println("home");
return "myhome";
}
}
输出:
preHandle
home
postHandle
afterCompletion
三、拦截器的应用
1、拦截器重定向次数过多
这里以一个Demo为例,假设访问网站之前需要身份认证(学生,医生,管理员),每次访问网站,拦截器的处理逻辑如下
/**
* 在请求处理之前进行调用(Controller方法调用之前)
*/
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
try {
//统一拦截(查询当前session是否存在user)(这里user会在每次登陆成功后,写入session)
//判断是否是学生
Student student = (Student) request.getSession().getAttribute("student");
//判断是否是医生
Doctor doctor = (Doctor) request.getSession().getAttribute("doctor");
//判断是否是管理员
Admin admin = (Admin) request.getSession().getAttribute("admin");
//String user=(String) request.getSession().getAttribute("userid");
if(student != null || doctor != null || admin != null){
return true;
}
//重定向到学生登录页面
response.sendRedirect(request.getContextPath()+"/stu");
} catch (IOException e) {
e.printStackTrace();
}
return false;//如果设置为false时,被请求时,拦截器执行到此处将不会继续操作
//如果设置为true时,请求将会继续执行后面的操作
}
这时需要对相应的controller进行拦截处理,需要student,doctor,admin的不放行。
@Override
public void addInterceptors(InterceptorRegistry registry) {
//注册TestInterceptor拦截器
InterceptorRegistration registration = registry.addInterceptor(new AdminInterceptor());
//允许访问的controller
registration.excludePathPatterns("/stu","/doctor","/admin");
registration.excludePathPatterns("/stu1","/doctor1","/admin1");
registration.excludePathPatterns("/stu/toReg","/doctor/toReg","/admin/toReg");
registration.excludePathPatterns("/stu/register","/doctor/register","/admin/register");
registration.excludePathPatterns("/stu/stuChecked","/doctor/stuChecked","/admin/stuChecked");
registration.excludePathPatterns("/stu/stuChecked1","/doctor/stuChecked1","/admin/stuChecked1");
registration.excludePathPatterns("/stu/toHomePage","/doctor/toHomePage","/admin/toHomePage");
}
由于每次页面访问都会处理拦截器中的逻辑,所以不用写addPathPatterns("/**") 这条语句。
如果配置拦截请求不当的话,会导致preHandle返回false,准备重定向时,发现重定向的页面被拦截,导致死循环。
2、页面静态样式丢失
//在自定义配置类中添加静态资源放行
//允许访问的静态资源
registration.excludePathPatterns("/assets/**");
registration.excludePathPatterns("/doc/**");
注意springboot默认的静态资源放在static下,所以在放行时不用写*"/static/assets"*
效果:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-7t4cQ2gT-1585972821014)(E:\java面试\Study_Repositories\images\springboot\拦截器设置登录页面.gif)]
四、过滤器的应用
后端处理跨域CORS问题
public class CorsFilter implements Filter {
@Override
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
HttpServletResponse response = (HttpServletResponse) res;
HttpServletRequest request = (HttpServletRequest) req;
// 不使用*,自动适配跨域域名,避免携带Cookie时失效
String origin = request.getHeader("Origin");
if(StringUtils.isNotBlank(origin)) {
response.setHeader("Access-Control-Allow-Origin", origin);
}
// 自适应所有自定义头
String headers = request.getHeader("Access-Control-Request-Headers");
if(StringUtils.isNotBlank(headers)) {
response.setHeader("Access-Control-Allow-Headers", headers);
response.setHeader("Access-Control-Expose-Headers", headers);
}
// 允许跨域的请求方法类型
response.setHeader("Access-Control-Allow-Methods", "*");
// 预检命令(OPTIONS)缓存时间,单位:秒
response.setHeader("Access-Control-Max-Age", "3600");
// 明确许可客户端发送Cookie,不允许删除字段即可
response.setHeader("Access-Control-Allow-Credentials", "true");
System.out.println("处理跨域问题");
chain.doFilter(request, response);
}
@Override
public void init(FilterConfig filterConfig) {
}
@Override
public void destroy() {
}
}
@Configuration
public class MyConfig extends WebMvcConfigurerAdapter {
@Bean
public FilterRegistrationBean registrationBean() {
FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean(new CorsFilter());
filterRegistrationBean.addUrlPatterns("/*");
return filterRegistrationBean;
}
}
...
2020-04-04 11:44:48.284 INFO 12128 --- [ restartedMain] com.wangxiaoxi.mheal.MhealApplication : Started MhealApplication in 7.158 seconds (JVM running for 8.851)
2020-04-04 11:44:55.319 INFO 12128 --- [nio-8080-exec-1] o.a.c.c.C.[Tomcat].[localhost].[/mheal] : Initializing Spring DispatcherServlet 'dispatcherServlet'
2020-04-04 11:44:55.319 INFO 12128 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet : Initializing Servlet 'dispatcherServlet'
2020-04-04 11:44:55.337 INFO 12128 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet : Completed initialization in 18 ms
处理跨域问题
处理跨域问题
处理跨域问题
处理跨域问题
处理跨域问题
处理跨域问题
处理跨域问题
处理跨域问题
处理跨域问题
161401080901 ------- 123456
log4j:WARN No appenders could be found for logger (druid.sql.Connection).
log4j:WARN Please initialize the log4j system properly.
log4j:WARN See http://logging.apache.org/log4j/1.2/faq.html#noconfig for more info.
2020-04-04 11:45:12.297 INFO 12128 --- [nio-8080-exec-8] com.alibaba.druid.pool.DruidDataSource : {dataSource-1} inited
2020-04-04 11:45:12.309 DEBUG 12128 --- [nio-8080-exec-8] c.w.m.mapper.AdminMapper.adminChecked : ==> Preparing: select * from admin where id = ? and password = ?
2020-04-04 11:45:12.543 DEBUG 12128 --- [nio-8080-exec-8] c.w.m.mapper.AdminMapper.adminChecked : ==> Parameters: 161401080901(String), 123456(String)
2020-04-04 11:45:12.615 DEBUG 12128 --- [nio-8080-exec-8] c.w.m.mapper.AdminMapper.adminChecked : <== Total: 1
处理跨域问题
主页
五、参考文档
推荐阅读
-
spring boot 枚举使用的坑整理
-
Spring Boot2.3 新特性分层JAR的使用
-
Spring Boot使用yml格式进行配置的方法
-
Spring Boot 配置 IDEA和DevTools 热部署的方法
-
使用Spring-boot-starter标准改造项目内的RocketMQ客户端组件
-
spring boot 使用utf8mb4的操作
-
使用Docker部署 spring-boot maven应用的方法
-
spring boot使用thymeleaf模板的方法详解
-
RestTemplate的使用和原理你都烂熟于胸了吗?【享学Spring MVC】
-
解决Spring Boot和Feign中使用Java 8时间日期API(LocalDate等)的序列化问题