Java Servlet中Filter过滤器的原理以及使用方式

详细介绍了Java Web Servlet中的Filter过滤器的原理以及常见用法。


过滤器属于Servlet规范,从2.3版本就开始有了。主要用于对到资源的请求或来自资源的响应执行过滤、筛选操作。

当存在过滤器的时候,对于来自客户端的请求来说,请求必须先经过滤器,放行之后,才能到达Web资源;对于返回的响应来说,响应同样会经过滤器,才能到达Web服务器,进而响应给客户端。

在这里插入图片描述

过滤器可以做很多事情,常见的包括:

  1. 过滤脏敏感字符(绿一些敏感的字符串);
  2. 避免中文乱码(统一设置请求和响应的编码);
  3. 权限验证(规定只有带指定Session或Cookie的请求,才能访问资源);
  4. 用于实现自动登录;

1 Filter接口

过滤器在Java中对应着javax.servlet.Filter接口,仅此而已,实现了Filter接口的类就可以被称作过滤器,就是这么简单。

Filter接口中有三个抽象方法,其中init和destroy方法作为过滤器的申请周期方法!

public interface Filter {

    default public void init(FilterConfig filterConfig) throws ServletException {}

    public void doFilter(ServletRequest request, ServletResponse response,
                         FilterChain chain)
            throws IOException, ServletException;

    default public void destroy() {}
}

1.1 过滤器的生命周期

  1. 诞生:过滤器的实例是在web应用被加载时就完成的实例化,并调用init方法初始化的。servlet 容器在实例化Filter后只调用init方法一次。在要求过滤器执行任何过滤工作之前,init 方法必须成功完成。区别于Servlet,过滤器会全部立即初始化。
  2. 每个过滤器在init初始化方法都会传递一个 FilterConfig 对象,从该对象可以获取其初始化参数。并可通过FilterConfig获取 ServletContext对象,比如可以使用该对象加载筛选任务所需的资源。
  3. 存活:和应用的生命周期一致的。在内存中是单例的。针对拦截范围内的资源,每次访问都会调用void doFIlter(request,response.chain)进行拦截。
  4. 死亡:应用被卸载时,Filter将被调用,此时会调用destroy方法,该方法只会被调用一次。

1.2 doFilter过滤方法

过滤器在 doFilter 方法中执行过滤操作。

doFilter方法中有一个FilterChain 参数对象,该对象由Servlet容器创建并传递给开发人员的。FilterChain表示一个过滤器链,客户端请求的资源在链的末尾。

在当前过滤器中,如果复合过滤规则,那么可以使用FilterChain#doFilter方法调用链中的下一个过滤器器,或者如果调用过滤器是链中的最后一个过滤器,则该方法将调用链末尾的资源。

也就是说,一个Web应用中可以有多个过滤器,它们将会按照一定顺序形成一个过滤器链,在链的最末尾就是要访问的资源,当一个请求到来的时候,他必须通过所有的过滤器,才能访问到真正的资源。

2 Filter的使用

开发一个过滤器很简单,只需要实现Filter接口,实现doFilter方法。

public class FirstFilter implements Filter {
    @Override
    public void init(FilterConfig filterConfig) {
        System.out.println("init");
    }

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        System.out.println("放行前");
        HttpServletRequest httpServletRequest= (HttpServletRequest) request;
        //获取当前请求的URL
        System.out.println(httpServletRequest.getRequestURL());
        //放行,调用下一个过滤器或者访问资源
        chain.doFilter(request, response);
        System.out.println("放行后");
    }

    @Override
    public void destroy() {
        System.out.println("destroy");
    }
}

随后我们还需要部署这个filter。通常情况下,Filter过滤器在 Web 应用程序的部署描述符中配置,也就是web.xml文件,这类似于Servlet。

首先是定义一个Filter:

<filter>
    <filter-name>FirstFilter</filter-name>
    <filter-class>com.example.filter.FirstFilter</filter-class>
    <!--当前过滤器的初始化参数,可以通过在init方法的参数FilterConfig对象获取-->
    <init-param>
        <param-name>aaa</param-name>
        <param-value>bbb</param-value>
    </init-param>
    <init-param>
        <param-name>ccc</param-name>
        <param-value>ddd</param-value>
    </init-param>
</filter>

一个<filter/>标签表示定义一个过滤器,<filter-name/>表示当前过滤器的name,<filter-class/>表示当前过滤器的类全路径名,<init-param/>表示当前过滤器的初始化参数,可以通过在init方法的参数FilterConfig对象获取这些参数。

