Spring Boot拦截器和过滤器的使用

Spring Boot拦截器和过滤器的使用

一、拦截器与过滤器

以下摘抄于此blog

拦截器与过滤器的区别:

拦截器与filter的区别

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,准备重定向时,发现重定向的页面被拦截,导致死循环

详情请看该blog

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
处理跨域问题
主页
五、参考文档

1、spring boot 过滤器、拦截器的区别与使用

2、springboot拦截器使用 登录拦截 重定向次数过多的解决方法

3、Vue之Axios跨域问题解决方案

4、controller与servlet的区别

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值