`
ahuaxuan
  • 浏览: 633478 次
  • 性别: Icon_minigender_1
  • 来自: 杭州
社区版块
存档分类
最新评论

弃成见,反省,并重新认识struts.i18n.encoding

阅读更多
[size=medium]之前和大家讨论了struts2.0中struts.i18n.encoding参数的作用,但是由于自己的不严谨的态度使自己得出了片面得结论,在此表示道歉.当然我们程序员的目的只有一个,就是寻找真相.所以下面我会和大家一起来重新理解struts.i18n.encoding参数的含义.

下面我从一个例子来重新审视这个参数的作用.首先我们来做一个实验,看看改参数是否用在了请求流程,是否用在了返回流程.首先下载struts2.0所有的包,我们会得到一个blank的例子程序.

首先有三个返回类型:
<constant name="struts.enable.DynamicMethodInvocation" value="true" />
    <constant name="struts.devMode" value="false" />
<constant name="struts.i18n.encoding" value="UTF-8" />
<constant name="struts.velocity.manager.classname" value="demo.DemoVelocityManager"/>

<package name="/" namespace="/" extends="struts-default">
		
		<action name="test" class="demo.HelloWorldAction">
			<result name="jsp">helloworld.jsp</result>
			<result name="velocity" type="velocity">helloworld.vm</result>
			<result name="freemarker" type="freemarker">helloworld.ftl</result>
		</action>
	</package>


接着定义action:
/**
 * 
 * @author ahuaxuan
 * @date 2008-6-8
 * @version $id$
 */
public class HelloWorldAction {

	private String requestEncoding;
	
	private String responseEncoding;
	
	public void check() {
		requestEncoding = ServletActionContext.getRequest().getCharacterEncoding();
		responseEncoding = ServletActionContext.getResponse().getCharacterEncoding();
	}
	public String doJsp() {
		check();
		return "jsp";
	}
	
	public String doVelocity() {
		check();
		return "velocity";
	}
	
	public String doFreemarker() {
		check();
		return "freemarker";
	}
}

访问:
http://localhost:8080/demo/test!jsp.action
页面输出:Languages
•	requestEncoding:UTF-8 
•	responseEncoding:ISO-8859-1 


http://localhost:8080/demo/test!freemarker.action

页面输出:Languages
•	requestEncoding:UTF-8 
•	responseEncoding:ISO-8859-1 


http://localhost:8080/demo/test!velocity.action
页面输出:Languages
•	requestEncoding:UTF-8 
•	responseEncoding:ISO-8859-1 


看上去返回流的编码没有变化,都是iso-8859-1.
struts.i18n.encoding换成GBK之后,3个页面的requestEncoding:都变成了requestEncoding:GBK,也就是该参数确实用在了请求流程中.
而且response的encoding还是iso-8859-1,看到这个结果可能有人会产生疑惑,不是说这个参数可以用在返回流中的吗,为什么没有体现出来呢?

其实问题出在一个时间上,但是请大家看看HelloWorldAction里的代码,其实是有问题的,因为在check方法是在action里的方法里调用的.而这个时候没有执行到result,struts2.0会在result中会设置response的一些参数(如果需要设置的话),所以这个时候的response中的encoding其实不是response最终的encoding.如何才能看到response中最终的encoding呢,只有在result被执行之后.

于是下面我们写一个filter.如下:
public void doFilter(ServletRequest req, ServletResponse res,
			FilterChain fc) throws IOException, ServletException {
		fc.doFilter(req, res);
		System.out.println("responseEncoding : " + res.getCharacterEncoding());
	}


然后在web.xml中配置在struts2的filter之前:
<filter-mapping>
        <filter-name>encode</filter-name>
        <url-pattern>/*</url-pattern>
</filter-mapping>

<filter-mapping>
        <filter-name>struts2</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>


然后分别请求

http://localhost:8080/demo/test!jsp.action
•	控制台输出:
•	responseEncoding:UTF-8


http://localhost:8080/demo/test!freemarker.action
控制台输出:
•	responseEncoding:GBK


http://localhost:8080/demo/test!velocity.action
控制台输出:
•	responseEncoding:GBK

由此可见在freemarker和velocity中struts.i18n.encoding确实被用来作为response返回流中content-type的charset值.

那么为什么jsp不是这样的呢.
因为jsp并不是模板,而是一个类,在真正运行的时候,servlet容器会把jsp编译成一个类.我们的HelloWorld.jsp就变成了HelloWorld_jsp.java,在这个类中我们可以看到如下代码:
try {
      _jspxFactory = JspFactory.getDefaultFactory();
      response.setContentType("text/html; charset=UTF-8");
      pageContext = _jspxFactory.getPageContext(this, request, response,
      			null, true, 8192, true);
      _jspx_page_context = pageContext;

修改jsp中@page标签中的charset为GBK之后,控制台也输出了responseEncoding:GBK
这说明,在jsp中,返回流的参数是由jsp的@page标签指定的,而不是有truts.i18n.encoding指定的.

由此可见, struts.i18n.encoding确实用在了请求和返回两个阶段,而且在返回阶段不同的view技术可能使用或者不使用struts.i18n.encoding,freemarker和velocity会以该值作为返回流的charset,而jsp会以页面上的@page标签中的charset作为返回流的charset.

至于源代码,它们分别在VelocityResult,freemarkermanager,dispatcher, FilterDispatcher,大家有兴趣可以自行查看.

对于之前误导大家认为该参数只用在返回流程中,我向大家说一声对不起.从这件事情中我也学习到很多,尤其是态度上,之前做实验的时候发现这个参数用在一个地方,便认为它只会用在这个地方,但是事实上这种想法是不对的,它用在一个地方不代表不能用在另外一个地方.我们应该抱着更为严谨的态度去看待所有的问题,其实当时只要在源码里search “struts.i18n.encoding”这个字符串就会立刻得到完整的结论,但是正因为自己不严谨的态度导致之前作出了片面的结论.

最后共享一些我放在之前放在一边的座右铭:态度决定高度,所以不管做什么事情都要先端正自己的态度,希望能与大家共勉.

附,由于ahuaxuan水平有限,很有可能还是没有挖掘出更深层次的见解,希望您能多指正.
[/size]
分享到:
评论
18 楼 only_java 2009-03-19  
web.xml中配置在struts2的filter之前,这是为什么?我把filter放在struts2后面发现还是乱码,放在前面确是正确的!是因为放在前面首先才能把response.encoding设置为utf8?
17 楼 buddhist 2009-03-15  
SunOne 写道
如果用StrutsPrepareAndExecuteFilter,struts.i18n.encoding就不一定起作用了。

StrutsPrepareAndExecuteFilter中:
     //这一步已经取出了reuqest的所有parameter
     prepare.createActionContext(request, response);

     prepare.assignDispatcherToThread();

     //虽然设置了request的encoding,但由于parameter已取出,action中request.getParameter()返回的是设置encoding之前的parameter的值
     prepare.setEncodingAndLocale(request, response);


如:
struts.i18n.encoding设置为UTF-8,jsp页面用UTF-8,jsp的form中提交一个中文如username,在action中看request.getParameter("username"),一样是乱码。

因此StrutsPrepareAndExecuteFilter前还是得加个CharacterEncodingFilter的,struts.i18n.encoding对request不起作用,虽然设置了。


设置后同样乱码的问题:
  String value = request.getParameter("name");
System.out.println(request.getCharacterEncoding() + " \t " + value);
byte nameb[] = value.getBytes("iso8859_1");
String encode = new String(nameb,"utf-8");
                System.out.println(encode);
用上面的方法, 第二行打印的是:utf-8  乱码
               第五行打印的是正确的汉字。

可能是和上面引用的内容类似的问题。不过并没有使用StrutsPrepareAndExecuteFilter。
唯一特别的地方就是使用了sitemesh.并用Spring管理Action类。

有哪位朋友有类似的问题?有没有优雅的解决方案。
16 楼 SunOne 2009-03-11  
如果用StrutsPrepareAndExecuteFilter,struts.i18n.encoding就不一定起作用了。

StrutsPrepareAndExecuteFilter中:
     //这一步已经取出了reuqest的所有parameter
     prepare.createActionContext(request, response);

     prepare.assignDispatcherToThread();

     //虽然设置了request的encoding,但由于parameter已取出,action中request.getParameter()返回的是设置encoding之前的parameter的值
     prepare.setEncodingAndLocale(request, response);


如:
struts.i18n.encoding设置为UTF-8,jsp页面用UTF-8,jsp的form中提交一个中文如username,在action中看request.getParameter("username"),一样是乱码。

因此StrutsPrepareAndExecuteFilter前还是得加个CharacterEncodingFilter的,struts.i18n.encoding对request不起作用,虽然设置了。
15 楼 qdoxford 2009-03-04  
虚心的态度是学习的最好动力,lz真是难得。
14 楼 jerry8086 2009-01-21  
我相信楼主写那篇文章,是站在纯技术的角度来讨论问题,但是后面跟贴的好多人进行人身攻击就有欠妥当了。看到楼主后面的声明和今天的这篇文章,我真的感到受益良多。楼主让我们感受到的不仅是你的渊博的知识,还有你对待知识的态度。
13 楼 wmj2003 2009-01-17  
赞一个!!!
12 楼 mysyche 2008-12-31  
这才是IT届真正的态度。
11 楼 nettang 2008-12-31  
先顶下楼主的治学的态度,再慢慢看文章内容
10 楼 kyo100900 2008-12-30  
 终于完全想弄清楚,为什么 freemarket, velocity的页面从来不用指定编码的原因了。
9 楼 savegod 2008-12-30  
用filter来指定字符集是比较常用的做法
8 楼 x03570227 2008-12-30  
最近才研究struts2,因为平时都用的utf-8,所以没怎么出过问题,也没去研究过这个参数的具体作用,这次算是彻底搞清楚了,回头再自己动手去做下类似的实验

非常感谢LZ
7 楼 wangbing9577 2008-12-29  
很好很强大。学习中。谢谢
6 楼 wangbing9577 2008-12-29  
很好很强大。学习中。谢谢
5 楼 ahuaxuan 2008-12-25  
还有一种方法:就是jsp返回指定新的result:
public class MyServletDispatcherResult extends StrutsResultSupport {

	public ServletDispatcherResult() {
	}

	public ServletDispatcherResult(String location) {
		super(location);
	}

	public void doExecute(String finalLocation, ActionInvocation invocation)
			throws Exception {
		if (log.isDebugEnabled())
			log.debug((new StringBuilder()).append("Forwarding to location ")
					.append(finalLocation).toString());
		PageContext pageContext = ServletActionContext.getPageContext();
		if (pageContext != null) {
			pageContext.include(finalLocation);
		} else {
			HttpServletRequest request = ServletActionContext.getRequest();
			HttpServletResponse response = ServletActionContext.getResponse();
//在这里设置content-type的charset也可以
			RequestDispatcher dispatcher = request
					.getRequestDispatcher(finalLocation);
			if (dispatcher == null) {
				response.sendError(404, (new StringBuilder())
						.append("result '").append(finalLocation).append(
								"' not found").toString());
				return;
			}
			if (!response.isCommitted()
					&& request
							.getAttribute("javax.servlet.include.servlet_path") == null) {
				request.setAttribute("struts.view_uri", finalLocation);
				request.setAttribute("struts.request_uri", request
						.getRequestURI());
				dispatcher.forward(request, response);
			} else {
				dispatcher.include(request, response);
			}
		}
	}

	private static final long serialVersionUID = -1970659272360685627L;
	private static final Log log = LogFactory.getLog(org / apache / struts2
			/ dispatcher / ServletDispatcherResult);

}
接着在struts.xml里指定这个全局的result为jsp默认的result就可以了.

不过这种方法貌似还没有你说的filter方法好,因为你的那种方法不仅可以使用于struts,任何使用jsp的场景应该都可以.
4 楼 sutra 2008-12-25  
那么对于jsp的话,我的所有jsp都是没有写<%@ page contentType...这个的,加了个filter

response.setCharacterEncoding("UTF-8");
chain.doFilter(request, response);

这样就好了。


不知道这样是不是最合适的解决方法。
3 楼 downpour 2008-12-24  
ahuaxuan针对这个问题的研究已经非常透彻了,这样的态度是非常好的。如果大家都本着实事求是的态度,无论是对于培训还是书籍,我想整个IT届会清净很多。
2 楼 1314520ln 2008-12-24  
LZ,辛苦你了,真的很赞赏你的态度.
1 楼 庄表伟 2008-12-24  
  赞赏这样的态度!

相关推荐

    《追风筝的人》:人心中的成见是座大山,但请不忘初心.docx

    《追风筝的人》:人心中的成见是座大山,但请不忘初心

    《计算机应用基础》实训大纲.doc

    科学带领我们走进事实,哪怕与 我们的成见相左.它劝告我们改变一下头脑中的假象,以找到和事实最匹配的东西.科 学,使我们在新思想和旧智慧之间保护平衡,我们需要更广泛地欣赏这种思想.我们的 任务是既要训练出更多的...

    2020计算机专业毕业实习报告.doc

    我也和你有过同样的经历,前面呆过的小公司对承诺的实现总是拖拉遮掩,最后我当面 和老板狠狠吵了一架,并且占了上风,把自己积累的对他的成见和轻视都倾泻而出,当 时大家都很不愉快,但我觉得很畅快,而且走的很...

    计算机应用技术专业毕业实习报告.docx

    我也和你有过同样的经受,前面呆过的小公司对允诺的实现总是拖拉遮掩,最后我当面和老板狠狠吵了一架,并且占了上风,把自己堆积的对他的成见和轻蔑都倾泻而出,当初大家都很不开心,但我觉得很畅快,而且走的很...

    计算机应用技术专业毕业实习报告范本.docx

    我也和你有过同样的经历,前面呆过的小公司对承诺的实现总是拖拉遮掩,最后我当面和老板狠狠吵了一架,并且占了上风,把自己积累的对他的成见和轻视都倾泻而出,当时大家都很不愉快,但我觉得很畅快,而且走的很...

    容易犯的错误或问题

    一定要用开放的心态,要不抱任何成见. 直接影响了对个人接受能力的评价. 每个人性格不同, 学习方法也不同, 不会是自己知道的或认为好的就一定是好的 在写程序的时候,如果用到新的东西的时候,一定要有确切的结论...

    大象——Thinking in UML(第2版)高清扫描版.part2.rar

    借用亚马逊网友 cheppinl 的一段评论:“从事IT工作15年,经历过编码、设计、管理,看了不少IT的书,客观来说,对国内人写的书抱有成见,一般都是东拼西凑,没有什么思想和深度。关于UML的书我也看过几本,包括国内...

    大象——Thinking in UML(第2版)高清扫描版.part1.rar

    借用亚马逊网友 cheppinl 的一段评论:“从事IT工作15年,经历过编码、设计、管理,看了不少IT的书,客观来说,对国内人写的书抱有成见,一般都是东拼西凑,没有什么思想和深度。关于UML的书我也看过几本,包括国内...

    政务新媒体运用SWOT分析.doc

    "易扭转群众对于政府的印象与成见。 " "入 "帮助职能部门一对一、一对多等方式快速有 "以全新的新媒体技术手段,更容易让群众接受" "能够应对新形势下民意沟通的实际 "效与群众沟通互动。 "和欢迎。 " "需要 " ...

    大数据金融缺点是什么.docx

    大数据是人类设计的产物,大数据的工具并不能使人们摆脱曲解、隔阂和成见,数据之间相关性也不等同于因果关系,大数据还存在选择性覆盖问题。 3、基于大数据开发的金融产品和交易工具对金融监管提出挑战。大数据的...

    Android程序设计基础

    感谢编辑Susannah Pfalzer在我几乎要推迟交稿时提供的好建议并为我鼓足勇气。特别要感谢我的家人,感谢他们在我写作本书期间表现出来的极大耐心。...   媒体评论  “跟本书的2005版一样,我认为Louis的这本书写...

    lm-social-bias

    随着机器学习方法被部署在诸如医疗保健,法律系统和社会科学等现实世界中,至关重要的是要认识到它们如何在这些敏感的决策过程中形成社会偏见和成见。 在这样的现实世界中,部署大规模的预训练语言模型(LM)可能会...

    论文研究 - 尼日利亚东南部一家三级医院门诊病人的癫痫病耻辱

    背景:癫痫病的耻辱感在发展中国家普遍存在,并对其患者的心理和社会福祉产生负面影响。 污名的经历因环境而异,可能与疾病的严重程度和社会特征有关。 这项研究试图描述癫痫门诊患者的耻辱感和行为耻辱的程度及其...

    Oracle MSA 白皮书

    如果您的公司成立不久而且处于快速成长期,或是一家寻求新商机和提高效率的根基稳固的企业,现在也许是您改变对实施大型 ERP 的成见的时候了。新型的固定价值、固定范围的产品和定向评估程序,已经向 IT 人手和资源...

    eslint-plugin-inclusive-language:一个ESLint插件,不仅可以在您的代码库中,而且可以在生活中提高使用包容性语言的意识

    包容性语言是指不含单词,短语或语调的语言,这些单词,短语或音调反映了特定人群或群体的偏见,成见或歧视性观点。 这也是一种语言,它不会故意或无意地将人们排除在群体之外。 ( ) 坚持使用包容性的语言听起来...

    透明的预测-研究论文

    认识这些要素对于理解透明度的重要性和挑战至关重要。 第三部分着眼于预测过程生成的信息流。 在此过程中,它解决了在此过程中实现透明的各种策略,有些策略是法律规定的,而另一些则被忽略了。 为此,本文引入了...

    论文通用人工智能的火花:GPT-4 早期实验

    内容概要: GPT-4的能力具有普遍性,它的许多能力跨越了广泛的领域,而且它在广泛的任务中的表现达到或超过了人类水平,这两者...6、认知谬误和非理性:自己不具备认知能力,会继承其训练数据中存在的一些偏见、成见或

    论文研究 - 关于肥胖问题的偏见和定型观念:一项行动计划

    减少负面偏见和成见对肥胖者和肥胖者的影响的最有用的策略之一是通过面对面和想象的环境均可实现的接触。 目的:分析刺激对暴露的影响(肥胖症偏见的培训过程),以减轻对肥胖者的负面态度。 参加者:西西里岛...

    GameThesis:一次点击冒险游戏的源代码

    该游戏采用点击式冒险的风格,旨在通过讲述一个必须离开家乡的男孩的故事来解决有关难民的一些神话和成见。 有关该故事的更多信息,请参见我的博客: : 该游戏利用Javascript游戏框架Crafty( )。 最新的游戏...

    Investigating_a_dataset:关于若干指标对一个国家家庭女工人数影响的主题的探索性数据分析

    Investigating_a_dataset 关于若干指标对一个国家家庭女工人数影响的主题的探索性数据分析分析步骤自由选择数据集(该项目中使用了Gapminder.com) 整理和清理数据探索指标及其对因变量的影响结论和成见笔记该项目已...

Global site tag (gtag.js) - Google Analytics