整理自网上:

前几天在论坛上看到一篇帖子,是关于Struts2.0中文乱码的,楼主采用的是spring的字符编码过滤器 (CharacterEncodingFilter)统一编码为GBK,前台提交表单数据到Action,但是在Action中得到的中文全部是乱码,前 台的页面编码都是GBK没有问题。这是为什么呢?下面我们就通过阅读FilterDispatcher和CharacterEncodingFilter 这两个过滤器的源代码,了解其实现细节,最终得出为什么中文还是乱码!

web.xml配置:

 1       <!-- spring字符集过滤器 -->  
 2       <filter>  
 3       <filter-name>CharacterEncoding</filter-name>  
 4       <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>  
 5       <init-param>  
 6       <param-name>encoding</param-name>  
 7       <param-value>GBK</param-value>  
 8       </init-param>  
 9       <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方法如下:
 1     protected void doFilterInternal(  
 2                 HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)  
 3                 throws ServletException, IOException {  
 4       
 5     if (this.encoding != null && (this.forceEncoding || request.getCharacterEncoding() == null)) {  
 6                 request.setCharacterEncoding(this.encoding);//设置字符集编码  
 7                 if (this.forceEncoding && responseSetCharacterEncodingAvailable) {  
 8                     response.setCharacterEncoding(this.encoding);  
 9                 }  
             }  
             filterChain.doFilter(request, response);//激活下一个过滤器  
         } 
很简洁,只要this.encoding != null就会设置request的字符集编码,this.encoding就是web.xml中CharacterEncoding过滤器配置的encoding为GBK。
到这里我们已经执行了一个Filter(CharacterEncoding)已经把request的字符集设置为GBK,然后执行 filterChain.doFilter(request, response);//激活下一个过滤器即我们定义的Struts2过滤器。
到这里request的字符集编码还是GBK,但是我们在Action中取得的中文为乱码,使用 request.getCharacterEncoding()获取的编码为UTF-8,那么我们可以肯定问题出在FilterDispatcher过滤 器上。查看FilterDispatcher的源代码,在其doFilter方法里找到了 prepareDispatcherAndWrapRequest方法,看其名字是对request进行预处理和封装的方法。
 1     protected HttpServletRequest prepareDispatcherAndWrapRequest(HttpServletRequest request, HttpServletResponse response) throws Ser                 vletException {  
 2       
 3             Dispatcher du = Dispatcher.getInstance();  
 4       
 5             if (du == null) {  
 6       
 7                 Dispatcher.setInstance(dispatcher);  
 8                 dispatcher.prepare(request, response);//设置编码的关键地方  
 9             } else {  
                 dispatcher = du;  
             }  
             //省略一些代码  
       
             return request;  
         } 
展开dispatcher.prepare(request, response)发现:
 1     public void prepare(HttpServletRequest request, HttpServletResponse response) {  
 2             String encoding = null;  
 3             if (defaultEncoding != null) {  
 4                 encoding = defaultEncoding;  
 5             }  
 6       
 7            //省略了一些代码  
 8       
 9             if (encoding != null) {  
                 try {  
                     request.setCharacterEncoding(encoding);//设置了字符集编码  
                 } catch (Exception e) {  
                     LOG.error("Error setting character encoding to '" + encoding + "' - ignoring.", e);  
                 }  
             }  
         //省略了一些代码  
         } 
可以发现FilterDispatcher过滤器设置了request的字符编码,值来自defaultEncoding(看上面的代码),而defaultEncoding则是通过struts的配置文件取得的,即struts.i18n.encoding的属性值。
     @Inject(StrutsConstants.STRUTS_I18N_ENCODING)  
        public static void setDefaultEncoding(String val) {  
            defaultEncoding = val;  
        } 
如果没有配置struts.i18n.encoding的值,默认是UTF-8.现在我们明白为什么中文是乱码了,也明白了为什么在Action中获取的 编码是UTF-8啦。解决方法也很简单,在struts.xml文件中配置好struts.i18n.encoding的值为GBK即可,可以选择是否去 掉spring的编码过滤器。
 <constant name="struts.i18n.encoding" value="gbk"></constant>
