【Spring进阶】Spring重写CharacterEncodingFilter完全解决编码问题

编码问题是在编程过程中经常遇到的问题之一,如果早期不指定统一的编码格式,开发过程中会遇到各种各样的乱码问题。还好spring为咱们提供了一个编码过滤器,可以帮助咱们解决大部分的乱码问题,本以为配置上它就可以高枕无忧,但是还是出现了问题。


编码问题浮现

// 获取前台传递过来的查询条件
 String conditions = request.getParameter("extra_search");

从request中取出的参数:conditions 出现了乱码

经过尝试后发现,将conditions 经过如下解码后,就没问题了。

conditions = new String(conditions.getBytes("ISO8859-1"), "UTF-8").trim();

很纳闷,spring的编码过滤器已经配置了,难道是不起作用吗?经过一番验证后发现:spring的编码过滤器只对post请求有效,对get请求就免疫了,get请求的参数只要是中文就会产生乱码问题。


怎么解决这个问题?

conditions = new String(conditions.getBytes("ISO8859-1"), "UTF-8").trim();

这句话的确管用,可以解决乱码问题,但只要是get请求,就需要对每个参数进行手动解码,太繁琐。所以就对spring的编码过滤器下手吧,对其进行改造,让他支持get请求解码。


自定义过滤器

package com.tgb.itoo.easyui.tool;

import java.io.IOException;
import java.io.UnsupportedEncodingException;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import javax.servlet.http.HttpServletResponse;

import org.springframework.web.filter.OncePerRequestFilter;

/**
* @Description: 自定义编码过滤器,解决乱码问题
* @author 牛迁迁
* @date 2016年3月18日 上午10:36:10
*/
public class EncodingFilter extends OncePerRequestFilter
{
    private String encoding;

    private boolean forceEncoding = false;

    /**
     * Set the encoding to use for requests. This encoding will be passed into a
     * {@link javax.servlet.http.HttpServletRequest#setCharacterEncoding} call.
     * <p>
     * Whether this encoding will override existing request encodings (and
     * whether it will be applied as default response encoding as well) depends
     * on the {@link #setForceEncoding "forceEncoding"} flag.
     */
    public void setEncoding(String encoding)
    {
        this.encoding = encoding;
    }

    /**
     * Set whether the configured {@link #setEncoding encoding} of this filter
     * is supposed to override existing request and response encodings.
     * <p>
     * Default is "false", i.e. do not modify the encoding if
     * {@link javax.servlet.http.HttpServletRequest#getCharacterEncoding()}
     * returns a non-null value. Switch this to "true" to enforce the specified
     * encoding in any case, applying it as default response encoding as well.
     * <p>
     * Note that the response encoding will only be set on Servlet 2.4+
     * containers, since Servlet 2.3 did not provide a facility for setting a
     * default response encoding.
     */
    public void setForceEncoding(boolean forceEncoding)
    {
        this.forceEncoding = forceEncoding;
    }

    public String filter(HttpServletRequest request, String input)
    {
        String ret = input;
        // 客户端请求参数值可能为(null)服务端过滤掉当null处理即可
        if (input == null || input.trim().equals("(null)"))
        {
            ret = null;
            return ret;
        }
        final String method = request.getMethod();
        // 该处可以实现各种业务的自定义的过滤机制
        if (method.equalsIgnoreCase("get"))
        {
            try
            {
                ret = new String(input.getBytes("ISO8859-1"), this.encoding);
            }
            catch (UnsupportedEncodingException e)
            {
                e.printStackTrace();
            }
        }
        return ret;
    }

    @Override
    protected void doFilterInternal(final HttpServletRequest request,
            HttpServletResponse response, FilterChain filterChain)
            throws ServletException, IOException
    {
        //设置request和response的编码格式
        if (this.encoding != null && (this.forceEncoding || request.getCharacterEncoding() == null))
        {
            request.setCharacterEncoding(this.encoding);
            if (this.forceEncoding)
            {
                response.setCharacterEncoding(this.encoding);
            }
        }

        //对request中的参数进行编码格式的转换
        filterChain.doFilter(new HttpServletRequestWrapper(request)
        {
            @Override
            public String getParameter(String name)
            {
                String value = super.getParameter(name);
                return filter(this, value);
            }

            @Override
            public String[] getParameterValues(String name)
            {
                String[] values = super.getParameterValues(name);
                if (values == null)
                {
                    return null;
                }
                for (int i = 0; i < values.length; i++)
                {
                    values[i] = filter(this, values[i]);
                }
                return values;
            }
        }, response);
    }
}


在web.xml中配置过滤器

<!--  自定义过滤器进行编码格式的设置-start-牛迁迁-2016年3月18日15:25:45 -->
<filter>
    <filter-name>EncodingFilter</filter-name>
    <filter-class>com.tgb.itoo.easyui.tool.EncodingFilter</filter-class>
    <init-param>
        <param-name>encoding</param-name>
        <param-value>UTF-8</param-value>
    </init-param>
    <init-param>
        <param-name>forceEncoding</param-name>
        <param-value>true</param-value>
    </init-param>
</filter>
<filter-mapping>
    <filter-name>EncodingFilter</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>
<!-- 编码格式的设置 end 牛迁迁 -->

小结

1. 上面过滤器的核心就是doFilterInternal方法,在这个方法中设置了request和response的编码格式,并且新增了对request中参数进行编码格式转换的方法。

2. 其中OncePerRequestFilter这个抽象过滤器很好的实现了对每个request只执行一次过滤操作,如果有类似的需求可以继承该类并实现doFilterInternal方法来完成。

3. forceEncoding=true是意思是指无论客户端请求是否包含了编码,都用过滤器里的编码来解析请求

这样编码问题就得以完美解决了,不过要注意的是编码问题一定要尽早发现和解决,要不然后期发现改动起来代价会很大。

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值