最近搜索

SpringMVC 文件 下载功能。

浏览:678
管理员 2020-02-12 13:59
@RequestMapping("/download")
    public ResponseEntity<byte[]> downLoad(String fileName, HttpServletRequest request) throws IOException {
        String path=request.getSession().getServletContext().getRealPath("statics/uploadfiles/"+fileName);
        File file =new File(path);
        HttpHeaders httpHeader=new HttpHeaders();
        //可以下载任意文件
        httpHeader.setContentType(MediaType.APPLICATION_OCTET_STREAM);
        httpHeader.setContentDispositionFormData("attachment",fileName);
        return new ResponseEntity(FileUtils.readFileToByteArray(file),httpHeader, HttpStatus.OK);
    }

只要前端页面传一个文件名就能实现下载



================================================================


@RequestMapping("/testHttpMessageDown")public ResponseEntity<byte[]> 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<byte[]> entity = new ResponseEntity<byte[]>(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,系统可以捕捉这个过程中抛出的异常,当捕捉到异常的时候我们可以记录当前已经传输的数据量,这样就可以完成下载状态和对应状态下载量和速度之类的数据记录。另外这种方式实现方式还可以实现一种断点续载的功能。




集成到项目的代码 spring boot项目 

/**
	 *  
	 * @param id  /article/down?id=2
	 * @param request
	 * @return
	 * @throws IOException
	 */
	@RequestMapping("/article/down")
	public ResponseEntity<byte[]> download(@RequestParam(value = "id", required = false) Integer id ,HttpServletRequest request) throws IOException {
		Article article = articleDao.findId(id);
        String webPath=request.getServletContext().getRealPath("");
		File file = new File(webPath+article.getFileUrl());
		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<byte[]> entity = new ResponseEntity<byte[]>(body, headers, statusCode);
		return entity;
	}


联系站长

站长微信:xiaomao0055

站长QQ:14496453