java中徹底解決中文亂碼

先分析一下出現亂碼的幾種情況:

  • 數據在頁面顯示有亂碼
  • 數據到服務器後有亂碼
  • 從服務器返回的有亂碼
  • 使用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放行,我在服務器程序裏面就不用再寫解決亂碼的代碼,從而提高程序的可維護性.

增強一個類有三種方式:

  1. 直接繼承該類
  2. 包裝設計模式
  3. 動態代理

顯然,這裏不適合用繼承,雖然它最簡單,但是一個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
    }
} 
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章