随后我们还需要定义这个过滤器可以作用于哪些资源或者哪些Servlet!

<filter-mapping>
    <filter-name>FirstFilter</filter-name>
    <!--指定拦截指定路径的资源URL-->
    <url-pattern>/aa/*</url-pattern>
</filter-mapping>
<filter-mapping>
    <filter-name>FirstFilter</filter-name>
    <!--指定拦截指定的ServletName-->
    <servlet-name>Servlet2</servlet-name>
    <!--调度程序-->
    <!--<dispatcher>REQUEST</dispatcher>-->
</filter-mapping>

通过多个<filter-mapping/>标签可以为一个过滤器配置多个过滤映射,当然也可以将多个映射一个到一个<filter-mapping/>标签中

  1. <filter-name/>指定某个过滤器的名字
  2. <url-pattern/>指定过滤器所拦截的资源路径URL,“/”表示所有的Web资源都需要途径该过滤器,“.xxx”表示拦截访问xxx后缀的资源的请求。
  3. <servlet-name/>指定过滤器所拦截的某个Servlet的名字。
  4. <dispatcher/>指定过滤器在拦截时所应用的调度模式,一共有五个可选配置:FORWARD, REQUEST, INCLUDE, ASYNC, ERROR。
    1. FORWARD:如果目标资源是通过RequestDispatcher的forward()方法访问的,那么该过滤器将被调用,除此之外,该过滤器不会被调用。
    2. REQUEST:当用户直接通过普通路径访问资源时,Web容器将会调用过滤器。如果目标资源是通过RequestDispatcher的include()或forward()方法访问时,那么该过滤器就不会被调用。这是默认的模式。
    3. INCLUDE:如果目标资源是通过RequestDispatcher的include()方法访问的,那么该过滤器将被调用,除此之外,该过滤器不会被调用。
    4. ERROR:如果目标资源是通过声明式的异常处理机制调用的,那么该过滤器将被调用。除此之外,过滤器不会被调用。
    5. SYNC:意味着过滤器将在从异步上下文AsyncContext的调用下应用。

在Servlet 3.0以及之后,支持在Filter实现类上直接使用@WebFilter注解的方式配置过滤器,降低了配置文件的复杂度。例如:

@WebFilter(urlPatterns = "/aa/*",servletNames = "Servlet2")

下面简单测试,如下有三个Servlet:

@WebServlet(name = "Servlet1", value = "/aa/Servlet1")
public class Servlet1 extends HttpServlet {

    @Override
    public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException {
        System.out.println("请求到达");
        response.setContentType("text/html;charset=utf-8");
        PrintWriter out = response.getWriter();
        out.println("Servlet1");
    }
}

@WebServlet(name = "Servlet2", value = "/bb/Servlet2")
public class Servlet2 extends HttpServlet {

    @Override
    public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException {
        System.out.println("请求到达");
        response.setContentType("text/html;charset=utf-8");
        PrintWriter out = response.getWriter();
        out.println("Servlet2");
    }
}

@WebServlet(name = "Servlet3", value = "/bb/Servlet3")
public class Servlet3 extends HttpServlet {

    @Override
    public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException {
        System.out.println("请求到达");
        response.setContentType("text/html;charset=utf-8");
        PrintWriter out = response.getWriter();
        out.println("Servlet3");
    }
}

如果我们采用上面的过滤器设置,那么在访问Servlet1和Servlet2的时候,将会经过过滤器,而访问Servlet3的时候则不会经过过滤器,控制台输出为:

在这里插入图片描述

如果我们注释掉chain.doFilter方法,即不放行,那么访问Servlet1和Servlet2的时候,页面上不会有任何输出,也不会输出控制台也不会输出“请求到达”字符串,因为请求被拦截了,而访问Servlet3的时候则可以正常访问:

在这里插入图片描述

3 Filter的执行顺序

上面的简单测试,我们可能会发现,在chain.doFilter之前的逻辑在请求到达指定的Servlet之前执行,chain.doFilter之后的逻辑则是在请求到达指定的Servlet并离开之后执行。

过滤器链的完整流程顺序是这样的:客户端发送http请求到Web服务器上,Web服务器对该请求URL找到对应负责的过滤器形成过滤器链,接着从第一个过滤器开始进行过滤操作,也就是调用Filter.doFilter方法,这个方法的逻辑是开发者编写的,当当前请求满足当前过滤器的要求或者是过滤操作完毕之后,应在调用chain.doFilter方法进行放行,该方法又会调用链中的下一个过滤器的doFilter方法继续过滤,如果当前过滤器是过滤器链的最后一个过滤器,那么chain.doFilter方法将会执行资源访问操作,访问完毕之后,将会依照最开始过滤器的调用顺序倒序的返回,接着执行chain.doFilter方法后面的代码。最终将响应结果交给Web服务器,Web服务器再将响应返回给客户端。

3.1 多个过滤器

当某个请求对应存在多个过滤器时,过滤器之间的执行顺序是通过在web.xml文件中某个Filter的首个<filter-mapping/>定义的先后顺序决定的。

如下,两个Filter:

public class Filter1 implements Filter {
    @Override
    public void init(FilterConfig filterConfig) {
        System.out.println("Filter1-init");
    }

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        System.out.println("-----Filter1放行前-----");
        HttpServletRequest httpServletRequest= (HttpServletRequest) request;
        //获取当前请求的URL
        System.out.println(httpServletRequest.getRequestURL());
        //放行,调用下一个过滤器或者访问资源
        chain.doFilter(request, response);
        System.out.println("-----Filter1放行后-----");
    }

    @Override
    public void destroy() {
        System.out.println("destroy");
    }
}


public class Filter2 implements Filter {
    @Override
    public void init(FilterConfig filterConfig) {
        System.out.println("Filter2-init");
    }

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        System.out.println("-----Filter2放行前-----");
        HttpServletRequest httpServletRequest= (HttpServletRequest) request;
        //获取当前请求的URL
        System.out.println(httpServletRequest.getRequestURL());
        //放行,调用下一个过滤器或者访问资源
        chain.doFilter(request, response);
        System.out.println("-----Filter2放行后-----");
    }

    @Override
    public void destroy() {
        System.out.println("destroy");
    }
}

以下是映射配置:

<filter>
    <filter-name>Filter1</filter-name>
    <filter-class>com.example.filter.Filter1</filter-class>
</filter>
<filter>
    <filter-name>Filter2</filter-name>
    <filter-class>com.example.filter.Filter2</filter-class>
</filter>

<!--Filter2的mapping在前-->
<filter-mapping>
    <filter-name>Filter2</filter-name>
    <!--指定拦截指定的ServletName-->
    <servlet-name>Servlet2</servlet-name>
</filter-mapping>
<filter-mapping>
    <filter-name>Filter1</filter-name>
    <!--指定拦截指定路径的资源URL-->
    <url-pattern>/aa/*</url-pattern>
    <!--指定拦截指定的ServletName-->
    <servlet-name>Servlet2</servlet-name>
</filter-mapping>
<filter-mapping>
    <filter-name>Filter2</filter-name>
    <!--指定拦截指定路径的资源URL-->
    <url-pattern>/aa/*</url-pattern>
</filter-mapping>

可以看到Filter2的mapping在前,因此Filter2将先被执行,但是在资源访问完毕返回时,则是倒序执行!

我们访问Servlet1和Servlet2,将会得到如下结果:

在这里插入图片描述

如果是通过注解的方式配置,就比较urlPatterns的字符串优先级。

4 Filter的应用

Filter的简单应用包括:

  1. 可以在Filter中根据条件决定是否调用chain.doFilter(request,response)方法,即是否让目标资源能够访问。
  2. 在访问目标资源之前,可以对request\response作预处理。
  3. 在目标资源访问之后,可以捕获目标资源的执行结果,从而实现一些特殊的功能。

4.1 脏话过滤器

脏话过滤器,将参数中的脏话替换为**。

/**
 * 脏话过滤器,拦截所有访问路径
 *
 * @author lx
 */
