深入Struts2的过滤器FilterDispatcher--中文乱码及字符编码过滤器
测试环境及其前置知识
- 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方法如下:
- 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);//激活下一个过滤器
- }
很简洁,只要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进行预处理和封装的方法。
- 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;
- }
展开dispatcher.prepare(request, response)发现:
- 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);
- }
- }
- //省略了一些代码
- }
可以发现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>
- 如果是UTF-8,那么默认可以不用配置,因为Struts2的默认常量就是utf-8
延伸--过滤器的其他一些思考
到了这里按说我们已经解决了问题,应该没有什么疑问了,但是前面说了,过滤器是按顺序执行的,那么我们把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),
- 必须是一个类似于/index.html,/news/index.html这样的请求或者serveStatic为false时请求一个不存在的action。
因为这样过滤器会认为你在找struts内部的静态资源,谈后它会去诸如struts的模板文件夹下去找这些静态资源。
当满足以上条件时才会激活下一个过滤器。看来这限制还挺多的,所以这就提出来一个注意事项了,当你在web.xml配置多个过滤器的时候,一定要把struts的过滤器放到最后,这样可以防止过滤器链被中断,导致你配置的其他过滤器不起作用。
深入Struts2的过滤器FilterDispatcher--中文乱码及字符编码过滤器的更多相关文章
- centos中文乱码修改字符编码使用centos支持中文
如何你的centos显示中文乱码,只要修改字符编码使centos支持中文就可以了,没有这个文件可以创建它,下面是修改步骤 一.中文支持 安装中文语言包: 复制代码 代码如下: yum groupins ...
- servlet中的字符编码过滤器的使用
一:简介 Servlet过滤器是客户端和目标资源的中间层组件,主要是用于拦截客户端的请求和响应信息.如当web容器收到一条客户端发来的请求 web容器判断该请求是否与过滤器相关联,如果相关联就交给过滤 ...
- 关于web.xml中配置Spring字符编码过滤器以解决中文乱码的问题
当出现中文乱码问题,Spring中可以利用CharacterEncodingFilter过滤器解决,如下代码所示: <!-- Spring字符编码过滤器:解决中文乱码问题 --> < ...
- 解决Linux文档显示中文乱码问题以及编码转换
解决Linux文档显示中文乱码问题以及编码转换 解决Linux文档显示中文乱码问题以及编码转换 使vi支持GBK编码 由于Windows下默认编码是GBK,而linux下的默认编码是UTF-8,所以打 ...
- SpringMVC配置字符编码过滤器CharacterEncodingFilter来解决表单乱码问题
1.GET请求 针对GET请求,可以配置服务器Tomcat的conf\server.xml文件,在其第一个<Connector>标签中,添加URIEncoding="UTF-8& ...
- Servlet字符编码过滤器,实现图书信息的添加功能,避免产生文字乱码现象的产生
同样的代码,网上可以找到和我一模一样的代码和配置,比我的更加详细,但是我重新写一个博客的原因自是把错误的原因写出来,因为这就是个坑,我弄了一天,希望对你们有所帮助.只为初学者发现错误不知道怎么解决有所 ...
- Servlet字符编码过滤器
在Java Web程序开发中,由于Web容器内部使用编码格式并不支持中文字符集,所以,处理浏览器请求中的中文数据就会出现乱码的现象.由于Web容器使用了ISO-8859-1的编码格式,所以在Web应用 ...
- spring设置字符编码过滤器
一.在web.xml中的配置 <!-- characterEncodingFilter字符编码过滤器 --> <filter> <filter-name>chara ...
- Jsp字符编码过滤器
通过此过滤器,可以实现统一将编码设置为UTF-8. 1.首先在web.xml中配置,添加如下代码: <!-- 过滤器 --> <filter> <filter-name& ...
随机推荐
- 第0周---python网络爬虫前奏
目标:掌握定向网络数据爬取和网页解析的基本能力 Python开发工具的选择
- urllib基本使用-Handler和自定义的opener()
""" 基本的urlopen()方法不支持代理.cookie等其他的HTTP/HTTPS高级功能.所以要支持这些功能: 使用相关的 Handler处理器 来创建特定功能的 ...
- 第七课 nodejs请求响应
1 server.js 接收请求接收请求参数 和接收完成需要对request增加两个监听事件 var http = require('http');var url = require('url');f ...
- Session基础知识
Session基础知识 主题 概念 Session的创建 Session的存储机制 Session的失效 参考资料 概念 Session代表一次用户会话.一次用户会话的含义是:从客 ...
- 高并发服务器建议调小 TCP 协议的 time_wait 超时时间
说明:操作系统默认 240 秒后,才会关闭处于 time_wait 状态的连接,在高并发访问下,服 务器端会因为处于 time_wait 的连接数太多,可能无法建立新的连接,所以需要在服务器上 调小此 ...
- debug_backtrace final catch
<?php function backtrace_str(){ $str = ''; $w = 0; $backtrace = debug_backtrace(); foreach($backt ...
- Docker Metasploit Framework
https://hub.docker.com/r/usertaken/metasploit-framework/ docker pull usertaken/metasploit-framework ...
- GBK和UTF-8文字编码的区别
UTF-8是一种国际化标准的文字编码,我们已知Windows系统程序已经将最初的UTF-8转向Unicode,而GBK的存在是为了中国国情而创造的,不过GBK也将伴随着中文字符的一直流传下去. GBK ...
- 阻止element组件中的<el-input/>的粘贴功能
需求: 阻止element组件中的<el-input/>的粘贴功能 实现思路: <el-input/>组件是由外层<div>和内层的<input>组成的 ...
- POCO c++ 使用例子
.定时器 #include "Poco/Timer.h" #include "Poco/Thread.h" using Poco::Timer; using P ...