JavaWeb三大组件之一Filter(过滤器)

这篇具有很好参考价值的文章主要介绍了JavaWeb三大组件之一Filter(过滤器)。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

定义

拦截所有访问web资源的请求或者响应(servlet、Jsp页面、HTML页面),从而实现我们自己的业务逻辑,这些逻辑可以是实现访问权限的控制、过滤敏感词、压缩响应等功能。

原理 

过滤器是"链接"在容器的处理过程中的,它会在servlet处理器之前访问进入的请求,并且在响应信息返回客服端之前访问这些响应信息。这样就可以动态的修改请求和响应中的内容。

JavaWeb三大组件之一Filter(过滤器)

创建Filter

创建web项目:

JavaWeb三大组件之一Filter(过滤器)

JavaWeb三大组件之一Filter(过滤器) 

JavaWeb三大组件之一Filter(过滤器)

或者像这样建立web项目:

JavaWeb三大组件之一Filter(过滤器) 

JavaWeb三大组件之一Filter(过滤器)

JavaWeb三大组件之一Filter(过滤器)JavaWeb三大组件之一Filter(过滤器) 

JavaWeb三大组件之一Filter(过滤器)  

添加Tomcat服务器:

JavaWeb三大组件之一Filter(过滤器) 

如果没有SmartTomcat,只有Tomcat像下面图片中这样:

JavaWeb三大组件之一Filter(过滤器) 

则选择Tomcat里面的local,并向下面这样配置:

JavaWeb三大组件之一Filter(过滤器) 

JavaWeb三大组件之一Filter(过滤器) 

JavaWeb三大组件之一Filter(过滤器) 

启动程序:

JavaWeb三大组件之一Filter(过滤器) 

JavaWeb三大组件之一Filter(过滤器) 

 添加java包和servlet依赖:

JavaWeb三大组件之一Filter(过滤器)

创建过滤器并实现它的方法:

JavaWeb三大组件之一Filter(过滤器) 

在web.xml中注册Filter: 

JavaWeb三大组件之一Filter(过滤器)

 文章来源地址https://www.toymoban.com/news/detail-470645.html

当我们在执行的时候,发现会报404错误,那是因为我们没有重写Filter里面的init方法,在用Filter的时候必须重写init方法,因为web 工程启动的时候执行构造器方法和init 初始化方法 ,如果不重写初始化方法,就不会走过滤器。

重写Filter里面的init方法,然后执行过滤器:

JavaWeb三大组件之一Filter(过滤器)

JavaWeb三大组件之一Filter(过滤器) 

JavaWeb三大组件之一Filter(过滤器) 

我们会发现在浏览器中什么都没有输出,但是控制台中输出了doFilter里面内容,说明我们的过滤器起作用了 ,他拦截了所有的请求。当我们在doFilter方法里面加上下面的逻辑,浏览器就会输出内容:

JavaWeb三大组件之一Filter(过滤器) 

 JavaWeb三大组件之一Filter(过滤器)

JavaWeb三大组件之一Filter(过滤器) 

上面filterChain里面的doFilter方法它的作用就是请求放行到下一个资源,这个资源有可能是过滤器,也可能是客户端。

 

Filter的生命周期 

JavaWeb三大组件之一Filter(过滤器) 

上面每一步分别对应不同的方法:

实例化对应Filter的构造器方法,初始化对应init()方法、销毁对应的是destroy()方法 

Filter它是一个接口,该接口里面有如下几个方法:

JavaWeb三大组件之一Filter(过滤器) 

destroy()

当web服务器调用该方法时,表示过滤器将被销毁。

init()

当web服务器调用该方法时,表示过滤器将被注册到服务中

doFilter()

当服务器调用Filter中的doFilter()方法,它会将每一个请求或者响应传递给下一个资源

具体实现:

JavaWeb三大组件之一Filter(过滤器) 

JavaWeb三大组件之一Filter(过滤器) 

1.可以看到Filter是在应用启动是被创建和初始化的。

JavaWeb三大组件之一Filter(过滤器) 

JavaWeb三大组件之一Filter(过滤器) 