@WebFilter("/*")
public class DirtyWordsFilter implements Filter {
    @Override
    public void init(FilterConfig filterConfig) {
        System.out.println("DirtyWordsFilter-init");
    }

    @Override
    public void doFilter(ServletRequest req, ServletResponse resp,
                         FilterChain chain) throws IOException, ServletException {

        HttpServletRequest request;
        HttpServletResponse response;
        try {
            request = (HttpServletRequest) req;
            response = (HttpServletResponse) resp;
        } catch (Exception e) {
            throw new RuntimeException("non-http request or response");
        }
        //传递一个装饰类,该类的getParameter能够过滤某些脏话
        DWHttpServletRequest dwrequest = new DWHttpServletRequest(request);
        chain.doFilter(dwrequest, response);
    }


    @Override
    public void destroy() {
        System.out.println("destroy");
    }
}

/**
 * 装饰类,接收一个request对象
 */
class DWHttpServletRequest extends HttpServletRequestWrapper {
    /**
     * 脏话词典
     */
    private String[] strs = {"坤坤", "凡凡", "禽兽", "畜生", "傻B"};

    public DWHttpServletRequest(HttpServletRequest request) {
        super(request);
    }

    /**
     * 增强了getParameter方法
     * <p>
     * 将参数中的脏话替换为**才返回
     */
    @Override
    public String getParameter(String name) {
        String value = super.getParameter(name);
        if (value == null) {
            return value;
        }
        for (String s : strs) {
            //将脏话替换为**才返回
            value = value.replace(s, "**");
        }
        return value;
    }
}

