關於Http文件上傳分析與實現

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



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章