过滤器/拦截器/AOP----Java Web 三大组件之一过滤器 Filter

录:

1、过滤器 Filter 的使用
2、多个过滤器的执行顺序
3、四种拦截方式
4、过滤器的应用场景
5、案例:过滤器实现分 IP 统计网站的访问次数
6、案例:过滤器处理全站编码问题
    6.1、准备工作
    6.2、测试未处理编码前是否出现乱码问题
    6.3、如何处理 GET 和 POST 请求的编码问题
    6.4、编写全站编码过滤器解决乱码问题

7、springboot 注册过滤器

JavaEE 规范里面的三大组件(都需要在web.xml中进行配置)是:

  1) Servlet(单例的)
  2) Listener(两个感知监听器不需要配置)
  3) Filter(单例的)

1、过滤器 Filter 的使用    <--返回目录

  过滤器作用:它会在一组资源(jsp、servlet、.css、.html等)的前面执行,它可以让请求得到目标资源,也可以不让请求达到。过滤器有拦截请求的能力。
  过滤器如何编写
    1) 写一个类实现Filter接口
    2) 在web.xml中配置

  创建一个类,实现Filter接口

public class MyFilter implements Filter {
    //Filter会在服务器启动时就创建    
    //过滤器创建之后马上执行,用来做初始化
    pullic void init(FilterConfig filterconfig)throws ServletException{}
    
    //每次过滤时都会执行
    public void doFilter(ServletRequest request,ServletResponse response,FilterChain chain)throws IOException,ServletException{}
    
    //过滤器销毁之前执行,用来做对非内存资源进行释放
    //Filter会在服务器关闭时销毁
    public void destroy(){}
}

  web.xml配置

<filter>
    <filter-name>MyFilter</filter-name>
    <filter-class>com.oy.filter.MyFilter</filter-class>
</filter>    
<filter-mapping>
    <filter-name>MyFilter</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>

  相关的 API:
  FilterConfig => 与 ServletConfig类似
    - 获取初始化参数:getInitParameter()
    - 获取过滤器名称:getFilterName()
    - 获取application:getServletContext()

  FilterChain    
    - doFilter(ServletRequest,ServletResponse):放行,就相当于调用Servlet的service()方法

    - 如果在 MyFilter#doFilter()方法里面不调用 chain.doFilter() 方法,则请求被拦截,无法到达目标资源

2、多个过滤器的执行顺序    <--返回目录

  Eclipse 新建一个 Dynamic Web Project, 创建了一个 Servlet 和 两个 Filter 用于测试

   MyServlet

package com.oy.servlet;