2.Filter是单例多线程的(创建和初始化只会被执行一次) 

3.doFilter()方法无论是那一个线程访问,只要由该Filter进行过滤,那么就会执行该Filter的doFilter()方法,并且是每过滤一次就会执行一次doFilter()。

JavaWeb三大组件之一Filter(过滤器) 

4.Filter中destroy方法是在应用被停止时调用的,它意味着销毁这个Filter。 

5.由于Filter是单列多线程的,所以为了保证线程安全,不能在Filter中定义可修改的成员变量,因为每个线程均可修改这个成员变量,这样就会带来线程安全问题。 

FilterConfig 

FilterConfig指的是Filter在web.xml中的注册信息 ,它将注册信息进行封装,然后通过形参的方式传给初始化方法。

FilterConfig里面的方法:

JavaWeb三大组件之一Filter(过滤器) 

演示使用:

package com.xihua;

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


public class MyFilter implements Filter {
    private FilterConfig filterConfig;
    public MyFilter() {
        System.out.println("执行了MyFilter的构造方法");
    }

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        this.filterConfig = filterConfig;
        System.out.println("执行了init方法");
    }

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        //获取过滤器的名字
        String filterName = filterConfig.getFilterName();
        System.out.println("过滤器的名字:" + filterName);
        //获取过滤器中所有的初始化参数名称
        Enumeration<String> names = filterConfig.getInitParameterNames();
        while (names.hasMoreElements()){
            String name = names.nextElement();
            //获取过滤器中初始化参数对应的值
            String value = filterConfig.getInitParameter(name);
            System.out.println(name + "=" + value);
        }
        //获取全局域
        ServletContext sc = filterConfig.getServletContext();
        System.out.println("servletContext=" + sc);

        filterChain.doFilter(servletRequest,servletResponse);
    }

    @Override
    public void destroy() {
        System.out.println("执行了destory方法");
    }
}
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
         version="4.0">
    <filter>
        <filter-name>MyFilter</filter-name>
        <filter-class>com.xihua.MyFilter</filter-class>
        <init-param>
            <param-name>school</param-name>
            <param-value>xihua</param-value>
        </init-param>
        <init-param>
            <param-name>researcher</param-name>
            <param-value>jack</param-value>
        </init-param>
    </filter>

    <filter-mapping>
        <filter-name>MyFilter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>
</web-app>

运行结果:

JavaWeb三大组件之一Filter(过滤器) 

<filter-mapping> 

<filter-mapping>标签表示拦截匹配,也就是要拦截那些请求。

<filter-name>:要拦截的过滤器名称

<url-pattern>:拦截那些路径

<url-pattern>

