该帖已经被评为精华帖
|
|
---|---|
作者 | 正文 |
发表时间:2008-12-24
最后修改:2008-12-24
下面我从一个例子来重新审视这个参数的作用.首先我们来做一个实验,看看改参数是否用在了请求流程,是否用在了返回流程.首先下载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] 声明:ITeye文章版权属于作者,受法律保护。没有作者书面许可不得转载。
推荐链接
|
|
返回顶楼 | |
发表时间:2008-12-24
最后修改:2008-12-24
赞赏这样的态度!
|
|
返回顶楼 | |
发表时间:2008-12-24
LZ,辛苦你了,真的很赞赏你的态度.
|
|
返回顶楼 | |
发表时间:2008-12-24
ahuaxuan针对这个问题的研究已经非常透彻了,这样的态度是非常好的。如果大家都本着实事求是的态度,无论是对于培训还是书籍,我想整个IT届会清净很多。
|
|
返回顶楼 | |
发表时间:2008-12-25
那么对于jsp的话,我的所有jsp都是没有写<%@ page contentType...这个的,加了个filter
response.setCharacterEncoding("UTF-8"); chain.doFilter(request, response); 这样就好了。 不知道这样是不是最合适的解决方法。 |
|
返回顶楼 | |
发表时间:2008-12-25
最后修改: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的场景应该都可以. |
|
返回顶楼 | |
发表时间:2008-12-30
最近才研究struts2,因为平时都用的utf-8,所以没怎么出过问题,也没去研究过这个参数的具体作用,这次算是彻底搞清楚了,回头再自己动手去做下类似的实验
非常感谢LZ |
|
返回顶楼 | |
发表时间:2008-12-30
用filter来指定字符集是比较常用的做法
|
|
返回顶楼 | |
发表时间:2008-12-30
终于完全想弄清楚,为什么 freemarket, velocity的页面从来不用指定编码的原因了。
|
|
返回顶楼 | |
发表时间:2008-12-31
先顶下楼主的治学的态度,再慢慢看文章内容
|
|
返回顶楼 | |