1.需求分析
由於最近看到有人論壇上發帖稱自己用了網上的某個框架,因爲是在裸機上面開發的,並沒有檢測到病毒,等用其他機器演示的時候整個項目出現了病毒,並且客戶直接否認了這個項目,突然讓我想到了學長說的一句話:工具類我一般自己寫,誰知道他們寫成什麼樣子給你用呢。又鑑於文件上傳功能比較常見,而且大部分人都還在使用像SmartUpload等組件.而我實在是不想使用這類工具了,所以打算自己動手寫一個文件上傳的實現
2.實現思路
首先,通過分析表單提交的內容到底包含一些什麼內容,然後逐步解析,從而得到自己想要的文件信息,最後通過流的形式寫入服務器硬盤中.
3.功能實現
首先,使用IDE自動生成一個web工程,在web工程中創建servlet命名爲:UploadServlet,並且在web.xml中映射成/UploadServlet;並且在index.jsp頁面中加入Form表單如下:
<form action="UploadServlet" method="post"
enctype="multipart/form-data">
用戶名:
<input type="text" name="username">
<br>
密碼:
<input type="text" name="password">
<br>
上傳文件
<input type="file" name="file">
<br>
<input type="submit" value="Submit">
</form>
而UploadServlet中的post方法中加入下列代碼:
response.setContentType("text/html");
response.setCharacterEncoding("UTF-8");
request.setCharacterEncoding("UTF-8");
PrintWriter out = response.getWriter();
BufferedReader bufferReader = new BufferedReader(new InputStreamReader(
request.getInputStream()));
String line = "";
while ((line = bufferReader.readLine()) != null) {
System.out.println(line);
}
然後通過打印出request流中的信息如下:
------WebKitFormBoundarysmYDzdkAUIGlvggB
Content-Disposition: form-data; name="username"
[email protected]
------WebKitFormBoundarysmYDzdkAUIGlvggB
Content-Disposition: form-data; name="password"
terrylmay
------WebKitFormBoundarysmYDzdkAUIGlvggB
Content-Disposition: form-data; name="file"; filename="SoftwareCache.java"
Content-Type: application/octet-stream
package com.redmoon.forum.plugin.errorquery;
public class SoftwareCache extends ObjectCache {
public String putSoftwareInfo(String type, int id) throws CacheException {
SoftwareDao softwareDao = new SoftwareDao();
result = softwareDao.getDescriptionByID(id, type);
rmCache.putInGroup(group + id + "_" + type, group, result);
System.out.println("返回的是從數據庫中取出的數據");
return result;
}
}
------WebKitFormBoundarysmYDzdkAUIGlvggB--
可以看到如果Form表單中使用了enctype="multipart/form-data"定義的表單當提交表單時表單字段信息以及文件信息放入到request的流中進行提交。所以如果想要獲取到上傳文件的內容只能通過解析流的方式拿到。而通過request.getHeader這種方法拿到的只能是圖中的Header裏面的信息
並且是拿不到Request Payload中的某個字段的信息的.後面就是最蛋疼的事了.恐怕解析起來要花好長時間,當然強力解析肯定是不行的.畢竟要找出規律纔有重用性
通過一天的學習,研究終於寫出了一個文本文件,圖片文件以及其他文件都能夠上傳的通用類,並且能夠支持多文件上傳.只要界面中能夠進行多選的話,不說廢話了.核心代碼如下
while (i != -1) {
// 拿到該行數據
String line = new String(buff, 0, i);
if (line.startsWith("Content-Disposition:")) {
// 如果不是文件域,那麼肯定是表單字段域了
if (!line.contains("filename")) {
int index = line.indexOf("name=");
String name = "";
if (index != -1) {
name = line.substring(index + 6, line.length() - 3);
System.out.println(name);
}
// 找到字段域中的值
in.readLine(buff, 0, 1024);
i = in.readLine(buff, 0, 1024);
String value = new String(buff, 0, i);
// 放入到fileds中.到時候查找的時候也方便查找
fields.put(name, value);
System.out.println("(" + name + "," + value + ")");
} else if (line.contains("filename")) {
int index = line.indexOf("filename=");
// 通過內容格式找到文件名稱
setFileName(line);
System.out.println(this.fileName);
// 連續讀取2行,取出無用信息
in.readLine(buff, <span style="background-color: rgb(255, 255, 255);">http:// </span><span style="font-family: Arial, Helvetica, sans-serif;">0, 1024);</span>
in.readLine(buff, 0, 1024);
// 讀取文件的內容
i = in.readLine(buff, 0, 1024);
line = new String(buff, 0, i, "ISO8859_1");
FileOutputStream out = new FileOutputStream(new File(
saveFilePath, fileName));
while (i != -1 && !line.startsWith(this.boundary)) {
i = in.readLine(buff, 0, 1024);
if (new String(buff, 0, i).startsWith(boundary)) {
out.write(line.substring(0, line.length() - 2)
.getBytes("ISO8859_1"));
break;
} else
out.write(line.getBytes("ISO8859_1"));
line = new String(buff, 0, i, "ISO8859_1");
}
}
}
i = in.readLine(buff, 0, 1024);
}
首先根據圖中的頭文件信息格式,來判斷如果包含有filename信息的,則直接對後面的信息進行存儲,如果不包含filename信息的,直接對其進行解析,然後把解析出來的字段以及他的value放入到map中.方便讀取.具體代碼文件下載:http://download.csdn.net/detail/maylorchao/7357091