在springboot中使用filter过滤器以及interceptor拦截器处理请求

结构图长这个B样
在这里插入图片描述

1、过滤器

什么是过滤器?
Filter 过滤器主要是用来过滤用户请求的,它允许我们对用户请求进行前置处理和后置处理,比如实现 URL 级别的权限控制、过滤非法请求等等。Filter 过滤器是面向切面编程——AOP 的具体实现(AOP切面编程只是一种编程思想而已)
长什么样子?
就长这p样:
过滤器:只想要在一堆东西里面选个B
在这里插入图片描述
下面是代码

public interface Filter {

   //初始化过滤器后执行的操作
    default void init(FilterConfig filterConfig) throws ServletException {
    }
   // 对请求进行过滤
    void doFilter(ServletRequest var1, ServletResponse var2, FilterChain var3) throws IOException, ServletException;
   // 销毁过滤器后执行的操作,主要用户对某些资源的回收
    default void destroy() {
    }
}

这就是过滤器
如何实现过滤的?
在这里插入图片描述
Filter接口中有一个叫做 doFilter 的方法,这个方法实现了对用户请求的过滤。具体流程大体是这样的:

1、 用户发送请求到 web 服务器,请求会先到过滤器。
2、 过滤器会对请求进行一些处理比如过滤请求的参数(request)。
3、修改返回给客户端的 response 的内容、判断是否让用户访问该接口等等。
4、用户请求响应完毕。
5、 进行一些自己想要的其他操作。
如何自定义过滤器呢?
1、手动配置
在配置中注册自定义的过滤器

@Configuration
public class MyFilterConfig {
    @Autowired
    MyFilter myFilter;
    @Bean
    public FilterRegistrationBean<MyFilter> thirdFilter() {
        FilterRegistrationBean<MyFilter> filterRegistrationBean = new FilterRegistrationBean<>();

        filterRegistrationBean.setFilter(myFilter);

        filterRegistrationBean.setUrlPatterns(new ArrayList<>(Arrays.asList("/api/*")));

        return filterRegistrationBean;
    }
}

手动注册配置实现

@Component
public class MyFilter implements Filter {
    private static final Logger logger = LoggerFactory.getLogger(MyFilter.class);

    @Override
    public void init(FilterConfig filterConfig) {
        logger.info("初始化过滤器:", filterConfig.getFilterName());
    }

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        //对请求进行预处理
        logger.info("过滤器开始对请求进行预处理:");
        HttpServletRequest request = (HttpServletRequest) servletRequest;
        String requestUri = request.getRequestURI();
        System.out.println("请求的接口为:" + requestUri);
        long startTime = System.currentTimeMillis();
        //通过 doFilter 方法实现过滤功能
        filterChain.doFilter(servletRequest, servletResponse);
        // 上面的 doFilter 方法执行结束后用户的请求已经返回
        long endTime = System.currentTimeMillis();
        System.out.println("该用户的请求已经处理完毕,请求花费的时间为:" + (endTime - startTime));
    }

    @Override
    public void destroy() {
        logger.info("销毁过滤器");
    }
}

2、通过注解实现
在自己的过滤器的类上加上@WebFilter 然后在这个注解中通过它提供好的一些参数进行配置

package github.javaguide.springbootfilter.filter;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
/**
 * 注解实现
 * @author Administrator
 *
 */
@WebFilter(filterName = "MyFilterWithAnnotation", urlPatterns = "/api/annotation/*")
public class MyFilterWithAnnotation implements Filter {

    private static final Logger logger = LoggerFactory.getLogger(MyFilterWithAnnotation.class);

    @Override
    public void init(FilterConfig filterConfig) {
        logger.info("初始化过滤器");
    }

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        //对请求进行预处理
        logger.info("过滤器开始对请求进行预处理:");
        HttpServletRequest request = (HttpServletRequest) servletRequest;
        String requestUri = request.getRequestURI();
        System.out.println("请求的接口为:" + requestUri);
        long startTime = System.currentTimeMillis();
        //通过 doFilter 方法实现过滤功能
        filterChain.doFilter(servletRequest, servletResponse);
        // 上面的 doFilter 方法执行结束后用户的请求已经返回
        long endTime = System.currentTimeMillis();
        System.out.println("该用户的请求已经处理完毕,请求花费的时间为:" + (endTime - startTime));
    }

    @Override
    public void destroy() {
        logger.info("销毁过滤器");
    }
}

