程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> 網頁編程 >> JSP編程 >> 關於JSP >> JSP中文件的上傳於下載示例

JSP中文件的上傳於下載示例

編輯:關於JSP

JSP中文件的上傳於下載示例


一、文件上傳的原理
1、文件上傳的前提:
a、form表單的method必須是post
b、form表單的enctype必須是multipart/form-data(決定了POST請求方式,請求正文的數據類型)
注意:當表單的enctype是multipart/form-data,傳統的獲取請求參數的方法失效。

請求正文:(MIME協議進行描述的,正文是多部分組成的)
-----------------------------7dd32c39803b2
Content-Disposition: form-data; name="username"

wzhting
-----------------------------7dd32c39803b2
Content-Disposition: form-data; name="f1"; filename="C:\Documents and Settings\wzhting\妗岄潰\a.txt"
Content-Type: text/plain

aaaaaaaaaaaaaaaaaa
-----------------------------7dd32c39803b2
Content-Disposition: form-data; name="f2"; filename="C:\Documents and Settings\wzhting\妗岄潰\b.txt"
Content-Type: text/plain

bbbbbbbbbbbbbbbbbbb
-----------------------------7dd32c39803b2--


c、form中提供input的type是file類型的文件上傳域

二、利用第三方組件實現文件上傳
1、commons-fileupload組件:
jar:commons-fileupload.jar commons-io.jar
2、核心類或接口
DiskFileItemFactory:設置環境
public void setSizeThreshold(int?sizeThreshold) :設置緩沖區大小。默認是10Kb。
當上傳的文件超出了緩沖區大小,fileupload組件將使用臨時文件緩存上傳文件
public void setRepository(java.io.File repository):設置臨時文件的存放目錄。默認是系統的臨時文件存放目錄。

ServletFileUpload:核心上傳類(主要作用:解析請求的正文內容)
boolean isMultipartContent(HttpServletRequest?request):判斷用戶的表單的enctype是否是multipart/form-data類型的。
List parseRequest(HttpServletRequest request):解析請求正文中的內容
setFileSizeMax(4*1024*1024);//設置單個上傳文件的大小
upload.setSizeMax(6*1024*1024);//設置總文件大小
FileItem:代表表單中的一個輸入域。
boolean isFormField():是否是普通字段
String getFieldName:獲取普通字段的字段名
String getString():獲取普通字段的值

InputStream getInputStream():獲取上傳字段的輸入流
String getName():獲取上傳的文件名

三、文件上傳中要注意的9個問題
1、如何保證服務器的安全
把保存上傳文件的目錄放到WEB-INF目錄中。
2、中文亂碼問題
2.1普通字段的中文請求參數
String value = FileItem.getString("UTF-8");
2.2上傳的文件名是中文
解決辦法:request.setCharacterEncoding("UTF-8");
3、重名文件被覆蓋的問題
System.currentMillions()+"_"+a.txt(樂觀)

UUID+"_"+a.txt:保證文件名唯一
4、分目錄存儲上傳的文件
方式一:當前日期建立一個文件夾,當前上傳的文件都放到此文件夾中。
方式二:利用文件名的hash碼打散目錄來存儲。
int hashCode = fileName.hashCode();

1001 1010 1101 0010 1101 1100 1101 1010
hashCode&0xf; 0000 0000 0000 0000 0000 0000 0000 1111 &
---------------------------------------------
0000 0000 0000 0000 0000 0000 0000 1010 取hashCode的後4位
0000~1111:整數0~15共16個

1001 1010 1101 0010 1101 1100 1101 1010
(hashCode&0xf0) 0000 0000 0000 0000 0000 0000 1111 0000 &
--------------------------------------------
0000 0000 0000 0000 0000 0000 1101 0000 >>4
--------------------------------------------
0000 0000 0000 0000 0000 0000 0000 1101
0000~1111:整數0~15共16個
5、限制用戶上傳的文件類型
通過判斷文件的擴展名來限制是不可取的。
通過判斷其Mime類型才靠譜。FileItem.getContentType();
6、如何限制用戶上傳文件的大小
6.1單個文件大小限制。超出了大小友好提示
抓異常進行提示:org.apache.commons.fileupload.FileUploadBase.FileSizeLimitExceededException
6.2總文件大小限制。超出了大小友好提示
抓異常進行提示:org.apache.commons.fileupload.FileUploadBase.SizeLimitExceededException
7、臨時文件的問題
commons-fileupload組件不會刪除超出緩存的臨時文件。

