通過HttpServletRequestWrapper(裝飾模式的應(yīng)用)增強(qiáng)HttpServletRequest的功能博客分類:
java應(yīng)用服務(wù)器TomcatServletSpring瀏覽器應(yīng)用一:解決tomcat下中文亂碼問題(先來個簡單的)
在tomcat下,我們通常這樣來解決中文亂碼問題:
過濾器代碼:
Java代碼
package filter;
import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;
import wrapper.GetHttpServletRequestWrapper;
public class ContentTypeFilter implements Filter {
private String charset = "UTF-8";
private FilterConfig config;
public void destroy() {
System.out.println(config.getFilterName()+"被銷毀");
charset = null;
config = null;
}
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
//設(shè)置請求響應(yīng)字符編碼
request.setCharacterEncoding(charset);
response.setCharacterEncoding(charset);
HttpServletRequest req = (HttpServletRequest)request;
System.out.println("----請求被"+config.getFilterName()+"過濾");
//執(zhí)行下一個過濾器(如果有的話,否則執(zhí)行目標(biāo)servlet)
chain.doFilter(req, response);
System.out.println("----響應(yīng)被"+config.getFilterName()+"過濾");
}
public void init(FilterConfig config) throws ServletException {
this.config = config;
String charset = config.getServletContext().getInitParameter("charset");
if( charset != null && charset.trim().length() != 0)
{
this.charset = charset;
}
}
}
web.xml中過濾器配置:
Xml代碼
<!--將采用的字符編碼配置成應(yīng)用初始化參數(shù)而不是過濾器私有的初始化參數(shù)是因?yàn)樵贘SP和其他地方也可能需要使用-->
<context-param>
<param-name>charset</param-name>
<param-value>UTF-8</param-value>
</context-param>
<filter>
<filter-name>ContentTypeFilter</filter-name>
<filter-class>filter.ContentTypeFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>ContentTypeFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
request.setCharacterEncoding(charset); 必須寫在第一次使用request.getParameter()之前,這樣才能保證參數(shù)是按照已經(jīng)設(shè)置的字符編碼來獲取。
response.setCharacterEncoding(charset);必須寫在PrintWriter out = request.getWriter()之前,這樣才能保證out按照已經(jīng)設(shè)置的字符編碼來進(jìn)行字符輸出。
通過過濾器,我們可以保證在Servlet或JSP執(zhí)行之前就設(shè)置好了請求和響應(yīng)的字符編碼。
但是這樣并不能完全解決中文亂碼問題:
對于post請求,無論是“獲取參數(shù)環(huán)節(jié)”還是“輸出環(huán)節(jié)"都是沒問題的;
對于get請求,"輸出環(huán)節(jié)"沒有問題,但是"獲取參數(shù)環(huán)節(jié)"依然出現(xiàn)中文亂碼,所以在輸出時直接將亂碼輸出了。
原因是post請求和get請求存放參數(shù)位置是不同的:
post方式參數(shù)存放在請求數(shù)據(jù)包的消息體中。get方式參數(shù)存放在請求數(shù)據(jù)包的請求行的URI字段中,以?開始以param=value¶me2=value2的形式附加在URI字段之后。而request.setCharacterEncoding(charset); 只對消息體中的數(shù)據(jù)起作用,對于URI字段中的參數(shù)不起作用,我們通常通過下面的代碼來完成編碼轉(zhuǎn)換:
Java代碼
String paramValue = request.getParameter("paramName");
paramValue = new String(paramValue.trim().getBytes("ISO-8859-1"), charset);
但是每次進(jìn)行這樣的轉(zhuǎn)換實(shí)在是很麻煩,有沒有統(tǒng)一的解決方案呢?
解決方案1: 在tomcat_home\conf\server.xml 中的Connector元素中設(shè)置URIEncoding屬性為合適的字符編碼
Java代碼
<Connector port="8080" protocol="HTTP/1.1"
connectionTimeout="20000"
redirectPort="8443"
URIEncoding="UTF-8"
/>
這樣做的缺點(diǎn)是,同一個tomcat下的其他應(yīng)用也將受到影響。而其每次部署時都需要類修改配置也很麻煩。
解決方案2:自定義請求包裝器包裝請求,將字符編碼轉(zhuǎn)換的工作添加到getParameter()方法中
Java代碼
package wrapper;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
public class GetHttpServletRequestWrapper extends HttpServletRequestWrapper {
private String charset = "UTF-8";
public GetHttpServletRequestWrapper(HttpServletRequest request) {
super(request);
}
/**
* 獲得被裝飾對象的引用和采用的字符編碼
* @param request
* @param charset
*/
public GetHttpServletRequestWrapper(HttpServletRequest request,
String charset) {
super(request);
this.charset = charset;
}
/**
* 實(shí)際上就是調(diào)用被包裝的請求對象的getParameter方法獲得參數(shù),然后再進(jìn)行編碼轉(zhuǎn)換
*/
public String getParameter(String name) {
String value = super.getParameter(name);
value = value == null ? null : convert(value);
return value;
}
public String convert(String target) {
System.out.println("編碼轉(zhuǎn)換之前:" + target);
try {
return new String(target.trim().getBytes("ISO-8859-1"), charset);
} catch (UnsupportedEncodingException e) {
return target;
}
}
}
修改過濾器的doFilter方法 代碼如下:
Java代碼
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
//設(shè)置請求響應(yīng)字符編碼
request.setCharacterEncoding(charset);
response.setCharacterEncoding(charset);
//新增加的代碼
HttpServletRequest req = (HttpServletRequest)request;
if(req.getMethod().equalsIgnoreCase("get"))
{
req = new GetHttpServletRequestWrapper(req,charset);
}
System.out.println("----請求被"+config.getFilterName()+"過濾");
//傳遞給目標(biāo)servlet或jsp的實(shí)際上時包裝器對象的引用,而不是原始的HttpServletRequest對象
chain.doFilter(req, response);
System.out.println("----響應(yīng)被"+config.getFilterName()+"過濾");
}
這樣一來,在servlet中調(diào)用包裝器的getParameters方法來獲取參數(shù),就已經(jīng)完成了字符編碼的轉(zhuǎn)換過程,我們就不需要在每次獲取參數(shù)時來進(jìn)行字符編碼轉(zhuǎn)換了。
這是我講課時的一個例子,不對之處,敬請指教,以免誤人子弟啊。
demo.rar (8.6 KB)
描述: 附:源程序
下載次數(shù): 305
分享到:
HttpServletRequestWrapper應(yīng)用(二):包 ... |
引用 一個窮學(xué)生的愛情2009-10-08 21:44
瀏覽 734
評論(25)論壇回復(fù) /
瀏覽 (25 / 10397)
收藏相關(guān)推薦評論
25 樓
Zahir 2010-04-18
引用用動態(tài)代理來做就好了,沒必要寫個wrapper出來
24 樓
舞指如歌 2010-04-18
引用寫的很詳細(xì),我以前也遇到同樣的問題,POST的用過濾器中setCharacterEncoding解決,但是GET請求里的參數(shù)的中文還是有亂碼問題,最后是通過修改config文件解決的,這下終于有了一個比較滿意的方案了,謝謝。
23 樓
whistler 2009-10-12
引用gufenglian 寫道
經(jīng)常遇到亂碼問題,一直在想為什么post行,get就不行了,現(xiàn)在思路清晰了。感謝樓主,我聽說tomcat可以配置成根據(jù)頁面編碼來設(shè)置uri。
樓主知道的話,可以講解一下
可以在Tomcat的配置文件的Connector標(biāo)簽中設(shè)置useBodyEncodingForURI屬性值為true。在默認(rèn)情況下,該參數(shù)為false(Tomcat4.0中該參數(shù)默認(rèn)為true)
22 樓
gufenglian 2009-10-12
引用經(jīng)常遇到亂碼問題,一直在想為什么post行,get就不行了,現(xiàn)在思路清晰了。感謝樓主,我聽說tomcat可以配置成根據(jù)頁面編碼來設(shè)置uri。
樓主知道的話,可以講解一下
21 樓
love1907 2009-10-12
引用曾經(jīng)de迷茫 寫道
whistler 寫道
zwq4166506 寫道
有個缺陷,比如form有個name屬性,請求的url也有個name屬性,如
Html代碼
<form method="post" action="?name=處理亂碼">
<input type="text" name="name"/>
<input type="submit" value="submit"/>
</form>
這樣就混亂了,結(jié)果出來還是亂碼。。。
確實(shí)是這樣,那么用的時候必須注意這個問題了,不能在post方式提交表單的情況下,在action屬性中附加中文參數(shù)了,
只能在表單中用隱藏域來代替了,我再想想能不能解決這個問題
感謝zwq4166506兄弟這么仔細(xì)幫我找bug
還是對中文處理再傳遞,有一種辦法是使用js代碼Js代碼
/url?¶m=encodeURI(encodeURI('中文')); //兩次編碼
然后服務(wù)器Java代碼
String param= java.net.URLDecoder.decode(request.getParameter("param") , "UTF-8");
沒搞懂為啥要兩次,encodeURI()
20 樓
seemoon 2009-10-12
引用講解清晰,傳業(yè)授道解惑,不算誤人子弟
19 樓
skzr.org 2009-10-12
引用zwq4166506 寫道
有個缺陷,比如form有個name屬性,請求的url也有個name屬性,如
Html代碼
<form method="post" action="?name=處理亂碼">
<input type="text" name="name"/>
<input type="submit" value="submit"/>
</form>
這樣就混亂了,結(jié)果出來還是亂碼。。。
我局的樓主所說的問題應(yīng)該是URL支不支持中文或其他語言的問題,也就是說使用瀏覽器地址欄直接訪問帶有中文或其他任何非標(biāo)準(zhǔn)字符的資源時出現(xiàn)的亂碼:
如果直接通過瀏覽器地址訪問帶有中文參數(shù)的url(如:http://localhost/web/xx.do?name=中文XX,或者是點(diǎn)擊<a href='http://localhost/web/xx.do?name=中文XX'>相當(dāng)于直接通過瀏覽器地址欄訪問</a>)
這個問題的解決好像只能夠通過修改tomcat的server.xml來支持服務(wù)器解析非iso8859-1的url,weblogic和webshere是默認(rèn)支持url的自動編碼解析的。
按照樓主的包裝或者自己轉(zhuǎn)碼的方法,不知道在解析奇數(shù)和偶數(shù)個數(shù)的中文時結(jié)果還會不會一致(之前用tomcat5.0的時候出現(xiàn)奇數(shù)或偶數(shù)個中文不正常)
至于說的server。xml里面配置的uriencode只是說uri支持直接書寫中文,不過如果是表單提交的話,他們會自動編碼的(無論是post 還是 get方式)!server。xml里面配置的uriencode只是對a標(biāo)簽和直接在瀏覽器地址欄中書寫的url起作用!
18 樓
wangdgsc 2009-10-11
引用還有樓上說要使用Spring的過濾器的哥們兒,Spring的過濾器我好像只能處理post請求,不能干別的
17 樓
wangdgsc 2009-10-11
引用我的字符串過濾器都是在Filter中直接處理get和post兩種請求,樓主的這種處理方式我也見到別人寫過,不過,樓主好像少覆蓋了一個方法getParameterMap()直接獲得參數(shù)集合,呵呵
16 樓
piggy 2009-10-11
引用目前我為公司寫的過濾器就是在spring過濾器的基礎(chǔ)上再判斷是否為tomcat,如果tomcat就是跟樓主這樣的處理。
15 樓
曾經(jīng)de迷茫 2009-10-11
引用whistler 寫道
zwq4166506 寫道
有個缺陷,比如form有個name屬性,請求的url也有個name屬性,如
Html代碼
<form method="post" action="?name=處理亂碼">
<input type="text" name="name"/>
<input type="submit" value="submit"/>
</form>
這樣就混亂了,結(jié)果出來還是亂碼。。。
確實(shí)是這樣,那么用的時候必須注意這個問題了,不能在post方式提交表單的情況下,在action屬性中附加中文參數(shù)了,
只能在表單中用隱藏域來代替了,我再想想能不能解決這個問題
感謝zwq4166506兄弟這么仔細(xì)幫我找bug
還是對中文處理再傳遞,有一種辦法是使用js代碼Js代碼
/url?¶m=encodeURI(encodeURI('中文')); //兩次編碼
然后服務(wù)器Java代碼
String param= java.net.URLDecoder.decode(request.getParameter("param") , "UTF-8");
14 樓
whistler 2009-10-10
引用zwq4166506 寫道
有個缺陷,比如form有個name屬性,請求的url也有個name屬性,如
Html代碼
<form method="post" action="?name=處理亂碼">
<input type="text" name="name"/>
<input type="submit" value="submit"/>
</form>
這樣就混亂了,結(jié)果出來還是亂碼。。。
確實(shí)是這樣,那么用的時候必須注意這個問題了,不能在post方式提交表單的情況下,在action屬性中附加中文參數(shù)了,
只能在表單中用隱藏域來代替了,我再想想能不能解決這個問題
感謝zwq4166506兄弟這么仔細(xì)幫我找bug
13 樓
whistler 2009-10-10
引用alex09 寫道
Java代碼
public void destroy() {
charset = null;
config = null;
System.out.println(config.getFilterName()+"被銷毀");
}
直接就爆掉的代碼啊
汗,哈哈,謝謝,太馬虎大意了,文章中已經(jīng)修改了,但是上傳文件中的還沒修改,麻煩下載了的兄弟們自己修改了。
再次感謝,不然不知道丟人到啥時候了
12 樓
alex09 2009-10-10
引用Java代碼
public void destroy() {
charset = null;
config = null;
System.out.println(config.getFilterName()+"被銷毀");
}
直接就爆掉的代碼啊
11 樓
zwq4166506 2009-10-10
引用有個缺陷,比如form有個name屬性,請求的url也有個name屬性,如
Html代碼
<form method="post" action="?name=處理亂碼">
<input type="text" name="name"/>
<input type="submit" value="submit"/>
</form>
這樣就混亂了,結(jié)果出來還是亂碼。。。
10 樓
yangtao309 2009-10-10
引用多謝樓主提醒,
原來樓主想說的是 處理get方式提交的亂碼問題
沒看太仔細(xì) 呵呵~~
對于一般的表單提交都會選擇post的吧
9 樓
whistler 2009-10-10
引用<div class="quote_title">yangtao309 寫道</div>
<div class="quote_div">中文過濾器 知道怎么自己寫就夠了<br>要用還是直接用spring自帶的比較好<br><pre name="code" class="java"> <!-- 著名 Character Encoding filter -->
<filter>
<filter-name>encodingFilter</filter-name>
<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
<init-param>
<param-name>encoding</param-name>
<param-value>UTF-8</param-value>
</init-param>
</filter>
</pre>
</div>
<p><br><br>我發(fā)現(xiàn)我的文章沒有突出主題,上來說過濾器的內(nèi)容可能比較多了,我是主體內(nèi)容如題,是說HttpServletRequestWrapper的應(yīng)用的。</p>
<p>通過查看org.springframework.web.filter.CharacterEncodingFilter源代碼,它也和我前面沒有使用HttpServletRequestWrapper包裝get方式請求處理亂碼的過濾器基本一樣啊,只是request.setCharacterEncoding(this.encoding); response.setCharacterEncoding(this.encoding);,在tomcat下是解決不了get請求獲取參數(shù)中文亂碼問題的。</p>
<p>請看org.springframework.web.filter.CharacterEncodingFilter源代碼片段:</p>
<p> </p>
<pre name="code" class="java">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);
}
</pre>
8 樓
yangtao309 2009-10-10
引用中文過濾器 知道怎么自己寫就夠了
要用還是直接用spring自帶的比較好
Java代碼
<!-- 著名 Character Encoding filter -->
<filter>
<filter-name>encodingFilter</filter-name>
<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
<init-param>
<param-name>encoding</param-name>
<param-value>UTF-8</param-value>
</init-param>
</filter>
7 樓
whaosoft 2009-10-09
引用lz 很謙虛 講的很全 呵呵 除非在項(xiàng)目中 一般在論壇系列的地方我才懶的說那么細(xì) 支持lz
6 樓
whistler 2009-10-09
引用hbcui1984 寫道
個人感覺還是直接修改tomcat配置文件方便,畢竟部署項(xiàng)目時,一般一個tomcat下只有一個應(yīng)用
恩,這個得看項(xiàng)目的情況了
如果項(xiàng)目作為產(chǎn)品的話,需要為每個客戶部署,每次都需要修改配置,比較麻煩
如果部署好之后,有可能會在以后進(jìn)行遷移,比如一開始是租的空間(修改配置也很麻煩,得委托客服修改),后來自己買了服務(wù)器,那么很有可能會遺忘配置的事情,造成麻煩
個人認(rèn)為盡可能的在應(yīng)用內(nèi)部將問題扼殺是一勞永逸的事情。