import java.io.IOException;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class MyServlet extends HttpServlet {
    private static final long serialVersionUID = 1L;

    @Override
    protected void service(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException {
        System.out.println("MyServlet#service()...");
    }
}
View Code

  MyFilter1

package com.oy.filter;

import java.io.IOException;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;

public class MyFilter1 implements Filter {
    public void init(FilterConfig fConfig) throws ServletException {}

    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
            throws IOException, ServletException {
        
        System.out.println("MyFilter1#doFilter start...");
        chain.doFilter(request, response);
        System.out.println("MyFilter1#doFilter end...");
        
    }

    public void destroy() {}
}
View Code

  MyFilter2

package com.oy.filter;

import java.io.IOException;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;

public class MyFilter2 implements Filter {
    public void init(FilterConfig fConfig) throws ServletException {}

    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
            throws IOException, ServletException {
        
        System.out.println("MyFilter2#doFilter start...");
        chain.doFilter(request, response);
        System.out.println("MyFilter2#doFilter end...");
        
    }

    public void destroy() {}
}
View Code

  web.xml 配置 Servlet 和 Filter(注意:Filter 执行顺序按照 web.xml 中的filter-mapping 配置顺序执行

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns="http://java.sun.com/xml/ns/javaee"
    xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
    id="WebApp_ID" version="2.5">
    <display-name>FilterDemo</display-name>
    <welcome-file-list>
        <welcome-file>index.html</welcome-file>
    </welcome-file-list>
    
    <servlet>
        <servlet-name>MyServlet</servlet-name>
        <servlet-class>com.oy.servlet.MyServlet</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>MyServlet</servlet-name>
        <url-pattern>/MyServlet</url-pattern>
    </servlet-mapping>
    
    <filter>
        <filter-name>MyFilter1</filter-name>
        <filter-class>com.oy.filter.MyFilter1</filter-class>
    </filter>
    <filter-mapping>
        <filter-name>MyFilter1</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>
    
    <filter>
        <filter-name>MyFilter2</filter-name>
        <filter-class>com.oy.filter.MyFilter2</filter-class>
    </filter>
    <filter-mapping>
        <filter-name>MyFilter2</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>
</web-app>
View Code

  配置 tomcat 服务器,启动项目:

    访问 http://localhost:8080/FilterDemo/MyServlet,控制台打印结果:

MyFilter1#doFilter start...
MyFilter2#doFilter start...
MyServlet#service()...
MyFilter2#doFilter end...
MyFilter1#doFilter end...

  如果注释掉 MyFilter#doFilter() 的放行方法,如下代码所示

public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
        throws IOException, ServletException {
    
    System.out.println("MyFilter2#doFilter start...");
    // chain.doFilter(request, response);
    System.out.println("MyFilter2#doFilter end...");
    
}

  控制台打印结果:请求被拦截,无法到达目标资源,即 MyServlet#service() 方法不会执行;但还是会回到 MyFilter1 放行方法处,继续执行后面的代码。

MyFilter1#doFilter start...
MyFilter2#doFilter start...
MyFilter2#doFilter end...
MyFilter1#doFilter end...

3、四种拦截方式    <--返回目录

过滤器有四种拦截方式,分别是:REQUEST、FORWARD、INCLUDE、ERROR。
  1)REQUEST:直接访问目标资源时执行过滤器。包括:在地址栏中直接访问、表单提交、超链接、重定向,只要在地址栏中可以看到目标资源的路径,就是REQUEST;
  2)FORWARD:转发访问执行过滤器。包括RequestDispatcher#forward()方法、<jsp:forward>标签都是转发访问;
  3)INCLUDE:包含访问执行过滤器。包括RequestDispatcher#include()方法、<jsp:include>标签都是包含访问;
  4)ERROR:当目标资源在web.xml中配置为<error-page>中时,并且真的出现了异常,转发到目标资源时,会执行过滤器。

<filter>
    <filter-name>MyFilter1</filter-name>
    <filter-class>com.oy.filter.MyFilter1</filter-class>
</filter>
<filter-mapping>
    <filter-name>MyFilter1</filter-name>
    <url-pattern>/*</url-pattern>
    <dispatcher>REQUEST</dispatcher>  默认是拦截REQUEST,一旦指定就没有默认值了
    <!-- 
    <dispatcher>FORWARD</dispatcher>
    <dispatcher>INCLUDE</dispatcher>
    <dispatcher>ERROR</dispatcher> 
    -->
</filter-mapping>

  过滤器配置 ERROR 的例子

   web.xml 配置

<filter>
    <filter-name>ErrorFilter</filter-name>
    <filter-class>com.oy.filter.ErrorFilter</filter-class>
</filter>
<filter-mapping>
    <filter-name>ErrorFilter</filter-name>
    <url-pattern>/*</url-pattern>
    <dispatcher>ERROR</dispatcher>
</filter-mapping>

<error-page>
    <error-code>500</error-code>
    <location>/WEB-INF/jsps/500.jsp</location>
</error-page>

  在 MyServlet#service() 写个运行时错误,比如 int a = 1/0;

  浏览器访问 这个 MyServlet 时发生运行时异常,返回 500 错误码。根据上面配置的 ErrorFilter 拦截到500错误,给前端返回 /WEB-INF/jsps/500.jsp。

  另外,<error-page>除了可以配置错误状态码外,还可以配置异常类型

<error-page>
    <exception-type>java.lang.RuntimeException</exception-type>
    <location>/WEB-INF/jsps/500.jsp</location>
</error-page>

4、过滤器的应用场景     <--返回目录 

  1)执行目标资源之前做预处理工作,例如设置编码,这种试通常都会放行,只是在目标资源执行之前做一些准备工作;
  2)通过条件判断是否放行,例如校验当前用户是否已经登录,或者用户IP是否已经被禁用;
  3)在目标资源执行后,做一些后续的特殊处理工作,例如把目标资源输出的数据进行处理;

5、案例:过滤器实现分 IP 统计网站的访问次数    <--返回目录

  分析:

  因为一个网站可能有多个页面,无论哪个页面被访问,都要统计访问次数,所以使用过滤器最为方便。

  因为需要分IP统计,所以可以在过滤器中创建一个Map,使用IP为key,访问次数为value。当有用户访问时,获取请求的IP,如果IP在Map中存在,说明以前访问过,那么在访问次数上加1,即可;IP在Map中不存在,那么设置次数为1。

  把这个Map存放到ServletContext中!使用 ServletContextListener 监听 ServletContext 的创建完成后,在 ServletContext 域中添加一个 Map,用于存储 ip 统计信息。

  MyServlet:用于测试,浏览器访问 http://localhost:8080/FilterDemo/MyServlet 时,将请求转发 到 /WEB-INF/jsps/showIp.jsp 显示 IP 统计信息

package com.oy.servlet;

import java.io.IOException;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class MyServlet extends HttpServlet {
    private static final long serialVersionUID = 1L;

    @Override
    protected void service(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException {
        // 请求 MyServlet, 转发到 showIp.jsp 页面
        req.getRequestDispatcher("/WEB-INF/jsps/showIp.jsp").forward(req, res);
    }
}
View Code

  MyServletContextListener:监听 ServletContext 的创建完成后,在 ServletContext 域中添加一个 Map,用于存储 ip 统计信息

package com.oy.listener;

import java.util.HashMap;
import java.util.Map;

import javax.servlet.ServletContext;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
public class MyServletContextListener implements ServletContextListener {

    @Override
    public void contextInitialized(ServletContextEvent sce) {
        ServletContext app = sce.getServletContext();
        Map<String, Integer> ipMap = new HashMap<>();
        app.setAttribute("ipMap", ipMap);
    }
    
}
View Code

  IPFilter:过滤器,拦截所有请求,判断当前请求的 ip 是否已经在ipMap 中存在?如果存在,则将 value 值加1;不存在,将 ip 作为 key,value 为 1,添加到 ipMap 中。

package com.oy.filter;

import java.io.IOException;
import java.util.Map;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;

public class IPFilter implements Filter {
    private ServletContext app;
    public void init(FilterConfig fConfig) throws ServletException {
        this.app = fConfig.getServletContext();
    }

    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
            throws IOException, ServletException {
        System.out.println("IPFilterFilter#doFilter start...");
        
        Map<String, Integer> ipMap = (Map<String, Integer>) app.getAttribute("ipMap");
        if (ipMap == null) return;
        
        String ip = request.getRemoteAddr();
        if (ipMap.containsKey(ip)) {
            int count = ipMap.get(ip);
            ipMap.put(ip, count + 1);
        } else {
            ipMap.put(ip, 1);
        }
        
        chain.doFilter(request, response); // 放行
        
        System.out.println("IPFilterFilter#doFilter end...");
    }

    public void destroy() {
    }
}
View Code

  web.xml: 配置前面的 Servlet、Listener 和 Filter

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
    xmlns="http://java.sun.com/xml/ns/javaee" 
    xsi:schemaLocation="http://java.sun.com/xml/ns/javaee 
    http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" id="WebApp_ID" version="2.5">
  <display-name>FilterDemo</display-name>
  <welcome-file-list>
    <welcome-file>index.html</welcome-file>
  </welcome-file-list>
  
  <servlet>
    <servlet-name>MyServlet</servlet-name>
    <servlet-class>com.oy.servlet.MyServlet</servlet-class>
  </servlet>
  <servlet-mapping>
    <servlet-name>MyServlet</servlet-name>
    <url-pattern>/MyServlet</url-pattern>
  </servlet-mapping>
  
  <!-- 过滤器 -->
  <filter>
    <filter-name>IPFilter</filter-name>
    <filter-class>com.oy.filter.IPFilter</filter-class>
  </filter>
  <filter-mapping>
    <filter-name>IPFilter</filter-name>
    <url-pattern>/*</url-pattern>
  </filter-mapping>
  
  <!-- 监听器 -->
  <listener>
    <listener-class>com.oy.listener.MyServletContextListener</listener-class>
  </listener>
</web-app>
View Code

  showIp.jsp: 取出ServletContext 域对象(也称为 application 域对象)中的 ipMap, 循环遍历

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>

<h1>分IP统计访问次数</h1>
<table align="center" width="50%" border="1">
    <tr>
        <th>IP地址</th>
        <th>次数</th>
    </tr>
<c:forEach items="${applicationScope.ipMap }" var="entry">
    <tr>
        <td>${entry.key }</td>
        <td>${entry.value }</td>
    </tr>
</c:forEach>
</table>

</body>
</html>
View Code

6、案例:过滤器处理全站编码问题    <--返回目录

6.1、准备工作    <--返回目录

  创建一个 Dynamic Web Project, 包含主页 index.jsp用于浏览器访问测试,一个 MyServlet 来接受 index.jsp 发来的请求。

   index.jsp: 用于浏览器访问测试;一个 a 标签发生 GET 请求,form 表单发生 POST 请求

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>主页</title>
</head>
<body>
    <h2>index 页面</h2>
    <a href="${pageContext.request.contextPath}/MyServlet?name=测试GET请求乱码" >测试GET请求乱码</a>
    <br/><br/>
    
    <form action="${pageContext.request.contextPath}/MyServlet" method="post">
        name: <input type="text" name="name" value="测试POST请求乱码" /><br/>
        <input type="submit" value="提交" />
    </form>
</body>
</html>
View Code

  MyServlet:接受 index.jsp 发来的请求,并获取请求中的参数,并将参数添加到response, 响应给浏览器

package com.oy.servlet;

import java.io.IOException;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class MyServlet extends HttpServlet {
    private static final long serialVersionUID = 1L;

    @Override
    public void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        String name = req.getParameter("name");
        resp.getWriter().print(name);
    }

    @Override
    public void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        String name = req.getParameter("name");
        resp.getWriter().print(name);
    }
}
View Code

  web.xml: 配置 servlet

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
    xmlns="http://java.sun.com/xml/ns/javaee" 
    xsi:schemaLocation="http://java.sun.com/xml/ns/javaee 
    http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" id="WebApp_ID" version="2.5">
  <display-name>FilterDemo</display-name>
  <welcome-file-list>
    <welcome-file>index.jsp</welcome-file>
    <welcome-file>index.html</welcome-file>
  </welcome-file-list>
  
  <servlet>
    <servlet-name>MyServlet</servlet-name>
    <servlet-class>com.oy.servlet.MyServlet</servlet-class>
  </servlet>
  <servlet-mapping>
    <servlet-name>MyServlet</servlet-name>
    <url-pattern>/MyServlet</url-pattern>
  </servlet-mapping>
  
</web-app>
View Code

  

6.2、测试未处理编码前是否出现乱码问题    <--返回目录

  测试访问:http://localhost:8080/FilterDemo/  (也可以访问http://localhost:8080/FilterDemo/index.jsp, 由于web.xml中配置了欢迎页<welcome-file>index.jsp</welcome-file>,所以/index.jsp可以省略)

   点击 a 标签,,发现响应乱码

  点击 "提交",发现响应乱码

 

6.3、如何处理 GET 和 POST 请求的编码问题    <--返回目录

  获取请求参数中的乱码问题:

  • POST请求:request.setCharacterEncoding(“utf-8”);
  • GET请求:new String(request.getParameter(“xxx”).getBytes(“iso-8859-1”), “utf-8”);

  响应的乱码问题:response.setContextType(“text/html;charset=utf-8”)。

具体解决编码问题的代码如下:

package com.oy.servlet;

import java.io.IOException;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class MyServlet extends HttpServlet {
    private static final long serialVersionUID = 1L;

    @Override
    public void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        /* 解决 GET 请求乱码问题 */
        // 将get请求参数先iso-8859-1解码,在utf-8编码(tomcat7的方式)
