zoukankan      html  css  js  c++  java
  • 关于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:UsersjtDesktopaa.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
  • 相关阅读:
    P1092 虫食算
    P1040 加分二叉树
    cfER76 abcd
    cf599 div2 a/b1/b2/c
    AtCoder Contest 144 DE
    Round G 2019
    luogu3084 Photo 单调队列优化DP
    luogu4234 最小差值生成树
    luogu1373 小a和uim之大逃离
    luogu1070 道路游戏 单调队列
  • 原文地址:https://www.cnblogs.com/doveshelly/p/8722201.html
Copyright © 2011-2022 走看看