另外,为了能让 Spring 找到它,你需要在启动类上加上 @ServletComponentScan 注解。

package github.javaguide.springbootfilter;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.web.servlet.ServletComponentScan;

@SpringBootApplication
@ServletComponentScan
public class SpringbootFilterApplication {

    public static void main(String[] args) {
        SpringApplication.run(SpringbootFilterApplication.class, args);
    }

}

如果有多个拦截器该如何决定他们的执行顺序?
新加入的过滤器2号

package github.javaguide.springbootfilter.filter;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
/**
 * 自定义的myfilter2
 * @author Administrator
 *
 */
@Component
public class MyFilter2 implements Filter {
    private static final Logger logger = LoggerFactory.getLogger(MyFilter2.class);

    @Override
    public void init(FilterConfig filterConfig) {
        logger.info("初始化过滤器2");
    }

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        //对请求进行预处理
        logger.info("过滤器开始对请求进行预处理2:");
        HttpServletRequest request = (HttpServletRequest) servletRequest;
        String requestUri = request.getRequestURI();
        System.out.println("请求的接口为2:" + requestUri);
        long startTime = System.currentTimeMillis();
        //通过 doFilter 方法实现过滤功能
        filterChain.doFilter(servletRequest, servletResponse);
        // 上面的 doFilter 方法执行结束后用户的请求已经返回
        long endTime = System.currentTimeMillis();
        System.out.println("该用户的请求已经被myfilter2处理完毕,请求花费的时间为:" + (endTime - startTime));
    }

    @Override
    public void destroy() {
        logger.info("销毁过滤器2");
    }
}

在配置中注册自定义的过滤器,通过FilterRegistrationBean 的setOrder 方法可以决定 Filter 的执行顺序

package github.javaguide.springbootfilter.config;

import github.javaguide.springbootfilter.filter.MyFilter;
import github.javaguide.springbootfilter.filter.MyFilter2;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.util.ArrayList;
import java.util.Arrays;
/**
 * 注册自定义的过滤器
 * @author Administrator
 *
 */
@Configuration
public class MyFilterConfig {
    @Autowired
    MyFilter myFilter;

    @Autowired
    MyFilter2 myFilter2;
  
    @Bean
    public FilterRegistrationBean<MyFilter> setUpMyFilter() {
        FilterRegistrationBean<MyFilter> filterRegistrationBean = new FilterRegistrationBean<>();
        filterRegistrationBean.setOrder(2);//执行顺序为2
        filterRegistrationBean.setFilter(myFilter);
        filterRegistrationBean.setUrlPatterns(new ArrayList<>(Arrays.asList("/api/*")));

        return filterRegistrationBean;
    }

    @Bean
    public FilterRegistrationBean<MyFilter2> setUpMyFilter2() {
        FilterRegistrationBean<MyFilter2> filterRegistrationBean = new FilterRegistrationBean<>();
        filterRegistrationBean.setOrder(1);//执行顺序为1
        filterRegistrationBean.setFilter(myFilter2);//设置过滤器
        filterRegistrationBean.setUrlPatterns(new ArrayList<>(Arrays.asList("/api/*")));//需要过滤的路径
        return filterRegistrationBean;
    }
}

controller

package github.javaguide.springbootfilter.web;

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("/api")
public class MyController {

    @GetMapping("/hello")
    public String getHello() throws InterruptedException {
        Thread.sleep(1000);
        return "Hello";
    }
}

访问路径:http://localhost:8080/api/hello

结果:
在这里插入图片描述
在这里插入图片描述

拦截器

什么是拦截器?与过滤器有区别吗?
拦截器(Interceptor)同 Filter 过滤器一样,它俩都是面向切面编程——AOP 的具体实现(AOP切面编程只是一种编程思想而已)
区别在于:
过滤器(Filter):当你有一堆东西的时候,你只希望选择符合你要求的某一些东西。定义这些要求的工具,就是过滤器。
拦截器(Interceptor):在一个流程正在进行的时候,你希望干预它的进展,甚至终止它进行,这是拦截器做的事情。
长什么样?

在这里插入图片描述拦截器:把水流变小点,把鱼都拦住!顺便发个电

在这里插入图片描述拦截器原理图示↑

代码:

public boolean preHandle(HttpServletRequest request,
                         HttpServletResponse response,
                         Object handler)


public void postHandle(HttpServletRequest request,
                       HttpServletResponse response,
                       Object handler,
                       ModelAndView modelAndView)


public void afterCompletion(HttpServletRequest request,
                            HttpServletResponse response,
                            Object handler,
                            Exception ex)

preHandle方法返回 true或 false。如果返回 true,则意味着请求将继续到达 Controller 被处理

在这里插入图片描述使用拦截器拦截请求图示↑
LogInterceptor用于过滤所有请求

package github.javaguide.springbootfilter.interceptor;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;
/**
 * 用来过滤所有请求
 * @author Administrator
 *
 */
public class LogInterceptor extends HandlerInterceptorAdapter {

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
            throws Exception {
        long startTime = System.currentTimeMillis();
        System.out.println("\n-------- LogInterception.preHandle --- ");
        System.out.println("请求路径: " + request.getRequestURL());
        System.out.println("开始时间: " + System.currentTimeMillis());

        request.setAttribute("startTime", startTime);

        return true;
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, //
                           Object handler, ModelAndView modelAndView) throws Exception {

        System.out.println("\n-------- LogInterception.postHandle --- ");
        System.out.println("请求路径: " + request.getRequestURL());

        // You can add attributes in the modelAndView
        // and use that in the view page
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, //
                                Object handler, Exception ex) throws Exception {
        System.out.println("\n-------- LogInterception.afterCompletion --- ");

        long startTime = (Long) request.getAttribute("startTime");
        long endTime = System.currentTimeMillis();
        System.out.println("请求路径: " + request.getRequestURL());
        System.out.println("结束时间: " + endTime);

        System.out.println("耗时: " + (endTime - startTime));
    }

}

OldLoginInterceptor是一个拦截器,如果用户输入已经被废弃的链接 “ / admin / oldLogin”,它将重定向到新的 “ / admin / login”

package github.javaguide.springbootfilter.interceptor;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;

public class OldLoginInterceptor extends HandlerInterceptorAdapter {
  /**
   * 在这儿从定向到/admin/login
   */
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
            throws Exception {

        System.out.println("\n-------- OldLoginInterceptor.preHandle --- ");
        System.out.println("Request URL: " + request.getRequestURL());
        System.out.println("Sorry! 这个借口被弃用了, 重定向到 /admin/login");

        response.sendRedirect(request.getContextPath() + "/admin/login");
        return false;
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, //
                           Object handler, ModelAndView modelAndView) throws Exception {

        //因为重定向了,这段代码永远不会运行
        System.out.println("\n-------- OldLoginInterceptor.postHandle --- ");
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, //
                                Object handler, Exception ex) throws Exception {

        //这段代码永远不会运行
        System.out.println("\n-------- QueryStringInterceptor.afterCompletion --- ");
    }

}

AdminInterceptor

package org.o7planning.sbinterceptor.interceptor;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;

public class AdminInterceptor extends HandlerInterceptorAdapter {

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
            throws Exception {

        System.out.println("\n-------- AdminInterceptor.preHandle --- ");
        return true;
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, //
            Object handler, ModelAndView modelAndView) throws Exception {

        System.out.println("\n-------- AdminInterceptor.postHandle --- ");
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, //
            Object handler, Exception ex) throws Exception {

        System.out.println("\n-------- AdminInterceptor.afterCompletion --- ");
    }

}

配置拦截器

package github.javaguide.springbootfilter.config;

import github.javaguide.springbootfilter.interceptor.AdminInterceptor;
import github.javaguide.springbootfilter.interceptor.LogInterceptor;
import github.javaguide.springbootfilter.interceptor.OldLoginInterceptor;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
/**
 * 拦截器的配置类
 * @author Administrator
 *
 */
@Configuration
public class WebConfig implements WebMvcConfigurer {
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
    	//loginteceptor 允许通过所有的url
        registry.addInterceptor(new LogInterceptor());

       
        //老的登录被弃用,重定向到新的url
        registry.addInterceptor(new OldLoginInterceptor())//
                .addPathPatterns("/admin/oldLogin");

        
        //此拦截器适用于/admin/*包括/admin/oldLogin这样的URL
        registry.addInterceptor(new AdminInterceptor())//
                .addPathPatterns("/admin/*")//
                .excludePathPatterns("/admin/oldLogin");
    }

}

自定义 Controller 验证拦截器的功能

package github.javaguide.springbootfilter.web;

import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
/**
 * 自定义controller验证拦截器
 * @author Administrator
 *
 */