FileItem.delete()方法刪除臨時文件。但一定要在關閉流之後。
8、多個文件上傳時,沒有上傳內容的問題
if(fileName==null||"".equals(fileName.trim())){
continue;
}
9、上傳進度檢測
給ServletFileUpload注冊一個進度監聽器即可,把上傳進度傳遞給頁面去顯示
//pBytesRead:當前以讀取到的字節數
//pContentLength:文件的長度
//pItems:第幾項
public void update(long pBytesRead, long pContentLength,
int pItems) {
System.out.println("已讀取:"+pBytesRead+",文件大小:"+pContentLength+",第幾項:"+pItems);

}

四:文件上傳示例:

JSP代碼:

servlet後台代碼:

public class UploadServlet extends HttpServlet {

	public void doGet(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		request.setCharacterEncoding("UTF-8");
		response.setContentType("text/html;charset=UTF-8");
		PrintWriter pout = response.getWriter();
		try {
			// 得到存放上傳文件的真實路徑
			String storePath = getServletContext()
					.getRealPath("/WEB-INF/files");

			// 設置環境
			DiskFileItemFactory factory = new DiskFileItemFactory();
			factory.setRepository(new File(getServletContext().getRealPath("/temp")));//設置臨時存放目錄
			// 判斷一下form是否是enctype=multipart/form-data類型的
			boolean isMultipart = ServletFileUpload.isMultipartContent(request);
			if (!isMultipart) {
				System.out.println("大傻鳥");
				return;
			}
			// ServletFileUpload核心類
			ServletFileUpload upload = new ServletFileUpload(factory);
//			upload.setProgressListener(new ProgressListener() {
//				//pBytesRead:當前以讀取到的字節數
//				//pContentLength:文件的長度
//				//pItems:第幾項
//				public void update(long pBytesRead, long pContentLength,
//						int pItems) {
//					System.out.println("已讀取:"+pBytesRead+",文件大小:"+pContentLength+",第幾項:"+pItems);
//				}
//				
//			});
			upload.setFileSizeMax(4 * 1024 * 1024);// 設置單個上傳文件的大小
			upload.setSizeMax(6 * 1024 * 1024);// 設置總文件大小
			// 解析
			List items = upload.parseRequest(request);
			for (FileItem item : items) {
				if (item.isFormField()) {
					// 普通字段
					String fieldName = item.getFieldName();
					String fieldValue = item.getString("UTF-8");
					System.out.println(fieldName + "=" + fieldValue);
				} else {
					// 得到MIME類型
					String mimeType = item.getContentType();
					// 只允許上傳圖片
					 if(mimeType.startsWith("image")){
						// 上傳字段
						InputStream in = item.getInputStream();
						// 上傳的文件名
						String fileName = item.getName();// C:\Documents and
						if(fileName==null||"".equals(fileName.trim())){
							continue;
						}
						// Settings\wzhting\妗岄潰\a.txt
						// a.txt
						fileName = fileName
								.substring(fileName.lastIndexOf("\\") + 1);// a.txt
						fileName = UUID.randomUUID() + "_" + fileName;
						System.out.println(request.getRemoteAddr()+"=============="+fileName);
						// 構建輸出流
						// 打散存儲目錄
						String newStorePath = makeStorePath(storePath, fileName);// 根據
						// /WEB-INF/files和文件名,創建一個新的存儲路徑
						// /WEB-INF/files/1/12
						String storeFile = newStorePath + "\\" + fileName;// WEB-INF/files/1/2/sldfdslf.txt
	
						OutputStream out = new FileOutputStream(storeFile);
	
						byte b[] = new byte[1024];
						int len = -1;
						while ((len = in.read(b)) != -1) {
							out.write(b, 0, len);
						}
						out.close();
						in.close();
						item.delete();//刪除臨時文件
					}
				 }
			}
		} catch (org.apache.commons.fileupload.FileUploadBase.FileSizeLimitExceededException e) {
			// 單個文件超出大小時的異常
			pout.write("單個文件大小不能超出4M");
		} catch (org.apache.commons.fileupload.FileUploadBase.SizeLimitExceededException e) {
			// 總文件超出大小時的異常
			pout.write("總文件大小不能超出6M");
		} catch (Exception e) {
			e.printStackTrace();
		}

	}