注意Filter中在写拦截所有路径的时候只能写成/*,而不能写成/,因为写成/它就不走拦截器中的doFilter方法了。 

在Servlet中/*即会拦截动态资源又会拦截静态资源,而/不会拦截动态资源

演示Filter拦截动态和静态资源如下:

package com.xihua;

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


public class MyFilter implements Filter {
    public MyFilter() {
        System.out.println("执行了MyFilter的构造方法");
    }

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        System.out.println("执行了init方法");
    }

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        System.out.println("执行doFilter之前");
        System.out.println("执行doFilter之后");
    }

    @Override
    public void destroy() {
        System.out.println("执行了destory方法");
    }
}
package com.xihua.servlet;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

public class SomeServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        System.out.println("执行SomeServlet");
    }
}
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
         version="4.0">
    <filter>
        <filter-name>MyFilter</filter-name>
        <filter-class>com.xihua.MyFilter</filter-class>
    </filter>
    <filter-mapping>
        <filter-name>MyFilter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>
    
    <servlet>
        <servlet-name>SomeServlet</servlet-name>
        <servlet-class>com.xihua.servlet.SomeServlet</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>SomeServlet</servlet-name>
        <url-pattern>/SomeServlet</url-pattern>
    </servlet-mapping>
</web-app>

JavaWeb三大组件之一Filter(过滤器) 

JavaWeb三大组件之一Filter(过滤器) 

JavaWeb三大组件之一Filter(过滤器)  

当将Filter中的拦截改为/时,过滤器将不起作用:

JavaWeb三大组件之一Filter(过滤器) 

下面演示Servlet/*和/的区别: 

JavaWeb三大组件之一Filter(过滤器) 

JavaWeb三大组件之一Filter(过滤器)  

JavaWeb三大组件之一Filter(过滤器) 

JavaWeb三大组件之一Filter(过滤器) 

在<filter-mapping>标签中可以不使用<url-pattern>标签,但是需要指定<servlet-name>,这样就能指定拦截某个servlet而不拦截其他请求:

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
         version="4.0">
    <filter>
        <filter-name>MyFilter</filter-name>
        <filter-class>com.xihua.MyFilter</filter-class>
    </filter>
    <filter-mapping>
        <filter-name>MyFilter</filter-name>
        <!--<url-pattern>/*</url-pattern>-->
        <servlet-name>SomeServlet</servlet-name>
    </filter-mapping>
    <servlet>
        <servlet-name>SomeServlet</servlet-name>
        <servlet-class>com.xihua.servlet.SomeServlet</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>SomeServlet</servlet-name>
        <url-pattern>/SomeServlet</url-pattern>
    </servlet-mapping>
</web-app>

 JavaWeb三大组件之一Filter(过滤器)

 

Filter里面的<dispatcher>标签

dispatcher表示分发器,表示过滤器所拦截的资源被servlet容器调用的方式,可以是REQUEST,INCLUDE,FORWARD,ERROR中的任何一个,默认是REQUEST。用户可以设置多个<dispatcher>子元素用来指定过滤器对资源的多种调用方式进行拦截。

FORWARD 表示当前过滤器只会拦截由一个Servlet通过RequestDispatcher的forward()完成跳转
INCLUDE 表示当前过滤器只会拦截由一个Servlet通过RequestDispatcher的include()完成跳转
REQUEST 表示当前过滤器会拦截普通请求,但对于forward()与include()的跳转不进行拦截,REQUEST是默认的。
ERROR 表示当跳转到指定的错误处理页面时,这个跳转请求会被当前过滤器拦截

下面演示上面四个子元素的区别:

两个servlet:SomeServlet、OtherServelt

package com.xihua.servlet;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

public class SomeServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        System.out.println("执行SomeServlet");
        req.getRequestDispatcher("/otherServlet").forward(req,resp);
    }
}
package com.xihua.servlet;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

public class OtherServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        System.out.println("执行了otherServlet");
    }
}

 在xml文件做如下配置:

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
         version="4.0">
    <!--注册Filter-->
    <filter>
        <filter-name>MyFilter</filter-name>
        <filter-class>com.xihua.MyFilter</filter-class>
    </filter>
    <filter-mapping>
        <filter-name>MyFilter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>
    <!--注册SomeServlet-->
    <servlet>
        <servlet-name>SomeServlet</servlet-name>
        <servlet-class>com.xihua.servlet.SomeServlet</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>SomeServlet</servlet-name>
        <url-pattern>/someServlet</url-pattern>
    </servlet-mapping>
    <!--注册OtherServlet-->
    <servlet>
        <servlet-name>OtherServlet</servlet-name>
        <servlet-class>com.xihua.servlet.OtherServlet</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>OtherServlet</servlet-name>
        <url-pattern>/otherServlet</url-pattern>
    </servlet-mapping>
</web-app>

执行someServlet请求,因为在someServlet中我们设定了一个请求转发,观察拦截器的拦截效果:

JavaWeb三大组件之一Filter(过滤器) 

再来看一下在<filter>标签里面添加<dispatcher>标签,并设定子元素为FORWARD:

    <filter-mapping>
        <filter-name>MyFilter</filter-name>
        <url-pattern>/*</url-pattern>
        <dispatcher>FORWARD</dispatcher>
    </filter-mapping>

JavaWeb三大组件之一Filter(过滤器) 

JavaWeb三大组件之一Filter(过滤器)   

将请求转发的关键字换成include:

JavaWeb三大组件之一Filter(过滤器) 

JavaWeb三大组件之一Filter(过滤器)  

出现上面的原因是因为:

JavaWeb三大组件之一Filter(过滤器)

JavaWeb三大组件之一Filter(过滤器) 

 

请求转发中forward和include的区别在于响应的标准输出流开启时间不一样,forward会请求传递给最后一个servlet,当最后一个servet执行完以后才会开启/返回响应。而include它是将其他请求包在第一个请求里面,并由第一个请求开启/返回响应。

 

Filter对请求和响应的修改 

JavaWeb三大组件之一Filter(过滤器) 

JavaWeb三大组件之一Filter(过滤器) 

JavaWeb三大组件之一Filter(过滤器) 

JavaWeb三大组件之一Filter(过滤器) 

多个Filter的执行顺序

两个Filter:MyFilter、UsFilter,在xml文件中先配置MyFilter,后配置UsFilter

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
         version="4.0">
    <!--注册MyFilter-->
    <filter>
        <filter-name>MyFilter</filter-name>
        <filter-class>com.xihua.MyFilter</filter-class>
    </filter>
    <filter-mapping>
        <filter-name>MyFilter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>

    <!--注册UsFilter-->
    <filter>
        <filter-name>UsFilter</filter-name>
        <filter-class>com.xihua.UsFilter</filter-class>
    </filter>
    <filter-mapping>
        <filter-name>UsFilter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>
    <!--注册SomeServlet-->
    <servlet>
        <servlet-name>SomeServlet</servlet-name>
        <servlet-class>com.xihua.servlet.SomeServlet</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>SomeServlet</servlet-name>
        <url-pattern>/someServlet</url-pattern>
    </servlet-mapping>

</web-app>

JavaWeb三大组件之一Filter(过滤器) 

JavaWeb三大组件之一Filter(过滤器) 

交换xml文件中的配置顺序:

JavaWeb三大组件之一Filter(过滤器) 

总结:多个Filter的执行顺序,与Filter的配置顺序有关。 

JavaWeb三大组件之一Filter(过滤器) 

Filter的执行原理 

Servlet的执行原理:在Servlet中有两个Map,这两个Map的key均为Servlet注册时的<url-pattern/>值,但value是不同的。第一个Map的value是Servlet实例对象的引用,第二个Map的value为<servlet-class/>的值,即Servlet类的全限定类名。

执行原理:

当对Servlet的请求到达Servlet容器时,会先对请求进行解析,使用该解析出的URL,作为比较对象,从第一个Map中查找是否有匹配的key,若不存在匹配的key,那么读取其value,即Servlet对象的引用,执行该Servlet的service()方法。

若不存在匹配的key ,那么再从第二个Map中查找是否有匹配的key。若存在,这读取其value,即读取其value,即要访问的Servlet的全限定类名。然后使用反射机制创建该Servlet实例,并将该实例写入到第一个Map中,然后在执行该Servlet的service()方法。

若第二个Map中也没有找到匹配的key,那么就跳转到错误处理页面404。

Filter的执行原理:

一个数组与一个Map :

一个Map:Map的key为<url-pattern/>的值,value为Filter实例对象的引用

一个数组:存在着与请求相匹配的所有Filter

执行原理:

当对某资源的请求到达Web容器时,会先对请求进行解析,使用解析出的URI作为比较对象,从Map中查找是否存在相匹配的key。若存在,那么读取其value,即Filter对象的引用,将该应用存入到数组中。然后继续向后查找,直到将Map查找完毕。这样在数组中就会存在按照查找顺序排好序的Filter引用。

数组初始化完毕后,开始按照数组元素顺序进行执行。所有数组中的Filter全部执行完毕后,再跳转到请求的目标资源。

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

到了这里,关于JavaWeb三大组件之一Filter(过滤器)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 过滤器Filter

    什么是Filter? Filter表示过滤器,是JavaWeb三大组件(Servlet、FIlter、Listener)之一。 过滤器可以把对资源的请求拦截下来,总而实现一些特殊的功能 使用过滤器后,要想访问web服务器上的资源,必须先经过过滤器,过滤器处理完毕后,才可以访问对应的资源。 过滤器一般完成

    2023年04月12日
    浏览(40)
  • 结果过滤器—MVC项目中结果过滤器(Result Filter)使用

    结果过滤器( ResultFilter ),是对执行的Action结果进行处理的一种AOP思想,适用于任何需要直接环绕 View 或格式化处理的逻辑。结果过滤器可以 替换或更改 Action 结果 。在 IActionResult 执行的前后执行,使用它能够控制Action的执行结果,比如:格式化结果等。需要注意的是,它只

    2024年02月12日
    浏览(55)
  • java过滤器(Filter)

    原文链接: java过滤器(Filter – 编程屋 目录 1 过滤器简介 2 Filter详细介绍 3 Filter的用法 3.1 用法1  3.2 用法2 filter也称之为过滤器,它是javaWeb三大组件之一(Servlet程序、Listener监听器、Filter过滤器) 作用: 既可以对请求进行拦截,也可以对响应进行处理。 常见场景: 权限检

    2024年02月20日
    浏览(43)
  • [Java]过滤器(Filter)

    一、什么是过滤器 过滤器是Servlet的高级特性之一,是实现Filter接口的Java类! 过滤器的执行流程:   从上面的图我们可以发现,当浏览器发送请求给服务器的时候, 先执行过滤器,然后才访问Web的资源。服务器响应Response,从Web资源抵达浏览器之前,也会途径过滤器。 过滤

    2024年02月11日
    浏览(43)
  • SpringCloudGateway--过滤器(内置filter)

    目录 一、概览 二、内置过滤器 1、StripPrefix 2、AddRequestHeader 3、AddResponseHeader 4、DedupeResponseHeader 5、AddRequestParameter 6、CircuitBreaker 7、FallbackHeaders 8、RequestRateLimiter 9、RedirectTo 10、RemoveRequestHeader 11、RemoveResponseHeader 12、RemoveRequestParameter 13、RewritePath  14、RewriteResponseHeader  15、S

    2024年02月01日
    浏览(68)
  • 布隆过滤器(Bloom Filter)

    通常我们会遇到很多要判断一个元素是否在某个集合中的业务场景,一般想到的是将集合中所有元素保存起来,然后通过比较确定。链表、树、散列表(又叫哈希表,Hash table)等等数据结构都是这种思路。但是随着集合中元素的增加,我们需要的存储空间也会呈现线性增长,

    2024年02月08日
    浏览(46)
  • 登录校验-Filter-登录校验过滤器

    目录 思路 登录校验Filter-流程 步骤 流程图 登录校验Filter-代码 过滤器类 工具类 测试登录 登录接口功能请求 其他接口功能请求 前后端联调  前端访问登录接口,登陆成功后,服务端会生成一个JWT令牌,并返回给前端,前端会将JWT令牌保存下来,在同一会话中共享JWT令牌信息

    2024年02月11日
    浏览(39)
  • SpringCloudGateway--过滤器(自定义filter)

    目录 一、概览  二、全局过滤器GlobalFilter 三、通过GatewayFilter实现 四、继承AbstractGatewayFilterFactory        当使用Spring Cloud Gateway构建API网关时,可以利用Spring Cloud Gateway提供的内置过滤器(filter)来实现对请求的处理和响应的处理。过滤器可以在请求被路由之前或之后被执

    2024年02月06日
    浏览(40)
  • springboot中使用filter过滤器

    filter过滤器其实是JavaEE中的规范,JavaWeb中的三大组件是filter过滤器、listener监听器,servlet服务。 过滤器的作用就是把请求拦截下来,从而对请求进行一些特殊操作,比如检验用户是否登录,判断权限,设置编码格式、敏感字符处理等。 filter过滤器中有三个方法: 分别是初始

    2024年02月08日
    浏览(53)
  • gateway之过滤器(Filter)详解

    在Spring Cloud中,过滤器(Filter)是一种关键的组件,用于在微服务架构中处理和转换传入请求以及传出响应。过滤器位于服务网关或代理中,并通过拦截请求和响应流量来提供各种功能。 过滤器在请求的不同生命周期阶段执行特定的操作,例如鉴权、认证、请求转发、限流、

    2024年02月05日
    浏览(44)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包