//        String name = req.getParameter("name"); // 如果时tomcat9, 直接获取就行
        String name = new String(req.getParameter("name").getBytes("iso-8859-1"), "utf-8");
        System.out.println("GET 请求,获取参数, name=" + name);
        // 告诉浏览器,响应结果使用utf-8
        resp.setContentType("text/html;charset=utf-8"); // 告诉浏览器,响应结果使用utf-8
        
        resp.getWriter().print(name);
    }

    @Override
    public void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        // 解决 POST 请求乱码问题
        req.setCharacterEncoding("UTF-8"); // 告诉服务器,从req.getParameter()获取参数时使用utf-8
        resp.setContentType("text/html;charset=utf-8"); // 告诉浏览器,响应结果使用utf-8
        
        String name = req.getParameter("name");
        resp.getWriter().print(name);
    }
}

  注意:在Http请求到达Servlet解析之前,GET过来的URL已经被Tomcat先做了一次URLDecode。Tomcat 7 对GET方式默认的URL解码结果是iso-8859-1而不是UTF-8!经过测试 Tomcat 9 默认URL解码时utf-8。

6.4、编写全站编码过滤器解决乱码问题    <--返回目录

  其实全站乱码问题的难点就是处理GET请求参数的问题。
  如果只是处理POST请求的编码问题,以及响应编码问题,那么这个过滤器就太简单的。
  如果是POST请求,当执行目标Servlet时,Servlet中调用request.getParameter()方法时,就会根据request.setCharacterEncoding()设置的编码来转码!这说明在过滤器中调 request.setCharacterEncoding()方法会影响在目标Servlet中的request.getParameter()方法的行为!
  但是如果是GET请求,我们又如何能影响request.getParameter()方法的行为呢?这是不好做到的!我们不可能先调用request.getParameter()方法获取参数,然后手动转码后,再施加在到request中!因为request只有getParameter(),而没有setParameter()方法。
  处理GET请求参数编码问题,需要在Filter中放行时,把request对象给“调包”了,也就是让目标Servlet使用我们“调包”之后的request对象。这说明我们需要保证“调包”之后的request对象中所有方法都要与“调包”之前一样可以使用,并且getParameter()方法还要有能力返回转码之后的参数。

   对request对象进行增强的条件,刚好符合装饰者模式的特点!因为我们不知道request对象的具体类型,但我们知道request是HttpServletRequest接口的实现类。这说明我们写一个类EncodingRequest,去实现HttpServletRequest接口,然后再把原来的request传递给EncodingRequest类!在EncodingRequest中对HttpServletRequest接口中的所有方法的实现都是通过代理原来的request对象来完成的,只有对getParameter()方法添加了增强代码!


  JavaEE已经给我们提供了一个HttpServletRequestWrapper类,它就是HttpServletRequest的包装类,但它做任何的增强!你可能会说,写一个装饰类,但不做增强,其目的是什么呢?使用这个装饰类的对象,和使用原有的request有什么分别呢?


  HttpServletRequestWrapper类虽然是HttpServletRequest的装饰类,但它不是用来直接使用的,而是用来让我们去继承的!当我们想写一个装饰类时,还要对所有不需要增强的方法做一次实现是很心烦的事情,但如果你去继承HttpServletRequestWrapper类,那么就只需要重写需要增强的方法即可了。

   EncodingRequest: 对 HttpServletRequest 进行装饰,增强了 getParameter() 方法

