构建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")等相关判断的疑惑。所以,对于已有的基础代码,还是多看,多写,多实践。

附完整代码

 @Test
public void buildUploadStream() throws IOException {
String url ="uploadurl";
file1 = "D:\\test.xls";
fileName = "test.xls"; String newLine = "\r\n";
String boundaryPrefix = "--";
String boundary = "----" + UUID.randomUUID().toString(); 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");
conn.setRequestProperty("Content-Type",
"multipart/form-data; boundary=" + boundary); OutputStream out = conn.getOutputStream(); StringBuilder sb = new StringBuilder(); 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=\"name\"");
sb.append(newLine);
sb.append(newLine);
sb.append(fileName);
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();
byte[] end_data = (newLine + boundaryPrefix + boundary + boundaryPrefix + newLine)
.getBytes();
out.write(end_data);
out.flush();
out.close(); BufferedReader reader = new BufferedReader(new InputStreamReader(
conn.getInputStream()));
String line = null;
while ((line = reader.readLine()) != null) {
System.out.println(line);
}
}

all code

构建multipart/form-data实现文件上传的更多相关文章

  1. Ajax(form表单文件上传、请求头之contentType、Ajax传递json数据、Ajax文件上传)

    form表单文件上传 上菜 file_put.html <form action="" method="post" enctype="multi ...

  2. jquery.form 兼容IE89文件上传

    导入部分 <script type="text/javascript" src="js/jquery-1.8.3.min.js" charset=&quo ...

  3. 构建基于阿里云OSS文件上传服务

    转载请注明来源:http://blog.csdn.net/loongshawn/article/details/50710132 <构建基于阿里云OSS文件上传服务> <构建基于OS ...

  4. Django 基于Ajax & form 简单实现文件上传

    前端实现 <!DOCTYPE html> <html lang="zh-CN"> <head> <meta charset="U ...

  5. form表单文件上传提交且接口回调显示提交成功

    前端: <form method="post" enctype="multipart/form-data" id="formSubmit&quo ...

  6. form表单文件上传 servlet文件接收

    需要导入jar包 commons-fileupload-1.3.2.jar commons-io-2.5.jar Upload.Jsp代码 <%@ page language="jav ...

  7. Spring MVC-表单(Form)标签-文件上传(File Upload)示例(转载实践)

    以下内容翻译自:https://www.tutorialspoint.com/springmvc/springmvc_upload.htm 说明:示例基于Spring MVC 4.1.6. 以下示例显 ...

  8. 实用ExtJS教程100例-009:ExtJS Form无刷新文件上传

    文件上传在Web程序开发中必不可少,ExtJS Form中有一个filefield字段,用来选择文件并上传.今天我们来演示一下如何通过filefield实现ExtJS Form无刷新的文件上传. 首先 ...

  9. WebApi实现Ajax模拟Multipart/form-data方式多文件上传

    前端页面代码: <input type="file" class="file_control" /><br /> <input t ...

  10. SSM+form表单文件上传

    这里介绍SSM如何配置上传文件 配置springmvc.xml: <!--配置上传下载--> <bean id="multipartResolver" class ...

随机推荐

  1. Javal连接字符串为Json

    public static String concatJson(String[] keys,String[] values,String[] alreadyJsonKeys){ if(keys==nu ...

  2. mongodbwindows安装过程附带安装包百度云

    1.mongodb安装包链接 链接:https://pan.baidu.com/s/1bxZ2oV-iJEs7RoH5kN6jVg 密码:ajuj   2.配置准备,创建文件夹及文件: 目录为:  \ ...

  3. java自动化-实际使用junit的演示

    本文简单介绍一下我写的http接口后端框架 在经过之前多篇博客介绍之后,读者应掌握如下技能 1,自动运行一个或者多个junit框架编写的java代码 2,对数据驱动以及关键字驱动有一定的了解和认识,甚 ...

  4. linux仅修改文件夹权限 分别批量修改文件和文件夹权限

    比如我想把/var/www/html下的文件全部改成664,文件夹改成775,怎么做呢 方法一: 先把所有文件及文件夹改成664,然后把所有文件夹改成775 chmod -R 664 ./ find ...

  5. css实现文本超出两行隐藏

    当文字显示超出两行时,多余部分文字隐藏,用到的css属性如下代码 display: -webkit-box; text-overflow: ellipsis; overflow: hidden; -w ...

  6. zuoye

    a=input('请输入一个数字:') b=input('请再输入一个数字') sum2=int(a)+int(b) print('两个数字的和是:{}'.format(sum2)) a=input( ...

  7. Java for Android 第二周课上实验一

    (一)命令行下程序开发 (二)IDEA下程序开发调试 Mac OS系统下使用的IDEA为 Netbeans (三)测试题我的学号后两位为10 使用简单的PHP小程序得我的题目为2:实现简单四则运算(能 ...

  8. php代码进行跨域请求处理

    以下的函数作为每个请求的前置操作 (thinkphp框架) public function appInit(&$params) { header('Access-Control-Allow-O ...

  9. Flutter 页面入栈和出栈

    Docs demo import 'package:flutter/material.dart'; void main() => runApp(new MyApp()); class MyApp ...

  10. BOM与DOM操作

    BOM: OM-JavaScript是运行在浏览器中的,所以提供了一系列对象用于和浏览器窗口进行交互,这些对象主要包括window.document.location.navigator和screen ...