Java Web(11)—Filter过滤器的原理以及用法

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

文章目录

  • 1 Filter接口
    • 1.1 过滤器的生命周期
    • 1.2 doFilter过滤方法
  • 2 Filter的使用
  • 3 Filter的执行顺序
    • 3.1 多个过滤器
  • 4 Filter的应用
    • 4.1 脏话过滤器
    • 4.2 编码过滤器
    • 4.3 统计IP访问次数
    • 4.4 禁止动态资源缓存的过滤器
    • 4.5 html标记过滤器

  过滤器属于Servlet规范,从2.3版本就开始有了。主要用于对到资源的请求或来自资源的响应执行过滤、筛选操作。
  当存在过滤器的时候,对于来自客户端的请求来说,请求必须先经过滤器,放行之后,才能到达Web资源;对于返回的响应来说,响应同样会经过滤器,才能到达Web服务器,进而响应给客户端
Java Web(11)—Filter过滤器的原理以及用法_第1张图片
  过滤器可以做很多事情,常见的包括:

  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>FirstFilterfilter-name>
    <filter-class>com.example.filter.FirstFilterfilter-class>
    
    <init-param>
        <param-name>aaaparam-name>
        <param-value>bbbparam-value>
    init-param>
    <init-param>
        <param-name>cccparam-name>
        <param-value>dddparam-value>
    init-param>
filter>

  一个标签表示定义一个过滤器,表示当前过滤器的name,表示当前过滤器的类全路径名,表示当前过滤器的初始化参数,可以通过在init方法的参数FilterConfig对象获取这些参数。
  随后我们还需要定义这个过滤器可以作用于哪些资源或者哪些Servlet!

<filter-mapping>
    <filter-name>FirstFilterfilter-name>
    
    <url-pattern>/aa/*url-pattern>
filter-mapping>
<filter-mapping>
    <filter-name>FirstFilterfilter-name>
    
    <servlet-name>Servlet2servlet-name>
    
    
filter-mapping>

  通过多个标签可以为一个过滤器配置多个过滤映射,当然也可以将多个映射一个到一个标签中

  1. 指定某个过滤器的名字
  2. 指定过滤器所拦截的资源路径URL,“/”表示所有的Web资源都需要途径该过滤器,“.xxx”表示拦截访问xxx后缀的资源的请求。
  3. 指定过滤器所拦截的某个Servlet的名字。
  4. 指定过滤器在拦截时所应用的调度模式,一共有五个可选配置: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的时候则不会经过过滤器,控制台输出为:
Java Web(11)—Filter过滤器的原理以及用法_第2张图片
  如果我们注释掉chain.doFilter方法,即不放行,那么访问Servlet1和Servlet2的时候,页面上不会有任何输出,也不会输出控制台也不会输出“请求到达”字符串,因为请求被拦截了,而访问Servlet3的时候则可以正常访问:
Java Web(11)—Filter过滤器的原理以及用法_第3张图片

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:

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>Filter1filter-name>
    <filter-class>com.example.filter.Filter1filter-class>
filter>
<filter>
    <filter-name>Filter2filter-name>
    <filter-class>com.example.filter.Filter2filter-class>
filter>


<filter-mapping>
    <filter-name>Filter2filter-name>
    
    <servlet-name>Servlet2servlet-name>
filter-mapping>
<filter-mapping>
    <filter-name>Filter1filter-name>
    
    <url-pattern>/aa/*url-pattern>
    
    <servlet-name>Servlet2servlet-name>
filter-mapping>
<filter-mapping>
    <filter-name>Filter2filter-name>
    
    <url-pattern>/aa/*url-pattern>
filter-mapping>

  可以看到Filter2的mapping在前,因此Filter2将先被执行,但是在资源访问完毕返回时,则是倒序执行!
  我们访问Servlet1和Servlet2,将会得到如下结果:
Java Web(11)—Filter过滤器的原理以及用法_第4张图片
  如果是通过注解的方式配置,就比较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方法
     * 

* 将参数中的脏话替换为**才返回 */ @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("

" + name + "

"
); } }

  尝试请求http://localhost:8081/filter/DirtyWordsServlet?name=坤坤,返回结果如下:
Java Web(11)—Filter过滤器的原理以及用法_第5张图片

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域对象中
     * 

* 这个方法只会调用一次 */ @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下的工具类
     * 

* 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("<"); break; case '>': result.append(">"); break; case '&': result.append("&"); break; case '"': result.append("""); break; default: result.append(c); } } return result.toString(); } }

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

你可能感兴趣的:(#,Java-Web,javaweb,servlet,filter,过滤器)