@Controller
public class InterceptorTestController {

    @RequestMapping(value = { "/", "/test" })
    public String test(Model model) {

        System.out.println("\n-------- MainController.test --- ");

        System.out.println(" ** You are in Controller ** ");

        return "test";
    }

    // This path is no longer used.
    // It will be redirected by OldLoginInterceptor
    @Deprecated
    @RequestMapping(value = { "/admin/oldLogin" })
    public String oldLogin(Model model) {

        // Code here never run.
        return "oldLogin";
    }

    @RequestMapping(value = { "/admin/login" })
    public String login(Model model) {

        System.out.println("\n-------- MainController.login --- ");

        System.out.println(" ** You are in Controller ** ");

        return "login";
    }

}

简单的前端页面
login.html

<!DOCTYPE HTML>
<html xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8" />
    <title>Spring Boot Mvc Interceptor example</title>
</head>
<body>

<div style="border: 1px solid #ccc;padding: 5px;margin-bottom:10px;">
    <a th:href="@{/}">Home</a>
    &nbsp;&nbsp; | &nbsp;&nbsp;
    <a th:href="@{/admin/oldLogin}">/admin/oldLogin (OLD URL)</a>
</div>

<h3>This is Login Page</h3>

<span style="color:blue">测试 OldLoginInterceptor &amp; AdminInterceptor</span>
<br/><br/>
See more info in the Console.

</body>

</html>

test.html

<!DOCTYPE HTML>
<html xmlns:th="http://www.thymeleaf.org">

<head>
    <meta charset="UTF-8"/>
    <title>Spring Boot Mvc Interceptor example</title>
</head>

<body>
<div style="border: 1px solid #ccc;padding: 5px;margin-bottom:10px;">
    <a th:href="@{/}">Home</a>
    &nbsp;&nbsp; | &nbsp;&nbsp;
    <a th:href="@{/admin/oldLogin}">/admin/oldLogin (OLD URL)</a>
</div>

<h3>Spring Boot Mvc Interceptor</h3>

<span style="color:blue;">Testing LogInterceptor</span>
<br/><br/>

See Log in Console..

</body>
</html>

访问地址:http://localhost:8080/admin/login
访问结果

------- LogInterception.preHandle --- 
请求路径: http://localhost:8080/admin/oldLogin
开始时间: 1579154118865

-------- OldLoginInterceptor.preHandle --- 
Request URL: http://localhost:8080/admin/oldLogin
Sorry! 这个借口被弃用了, 重定向到 /admin/login

-------- LogInterception.afterCompletion --- 
请求路径: http://localhost:8080/admin/oldLogin
结束时间: 1579154118865
耗时: 0

-------- LogInterception.preHandle --- 
请求路径: http://localhost:8080/admin/login
开始时间: 1579154118876

-------- AdminInterceptor.preHandle --- 

-------- MainController.login --- 
 ** You are in Controller ** 

-------- AdminInterceptor.postHandle --- 

-------- LogInterception.postHandle --- 
请求路径: http://localhost:8080/admin/login

-------- AdminInterceptor.afterCompletion --- 

-------- LogInterception.afterCompletion --- 
请求路径: http://localhost:8080/admin/login
结束时间: 1579154118878
耗时: 2

最后再来说说监听器:

监听器

什么是监听器?
在这里插入图片描述嘿嘿,不用我多说了吧!!!

上代码

// 监听器
interface BedListener {
  // 监听器在参数中收到了某个事件,而这个事件往往是只读的
  // 监听器的方法名通常以"on"开头
  void onBedSound (String sound);
}

class Neighbor {
  BedListener listener;

  // 依然是所谓控制反转
  setListener (BedListener listener) {
    this.listener = listener;
  }

  void doInterestingStuff () {
    // 根据当地法律法规,部分内容无法显示

    // 将事件发送给监听器
    listener.onBedSound("嘿咻");
    listener.onBedSound("oyeah");
  }
}

class Main {
  public static void main (String args[]) {
    Neighbor n = new Neighbor();
    n.setListener (sound -> generatePower());
    n.doInterestingStuff();
  }

  private static void generatePower() {
    // 根据当地法律法规,部分内容无法显示
  }
}

参考资源:
代码源码
原大佬的博客
知乎大佬的图

发布了34 篇原创文章 · 获赞 21 · 访问量 1920

猜你喜欢

转载自blog.csdn.net/qq_44156131/article/details/104001057