zoukankan      html  css  js  c++  java
  • 构建multipart/form-data实现文件上传

    构建multipart/form-data实现文件上传

    通常文件上传都是通过form表单中的file控件,并将form中的content-type设置为multipart/form-data。现在我们通过java来构建这部分请求内容实现文件上传功能。

    一、关于multipart/form-data

    文件上传本质上是一个POST请求。只不过请求头以及请求内容遵循一定的规则(协议)

    • 请求头(Request Headers)中需要设置 Content-Type 为 multipart/form-data; boundary=${boundary}。其中${boundary}分割线,需要在代码中替换,且尽量复杂,不易重复

    • 请求正文(Request Body)需要使用在 Header中设置的 ${boundary}来分割当前正文中的FormItem,内容格式如下

      --${boundary}
      Content-Disposition: form-data; name="id"
       
      testCodeUpload
      --${boundary}
      Content-Disposition: form-data; name="file";filename="xx.txt"
      Content-Type: application/octet-stream
       
      {{这里写入文件流}}
      --${boundary}--

      正文开始以前缀+${boundary}开始,以 前缀 +${boundary}+前缀结束。中间每个FormItem  前缀+${boundary}开始,以一个空白的换行结束。

    二、代码实现

    实例代码采用HttpURLConnection实现一个简单POST请求

    • 建立http请求,设置基本参数

    URL postUrl = new URL(url);
    HttpURLConnection conn = (HttpURLConnection) postUrl.openConnection();
    conn.setRequestMethod("POST");
    conn.setDoInput(true);
    conn.setDoOutput(true);
    conn.setUseCaches(false);
    conn.setRequestProperty("connection", "Keep-Alive");
    conn.setRequestProperty("Charset", "UTF-8");
    • 添加文件上传必须的请求信息,获取http请输出流

    String boundary = "----" + UUID.randomUUID().toString();
    conn.setRequestProperty("Content-Type",
    "multipart/form-data; boundary=" + boundary);
    OutputStream out = conn.getOutputStream();
    StringBuilder sb = new StringBuilder();
    • 一组FormItem

    sb.append(boundaryPrefix);
    sb.append(boundary);
    sb.append(newLine);
    sb.append("Content-Disposition: form-data; name="id"");
    sb.append(newLine);
    sb.append(newLine);
    sb.append("testCodeUpload");
    sb.append(newLine);
    • 文件写人

    sb.append(boundaryPrefix);
    sb.append(boundary);
    sb.append(newLine);
    sb.append("Content-Disposition: form-data; name="file"; filename=""
    + fileName + """);
    sb.append("Content-Type: application/octet-stream");
    sb.append(newLine);
    sb.append(newLine);
    out.write(sb.toString().getBytes());
    File file = new File(file1);
    FileInputStream in = new FileInputStream(file);
    byte[] bufferOut = new byte[1024];
    int bytes = 0;
    while ((bytes = in.read(bufferOut)) != -1) {
    out.write(bufferOut, 0, bytes);
    }
    out.write(newLine.getBytes());
    in.close();
    • 结束标志 前缀+boundary +前缀
    byte[] end_data = (newLine + boundaryPrefix + boundary + boundaryPrefix + newLine)
    .getBytes();
    out.write(end_data);
    out.flush();
    out.close();

    三、文件接收

    • 文件接收端通过迭代每个FileItem获取不同的数据

    FileItemFactory factory = new DiskFileItemFactory();
    ServletFileUpload upload = new ServletFileUpload(factory);
    upload.setHeaderEncoding("UTF-8");
    try {
      items = upload.parseRequest(request);
    } catch (FileUploadException ex) {
      ex.printStackTrace();
      out.println(ex.getMessage());
      return;
    }
    Iterator<FileItem> itr = items.iterator();
    String id = "", fileName = "";
    int chunks = 1, chunk = 0;
    FileItem tempFileItem = null;
    while (itr.hasNext()) {
    FileItem item = (FileItem) itr.next();
    if (item.getFieldName().equals("id")) {
      id = item.getString();
    } else if (item.getFieldName().equals("name")) {
      fileName = new String(item.getString().getBytes("ISO-8859-1"), "UTF-8");
    } else if (item.getFieldName().equals("file")) {
      tempFileItem = item;
    }

    四、总结

    通过代码实现一遍文件上传,了解其运行机制,解开了以前在写文件上传代码中item.getFieldName().equals("name")等相关判断的疑惑。所以,对于已有的基础代码,还是多看,多写,多实践。

    附完整代码

     1 @Test
     2     public void buildUploadStream() throws IOException {
     3         String url ="uploadurl";
     4         file1 = "D:\test.xls";
     5         fileName = "test.xls";
     6         
     7         String newLine = "
    ";
     8         String boundaryPrefix = "--";
     9         String boundary = "----" + UUID.randomUUID().toString();
    10 
    11         URL postUrl = new URL(url);
    12         HttpURLConnection conn = (HttpURLConnection) postUrl.openConnection();
    13 
    14         conn.setRequestMethod("POST");
    15         conn.setDoInput(true);
    16         conn.setDoOutput(true);
    17         conn.setUseCaches(false);
    18 
    19         conn.setRequestProperty("connection", "Keep-Alive");
    20         conn.setRequestProperty("Charset", "UTF-8");
    21         conn.setRequestProperty("Content-Type",
    22                 "multipart/form-data; boundary=" + boundary);
    23 
    24         OutputStream out = conn.getOutputStream();
    25 
    26         
    27         StringBuilder sb = new StringBuilder();
    28 
    29         sb.append(boundaryPrefix);
    30         sb.append(boundary);
    31         sb.append(newLine);
    32 
    33         sb.append("Content-Disposition: form-data; name="id"");
    34         sb.append(newLine);
    35         sb.append(newLine);
    36         sb.append("testCodeUpload");
    37         sb.append(newLine);
    38 
    39         sb.append(boundaryPrefix);
    40         sb.append(boundary);
    41         sb.append(newLine);
    42 
    43         sb.append("Content-Disposition: form-data; name="name"");
    44         sb.append(newLine);
    45         sb.append(newLine);
    46         sb.append(fileName);
    47         sb.append(newLine);
    48 
    49         sb.append(boundaryPrefix);
    50         sb.append(boundary);
    51         sb.append(newLine);
    52 
    53         sb.append("Content-Disposition: form-data; name="file"; filename=""
    54                 + fileName + """);
    55         sb.append("Content-Type: application/octet-stream");
    56         sb.append(newLine);
    57         sb.append(newLine);
    58 
    59         out.write(sb.toString().getBytes());
    60         
    61         File file = new File(file1);
    62         FileInputStream in = new FileInputStream(file);
    63         byte[] bufferOut = new byte[1024];
    64         int bytes = 0;
    65         while ((bytes = in.read(bufferOut)) != -1) {
    66             out.write(bufferOut, 0, bytes);
    67         }
    68         out.write(newLine.getBytes());
    69         in.close();
    70         byte[] end_data = (newLine + boundaryPrefix + boundary + boundaryPrefix + newLine)
    71                 .getBytes();
    72         out.write(end_data);
    73         out.flush();
    74         out.close();
    75 
    76         BufferedReader reader = new BufferedReader(new InputStreamReader(
    77                 conn.getInputStream()));
    78         String line = null;
    79         while ((line = reader.readLine()) != null) {
    80             System.out.println(line);
    81         }
    82     }
    all code
  • 相关阅读:
    vipw和vigr命令
    linux sudo命令
    linux中切换用户方式su和su -的区别
    ls Common Command-Line Options
    字符串同构问题 字符串操作:数组计数字符个数问题
    聚类算法
    Python实践之(七)逻辑回归(Logistic Regression)
    Gradient Boost Decision Tree(&Treelink)
    天池大数据周冠军分享|附移动推荐算法赛答辩会Top5选手PPT
    【天池大数据赛题解析】资金流入流出预测(附Top4答辩ppt)
  • 原文地址:https://www.cnblogs.com/yfrs/p/uploadbyjavacode.html
Copyright © 2011-2022 走看看