Filter:过滤器

1、概念:过滤器的作用:般用于完成通用的操作,如:登入验证,统一编码处理、敏感字符过滤…

快速入门:

  • 创建一个web项目
  • 定义一个类实现filter过滤器接口、从写方法。
  • 将过滤器配置到web.xml中、

1、创建web的结构

java 使用过滤器get乱码 java过滤器过滤特殊字符_xml

2、filter类

/*
创建一个类实现javax.servlet.Filter接口、从写它里面的方法
init() ---  在你的服务启动时、会做数据的初始化、
doFilter() ---  过滤器的主要方法、对request、response做一些处理。
destroy()  ---  在服务器关闭时销毁数据。
* */
public class CharacterFilter implements Filter {
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        System.out.println("filterConfig配置"+filterConfig);
    }

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        System.out.println("进入过滤");
        /*
            这个调用chain.doFilter(request,response);//方法就是将执行下一个过滤器、或xxxServlet
            如果没有下一个过滤就执行xxxServlet然后就会根据你的请求执行对应的get/post方法
        * */
	     chain.doFilter(request,response);//简单来说这个就好比如过滤完成放行的意思
    
    }

    @Override
    public void destroy() {
        System.out.println("销毁过滤");
    }
}

3、web.xml

<!-- 过滤器  -->
<filter>
  <filter-name>characterFilter</filter-name>
  <filter-class>com.wei.config.CharacterFilter</filter-class>
</filter>
<filter-mapping>
  <filter-name>characterFilter</filter-name>
  <url-pattern>/a</url-pattern>  <!-- 拦截路径-->
</filter-mapping>
<!-- 
	<url-pattern>/a</url-pattern>   拦截路径
	这里设置要过滤什么请求
-->

4、运行结果

java 使用过滤器get乱码 java过滤器过滤特殊字符_xml_02

把服务器关了后会执行销毁的方法。

5、案例小结

注意点

chain.doFilter(request,response);//简单来说这个就好比如过滤完成放行的意思
这个一定要放行

web.xml

<!-- 过滤器  -->
<filter>
  <filter-name>characterFilter</filter-name>
  <filter-class>com.wei.config.CharacterFilter</filter-class>
</filter>
<filter-mapping>
  <filter-name>characterFilter</filter-name>
  <url-pattern>/a</url-pattern>  <!-- 拦截路径-->
</filter-mapping>
<!-- 
	<url-pattern>/a</url-pattern>   拦截路径
	这里设置要过滤什么请求
  配置要拦截的资源
  以指定资源匹配。例如"/index.jsp"
  以目录匹配。例如"/servlet/*"
  以后缀名匹配,例如"*.jsp"
  通配符,拦截所有web资源。"/*"
-->

多个过滤器执行的先后:

在web.xml中定义多个过滤、并指定你过滤同一个请求、最后他的执行先后是什么。

代码测试

1、创建多个xxxFilter类

public class AFilter implements Filter {
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {

    }

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        System.out.println("A过滤");
        chain.doFilter(request,response);
    }

    @Override
    public void destroy() {

    }
}
public class BFilter implements Filter {
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {

    }

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        System.out.println("B过滤");
        chain.doFilter(request,response);
    }

    @Override
    public void destroy() {

    }
}

2、配置webxml

<?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">
    <!-- B过滤器  -->
    <filter>
        <filter-name>bFilter</filter-name>
        <filter-class>com.wei.config.BFilter</filter-class>
    </filter>
    <filter-mapping>
        <filter-name>bFilter</filter-name>
        <url-pattern>/abc</url-pattern>  <!-- 拦截路径-->
    </filter-mapping>
    <!-- A过滤器  -->
    <filter>
        <filter-name>aFilter</filter-name>
        <filter-class>com.wei.config.AFilter</filter-class>
    </filter>
    <filter-mapping>
        <filter-name>aFilter</filter-name>
        <url-pattern>/abc</url-pattern>  <!-- 拦截路径-->
    </filter-mapping>
</web-app>

3、测试效果

B过滤
A过滤
进入UserServlet

4、小结

注意

在web.xml中定义多个过滤的执行效果可以看出来、<filter-mapping>前面的过滤器会被先执行、后面的会接着执行

