青锋开源架构-springboot2.6.x+vue3-antdesign-vite之整合拦截器/过滤器

开源项目下载地址:

青锋开源架构-springboot2.6.x+vue3-antdesign-vite: 青锋-springboot2.6.x+vue3-antdesign-vite开源架构,实现了系统管理模块、权限控制模块(菜单权限、功能按钮权限、数据权限)、代码生成器(单表、树表)、quartz动态定时器等功能。

拦截器的整合

拦截器的工作流程

preHandle方法一定是最先执行的方法,如果它返回为false下面的方法均不执行。

postHandle是在返回再次调用拦截器的方法。

afterCompletion方法是最终执行的方法,可以看做finally,用于关闭一些一定要close的东西。

青锋开源架构-springboot2.6.x+vue3-antdesign-vite之整合拦截器/过滤器_第1张图片

拦截器的使用场景

1、乱码问题:用request,response参数去设置编码;

2、解决权限验证问题(是否登陆,取session对象查看);

创建拦截器

创建自己的拦截器,通过实现HandlerInterceptor接口,重写接口的三个方法,

1、preHandle(),预处理回调方法,实现处理器的预处理,如:登录检查,都是在请求controller层之前执行,

2、postHandle(),后处理回调方法,实现处理器的后处理,但是要在渲染视图之前

3、afterCompletion(),整个请求处理完毕回调方法,要在整个视图渲染完毕后回调

 

package com.qingfeng.framework.servlet;

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;

/**
 * @author Administrator
 * @version 1.0.0
 * @ProjectName qingfeng
 * @Description 自定义拦截器
 * @createTime 2022年01月12日 13:25:00
 */
public class CustomInterceptor implements HandlerInterceptor {

    //这个方法是在访问接口之前执行的,我们只需要在这里写验证登陆状态的业务逻辑,就可以在用户调用指定接口之前验证登陆状态了
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        //每一个项目对于登陆的实现逻辑都有所区别,我这里使用最简单的Session提取User来验证登陆。
        System.out.println("------------------自定义拦截器-进来了---------------");
        String path = request.getServletPath();
        System.out.println("path:"+path);
        HttpSession session = request.getSession();
        //这里的User是登陆时放入session的
//        User user = (User) session.getAttribute("user");
        //如果session中没有user,表示没登陆
//        if (user == null){
//            //这个方法返回false表示忽略当前请求,如果一个用户调用了需要登陆才能使用的接口,如果他没有登陆这里会直接忽略掉
//            //当然你可以利用response给用户返回一些提示信息,告诉他没登陆
//            return false;
//        }else {
//            return true;    //如果session里有user,表示该用户已经登陆,放行,用户即可继续调用自己需要的接口
//        }
        return true;
    }

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

}

注册拦截器

注册自己创建的拦截器,实现WebConfigurer接口

通配符的含义:

通配符

描述

?

匹配任何单字符

*

匹配0或者任意数量的字符

**

匹配0或者更多的目录

Path

Description

/app/*.x

匹配(Matches)所有在app路径下的.x文件

/app/p?ttern

匹配(Matches) /app/pattern 和 /app/pXttern,但是不包括/app/pttern

/**/example

匹配(Matches) /app/example, /app/foo/example, 和 /example

/app/**/dir/file.

匹配(Matches) /app/dir/file.jsp, /app/foo/dir/file.html,/app/foo/bar/dir/file.pdf, 和 /app/dir/file.java

package com.qingfeng.framework.servlet;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

/**
 * @author Administrator
 * @version 1.0.0
 * @ProjectName qingfeng
 * @Description 注册拦截器
 * @createTime 2022年01月12日 13:29:00
 */
@Configuration
public class WebConfigurer  implements WebMvcConfigurer {

    @Override
    public void addInterceptors(InterceptorRegistry registry) {

        //这个方法用来注册拦截器,我们自己写好的拦截器需要通过这里添加注册才能生效
        //多个拦截器时 以此添加 执行顺序按添加顺序
        registry.addInterceptor(getHandlerInterceptor())
                .addPathPatterns("/common/**").excludePathPatterns("/login/**");
    }

    // 这个方法是用来配置静态资源的,比如html,js,css,等等
    public void addResourceHandlers(ResourceHandlerRegistry registry) {
    }

    //后台
    @Bean
    public static HandlerInterceptor getHandlerInterceptor() {
        return new CustomInterceptor();
    }

}

请求验证

青锋开源架构-springboot2.6.x+vue3-antdesign-vite之整合拦截器/过滤器_第2张图片

 

过滤器的整合
过滤器的概念
在讲Spring boot之前,我们先了解一下过滤器和拦截器。这两者在功能方面很类似,但是在具体技术实现方面,差距还是比较大的。在分析两者的区别之前,我们先理解一下AOP的概念,AOP不是一种具体的技术,而是一种编程思想。在面向对象编程的过程中,我们很容易通过继承、多态来解决纵向扩展。 但是对于横向的功能,比如,在所有的service方法中开启事务,或者统一记录日志等功能,面向对象的是无法解决的。所以AOP——面向切面编程其实是面向对象编程思想的一个补充。而我们今天讲的过滤器和拦截器都属于面向切面编程的具体实现。而两者的主要区别包括以下几个方面:
1、Filter是依赖于Servlet容器,属于Servlet规范的一部分,而拦截器则是独立存在的,可以在任何情况下使用。
2、Filter的执行由Servlet容器回调完成,而拦截器通常通过动态代理的方式来执行。
3、Filter的生命周期由Servlet容器管理,而拦截器则可以通过IoC容器来管理,因此可以通过注入等方式来获取其他Bean的实例,因此使用会更方便。
过滤器的使用场景
Java过滤器是处于客户端与服务器资源文件之间的一道过滤网,在访问资源文件之前,通过一系列的过滤器可以对请求进行修改、判断等,把不符合规则的请求在中途拦截或修改;也可以对响应进行过滤,拦截或修改响应。