	// 根據 /WEB-INF/files和文件名,創建一個新的存儲路徑 /WEB-INF/files/1/12
	private String makeStorePath(String storePath, String fileName) {
		int hashCode = fileName.hashCode();
		int dir1 = hashCode & 0xf;// 0000~1111:整數0~15共16個
		int dir2 = (hashCode & 0xf0) >> 4;// 0000~1111:整數0~15共16個

		String path = storePath + "\\" + dir1 + "\\" + dir2; // WEB-INF/files/1/12
		File file = new File(path);
		if (!file.exists())
			file.mkdirs();

		return path;
	}

	public void doPost(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {

		doGet(request, response);
	}

}


---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

五:文件下載

1.顯示上述存儲所有的照片信息:

//顯示所有上傳的文件,封裝到域對象中,交給jsp去顯示
public class ShowAllFilesServlet extends HttpServlet {

	public void doGet(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		Map map = new HashMap();//key:UUID文件名;value:老文件名
		//得到存儲文件的根目錄
		String storePath = getServletContext().getRealPath("/WEB-INF/files");
		//遞歸遍歷其中文件
		File file = new File(storePath);
		treeWalk(file,map);
		//交給JSP去顯示:如何封裝數據.用Map封裝。key:UUID文件名;value:老文件名
		request.setAttribute("map", map);
		request.getRequestDispatcher("/listFiles.jsp").forward(request, response);
	}
	//遍歷/WEB-INF/files所有文件,把文件名放到map中
	private void treeWalk(File file, Map map) {
		if(file.isFile()){
			//是文件
			String uuidName = file.getName();//  UUID_a_a.txt//真實文件名
			String oldName = uuidName.substring(uuidName.indexOf("_")+1);
			map.put(uuidName, oldName);
		}else{
			//是一個目錄
			File[] fs = file.listFiles();
			for(File f:fs){
				treeWalk(f,map);
			}
		}
	}

	public void doPost(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {

		doGet(request, response);
	}

}
2.顯示所有文件listFiles.jsp頁面中的內容:

    

本站有以下好圖片

${me.value}  下載
3.文件下載DownloadServlet:

public class DownloadServlet extends HttpServlet {

	public void doGet(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		response.setContentType("text/html;charset=UTF-8");
		OutputStream out = response.getOutputStream();
		
		String filename = request.getParameter("filename");//get請求方式
		filename = new String(filename.getBytes("ISO-8859-1"),"UTF-8");//中文編碼
		
		//截取老文件名
		String oldFileName = filename.split("_")[1];
		//得到存儲路徑
		String storePath = getServletContext().getRealPath("/WEB-INF/files");
		//得到文件的全部路徑
		String filePath = makeStorePath(storePath, filename)+"\\"+filename;
		
		//判斷文件是否存在
		File file = new File(filePath);
		if(!file.exists()){
			out.write("對比起!你要下載的文件可能已經不存在了".getBytes("UTF-8"));
			return;
		}
		
		InputStream in = new FileInputStream(file);
		//通知客戶端以下載的方式打開
		response.setHeader("Content-Disposition", "attachment;filename="+URLEncoder.encode(oldFileName, "UTF-8"));
		
		byte[] b = new byte[1024];
		int len = -1;
		while((len=in.read(b))!=-1){
			out.write(b, 0, len);
		}
		in.close();
		out.write("下載成功".getBytes("UTF-8"));
	}

	public void doPost(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {

		doGet(request, response);
	}
	private String makeStorePath(String storePath, String fileName) {
		int hashCode = fileName.hashCode();
		int dir1 = hashCode & 0xf;// 0000~1111:整數0~15共16個
		int dir2 = (hashCode & 0xf0) >> 4;// 0000~1111:整數0~15共16個

		String path = storePath + "\\" + dir1 + "\\" + dir2; // WEB-INF/files/1/12
		File file = new File(path);
		if (!file.exists())
			file.mkdirs();

		return path;
	}
}


  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved