Filter实现全站编码

https://zhuanlan.zhihu.com/p/65726805

注意:
从Tomcat8开始,默认编码已经改为UTF-8,所以已经不会出现Get请求乱码问题了。
只需处理Post乱码。

我们往常对乱码的处理都放在Servlet的doGet和doPost方法中:

image.png

image.png这个案例采用的Tomcat7

但是这样太麻烦了,每写一个Servlet都要处理乱码。于是就想到用Filter处理。我能想到的有两种处理方式:装饰者模式、动态代理。

装饰者模式处理乱码的方案大家可以直接看崔老师的视频:

案例3:全站编码问题

这里主要讲动态代理方式。


Filter+动态代理解决全站编码问题

对动态代理不熟悉的朋友,可以参考:Java 动态代理作用是什么?

web.xml

<!DOCTYPE web-app PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN" "http://java.sun.com/dtd/web-app_2_3.dtd" >

<web-app>
    <display-name>Archetype Created Web Application</display-name>
    <!--编码过滤器-->
    <filter>
        <filter-name>CharacterEncodingFilter</filter-name>
        <filter-class>org.summerframework.web.filter.CharacterEncodingFilter</filter-class>
    </filter>
    <filter-mapping>
        <filter-name>CharacterEncodingFilter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>

    <!--测试Servlet-->
    <servlet>
        <servlet-name>TestServlet</servlet-name>
        <servlet-class>org.summerframework.web.servlet.TestServlet</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>TestServlet</servlet-name>
        <url-pattern>/TestServlet</url-pattern>
    </servlet-mapping>
</web-app>

TestServlet

public class TestServlet extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        String username = request.getParameter("username");
        System.out.println(username);
        response.getWriter().write(username);
    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        String username = request.getParameter("username");
        System.out.println(username);
        response.getWriter().write(username);
    }
}

CharacterEncodingFilter

public class CharacterEncodingFilter implements Filter {
    public void destroy() {
    }

    public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws ServletException, IOException {

        // 【响应编码设置】后面Servlet拿到的Response对象都是已经设置过编码的
        res.setContentType("text/html;charset=utf-8");

        /*
         * 【请求编码设置】思路:
         *
         * 1.特别注意,这里的request/response类型是ServletRequest/ServletResponse,我们要强转成Http相关的
         *
         *
         * 2.Filter传给后面Servlet的Request对象肯定不能是原先的,不然request.getParameter()还是会乱码
         *   这里使用动态代理生成代理对象,所以后面Servlet拿到的其实是代理Request
         *
         * 3.对于Get、Post请求,解决乱码的方式是不同的,所以代理对象内部必须有针对两者的判断
         * */

        // 1.强转req/res 【思考一下为什么要加final】
        final HttpServletRequest request = (HttpServletRequest) req;
        HttpServletResponse response = (HttpServletResponse) res;

        // 2.使用Proxy.newProxyInstance()创建Request代理对象
        Object proxyRequest = Proxy.newProxyInstance(
                this.getClass().getClassLoader(), /*类加载器*/
                req.getClass().getInterfaces(), /*代理对象要和目标对象实现相同接口*/
                new InvocationHandler() { /*InvocationHandler,采用匿名内部类的方式*/
                    @Override
                    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                        // 由于乱码的根源在于getParameter(),所以我们只盯着这个方法
                        if (!"getParameter".equalsIgnoreCase(method.getName())) {
                            return method.invoke(request, args);
                        }

                        // 3.判断是Get还是Post
                        if ("GET".equalsIgnoreCase(request.getMethod())) {
                            // 按默认编码ISO-8859-1取出
                            String value = (String) method.invoke(request, args);
                            // 按IOS-8859-1得到字节,再按UTF-8转成中文
                            value = new String(value.getBytes("ISO-8859-1"), "UTF-8");
                            // 返回正确的中文
                            return value;
                        } else {
                            // 目标方法前设置编码
                            request.setCharacterEncoding("UTF-8");
                            Object value = method.invoke(request, args);
                            return value;
                        }

                    }
                });
        //把代理request对象传给Servlet
        chain.doFilter((HttpServletRequest) proxyRequest, res);
    }

    public void init(FilterConfig config) throws ServletException {

    }

}

index.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>

<a href="/TestServlet?username=张三">点击发送Get请求</a><br/>

<form action="/TestServlet" method="post">
    用户名:<input type="text" name="username" value="李四"/>
    <input type="submit" value="提交Post请求">
</form>

</body>
</html>

示意图:

image.png

标签: Java Web Filter, Proxy, CharEncoding

评论已关闭