构建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 = "\r\n"; 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
共同学习,写下你的评论
评论加载中...
作者其他优质文章