延伸--过滤器的其他一些思考
到了这里按说我们已经解决了问题,应该没有什么疑问了,但是前面说了,过滤器是按顺序执行的,那么我们把spring的字符过滤器放在 struts的过滤器后面行不行呢,想想是可以的,因为先执行struts的过滤器,设置编码为UTF-8,然后执行spring的过滤器设置成GBK。 但是实际上不是那么回事,在实际调试过程中spring的过滤器压根就没有执行,为什么呢?接着看FilterDispatcher的doFilter方 法
 1     public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {  
 2       
 3       
 4             HttpServletRequest request = (HttpServletRequest) req;  
 5             HttpServletResponse response = (HttpServletResponse) res;  
 6             ServletContext servletContext = getServletContext();  
 7       
 8             String timerKey = "FilterDispatcher_doFilter: ";  
 9             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的过滤器放到最后,这样可以防止过滤器链被中断,导致你配置的其他过滤器不起作用。

Struts2中文乱码问题 过滤器源码分析的更多相关文章

  1. Spring Security(四) —— 核心过滤器源码分析

    摘要: 原创出处 https://www.cnkirito.moe/spring-security-4/ 「老徐」欢迎转载,保留摘要,谢谢! 4 过滤器详解 前面的部分,我们关注了Spring Sec ...

  2. Camus导入中文乱码问题(源码修改、编译、部署、任务启动)

    Camus使用过程中业务方反映从Kafka导入至HDFS中的数据有中文乱码问题,且业务方确认写入的数据编码为UTF-8,开始跟进.   问题重现:   (1)编写代码将带有中文的字符串以编码UTF-8 ...

  3. Struts2 源码分析——过滤器(Filter)

    章节简言 上一章笔者试着建一个Hello world的例子.是一个空白的struts2例子.明白了运行struts2至少需要用到哪一些Jar包.而这一章笔者将根据前面章节(Struts2 源码分析—— ...

  4. Struts2 源码分析——调结者(Dispatcher)之执行action

    章节简言 上一章笔者写关于Dispatcher类如何处理接受来的request请求.当然读者们也知道他并非正真的执行action操作.他只是在执行action操作之前的准备工作.那么谁才是正真的执行a ...

  5. Struts2请求处理流程及源码分析

    1.1 Struts2请求处理 1. 一个请求在Struts2框架中的处理步骤: a) 客户端初始化一个指向Servlet容器的请求: b) 根据Web.xml配置,请求首先经过ActionConte ...

  6. Struts2 源码分析-----工作原理分析

    请求过程 struts2 架构图如下图所示: 依照上图,我们可以看出一个请求在struts的处理大概有如下步骤: 1.客户端初始化一个指向Servlet容器(例如Tomcat)的请求: 2.这个请求经 ...

  7. JavaWeb过滤器Filter(附tomcat部分源码分析)

    过滤器Filter 过滤器通常对一些web资源进行拦截,做完一些处理器再交给下一个过滤器处理,直到所有的过滤器处理器,再调用servlet实例的service方法进行处理.过滤器可以对request进 ...

  8. Struts2 源码分析——DefaultActionInvocation类的执行action

    本章简言 上一章讲到关于拦截器的机制的知识点,让我们对拦截器有了一定的认识.我们也清楚的知道在执行用户action类实例之前,struts2会先去执行当前action类对应的拦截器.而关于在哪里执行a ...

  9. Struts2 源码分析——拦截器的机制

    本章简言 上一章讲到关于action代理类的工作.即是如何去找对应的action配置信息,并执行action类的实例.而这一章笔者将讲到在执行action需要用到的拦截器.为什么要讲拦截器呢?可以这样 ...

随机推荐

  1. cookbook_模块和包

    1把模块按层次结构组织成包 只需确保每个目录中都定义了__init__.py即可. 2对所有符号的导入进行精确控制 当用户使用from module import * 语句时,我们希望对从模块或包中导 ...

  2. containsObject 总是不含有,你会用吗

    结论:containsObject:是在比较内存地址,即使两个对象内容完全一样,地址不同,那也是不同的.我个人认为这个方法应该叫是否存在同一个对象 (开始不知道这个知识,被坑,至少浪费了3个钟头,数组 ...

  3. Django websocket之web端实时查看日志实践案例

    这是Django Channels系列文章的第二篇,以web端实现tailf的案例讲解Channels的具体使用以及跟Celery的结合 通过上一篇<Django使用Channels实现WebS ...

  4. 夯实Java基础(十三)——字符串

    字符串应该是我们在Java中用的最频繁.最多的,可见字符串对于我们来说是多么的重要,所以我们非常有必要去深入的了解一下. 1.String String就代表字符串,在Java中字符串属于对象.我们刚 ...

  5. GDOI#348大陆争霸[SDOI2010]最短路有限制条件

    在一个遥远的世界里有两个国家:位于大陆西端的杰森国和位于大陆东端的 克里斯国.两个国家的人民分别信仰两个对立的神:杰森国信仰象征黑暗和毁灭 的神曾·布拉泽,而克里斯国信仰象征光明和永恒的神斯普林·布拉 ...

  6. unity 四叉树管理场景

    当场景元素过多时,需要实时的显示及隐藏物体使得性能提示,但是物体那么多,怎么知道哪些物体需要显示,哪些物体不需要显示的.当然,遍历物体判断该物体是否可以显示是最容易想到的方法,但是每次更新要遍历所有物 ...

  7. springboot-jsp打jar问题

    [**前情提要**]最近做了一个项目,项目是springboot+jsp结构的,但是在发布生产环境的时候又需要用maven打成jar包,但是一开始的默认配置都不成功.下面的文章就是具体的解决过程. - ...

  8. IBM实习工作(二)

    2019年秋招前夕再次到ibm项目组参加实习两周,这次主要负责的需求是建立牛奶数据池,在二级菜单建立对账单数据池,数据由Excel导入生成. 分析整个需求,主要分为以下几块: 1.牛奶数据池前台页面, ...

  9. vue过滤器微信小程序过滤器和百度智能小程序过滤器

    因为最近写了微信小程序和百度小程序,用到了过滤器,感觉还挺好用的,所以就来总结一下,希望能帮到你们. 1. 微信小程序过滤器: 1.1:首先建一个单独的wxs后缀的文件,一般放在utils文件夹里面. ...

  10. 使用re.split 按标点+空格的一种分割办法

    import re import string t1 = re.split("["+string.punctuation+" ]","(555) 12 ...