建议每个Filter做自己的逻辑判断、不要相互关联着。

注解版过滤器

使用注解开发、会减少大量代码、

代码测试

1、创建类实现Filter接口

@WebFilter(filterName = "AnnotationFilter",urlPatterns = {"/abc","/acd"})
public class AnnotationFilter implements Filter {
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {

    }

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        System.out.println("注解版过滤器");
        chain.doFilter(request,response);
    }

    @Override
    public void destroy() {

    }
}

之前做过滤器都是创建好类之后、将过滤添加配置到web.xml中、配置过滤、使用注解后不用在web.xml中配置、简单来说就是使用注解来实现过滤器不用在web.xml中配置

2、测试结果

注解版过滤器
进入UserServlet

3、详解

@WebFilter() 注解

public @interface WebFilter {

    String description() default "";

    String displayName() default "";
    
    WebInitParam[] initParams() default {};		//配置初始化参数,跟Servlet配置一样

    String filterName() default "";   //设置过滤的名称、可以不写

    String smallIcon() default "";

    String largeIcon() default "";

    String[] servletNames() default {};

    String[] value() default {};					// 要过滤的资源路径或请求

    String[] urlPatterns() default {};		// 要过滤的资源路径或请求

    DispatcherType[] dispatcherTypes() default {DispatcherType.REQUEST};  //拦截方式配置:资源被访问的方式
    
    boolean asyncSupported() default false;

}

没写注释的我就不知道什么意思了、自行百度。

注解属性使用

@WebFilter(filterName = "AnnotationFilter",
        urlPatterns = {"/abc","/acd"},
        dispatcherTypes = {DispatcherType.FORWARD},
        initParams = {@WebInitParam(name = "a",value = "b")})
public class AnnotationFilter implements Filter {
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
      //获取注解的初始化的值
        System.out.println(filterConfig.getInitParameter("a"));
    }

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        System.out.println("注解版过滤器");
        chain.doFilter(request,response);
    }

    @Override
    public void destroy() {

    }
}

要注意的就是这个属性

dispatcherTypes = {DispatcherType.FORWARD}
DispatcherType.XXXXX  ----  这个是设置拦截的类型

可以设置的值为:

1. REQUEST:默认值。浏览器直接请求资源
2. FORWARD:转发访问资源
3. INCLUDE:包含访问资源
4. ERROR:错误跳转资源
5. ASYNC:异步访问资源

java 使用过滤器get乱码 java过滤器过滤特殊字符_ide_03

设置了这个值、对资源的过滤就有一个过滤的条件、比如设置转发类型、在转发的地址、在@WebFilter注解中设置了则此过滤器的被执行的路径、如果转发的地址不和注解中设置的过滤路径一样、则这个不执行该注解

如果有多个过滤器、一些过滤器是在web.xml中设置的一些是使用注解设置的过滤器该怎么办?会先运行谁?

  • 注解配置:按照类名和字符串比较规则值小的先执行
  • 如 AFilter 和 BFilter,AFilter就先执行
  • web.xml配置<filter-mapping>谁定义在上边,谁先执行
  • 优先执行web.xml中的过滤。

过滤器总结

  • 过滤器执行流程
  • 执行过滤器
  • 执行放行后的资源
  • 回来执行下一个过滤器或者servlet
  • 过滤器生命周期方法
  • init:在服务器启动后,会创建FIlter对象然后调用init方法。只执行一次。用于加载资源
  • doFilter:每一次请求被拦截资源是会被创建。执行多次。
  • destroy:在服务器正常关闭后,Filter对象被销毁、只执行一次。用于释放资源
  • 多过滤器的执行顺序
  • 注解配置:按照类名和字符串比较规则值小的先执行
  • 如 AFilter 和 BFilter,AFilter就先执行
  • web.xml配置<filter-mapping>谁定义在上边,谁先执行

敏感字过滤

敏感字过滤、常见于留言评论是出现辱骂、广告的一些词

技术所需

  • servlet
  • maven

前期准备

  • 创建一个web项目
  • 导入所需要的pom坐标
  • 创建xxx.filter类、创建servlet
  • 敏感字xx.txt文件
  • 编写前端页面

最后实现的效果

  • 将敏感字过滤掉、过滤后的敏感字设置为**

