首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > 软件管理 > 软件架构设计 >

深入Struts2的过滤器FilterDispatcher-中文乱码及字符编码过滤器

2012-09-19 
深入Struts2的过滤器FilterDispatcher--中文乱码及字符编码过滤器前几天在论坛上看到一篇帖子,是关于Strut

深入Struts2的过滤器FilterDispatcher--中文乱码及字符编码过滤器
前几天在论坛上看到一篇帖子,是关于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方法如下:


可以发现FilterDispatcher过滤器设置了request的字符编码,值来自defaultEncoding(看上面的代码),而defaultEncoding则是通过struts的配置文件取得的,即struts.i18n.encoding的属性值。

延伸--过滤器的其他一些思考
到了这里按说我们已经解决了问题,应该没有什么疑问了,但是前面说了,过滤器是按顺序执行的,那么我们把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);              }          }      }  


看上面的代码mapping=actionMapper.getMapping(request,dispatcher.getConfigurationManager());这个是得到当前请求Action的信息,比如Action的名字,命名空间,result值等,只要这个mapping不为null,过滤器就会直接执行action而不会激活下一个过滤器,这就会使得spring的那个过滤器起不了作用。那么什么时候才会激活下一个过滤器呢?答案是一个很普通的请求,多么普通呢?
不能是一个存在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的过滤器放到最后,这样可以防止过滤器链被中断,导致你配置的其他过滤器不起作用。 1 楼 mizhihua 2012-02-08   多谢楼主,学习了。 2 楼 sei_ljf 2012-02-08   mizhihua 写道多谢楼主,学习了。
呵呵 转载别人的 共同学习~

热点排行