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;
	}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值