SpringMVC实现文件下载的两种方法

您所在的位置:网站首页 坤宁男主谢危和女主关系 SpringMVC实现文件下载的两种方法

SpringMVC实现文件下载的两种方法

2023-11-08 10:06| 来源: 网络整理| 查看: 265

这两天玩spring的过程中遇到了一个很常见的问题——文件下载。以往很多时候都是直接给一个文件的静态链接,这种方法有很多局限性,其中一个很明显的局限性就是不易统计下次状态,还有就是需要http服务器来保存文件,不可访问服务器本机文件系统的文件,综上所述,我们需要一种易于统计并可下载本地文件系统中文件的方法:那就是服务器读取本地文件流,然后将文件流输出到客户端。这个过程中流传输异常、完成都可以轻易获取,方便统计该次下载的状态。我对spring框架并不是太熟,基本上是面向搜索引擎的编程。这次想用spring完成一个文件下载的过程,于是查了相关资料,获得两种实现方式。

基于ResponseEntity实现 @RequestMapping("/testHttpMessageDown") public ResponseEntity download(HttpServletRequest request) throws IOException { File file = new File("E://123.jpg"); byte[] body = null; InputStream is = new FileInputStream(file); body = new byte[is.available()]; is.read(body); HttpHeaders headers = new HttpHeaders(); headers.add("Content-Disposition", "attchement;filename=" + file.getName()); HttpStatus statusCode = HttpStatus.OK; ResponseEntity entity = new ResponseEntity(body, headers, statusCode); return entity; } Java通用下载实现

下载过程的实现,在java中调用reponse.getOutputStream()方法会自动激活下载操作

public static void download(String fileName, String filePath, HttpServletRequest request, HttpServletResponse response) throws Exception { //声明本次下载状态的记录对象 DownloadRecord downloadRecord = new DownloadRecord(fileName, filePath, request); //设置响应头和客户端保存文件名 response.setCharacterEncoding("utf-8"); response.setContentType("multipart/form-data"); response.setHeader("Content-Disposition", "attachment;fileName=" + fileName); //用于记录以完成的下载的数据量,单位是byte long downloadedLength = 0l; try { //打开本地文件流 InputStream inputStream = new FileInputStream(filePath); //激活下载操作 OutputStream os = response.getOutputStream(); //循环写入输出流 byte[] b = new byte[2048]; int length; while ((length = inputStream.read(b)) > 0) { os.write(b, 0, length); downloadedLength += b.length; } // 这里主要关闭。 os.close(); inputStream.close(); } catch (Exception e){ downloadRecord.setStatus(DownloadRecord.STATUS_ERROR); throw e; } downloadRecord.setStatus(DownloadRecord.STATUS_SUCCESS); downloadRecord.setEndTime(new Timestamp(System.currentTimeMillis())); downloadRecord.setLength(downloadedLength); //存储记录 }

下载记录信息实体

public class DownloadRecord { public static final int STATUS_ERROR = 0; public static final int STATUS_SUCCESS = 1; private String uid; private String ip; private int port; private String ua; private String fileName; private String filePath; private long length; private int status; private Timestamp startTime; private Timestamp endTime; public DownloadRecord() { } public DownloadRecord(String fileName, String filePath, HttpServletRequest request) { this.uid = UUID.randomUUID().toString().replace("-",""); this.fileName = fileName; this.filePath = filePath; this.ip = request.getRemoteAddr(); this.port = request.getRemotePort(); this.ua = this.ua = request.getHeader("user-agent"); this.startTime = new Timestamp(System.currentTimeMillis()); } /** getter and setter **/ } 比较

1、 基于ResponseEntity的实现的局限性还是很大,从代码中可以看出这种下载方式是一种一次性读取的下载方式,在文件较大的时候会直接抛出内存溢出(我自己亲测一个1.8G的文件在执行下载操作的时候直接抛出了内存溢出)。还有就是这种方式在进行下载统计的时候也存在局限性,无法统计在下载失败的情况已完成下载量,因此限制了对下载的功能扩展。虽然这种实现方式有局限性,但是也有着优点——简洁。在很多时候我们并不需要那么复杂的下载功能时,这种实现就应该是首选了。 2、 然而下载java通用实现在功能上比第一种实现更加丰富,对下载的文件大小无限制(循环读取一定量的字节写入到输出流中,因此不会造成内存溢出,但是在下载人数过多的时候应该还是出现一些异常,不过下载量较大的文件一般都会使用ftp服务器来做吧),另外因为是这种实现方式是基于循环写入的方式进行下载,在每次将字节块写入到输出流中的时都会进行输出流的合法性检测,在因为用户取消或者网络原因造成socket断开的时候,系统会抛出SocketWriteException,系统可以捕捉这个过程中抛出的异常,当捕捉到异常的时候我们可以记录当前已经传输的数据量,这样就可以完成下载状态和对应状态下载量和速度之类的数据记录。另外这种方式实现方式还可以实现一种断点续载的功能。



【本文地址】


今日新闻


推荐新闻


    CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3