package com.oy.servlet;

import java.io.UnsupportedEncodingException;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;

public class EncodingRequest extends HttpServletRequestWrapper {
    
    private HttpServletRequest request;
    
    public EncodingRequest(HttpServletRequest request) {
        // 将 request 传给 父类 HttpServletRequestWrapper,未增强的方法有父类实现
        super(request);
        this.request = request;
    }
    
    // 增强
    public String getParameter(String name) {
        String value = request.getParameter(name);
        try {
            value = new String(value.getBytes("ISO-8859-1"), "utf-8");
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
        return value;
        
//        String method = request.getMethod();
//        if("post".equalsIgnoreCase(method)) {
//            try {
//                request.setCharacterEncoding("utf-8");
//            } catch (UnsupportedEncodingException e) {
//                e.printStackTrace();
//            }
//        } else if("get".equalsIgnoreCase(method)) {
//            String value = request.getParameter(name);
//            try {
//                value = new String(value.getBytes("ISO-8859-1"), "utf-8");
//            } catch (UnsupportedEncodingException e) {
//                e.printStackTrace();
//            }
//            return value;
//        }
//        return request.getParameter(name);
    }
}
View Code

  自定义 编码过滤器 CharacterEncodingFilter,如果是 GET 请求,将 tomcat 传递过来的 request 进行调包,使用自定义的 EncodingRequest

package com.oy.filter;

import java.io.IOException;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;

import com.oy.servlet.EncodingRequest;

public class CharacterEncodingFilter implements Filter {
    public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws IOException, ServletException {
        // 告诉浏览器,响应结果使用utf-8
        resp.setContentType("text/html;charset=utf-8");
        // 先将 ServletRequest 强转为 HttpServletRequest
        HttpServletRequest request = (HttpServletRequest) req;
                
        /* 处理 POST 请求编码问题 */
        String method = request.getMethod();
        if ("post".equalsIgnoreCase(method)) {
            req.setCharacterEncoding("UTF-8"); // 告诉服务器,从req.getParameter()获取参数时使用utf-8
            chain.doFilter(req, resp);
            return;
        }
        
        /* 处理 GET 请求编码问题 */
        if ("get".equalsIgnoreCase(method)) {
            // 使用装饰者模式,将 HttpServletRequest 进行修饰增强(增强了getParameter()方法)
            chain.doFilter(new EncodingRequest(request), resp);
        } else {
            chain.doFilter(req, resp);
        }
    }