1、项目结构图

java 使用过滤器get乱码 java过滤器过滤特殊字符_java_04

2、导入的pom依赖

<dependencies>
  <!--servlet-->
  <dependency>
    <groupId>javax.servlet</groupId>
    <artifactId>javax.servlet-api</artifactId>
    <version>3.1.0</version>
    <scope>provided</scope>
  </dependency>
</dependencies>

3、xxx.servlet

@WebServlet("/a")
public class CharacterServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        req.setCharacterEncoding("utf-8");
        resp.setContentType("text/html;charset=utf-8");
        System.out.println("进入CharacterServlet");
        String name = req.getParameter("name");
        System.out.println("CharacterServlet的获取的>>>"+name);
        req.setAttribute("flag",name);
        req.getRequestDispatcher("index.jsp").forward(req,resp);
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        doGet(req, resp);
    }
}

4、编写过滤器

/*
创建一个类实现javax.servlet.Filter接口、从写它里面的方法
init() ---  在你的服务启动时、会做数据的初始化、
doFilter() ---  过滤器的主要方法、对request、response做一些处理。
destroy()  ---  在服务器关闭时销毁数据。
* */
@WebFilter(filterName = "CharacterFilter",urlPatterns = {"/a"})
public class CharacterFilter implements Filter {
    private static List<String> list = null; // 敏感字集合
    static {
        BufferedReader br = null; // 字符缓存流
        list = new ArrayList<String>();
        try {
            // 获取resources下指定文件路径
            String fileName = CharacterFilter.class.getClassLoader().getResource("name.txt").getPath();//获取文件路径
//            System.out.println(fileName);
            br = new BufferedReader(new FileReader(fileName));
            String str = null;
            while ((str = br.readLine()) != null){ //读取数据
                list.add(str); //添加到集合
            }
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally{
            if (br != null) {
                try {
                    br.close();//释放资源
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        System.out.println("filterConfig配置"+filterConfig);
    }

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        System.out.println("进入文字过滤");
        //创建动态代理对象
        ServletRequest Proxy_Request = (ServletRequest)Proxy.newProxyInstance(request.getClass().getClassLoader(), request.getClass().getInterfaces(), new InvocationHandler() {
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                if (method.getName().equals("getParameter")) { // 判断是否是getParameter()、增强getParameter()方法
                    String value = (String) method.invoke(request, args);  //增强返回值
                    if (value != null) {
                        for (String str : list) { //遍历敏感字
                            if (value.contains(str)) { // 验证是否包含
                                StringBuilder sb = new StringBuilder();
                                int length = str.length();
                                for (int i = 0; i < length; i++) {
                                    sb.append("*"); // 添加星号
                                }
                                value = value.replace(str,sb.toString()); // 将敏感字替换为*、然后将值重新复制给value变量
                            }
                        }
                    }
                    return value; // 将新的值返回出去
                }
                return method.invoke(request,args); //执行方法
            }
        });
        /*
            这个调用chain.doFilter(request,response);//方法就是将执行下一个过滤器、或xxxServlet
            如果没有下一个过滤就执行xxxServlet然后就会根据你的请求执行对应的get/post方法
        * */
        // 这里要注意这里传递过去的是增强后的代理对象
        chain.doFilter(Proxy_Request,response);//简单来说这个就好比如过滤完成放行的意思/

    }

    @Override
    public void destroy() {
        System.out.println("销毁过滤");
    }
}

5、敏感字xx.txt

xx
xxx
傻
//自行该敏感字

6、前端页面

<html>
  <head>
    <title>$Title$</title>
  </head>
  <body>
        <form action="/a" method="post">
            <input type="name" name="name">
            <input type="submit" value="确定">
        </form>
  <h1>敏感词过滤结果>>>${flag != null ? flag : "无"}</h1>
  </body>
</html>

7、测试结果

java 使用过滤器get乱码 java过滤器过滤特殊字符_java 使用过滤器get乱码_05

java 使用过滤器get乱码 java过滤器过滤特殊字符_xml_06

注意:

在实现filter类的doFilter()方法中最为重要、当中使用了动态代理、对request中的getParameter()进行了增强、将检查到的敏感字替换成***、将其后的结果做为最新的返回值返回。