SpringMVC 實現文件下載

SpringMVC 實現文件下載文件

利用程序實現下載需要設置兩個報頭:

  • 1.Web服務器需要告訴瀏覽器其所輸出內容的類型不是普通文本文件或HTML文件,而是一個要保存到本地的下載文件。設置Content-Type 的值爲:application/x-msdownload。
  • 2.Web服務器希望瀏覽器不直接處理相應的實體內容,而是由用戶選擇將相應的實體內容保存到一個文件中,這需要設置Content-Disposition報頭。該報頭指定了接收程序處理數據內容的方式,在HTTP應用中只有attachment是標準方式,attachment表示要求用戶干預。在attachment後面還可以指定filename參數,該參數是服務器建議瀏覽器將實體內容保存到文件中的文件名稱。

瀏覽文件

提供一個頁面瀏覽文件目錄,如果不清楚應該在哪存放文件,可以先輸出realpath,再進入目錄新建文件夾以及存放部分文件。

	@RequestMapping("file/show")
	public String show(HttpServletRequest request, Model model) {
		System.out.println("請求文件查看");
		String realpath = request.getServletContext().getRealPath("") + "fileUpload\\temp\\";
		File dir = new File(realpath);
		File files[] = dir.listFiles();
		// 獲取該目錄下的所有文件名
		ArrayList<String> fileName = new ArrayList<String>();
		for (int i = 0; i < files.length; i++) {

			fileName.add(files[i].getName());
		}
		
		model.addAttribute("files", fileName);
		return "showDownFiles";
	}

瀏覽文件jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
	pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<%
	String path = request.getContextPath();
	String basePath = request.getScheme() + "://" + request.getServerName() + ":" + request.getServerPort()
			+ path + "/";
%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">

<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>
	<c:forEach var="filename" items="${files}">
		<a href="${pageContext.request.contextPath }/file/down2?filename=${filename}">${filename}</a>
		<br />
	</c:forEach>
	<br/>

</body>
</html>

結果如下:
在這裏插入圖片描述

使用ResponseEntity

ResponseEntity是一個響應實體,其中包含了返回的頭部信息,狀態信息以及內容。如下:
在這裏插入圖片描述
在這裏插入圖片描述
因此可以將文件解析成二進制流存儲進ResponseEntity的body中,同時設置其響應頭與狀態便可以進行下載。

@RequestMapping("/file/down2")
	public ResponseEntity<byte[]> download(@RequestParam String filename, HttpServletRequest request)
			throws IOException {
		//通過存放文件目錄和文件名獲取文件全路徑
		String filePath = request.getServletContext().getRealPath("") + "fileUpload\\temp\\" + filename;
		File file = new File(filePath);
		//定義響應頭並設置下載文件報頭
		HttpHeaders headers = new HttpHeaders();
		headers.add("Content-Type", "application/x-msdownload");
		headers.add("Content-Disposition", "attachment; filename=" + URLEncoder.encode(filename, "UTF-8"));
		//返回一個響應實體(body,header,status)
		return new ResponseEntity<byte[]>(FileUtils.readFileToByteArray(file), headers, HttpStatus.OK);
	}

這裏需要注意的是,使用header的setContentType裏面,使用的是MediaType類的常量,其中好像並沒有找到"application/x-msdownload"類型,經過網絡查詢發現使用的是:MediaType.APPLICATION_OCTET_STREAM,不過我測試的時候並沒有效果(後來發現是status的問題,使用HttpStatus.OK就可以了),因此採用了add手動添加。
還有一點就是,使用ResponseEntity,需要一次性將讀取出來,如果文件過大可以就會發生OOM異常。如果只有小文件的傳輸,可以使用ResponseEntity;一旦文件過大,建議採用下面的方式。不過ResponseEntity的好處就在於簡潔,只需要獲取文件,設置頭,然後封裝到ResponseEntity返回。

使用Java常規方法

Java常規方式,有點類似json響應,服務器接收用戶下載文件請求時,獲取響應的輸出流,加載服務器的文件作爲輸入流,然後一邊從本地輸入,一邊向客戶端傳輸。這種方式就有效的解決了文件過大會產生OOM異常的問題。同時,如果客戶端的連接異常關閉則會拋出異常,可以進行有效的進行捕獲進行處理。也可以擴展下載量統計,斷點下載(RandomAccessFile)等功能。

@RequestMapping("file/down2")
	public String down(@RequestParam String filename, HttpServletRequest request, HttpServletResponse response) {
		System.out.println("請求文件下載");
		FileInputStream in = null; // 輸入流
		ServletOutputStream out = null; // 輸出流
		try {
			// 獲得文件路徑
			String aFilePath = request.getServletContext().getRealPath("") + "fileUpload\\temp\\";
			// 設置下載文件使用的報頭
			response.setHeader("Content-Type", "application/x-msdownload");
			response.setHeader("Content-Disposition", "attachment; filename=" + URLEncoder.encode(filename, "utf-8"));
			// 讀入文件
			in = new FileInputStream(aFilePath + "\\" + filename);
			// 得到響應對象的輸出流,用於向客戶端輸出二進制數據
			out = response.getOutputStream();
			out.flush();
			int len = 0;
			byte b[] = new byte[1024];
			while ((len = in.read(b)) != -1 & in != null) {
				out.write(b, 0, len);
			}
			out.flush();

		} catch (Exception e) {
			e.printStackTrace();
			try {
				in.close();
			} catch (IOException e1) {
			}
			try {
				out.close();
			} catch (IOException e1) {
			}
		}
		return null;
	}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章