    public void init(FilterConfig fConfig) throws ServletException {}
    public void destroy() {}
}
View Code

  web.xml:注册CharacterEncodingFilter

<!-- 过滤器 -->
<filter>
  <filter-name>CharacterEncodingFilter</filter-name>
  <filter-class>com.oy.filter.CharacterEncodingFilter</filter-class>
</filter>
<filter-mapping>
  <filter-name>CharacterEncodingFilter</filter-name>
  <url-pattern>/*</url-pattern>
</filter-mapping>
View Code

  所以,MyServlet 中无需编写处理编码的代码了

public class MyServlet extends HttpServlet {
    private static final long serialVersionUID = 1L;

    @Override
    public void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        String name = req.getParameter("name");
        resp.getWriter().print(name);
    }

    @Override
    public void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        String name = req.getParameter("name");
        resp.getWriter().print(name);
    }
}
View Code

后注:spring 项目中通常修改Tomcat的conf目录下的server.xml中配置Connector的URIEconding=“UTF-8"属性来处理 GET 请求编码,通过配置spirng 提供的 org.springframework.web.filter.CharacterEncodingFilter 来处理 POST 编码。

<!-- POST编码过滤器 -->
<filter>
    <filter-name>encodingFilter</filter-name>
    <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
    <!-- <async-supported>true</async-supported> -->
    <init-param>
        <param-name>encoding</param-name>
        <param-value>UTF-8</param-value>
    </init-param>
</filter>
<filter-mapping>
    <filter-name>encodingFilter</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>
View Code

7、springboot 注册过滤器    <--返回目录

  https://www.cnblogs.com/tiancai/p/11196667.html

 参考:

  1)关于HTTP GET请求的url中文参数编码

原文地址:https://www.cnblogs.com/xy-ouyang/p/12682155.html