测试Servlet:

@WebServlet("/DirtyWordsServlet")
public class DirtyWordsServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws IOException {
        String name = req.getParameter("name");
        resp.setContentType("text/html;charset=utf-8");
        PrintWriter out = resp.getWriter();
        out.println("<h1>" + name + "</h1>");
    }
}

尝试请求http://localhost:8081/filter/DirtyWordsServlet?name=坤坤,返回结果如下:

在这里插入图片描述

4.2 编码过滤器

我们前面说过,tomcat8以下的版本默认对于URL采用iso-8859-1解码,那么get请求参数具有中文等特殊字符时,获取参数值的时候需要进行转码,并且在对于post请求的参数也需要通过setCharacterEncoding设置编码,非常麻烦。

现在有了Filter过滤器,我们可以使用一个Filter解决全部的get请求的乱码问题,这里涉及到动态代理的应用(tomcat8及其以上不适用,因为tomcat8默认对于URL采用utf-8解码,可以直接获取正常的参数值)。

同时,还能统一设置Post请求编码,以及响应编码,有了这个过滤器,就不必在各个Servlet中设置请求编码或者响应编码了。

Spring MVC中的CharacterEncodingFilter就是一个编码过滤器的实现!

@WebFilter("/*")
public class EncodingFilter implements Filter {
    @Override
    public void init(FilterConfig filterConfig) {
        System.out.println("EncodingFilter-init");
    }

    @Override
    public void doFilter(ServletRequest request, ServletResponse response,
                         FilterChain chain) throws IOException, ServletException {
        //将request和response强转成http协议的
        HttpServletRequest req = (HttpServletRequest) request;
        HttpServletResponse resp = (HttpServletResponse) response;

        /*
         * 通用编码设置
         */
        
        //解决post请求提交参数的乱码问题
        req.setCharacterEncoding("UTF-8");
        
        //统一设置响应编码
        resp.setContentType("text/html;charset=UTF-8");

        //使用JDK的动态代理,动态的增强req对象的getParameter(name)方法
        //解决tomcat8一下的版本的get请求url乱码的问题(tomcat8之后的版本不需要了)
        HttpServletRequest myReq = (HttpServletRequest) Proxy.newProxyInstance(HttpServletRequest.class.getClassLoader(), new Class[]{HttpServletRequest.class}, (proxy, method, args) -> {

            Object obj;
            //如果是getParameter方法被调用
            if ("getParameter".equalsIgnoreCase(method.getName())) {
                //获取本次的请求方法
                String md = req.getMethod();
                //解决get请求提交参数的乱码问题,动态增强
                if ("get".equalsIgnoreCase(md)) {
                    //调用目标对象的getParameter方法
                    String v = (String) method.invoke(req, args);
                    //对获取到的结果进行转码(tomcat8之后的版本不需要了)
                    return new String(v.getBytes(StandardCharsets.ISO_8859_1), StandardCharsets.UTF_8);
                }
                //其他请求
                obj = method.invoke(req, args);
            }
            //如果是其他方法被调用,那么直接通过目标对象调用
            else {
                obj = method.invoke(req, args);
            }
            return obj;
        });
        //将代理对象放行
        chain.doFilter(myReq, response);

    }


    @Override
    public void destroy() {
        System.out.println("destroy");
    }
}

4.3 统计IP访问次数

IP工具类:

/**
 * @author lx
 */
public class IpUtil {

