先分析一下出現亂碼的幾種情況:
- 數據在頁面顯示有亂碼
- 數據到服務器後有亂碼
- 從服務器返回的有亂碼
- 使用Ajax收發時有亂碼
數據在頁面顯示有亂碼
也就是服務器獲取數據時沒有問題,在客戶端上顯示數據爲亂碼,這種情況最好解決,只需修改頁面的編碼即可:
pageEncoding="utf-8"
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
數據到服務器後有亂碼
通常出現在表單提交數據給服務器,服務器獲取時得到的是亂碼,以Tomcat爲例,出現這種情況是因爲沒有告訴服務器以什麼編碼去獲取數據,假設頁面是以utf-8的編碼顯示的數據,你填寫時沒有問題,看起來是沒有問題,但是計算機只認識0和1,它在傳輸過程中是以二進制的樣式進入到服務器的,這時你的服務器就不知道它之前是什麼編碼,如果你沒有指定,它就會按照老外的喜好,以iso8859-1的編碼去讀取,結果就出亂碼了.
這種情況的解決方式又要一分爲二,爲POST和GET方式,POST解決方案很簡單,既然獲取時有亂碼,那麼在獲取之前,設置編碼即可:
request.setCharacterEncoding("utf-8");
然後再使用傳統方法獲取:
String value = request.getParameter("value");
需要注意,這種設置只對POST提交有效,如果是GET則相對麻煩一點.因爲亂碼是在調用方法getParameter()時出現的,方法內部的編碼肯定出現了問題,既然它不能自動使用UTF-8,那我們就手動來轉:
if(request.getMethod().equalsIgnoreCase("get")){
value = new String(value.getBytes("iso8859-1"),"utf-8");
}
由於POST提交方式已經得到了解決,我們就只需要在提交方式爲GET時進行處理.這樣,就能保證服務器獲取的數據肯定不是亂碼
從服務器返回的有亂碼
通常只需要設置response的編碼:
response.setCharacterEncoding("utf-8");
然後再設置瀏覽器的編碼爲UTF-8
或者通知瀏覽器以UTF-8的編碼打開
response.setContentType("text/html;charset=utf-8");
這樣就能保證瀏覽器收到的是UTF-8的數據,並且顯示也沒有問題.
使用Ajax收發時有亂碼
如果是使用Ajax或者JavaScript提交的表單,是用get就需要對傳遞的中文進行編碼.使用JS的內置函數encodeURI(),這個函數把URI字符串採用UTF-8編碼格式轉化成escape格式的字符串,如果不使用該函數,將由瀏覽器進行默認的編碼,但這是一種不能預測的行爲.總而言之,只要上述問題解決了,Ajax也就清靜了
另外,如果獲取數據時,服務器端的每個程序都需要針對POST,GET進行設置,且都是同樣的寫法,那就顯得太不優雅了,所以最後用一個過濾器替換掉對所有頁面的request和response的設置.那我就需要在過濾器裏面對request或者response對象進行增強,然後把增強後的request或者response放行,我在服務器程序裏面就不用再寫解決亂碼的代碼,從而提高程序的可維護性.
增強一個類有三種方式:
- 直接繼承該類
- 包裝設計模式
- 動態代理
顯然,這裏不適合用繼承,雖然它最簡單,但是一個request對象中包含着衆多的數據,如果想創造一個request對象,就必須知道request是如何產生的,然後用服務器創造request對象的方式去創造我的"MyRequest"對象,來達到增強的目的.所以在這裏放棄這種方式.
過濾器+包裝類
public class CharacterFilter implements Filter {
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest) req;
HttpServletResponse response = (HttpServletResponse) res;
//POST的亂碼解決方案
request.setCharacterEncoding("utf-8");
//返回數據的亂碼解決方案
response.setCharacterEncoding("utf-8");
response.setContentType("text/html;charset=utf-8");
//將增強後的對象放行
MyRequest myRequest = new MyRequest(request);
chain.doFilter(myRequest, response); //這樣一來,後面所有的操作都是基於這個增強後的對象進行的
}
/**創建一個request對象的包裝類:
1.編寫一個類,實現與被增強對象相同的接口
2.在類中定義一個變量,記住被增強對象
3.在類中定義一個構造方法,接收被增強對象
4.覆寫想要增強的方法
5.對於不想增強的方法,直接調用被增強對象(目標對象)的方法
包裝設計模式"五步曲"
*/
class MyRequest extends HttpServletRequestWrapper{
private HttpServletRequest request;
public MyRequest(HttpServletRequest request) {
super(request);
this.request = request;
}
@Override
public String getParameter(String name) {
//如果請求方式是POST,則不用增強,直接調用目標對象的方法
if(this.request.getMethod().equalsIgnoreCase("POST")){
return this.request.getParameter(name);
}
/*程序運行到此,請求方式必然爲GET
先獲取值,再進行手動轉換*/
String value = this.request.getParameter(name);
try {
value = new String(value.getBytes("iso8859-1"),"utf-8");
} catch (UnsupportedEncodingException e) {
throw new RuntimeException(e);
}
return value; //返回
}
}
public void destroy() {
// TODO Auto-generated method stub
}
public void init(FilterConfig fConfig) throws ServletException {
// TODO Auto-generated method stub
}
}
過濾器記得在web.xml中配置一把
過濾器+動態代理
public class CharacterFilter2 implements Filter {
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
final HttpServletRequest request = (HttpServletRequest) req;
HttpServletResponse response = (HttpServletResponse) res;
//POST的亂碼解決方案
request.setCharacterEncoding("utf-8");
//返回數據的亂碼解決方案
response.setCharacterEncoding("utf-8");
response.setContentType("text/html;charset=utf-8");
//用動態代理攔截,增強getParameter()後,放行
chain.doFilter((ServletRequest) Proxy.newProxyInstance(CharacterFilter2.class.getClassLoader(), request.getClass().getInterfaces(),
new InvocationHandler(){ //直接實現接口
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
//如果請求方式是POST,則不用增強,直接調用目標對象的方法
if(request.getMethod().equalsIgnoreCase("POST")){
return method.invoke(request, args);
}
String methodName = method.getName();
//如果傳遞進來的方法不是getParameter(),則不用增強
if(!methodName.equals("getParameter")){
return method.invoke(request, args);
}
//爲GET,並且是getParameter(),...
String value = (String) method.invoke(request, args);
if(value!=null){
value = new String(value.getBytes("iso8859-1"),"utf-8");
}
return value;
}
}), response);
}
public void destroy() {
// TODO Auto-generated method stub
}
public void init(FilterConfig fConfig) throws ServletException {
// TODO Auto-generated method stub
}
}