網上有很多講解決Servlet中文亂碼的問題,一般的解決方案是加一個過濾器,在doFilter方法中加入:
- request.setCharacterEncoding("UTF-8");
可是這樣並不能解決GET方式傳遞的資料。如果你能修改tomcat的配置檔案,你可以把網址的編碼設為UTF-8(或其它):在server.xml的<Connector> 加入 URIEncoding=”UTF-8″。當然,更大的可能性是你沒有許可權修改這個檔案,或者有多個網站,但使用了不同的編碼。所以需要在doFilter中判斷是get還是post後再作相應的處理
- if(httpServletRequest.getMethod().toLowerCase().equals("get")){
- for(String[] strs : request.getParameterMap().values()){
- for(int i = 0; i < strs.length; i++){
- strs[i] = new String(strs[i].getBytes("ISO-8859-1"), "UTF-8");
- System.out.println(strs[i]);
- }
- }
- }
- else{
- request.setCharacterEncoding("UTF-8");
- }
這樣看起來似乎是完美了,但是實際應用中,經常使用到混合POST和GET方式提交。如用POST方式提交一個單表到www.xxx.com/deal?page=2。如果使用上述的過濾器,自然是按POST方式進行處理,那通過網址傳過來的中文資料就會亂碼了。
好在可以得到QueryString,似乎只要把QueryString中的出現的引數處理一下就行了(先忽略重複name的問題):
- HttpServletRequest httpServletRequest = (HttpServletRequest) request;
- String[] expressions = httpServletRequest.getQueryString().split("&");
- for(String expression : expressions){
- String[] parts = expression.split("=");
- if(parts.length == 2){
- request.getParameterMap().put(parts[0], new String[]{ decode(parts[1])});
- }
- }
執行下。。。OMG。。。java.lang.IllegalStateException: No modifications are allowed to a locked ParameterMap。原來這個Map是不能新增值的。可是第一個過濾器中我卻成功修改了值,所以產生了第一種方案,我不用put,我去改values。
- public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
- request.setCharacterEncoding("UTF-8"); //這句得在下面那個強制轉換之前,不知道為什麼。這句用來處理post的情況
- HttpServletRequest httpServletRequest = (HttpServletRequest) request;
- //建立一個ArrayList用來存所有的Get方式提交的name對應在Parameter裡的value
- ArrayList<String> queryValues = new ArrayList<String>();
- Map<String, String[]> map = request.getParameterMap();
- String query = httpServletRequest.getQueryString();
- if(query != null){
- String[] expressions = query.split("&");
- for(String expression : expressions){
- String[] parts = expression.split("=");
- if(parts.length == 2){
- String[] values = map.get(parts[0]);
- for(String value : values){
- queryValues.add(value);
- }
- }
- }
- }
- //遍歷value,如果是get方式提交的(存在於queryValues中),就轉一下編碼
- for(String[] strs : request.getParameterMap().values()){
- for(int i = 0; i < strs.length; i++){
- for(String qStr : queryValues){
- if(qStr.equals(strs[i])){
- strs[i] = new String(qStr.getBytes("ISO-8859-1"), "UTF-8");
- //ISO-8859-1是tomcat中預設的,UTF-8是urlencode的編碼
- break;
- }
- }
- }
- }
- chain.doFilter(request, response);
- }
這樣做蠻複雜的,效率又不高。如果post和get中有相同的name,就會出錯,可以稍加修改:
- public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
- request.setCharacterEncoding("UTF-8");
- HttpServletRequest httpServletRequest = (HttpServletRequest) request;
- ArrayList<String> queryValues = new ArrayList<String>();
- Map<String, String[]> map = request.getParameterMap();
- String query = httpServletRequest.getQueryString();
- if(query != null){
- String[] expressions = query.split("&");
- for(String expression : expressions){
- String[] parts = expression.split("=");
- if(parts.length == 2){
- /*String[] values = map.get(parts[0]);
- for(String value : values){
- queryValues.add(value);
- }*/
- //將上面這段修改為
- String str = URLDecoder.decode(parts[1], "UTF-8");
- System.out.println(str);
- queryValues.add(new String(str.getBytes("UTF-8"), "ISO-8859-1"));
- }
- }
- }
- for(String[] strs : request.getParameterMap().values()){
- for(int i = 0; i < strs.length; i++){
- for(String qStr : queryValues){
- if(qStr.equals(strs[i])){
- strs[i] = new String(qStr.getBytes("ISO-8859-1"), "UTF-8");
- break;
- }
- }
- }
- }
- chain.doFilter(request, response);
- }
另一種方案是,把parameter中的成員都放到Attribute中,然後把QueryString中的成員也放到Attribute中,覆蓋了parameter中的GET方式提交的成員。缺點是,資料得用getAttribute來讀了…