深入Struts2的过滤器FilterDispatcher--中文乱码及字符编码过滤器(转)
[size=large]引用
前几天在论坛上看到一篇帖子,是关于Struts2.0中文乱码的,楼主采用的是spring的字符编码过滤器(CharacterEncodingFilter)统一编码为GBK,前台提交表单数据到Action,但是在Action中得到的中文全部是乱码,前台的页面编码都是GBK没有问题。这是为什么呢?下面我们就通过阅读FilterDispatcher和CharacterEncodingFilter这两个过滤器的源代码,了解其实现细节,最终得出为什么中文还是乱码!
测试环境及其前置知识
Struts2.0.14
Spring2.5.6
Eclipse3.4
Filter的相关知识,尤其要知道Filter的执行顺序是按照web.xml中配置的filter-mapping顺序执行的。
web.xml定义文件
这里直接采用那篇帖子的web配置
<!-- spring字符集过滤器 -->
<filter>
<filter-name>CharacterEncoding</filter-name>
<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
<init-param>
<param-name>encoding</param-name>
<param-value>GBK</param-value>
</init-param>
<init-param>
<param-name>forceEncoding</param-name>
<param-value>true</param-value>
</init-param>
</filter>
<filter>
<filter-name>Struts2</filter-name>
<filter-class>org.apache.struts2.dispatcher.FilterDispatcher</filter-class>
</filter>
<filter-mapping>
<filter-name>CharacterEncoding</filter-name>
<url-pattern>*.action</url-pattern>
</filter-mapping>
<filter-mapping>
<filter-name>Struts2</filter-name>
<url-pattern>*.action</url-pattern>
</filter-mapping>
分析过滤器源代码,找出为什么
根据filter的执行顺序知,会先执行CharacterEncoding过滤器,再执行Struts2过滤器。
CharacterEncodingFilter的核心doFilterInternal方法如下:
Java代码
protected void doFilterInternal( HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException { if (this.encoding != null && (this.forceEncoding || request.getCharacterEncoding() == null)) { request.setCharacterEncoding(this.encoding);//设置字符集编码 if (this.forceEncoding && responseSetCharacterEncodingAvailable) { response.setCharacterEncoding(this.encoding); } } filterChain.doFilter(request, response);//激活下一个过滤器 }
protected HttpServletRequest prepareDispatcherAndWrapRequest(HttpServletRequest request, HttpServletResponse response) throws ServletException { Dispatcher du = Dispatcher.getInstance(); if (du == null) { Dispatcher.setInstance(dispatcher); dispatcher.prepare(request, response);//设置编码的关键地方 } else { dispatcher = du; } //省略一些代码 return request; }
public void prepare(HttpServletRequest request, HttpServletResponse response) { String encoding = null; if (defaultEncoding != null) { encoding = defaultEncoding; } //省略了一些代码 [size=large][/size] if (encoding != null) { try { request.setCharacterEncoding(encoding);//设置了字符集编码 } catch (Exception e) { LOG.error("Error setting character encoding to '" + encoding + "' - ignoring.", e); } } //省略了一些代码 }
@Inject(StrutsConstants.STRUTS_I18N_ENCODING) public static void setDefaultEncoding(String val) { defaultEncoding = val; }
<constant name="struts.i18n.encoding" value="gbk"></constant>
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException { HttpServletRequest request = (HttpServletRequest) req; HttpServletResponse response = (HttpServletResponse) res; ServletContext servletContext = getServletContext(); String timerKey = "FilterDispatcher_doFilter: "; try { UtilTimerStack.push(timerKey); request = prepareDispatcherAndWrapRequest(request, response); ActionMapping mapping; try { mapping = actionMapper.getMapping(request, dispatcher.getConfigurationManager());//关键,获取Action的映射配置 } catch (Exception ex) { LOG.error("error getting ActionMapping", ex); dispatcher.sendError(request, response, servletContext, HttpServletResponse.SC_INTERNAL_SERVER_ERROR, ex); return; } if (mapping == null) { //走到这里说明请求的不是一个action String resourcePath = RequestUtils.getServletPath(request); if ("".equals(resourcePath) && null != request.getPathInfo()) { resourcePath = request.getPathInfo(); } if (serveStatic && resourcePath.startsWith("/struts")) { findStaticResource(resourcePath, findAndCheckResources(resourcePath), request, response); } else {//很普通的一个request(非Action,非struts的静态资源) chain.doFilter(request, response);//激活下一个过滤器 } // The framework did its job here return; } //调用action dispatcher.serviceAction(request, response, servletContext, mapping); } finally { try { ActionContextCleanUp.cleanUp(req); } finally { UtilTimerStack.pop(timerKey); } } }