    /**
     * 获取用户真实IP地址
     *
     * @param request 请求
     * @return ip
     */
    public static String getIpAddr(HttpServletRequest request) {
        String ip = request.getHeader("x-forwarded-for");
        System.out.println("x-forwarded-for ip: " + ip);
        if (ip != null && ip.length() != 0 && !"unknown".equalsIgnoreCase(ip)) {
            // 多次反向代理后会有多个ip值,第一个ip才是真实ip
            if (ip.contains(",")) {
                ip = ip.split(",")[0];
            }
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("Proxy-Client-IP");
            System.out.println("Proxy-Client-IP ip: " + ip);
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("WL-Proxy-Client-IP");
            System.out.println("WL-Proxy-Client-IP ip: " + ip);
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("HTTP_CLIENT_IP");
            System.out.println("HTTP_CLIENT_IP ip: " + ip);
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("HTTP_X_FORWARDED_FOR");
            System.out.println("HTTP_X_FORWARDED_FOR ip: " + ip);
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("X-Real-IP");
            System.out.println("X-Real-IP ip: " + ip);
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getRemoteAddr();
            System.out.println("getRemoteAddr ip: " + ip);
        }
        System.out.println("获取客户端ip: " + ip);
        return ip;
    }
}

IP统计过滤器:

/**
 * 根据ip统计访问次数
 *
 * @author lx
 */
@WebFilter("/*")
public class IPCountFilter implements Filter {
    private FilterConfig config;

    /**
     * 在init方法中初始化一个map集合,用于存放ip以及它们的访问次数,将map存入ServletContext域对象中
     * <p>
     * 这个方法只会调用一次
     */
    @Override
    public void init(FilterConfig config) {
        this.config = config;
        //准备一个map空集合:
        Map<String, Integer> map = new HashMap<>();
        //将map集合存放在ServletContext域对象当中:
        ServletContext context = config.getServletContext();
        //存进去:
        context.setAttribute("map", map);
    }

    @Override
    public void doFilter(ServletRequest req,
                         ServletResponse res, FilterChain chain)
            throws IOException, ServletException {
        /*
         * 开发步骤:
         * 1:获得当前请求的ip地址:
         * 2:从一个map集合当中进行查询,
         *   如果查询不到,存1进去。
         *   如果查询到,将值+1后存进去。
         * 3:在页面上展示即可
         */
        //强制转换:
        HttpServletRequest request;
        HttpServletResponse response;
        try {
            request = (HttpServletRequest) req;
            response = (HttpServletResponse) res;
        } catch (ClassCastException e) {
            throw new ServletException("non-HTTP request or response");
        }
        //获取ip地址
        String ip = request.getRemoteAddr();

        //从context当中获得map集合:
        ServletContext context = config.getServletContext();
        Map<String, Integer> map = (Map<String, Integer>) context.getAttribute("map");

        //从map集合当中获得ip对应的值,并且记录访问次数
        Integer count = map.computeIfAbsent(ip, s -> 0);

        //将值存回map集合当中
        map.put(ip, ++count);
        //map集合存回ServletContext当中:
        context.setAttribute("map", map);
        //放行
        chain.doFilter(request, response);
    }

    @Override
    public void destroy() {

    }
}

IPCountServlet:

@WebServlet("/IPCountServlet")
public class IPCountServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        resp.setContentType("text/html;charset=utf-8");
        PrintWriter out = resp.getWriter();

        ServletContext servletContext = getServletContext();
        //从context当中获得map集合:
        Map<String, Integer> map = (Map<String, Integer>) servletContext.getAttribute("map");
        for (Map.Entry<String, Integer> stringIntegerEntry : map.entrySet()) {
            out.println("IP: " + stringIntegerEntry.getKey() + "的访问次数为: " + stringIntegerEntry.getValue());
        }

    }
}

注意,如果是localhost,那么可能将获取0:0:0:0:0:0:0:1的IPV6的形式地址,对应ipv4来说相当于127.0.0.1,也就是本机。

4.4 禁止动态资源缓存的过滤器

假设动态资源访问路径为“/Servlet”和“.JSP”。Servlet、JSP等动态资源不应该被浏览器缓存,因为响应结果随时可能改变。

@WebFilter(urlPatterns = {"/servlet/*", "*.jsp"})
public class NocacheFilter implements Filter {
    @Override
    public void init(FilterConfig filterConfig) {
        System.out.println("NocacheFilter-init");
    }

