關於TomCat上傳文件中文名亂碼的問題


        最近在學習TomCat文件上傳這一部分,由於文件上傳必須要三個條件:  

  1.表單提交方式必須為Post

  2.表單中需要有<input type=”file”>元素,還需要有name屬性和值(name的值)。

  3.表單enctype=”multipart/form-data”

  而且,這種方式提交后對瀏覽器進行抓包分析如下:

 1 POST /web06/jsp/upload.jsp HTTP/1.1
 2 Accept: text/html, application/xhtml+xml, */*
 3 X-HttpWatch-RID: 22006-10026
 4 Referer: http://localhost:8080/web06/jsp/upload.jsp
 5 Accept-Language: zh-CN
 6 User-Agent: Mozilla/5.0 (Windows NT 6.3; WOW64; Trident/7.0; rv:11.0) like Gecko
 7 Content-Type: multipart/form-data; boundary=-------------------------7e139d10110a64(分割線,將請求體的內容分成幾塊,后面帶兩個橫杠表示內容結束)
 8 Accept-Encoding: gzip, deflate
 9 Host: localhost:8080
10 Content-Length: 322
11 DNT: 1
12 Connection: Keep-Alive
13 Cache-Control: no-cache
14 Cookie: JSESSIONID=D51DCB996556C94861B2C72C4D978010
15 
16 -----------------------------7e139d10110a64
17 Content-Disposition: form-data; name="info"
18 
19 aaa
20 -----------------------------7e139d10110a64
21 Content-Disposition: form-data; name="upload"; filename="C:\Users\jt\Desktop\aa.txt"
22 Content-Type: text/plain
23 
24 hello world!!!
25 -----------------------------7e139d10110a64—-(有兩個橫杠表示結束)

  要想獲得普通項的參數,不能像以前那樣通過request.getParameter()來得到了.因此,借住第三方工具包,本文采用的是Apache公司的FileUpload工具包.代碼如下:

 1 public class UploadServlet extends HttpServlet {
 2     protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
 3         try {
 4             DiskFileItemFactory diskFileItemFactory = new DiskFileItemFactory();
 5             ServletFileUpload servletFileUpload = new ServletFileUpload(diskFileItemFactory);
 6 request.setCharacterEncoding("utf-8");  7             List<FileItem> fileitems = servletFileUpload.parseRequest(request);
 8 //System.setProperty("sun.jnu.encoding","utf-8");//設置系統對文件名編碼的字符集  9             for (FileItem itme : fileitems) {
10                 if (itme.isFormField()) {//是普通項
11                     String name = itme.getFieldName();
12                     String value = itme.getString("utf-8");
13  //String value = itme.getString(); 14 //value = new String(value.getBytes("iso-8859-1"),"utf-8"); 15                     System.out.println(name+"---"+value);
16                 } else {//文件上傳項
17                     String realPath = this.getServletContext().getRealPath("/upload");
18                     File file = new File(realPath);
19                     if (!file.exists()) {
20                         file.mkdirs();//不存在就創建文件夾
21                     }
22                     //獲得文件輸入流
23                     InputStream is = itme.getInputStream();
24                     //獲得輸出流
25                     String filename =itme.getName();
26                     System.out.println(filename);
27 //System.out.println(System.getProperty("file.encoding")); 28 //System.out.println(System.getProperty("sun.jnu.encoding")); 29                     int index = filename.lastIndexOf("\\");//兼容IE瀏覽器,如果是IE瀏覽器,則獲得filename為全路徑
30                     if (index != -1) {
31                         filename = filename.substring(index + 1);
32                     }
33                     System.out.println(filename);
34                     String newFilename = Utils.getName(filename);//工具類,防止文件名重名,調用UUID
35                     String path = Utils.getFilename(newFilename);//工具類,將文件進行分類存放
36                     File newFile = new File(realPath +"/"+ path);
37                     if (!newFile.exists()) {
38                          newFile.mkdirs();
39                     }
40                     FileOutputStream os = new FileOutputStream(realPath +"/"+ path+ newFilename);
41                     IOUtils.copy(is,os);
42                     is.close();
43                     os.close();
44                 }
45             }
46         } catch (FileUploadException e) {
47             e.printStackTrace();
48         }
49     }            

  上面代碼中標紅部分是比較關鍵的地方.下面對普通項和文件項亂碼問題分別進行解釋:

1.普通項

  獲得普通項的值得代碼為:

String value = itme.getString("utf-8");

  和這個方法有個重載的如下:

String value = itme.getString();

  很顯然大家也知道結果,上面那個采用字符集"utf-8"進行編碼,如果value含有中文,那么結果不會亂碼,而采用下面一種則會亂碼.我當時就在想,我在程序開始已經設置了請求緩沖流的字符集如下:

 request.setCharacterEncoding("utf-8");

  為什么我調用下面getString()還會出現亂碼呢?去查看源碼才發現自己對這幾個方法根本沒有理解,只是套模板用而已.下面先看一下setCharacterEncoding()方法的作用,API中的解釋如下:

public void setCharacterEncoding(String env) throws java.io.UnsupportedEncodingException
重寫此請求正文中使用的字符編碼的名稱。必須在使用 getReader() 讀取請求參數或讀取輸入之前調用此方法。否則,此方法沒有任何效果。 

 

   當你提交不含文件的表單,調用getParameter方法從請求緩沖流獲得數據時,設置該方法可以解決亂碼問題,(只限Post請求和Tomcat8.0的get請求).查看getParameter源碼如下:

 6 private void mergeParameters(){
 7 if ((queryParamString == null) || (queryParamString.length() < 1))
 8 return;
 9 HashMap queryParameters = new HashMap();
10 String encoding = getCharacterEncoding();
11 if (encoding == null) 12 encoding = "ISO-8859-1";
13 try{
14 RequestUtil.parseParameters(queryParameters, queryParamString, encoding);
15 }catch (Exception e){
16 ;
17 }
18 Iterator keys = parameters.keySet().iterator();
19 while (keys.hasNext()){
20   String key = (String) keys.next();
21   Object value = queryParameters.get(key);
22   if (value == null){
23     queryParameters.put(key, parameters.get(key));
24     continue;
25     }
26     queryParameters.put(key, mergeValues(value, parameters.get(key)));
27   }
28   parameters = queryParameters;
29 }
 主要在10 11 12三行代碼,10行調用了getCharacterEncoding()方法獲得字符集,如果沒設置的話就默認設置字符集為iso-8859-1.
    而在提交含有文件(即設置了enctype屬性)的請求中就不一樣了,下面看一下getString()方法的源碼:
1  public String getString() {
 2 byte[] rawdata = get();//通過緩沖流獲得字節數組  3  String charset = getCharSet();//獲得字符集,並沒有看到setCharSet方法,因此,調用該方法,只能得到charset=null 4  if (charset == null) {//如果字符集是空  5 charset = DEFAULT_CHARSET;//這是個自定義常量為ISO-8859-1  6  } 7  try {  8  return new String(rawdata, charset);//通過iso-8859-1進行編碼得到了結果,肯定會亂碼 9  } catch (UnsupportedEncodingException e) { 10  return new String(rawdata); 11  } 12 }  

   public String getString(final String charset) throws UnsupportedEncodingException { return new String(get(), charset); }     

    這是重載的getString(String )方法,可以看到get()獲得字符數組之后,直接調用new String方法得到參數.

    那么如果用 String value = itme.getString();則可以先用iso-8859-1解碼,然后再用utf-8編碼,也能獲得正確的結果.

String value = new String((value.getbytes("iso-8859-1"),"utf-8");
2.文件項上傳(文件名亂碼和文件內容亂碼)
請參考: https://blog.csdn.net/QQ578473688/article/details/77265815?locationNum=7&fps=1


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM