Struts2中文乱码问题 过滤器源码分析
前几天在论坛上看到一篇帖子,是关于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>
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);//激活下一个过滤器
}
到这里我们已经执行了一个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;
}
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);
}
}
//省略了一些代码
}
@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方 法
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);
}
}
}
- 不能是一个存在action。
- serveStatic(struts.serve.static配置项值)为true时,不能是一个相对路径以"/struts"开头的请求,如(/struts.html,/struts/index.html),
- 必须是一个类似于/index.html,/news/index.html这样的请求或者serveStatic为false时请求一个不存在的action。
因为这样过滤器会认为你在找struts内部的静态资源,谈后它会去诸如struts的模板文件夹下去找这些静态资源。
Struts2中文乱码问题 过滤器源码分析的更多相关文章
- Spring Security(四) —— 核心过滤器源码分析
摘要: 原创出处 https://www.cnkirito.moe/spring-security-4/ 「老徐」欢迎转载,保留摘要,谢谢! 4 过滤器详解 前面的部分,我们关注了Spring Sec ...
- Camus导入中文乱码问题(源码修改、编译、部署、任务启动)
Camus使用过程中业务方反映从Kafka导入至HDFS中的数据有中文乱码问题,且业务方确认写入的数据编码为UTF-8,开始跟进. 问题重现: (1)编写代码将带有中文的字符串以编码UTF-8 ...
- Struts2 源码分析——过滤器(Filter)
章节简言 上一章笔者试着建一个Hello world的例子.是一个空白的struts2例子.明白了运行struts2至少需要用到哪一些Jar包.而这一章笔者将根据前面章节(Struts2 源码分析—— ...
- Struts2 源码分析——调结者(Dispatcher)之执行action
章节简言 上一章笔者写关于Dispatcher类如何处理接受来的request请求.当然读者们也知道他并非正真的执行action操作.他只是在执行action操作之前的准备工作.那么谁才是正真的执行a ...
- Struts2请求处理流程及源码分析
1.1 Struts2请求处理 1. 一个请求在Struts2框架中的处理步骤: a) 客户端初始化一个指向Servlet容器的请求: b) 根据Web.xml配置,请求首先经过ActionConte ...
- Struts2 源码分析-----工作原理分析
请求过程 struts2 架构图如下图所示: 依照上图,我们可以看出一个请求在struts的处理大概有如下步骤: 1.客户端初始化一个指向Servlet容器(例如Tomcat)的请求: 2.这个请求经 ...
- JavaWeb过滤器Filter(附tomcat部分源码分析)
过滤器Filter 过滤器通常对一些web资源进行拦截,做完一些处理器再交给下一个过滤器处理,直到所有的过滤器处理器,再调用servlet实例的service方法进行处理.过滤器可以对request进 ...
- Struts2 源码分析——DefaultActionInvocation类的执行action
本章简言 上一章讲到关于拦截器的机制的知识点,让我们对拦截器有了一定的认识.我们也清楚的知道在执行用户action类实例之前,struts2会先去执行当前action类对应的拦截器.而关于在哪里执行a ...
- Struts2 源码分析——拦截器的机制
本章简言 上一章讲到关于action代理类的工作.即是如何去找对应的action配置信息,并执行action类的实例.而这一章笔者将讲到在执行action需要用到的拦截器.为什么要讲拦截器呢?可以这样 ...
随机推荐
- python对数据去重处理
我们在数据处理时,经常需要用到对重复数据进行过滤处理. 对数据去重有两种处理方式,如下: 1.对重复数据去重,并且会自动排序 使用函数 set # 列表去重 list_a = [6, 6, 5, ...
- poj 3253 Fence Repair(优先队列+huffman树)
一个很长的英文背景,其他不说了,就是告诉你锯一个长度为多少的木板就要花多少的零钱,把一块足够长(不是无限长)的木板锯成n段,每段长度都告诉你了,让你求最小花费. 明显的huffman树,优先队列是个很 ...
- java的properties文件从数据库添加到文件
package com.xian.jdbc; import java.io.BufferedInputStream; import java.io.FileInputStream; import ja ...
- maven的编译规范
maven的中央仓库上的jar的包名必须小写.否则maven编译不通过. 如:Memcached-Java-Client-3.0.2 的jar包. 目录如下: com.whalin.memcached ...
- 一文了解:Redis基础类型
Redis基础类型 Redis特点 开源的,BSD许可高级的key-value存储系统 可以用来存储字符串,哈希结构,链表,集合 安装 windows:https://github.com/micro ...
- JavaScript数据结构——链表的实现与应用
链表用来存储有序的元素集合,与数组不同,链表中的元素并非保存在连续的存储空间内,每个元素由一个存储元素本身的节点和一个指向下一个元素的指针构成.当要移动或删除元素时,只需要修改相应元素上的指针就可以了 ...
- 夯实Java基础(五)——==与equals()
1.前言 我们在学习Java的时候,看到==.equals()就认为比较简单,随便看了一眼就过了,其实你并没有深入去了解二者的区别.这个问题在面试的时候出现的频率比较高,而且据统计有85%的人理直气壮 ...
- Leetcode的SQL题解:185. 部门工资前三高的员工
题目 查询部门工资前三高的员工. 我用的数据库是oracle. 下面是数据表的信息. Employee表数据: | ID | NAME | Salary | DepartmentId | | -- | ...
- C#使用代理IP发送请求
https://www.cnblogs.com/benbenfishfish/p/5830149.html 获取可代理的IP https://www.cnblogs.com/ShalenChe/p ...
- 浅谈IDEA集成SSM框架(SpringMVC+Spring+MyBatis)
前言 学习完MyBatis,Spring,SpringMVC之后,我们需要做的就是将这三者联系起来,Spring实现业务对象管理,Spring MVC负责请求的转发和视图管理, MyBatis作为数据 ...