    @Override
    public void doFilter(ServletRequest req, ServletResponse resp,
                         FilterChain chain) throws IOException, ServletException {
        //强制转换: 
        HttpServletRequest request;
        HttpServletResponse response;
        try {
            request = (HttpServletRequest) req;
            response = (HttpServletResponse) resp;
        } catch (ClassCastException e) {
            throw new ServletException("non-HTTP request or response");
        }

        //设置动态资源的过期时间和浏览器不缓存
        response.setHeader("Expires", "-1");
        response.setHeader("Cache-Control", "no-cache");
        response.setHeader("Pragma", "no-cache");

        //放行:
        chain.doFilter(request, response);
    }


    @Override
    public void destroy() {
        System.out.println("destroy");
    }
}

4.5 html标记过滤器

@WebFilter("/*")
public class HTMLFilter implements Filter {
    @Override
    public void init(FilterConfig filterConfig) {
        System.out.println("HTMLFilter-init");
    }

    @Override
    public void doFilter(ServletRequest request, ServletResponse response,
                         FilterChain chain) throws IOException, ServletException {
        //增强对象
        HTMLHttpServlet htmlHttpServlet = new HTMLHttpServlet((HttpServletRequest) request);
        //放行
        chain.doFilter(htmlHttpServlet, response);

    }

    @Override
    public void destroy() {
        System.out.println("destroy");
    }
}

/**
 * html标记过滤器,增强类
 */
class HTMLHttpServlet extends HttpServletRequestWrapper {

    /**
     * Constructs a request object wrapping the given request.
     *
     * @param request the {@link HttpServletRequest} to be wrapped.
     * @throws IllegalArgumentException if the request is null
     */
    public HTMLHttpServlet(HttpServletRequest request) {
        super(request);
    }

    /**
     * 增强getParameter方法
     */
    @Override
    public String getParameter(String name) {
        String value = super.getParameter(name);
        return filter(value);
    }

    /**
     * tomcat 当中webapps/examples项目下的/WEB-INF/classes/utils下的工具类
     * <p>
     * Filter the specified message string for characters that are sensitive
     * in HTML.  This avoids potential attacks caused by including JavaScript
     * codes in the request URL that is often reported in error messages.
     *
     * @param message The message string to be filtered
     * @return the filtered version of the message
     */
    public static String filter(String message) {

        if (message == null)
            return null;

        char content[] = new char[message.length()];
        message.getChars(0, message.length(), content, 0);
        StringBuilder result = new StringBuilder(content.length + 50);
        for (char c : content) {
            switch (c) {
                case '<':
                    result.append("&lt;");
                    break;
                case '>':
                    result.append("&gt;");
                    break;
                case '&':
                    result.append("&amp;");
                    break;
                case '"':
                    result.append("&quot;");
                    break;
                default:
                    result.append(c);
            }
        }
        return result.toString();
    }
}

如有需要交流,或者文章有误,请直接留言。另外希望点赞、收藏、关注,我将不间断更新各种Java学习博客!

  • 6
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 8
    评论
好的,关于Java过滤器Filter使用,我可以给您一些详解。 Java过滤器Filter是一种Web组件,它可以对请求(request)和响应(response)进行过滤和处理。通常情况下,我们使用Java过滤器Filter来对请求进行预处理,或者对响应进行后处理。这样可以减轻Servlet的负担,提高程序的可重用性。 Java过滤器Filter使用非常简单,只需要创建一个Java类,实现javax.servlet.Filter接口,并重写doFilter方法即可。在doFilter方法,我们可以对请求和响应进行处理,然后将它们传递给下一个过滤器Servlet。 下面是一个简单的Java过滤器Filter的示例,它可以过滤掉某个包的请求: ``` public class PackageFilter implements Filter { private String packageName; @Override public void init(FilterConfig filterConfig) throws ServletException { packageName = filterConfig.getInitParameter("packageName"); } @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { HttpServletRequest req = (HttpServletRequest) request; String path = req.getServletPath(); if (path.startsWith(packageName)) { // 过滤掉指定包的请求 return; } chain.doFilter(request, response); } @Override public void destroy() { // do nothing } } ``` 在这个例子,我们通过init方法获取了过滤器初始化参数packageName,然后在doFilter方法判断请求路径是否以packageName开头,如果是,则直接返回,否则将请求传递给下一个过滤器Servlet使用Java过滤器Filter可以方便地对请求和响应进行处理,从而提高程序的可重用性和性能。同时,Java过滤器Filter还可以通过配置文件进行灵活的配置,满足不同场景的需求。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 8
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

刘Java

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值