编码问题是在编程过程中经常遇到的问题之一,如果早期不指定统一的编码格式,开发过程中会遇到各种各样的乱码问题。还好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是意思是指无论客户端请求是否包含了编码,都用过滤器里的编码来解析请求
这样编码问题就得以完美解决了,不过要注意的是编码问题一定要尽早发现和解决,要不然后期发现改动起来代价会很大。