spring boot 用ResponseEntity实现下载文件(解决前后端分离跨域问题)

前言

项目前后端分离,web端:vue,服务器:spring cloud。
最近项目集成spring cloud了,所有接口都由网关转发,刚开始写了一个下载文件接口是直接将文件写到OutputStream的,但这样做后就会导致网关截拦器取不到用户信息(网关目前是单机部署,用户信息由security框架写到内存中的),最后用org.springframework.http.ResponseEntity实现了文件下载。

1、OutputStream方式
 @ApiOperation(notes = "文件下载", value = "文件下载")
 @RequestMapping("/download")
 public void download(HttpServletResponse response,@RequestBody String id) {
     //id 校验文件记录是否存在
     FileObj fileobj =      fileService.findByid(id);
    //获取文件服务器路径
    String fileId = fileobj.getid;
    //从文件服务器下载文件到本地服务器,并返回路径
     String downloadUrl = geturlfromServer(fileId);
     if(StringUtils.isEmpty(downloadUrl)){
        //return ;
     }
     log.info("下载文件名称:{}",fileobj.getfileName());
     String fileName = null; // 文件名称的编码
     InputStream in = null;
     OutputStream out = null;
     try {
         response.reset();
         fileName = new String(fileobj.getfileName().getBytes("Gb2312"), "ISO-8859-1");
         response.setHeader("Content-Disposition", "attachment;fileName=" + fileName); // 设置文件头
         File file = new File(downloadUrl + "/" +fileobj.getfileName());
         in = new FileInputStream(file);
         int len;
         byte[] buffer = new byte[1024];
         out = response.getOutputStream();
         while ((len = in.read(buffer)) > 0) {
             out.write(buffer, 0, len);
         }
     } catch (Exception e) {
         e.printStackTrace();
     }finally {
         try {
             if (null != out) {
                 out.close();
             }
             if(null != in){
                 in.close();
             }
         } catch (IOException var3) {
             log.error(var3.getMessage(), var3);
         }
     }
 }

这样是可以实现文件下载的,但由于框原因,用户信息取不到,又换了另一种方法

2、返回文件服务器url,由前端组件下载

上面方法丢失用户信息的原因,可能是由于清空了response的信息,导致框获取信息失败,我这里上传的文件是直接上传到文件服务器的,所以可以获取url地址直接在浏览器查看文件。

@ApiOperation(notes = "文件下载", value = "文件下载")
@GetMapping("/downloadurl")
public ResponseEntity<FileOutputOjb> download(HttpServletResponse response, @RequestParam("fileName") String fileName, @RequestParam("fileid") String fileid) {
   //从文件服务器直接获取下载地址
   //https://file.colck.com/sdfasdfasdf.pdf?token=sdfasdfasdf
    String  urlStr = geturlfromServer(fileid);
    log.info("urlStr:{}",urlStr);
    FileOutput fileOutput = new FileOutput();
    fileOutput.setUrlStr(urlStr);
    fileOutput.setFileName(fileName);
    return ResponseEntity.ok(fileOutput);
}

返回Url,和原文件名(因为文件名传上服务器后会重命名成一串数字)。前端用组件可以实现下载,文件名也是原文件名。但必须要文件服务器配置允许跨域,否则就无法下载。即使申请了文件服务器同域名,虽然不再跨域但是还是无法下载(net::ERR_CONNECTION_RESET)。最后用ResponseEntity实现

3、org.springframework.http.ResponseEntity

@ApiOperation(notes = "文件下载", value = "文件下载")
@GetMapping("/downloadfile")
public org.springframework.http.ResponseEntity<FileSystemResource> downloadFile(HttpServletResponse response,
                                                                                @RequestParam("id") Long id, @RequestParam("fileId") String fileId) {
    String downloadUrl = getfilePathfromServer(fileId);
    log.info("下载文件名称:{}",fileId);
    String fileName = null; // 文件名称的编码
    InputStream in = null;
    OutputStream out = null;
    try {
        fileName = new String(fileojb.getfileName.getBytes("Gb2312"), "ISO-8859-1");
        //response.setHeader("Content-Disposition", "attachment;fileName=" + fileName); // 设置文件头
        File file = new File(downloadUrl + "/" + fileojb.getfileName);
        HttpHeaders headers = new HttpHeaders();
        headers.add("Cache-Control", "no-cache, no-store, must-revalidate");
        headers.add("Content-Disposition", "attachment; filename=" + fileName);
        headers.add("Pragma", "no-cache");
        headers.add("Expires", "0");
        headers.add("Last-Modified", new Date().toString());
        headers.add("ETag", String.valueOf(System.currentTimeMillis()));
        return  org.springframework.http.ResponseEntity
                .ok()
                .headers(headers)
                .contentLength(file.length())
                .contentType(MediaType.parseMediaType("application/octet-stream"))
                .body(new FileSystemResource(file));

    } catch (Exception e) {
        e.printStackTrace();
        log.info("dfsId:{}下载文件失败,cause:{}",fielId,e);
    }finally {
    }
    return org.springframework.http.ResponseEntity.status(Integer.parseInt(MsgCode.DEFINED_ERROR.getCode())).build();
}

你可能感兴趣的:(spring,boot)