服务器

FILTER

FILTER

FILTER

浏览器

通过参数过滤

通过SESSION

SERVLET

设置编码

属性过滤

JSP

HTML

等等资源文件

FILTER

FILTER

FILTER

设置响应头

设置编码

FILTER链

中文网

PHP

青锋开源架构-springboot2.6.x+vue3-antdesign-vite之整合拦截器/过滤器_第3张图片


如图,浏览器发出的请求先递交给第一个filter进行过滤,符合规则则放行,递交给filter链中的下一个过滤器进行过滤。过滤器在链中的顺序与它在web.xml中配置的顺序有关,配置在前的则位于链的前端。当请求通过了链中所有过滤器后就可以访问资源文件了,如果不能通过,则可能在中间某个过滤器中被处理掉。

在doFilter()方法中,chain.doFilter()前的一般是对request执行的过滤操作,chain.doFilter后面的代码一般是对response执行的操作。过滤链代码的执行顺序如下:

CODE2

CODE1

浏览器

目标资源

CHAIN.DOFILTER()

CHAIN.DOFILTER()

PHP中文网

CODE1

CODE2

青锋开源架构-springboot2.6.x+vue3-antdesign-vite之整合拦截器/过滤器_第4张图片


过滤器一般用于登录权限验证、资源访问权限控制、敏感词汇过滤、字符编码转换等等操作,便于代码重用,不必每个servlet中还要进行相应的操作。
实现一、通过FilterRegistrationBean配置
创建CustomizeFilter

package com.qingfeng.framework.servlet;

import javax.servlet.*;
import java.io.IOException;

/**
 * @author Administrator
 * @version 1.0.0
 * @ProjectName qingfeng
 * @Description 过滤器
 * @createTime 2022年01月18日 13:18:00
 */
public class CustomizeFilter implements Filter {

    public void init(FilterConfig filterConfig) throws ServletException {

    }

    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        long start = System.currentTimeMillis();
        filterChain.doFilter(servletRequest,servletResponse);
        System.out.println("Execute cost="+(System.currentTimeMillis()-start));
    }

    public void destroy() {

    }
}

这段代码的逻辑比较简单,就是在方法执行前先记录时间戳,然后通过过滤器链完成请求的执行,在返回结果之间计算执行的时间。这里需要主要,这个类必须继承Filter类,这个是Servlet的规范,这个跟以前的Web项目没区别。但是,有了过滤器类以后,以前的web项目可以在web.xml中进行配置,但是spring boot项目并没有web.xml这个文件,那怎么配置?在Spring boot中,我们需要FilterRegistrationBean来完成配置。其实现过程如下:

创建FilterConfig

package com.qingfeng.framework.servlet;

import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/**
 * @author Administrator
 * @version 1.0.0
 * @ProjectName qingfeng
 * @Description 过滤器配置
 * @createTime 2022年01月18日 13:19:00
 */
@Configuration
public class FilterConfig {
    @Bean
    public FilterRegistrationBean registFilter() {
        FilterRegistrationBean registration = new FilterRegistrationBean();
        registration.setFilter(new CustomizeFilter());
        registration.addUrlPatterns("/*");
        registration.setName("LogCostFilter");
        registration.setOrder(1);
        return registration;
    }
}

这样配置就完成了,需要配置的选项主要包括实例化Filter类,然后指定url的匹配模式,设置过滤器名称和执行顺序,这个过程和在web.xml中配置其实没什么区别,只是形式不同而已。现在我们可以启动服务器访问任意URL:

实现二、通过WebFilter配置

除了通过 FilterRegistrationBean 来配置以外,还有一种更直接的办法,直接通过注解就可以完成了:

 

package com.qingfeng.framework.servlet;

import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import java.io.IOException;

/**
 * @author Administrator
 * @version 1.0.0
 * @ProjectName qingfeng
 * @Description TODO
 * @createTime 2022年01月18日 13:25:00
 */
@WebFilter(urlPatterns = "/*", filterName = "CustomizeFilter2")
public class CustomizeFilter2 implements Filter {

    public void init(FilterConfig filterConfig) throws ServletException {

    }

    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws ServletException, IOException {
        long start = System.currentTimeMillis();
        filterChain.doFilter(servletRequest, servletResponse);
        System.out.println("CustomizeFilter2 Execute cost=" + (System.currentTimeMillis() - start));
    }

    @Override
    public void destroy() {

    }
}

这里直接用@WebFilter就可以进行配置,同样,可以设置url匹配模式,过滤器名称等。这里需要注意一点的是@WebFilter这个注解是Servlet3.0的规范,并不是Spring boot提供的。除了这个注解以外,我们还需在配置类中加另外一个注解:@ServletComponetScan,指定扫描的包。

@SpringBootApplication
@MapperScan("com.qingfeng.*.mapper")
@ServletComponentScan("com.qingfeng.framework.servlet")
public class QingfengApplication {

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

}

第二个Filter我们并没有指定执行的顺序,但是却在第一个Filter之前执行。这里需要解释一下,@WebFilter这个注解并没有指定执行顺序的属性,其执行顺序依赖于Filter的名称,是根据Filter类名(注意不是配置的filter的名字)的字母顺序倒序排列,并且@WebFilter指定的过滤器优先级都高于FilterRegistrationBean配置的过滤器。有兴趣的朋友可以自己实验一下。

你可能感兴趣的:(springboot,系统架构,spring,boot,vue)