深入Struts2的过滤器FilterDispatcher中文乱码及字符编码过滤器
来源:互联网 发布:苏联陈兵百万知乎 编辑:程序博客网 时间:2024/06/05 23:07
引用
本文是关于Struts2.0中文乱码。
先抛出问题:采用spring的字符编码过滤器(CharacterEncodingFilter)统一编码为GBK,前台提交表单数据到Action,但是在Action中得到的中文全部是乱码,前台的页面编码都是GBK没有问题。
这是为什么呢?下面我们就通过阅读FilterDispatcher和CharacterEncodingFilter这两个过滤器的源代码,了解其实现细节,并解决这个问题。
测试环境及其前置知识 - Struts2.0.14
- Spring2.5.6
- Eclipse3.4
- Filter的相关知识,注意:Filter的执行顺序是按照web.xml中配置的filter-mapping顺序执行的。
- <!-- 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>
CharacterEncodingFilter的核心doFilterInternal方法如下:
- 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);//激活下一个过滤器
- }
到这里我们已经执行了一个Filter(CharacterEncoding)已经把request的字符集设置为GBK,然后执行filterChain.doFilter(request, response);//激活下一个过滤器即我们定义的Struts2过滤器。
到这里request的字符集编码还是GBK,但是我们在Action中取得的中文为乱码,使用request.getCharacterEncoding()获取的编码为UTF-8,那么我们可以肯定问题出在FilterDispatcher过滤器上。查看FilterDispatcher的源代码,在其doFilter方法里找到了prepareDispatcherAndWrapRequest方法,看其名字是对request进行预处理和封装的方法。
- 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;
- }
- //省略了一些代码
- 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>
到了这里按说我们已经解决了问题,应该没有什么疑问了,但是前面说了,过滤器是按顺序执行的,那么我们把spring的字符过滤器放在struts的过滤器后面行不行呢,想想是可以的,因为先执行struts的过滤器,设置编码为UTF-8,然后执行spring的过滤器设置成GBK。但是实际上不是那么回事,在实际调试过程中spring的过滤器压根就没有执行,为什么呢?接着看FilterDispatcher的doFilter方法
- 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);
- }
- }
- }
- 不能是一个存在action。
- serveStatic(struts.serve.static配置项值)为true时,不能是一个相对路径以"/struts"开头的请求,如(/struts.html,/struts/index.html),因为这样过滤器会认为你在找struts内部的静态资源,谈后它会去诸如struts的模板文件夹下去找这些静态资源。
- 必须是一个类似于/index.html,/news/index.html这样的请求或者serveStatic为false时请求一个不存在的action。
当满足以上条件时才会激活下一个过滤器。看来这限制还挺多的,所以这就提出来一个注意事项了:
当你在web.xml配置多个过滤器的时候,一定要把struts的过滤器放到最后,这样可以防止过滤器链被中断,导致你配置的其他过滤器不起作用。
- 深入Struts2的过滤器FilterDispatcher--中文乱码及字符编码过滤器
- 深入Struts2的过滤器FilterDispatcher--中文乱码及字符编码过滤器 {转}
- 深入Struts2的过滤器FilterDispatcher中文乱码及字符编码过滤器
- 深入Struts2的过滤器FilterDispatcher--中文乱码及字符编码过滤器
- 深入Struts2的过滤器FilterDispatcher--中文乱码及字符编码过滤器
- 深入Struts2的过滤器FilterDispatcher--中文乱码及字符编码过滤器
- Struts2的过滤器FilterDispatcher
- 字符编码的过滤器
- 针对struts2配置了字符过滤器还是乱码的深入研究
- Spring MVC 自带的字符编码过滤器以及Tomcat字符编码设置,彻底解决中文参数乱码问题
- Struts2两种过滤器StrutsPrepareAndExecuteFilter与FilterDispatcher的区别
- Struts2两种过滤器StrutsPrepareAndExecuteFilter与FilterDispatcher的区别
- 中文乱码?——字符过滤器的配置
- JSP字符编码过滤器 防止乱码
- struts2.2.3 配置中文乱码拦截过滤器
- struts2.2.3 配置中文乱码拦截过滤器
- struts2.2.3 配置中文乱码拦截过滤器
- 过滤器解决Struts2中的中文乱码问题
- NDIS_NBL_FLAGS_IS_LOOPBACK_PACKET Flag
- 使用Systemtap生成Flame Graph(火焰图)
- #小练习 pickle模块 _ version3
- C#高级编程 string
- 关于select函数中timeval和fd_s重新设置的问题
- 深入Struts2的过滤器FilterDispatcher中文乱码及字符编码过滤器
- equals()与==
- Crypto++学习总结---RSA
- 阻塞、非阻塞、同步、异步浅析
- 卫计委:全面推进免费孕前优生健康检查全覆盖
- 绑定远程服务
- Android 百度地图开发(一)--- 申请API Key和在项目中显示百度地图
- Protocol Buffers定义协议格式
- HDU 4417 Super Mario (树状数组+离线处理)(划分树+二分答案)