需求

提供一个接口,前端通过按钮下载文件,根据不同的id下载对应的文件,由于都是多个文件,需要进行打压缩包下载,文件保存在oss服务器上

注意:我的压缩包名称和文件名称都是通过日期或者uuid生成的,自己根据需求去修改

编写接口相关代码

controller

/*** 下载文件** @param signId*/@GetMapping("/downloadFile")@ApiOperationSupport(order = 5)@ApiOperation(value = "下载文档", notes = "传入signId")public void downloadFile(@ApiParam(value = "签署id", required = true) @RequestParam Long signId, HttpServletResponse response) throws Exception {signDocumentService.downloadFile(signId,response);}

mapper

 /*** 根据singId查询Attach** @param singId* @return SignDocument*/List<SignDocumentVO> selectAttachs(@Param("singId") Long singId);

mapper.xml

     <select id="selectAttachs" resultType="com.dmyz.signature.sign.vo.SignDocumentVO">selectba.link,ba.original_namefrom dmyz_sign_document dsdleft join blade_attach ba on ba.id=dsd.attach_idwhere sign_id =#{singId} and  dsd.is_deleted = 0</select>

service

 /*** 根据id查询附件并下载** @param signId* @param response* @throws Exception*/void downloadFile(Long signId, HttpServletResponse response) throws IOException;

serviceImpl

这里我要从oss上下载,所以我先从oss下载到项目本地了,不然File无法识别远程文件,只能识别本地文件,这块逻辑自行修改,代码参考即可

  /*** 根据id查询附件并下载** @param signId* @param response* @throws Exception*/@Overridepublic void downloadFile(Long signId, HttpServletResponse response) throws IOException {String path = null;String download = null;ServletOutputStream out=null;FileInputStream fis=null;try {// 根据signId查询签署文档List<Map<String, String>> maps = signDocumentMapper.selectAttachs(signId);// 如果不为空if (!maps.isEmpty()) {for (Map<String, String> map : maps) {String link =  map.get("filePath");String uuid = UUID.randomUUID().toString().replace("-", "");// 文件名称 uuid随机生成String fileName =uuid+PDF;// 把oss文件下载到项目本地path = SignDocumentServiceImpl.class.getClass().getResource("/").getPath() +FileUtil.getNameWithoutExtension(link) + PDF;// 把获取到的oss文件链接下载到本地download = download(link, path);File file = new File(download);response.setCharacterEncoding("utf-8");response.setContentType("application/file");response.setHeader("Content-Disposition", "attachment;FileName=" + fileName);out = response.getOutputStream();int len = 0;byte[] buffer = new byte[1024];fis = new FileInputStream(file);while ((len = fis.read(buffer)) > 0) {out.write(buffer, 0, len);out.flush();}response.flushBuffer();}}}catch (Exception e) {log.error("下载单个pdf文件失败,原因:{}", e);}finally {out.close();fis.close();}}

访问接口测试

浏览器输入

localhost:8080/downloadFile?signId=1001

本地选择保存目录


点击保存 就看到在指定的位置上有我们的文件了

可以正常打开查看

方案再次修改

上面这种方式,在我本地是可以的,但是到了开发环境就有一个问题,不能再linux创建目录去保存文件

这时候就要去修改代码了,我们通过流的方式直接下载,而不用再次保存了

修改代码,首先应该是post请求,不能用get,我忘记改了

    public void downloadZipFile(Long signId, HttpServletResponse response) throws Exception {// 文件路径 从oss上获取String url;// 多个文件集合ArrayList<String> files = new ArrayList<>();// 根据signId查询签署文档List<SignDocumentVO> signDocumentVOS = signDocumentMapper.selectAttachs(signId);for (SignDocumentVO signDocumentVO : signDocumentVOS) {url = signDocumentVO.getLink();// 把多个文件添加到集合里面,方便打包下载files.add(url);}// 配置文件下载response.setCharacterEncoding("utf-8");response.setContentType("application/file");//压缩包文件名SimpleDateFormat fileZipName = new SimpleDateFormat("yyyyMMddhhmmss");// 下载文件时候防止显示中文乱码 指定文件类型 .zipresponse.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(fileZipName.format(new Date()) + ".zip", "UTF-8"));response.flushBuffer();// 打包下载ZipUtils.getZipFile(IOUtils.getByte(files), response.getOutputStream(), response);}

新增两个工具类

1 根据oss文件的url获取输出流,利用输入流输出流得到一个字节数组

package com.dmyz.signature.util;import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.util.Arrays;
import java.util.Map;
import java.util.Set;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;public class ZipUtils {public static void getZipFile(Map<String, byte[]> stringByte, OutputStream outputStream, HttpServletResponse response) throws Exception {//将文件打包成压缩文件ZipOutputStream zipout = new ZipOutputStream(outputStream);Set<Map.Entry<String, byte[]>> dataEntrys = stringByte.entrySet();for (Map.Entry<String, byte[]> data : dataEntrys) {InputStream bufferIn = new BufferedInputStream(new ByteArrayInputStream(data.getValue()));byte[] bs = new byte[1024];Arrays.fill(bs, (byte) 0);//创建压缩文件内的文件zipout.putNextEntry(new ZipEntry(data.getKey()));int len = 0;while ((len = bufferIn.read(bs)) > 0) {zipout.write(bs, 0, len);zipout.flush();}response.flushBuffer();bufferIn.close();}try {zipout.close();outputStream.flush();} catch (IOException e) {}}}

2 将得到的字节数组,利用ZipOutputStream进行压缩

package com.dmyz.signature.util;import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.text.SimpleDateFormat;
import java.util.*;import static com.dmyz.signature.constant.SignConstant.PDF;/*** @author Administrator*/
public class IOUtils {public static Map<String, byte[]> getByte(List<String> urlPaths) {Map<String, byte[]> stringMap = new HashMap<String, byte[]>();byte[] data = new byte[1024];ByteArrayOutputStream outputStream = null;InputStream inputStream = null;try {for (String urlPath : urlPaths) {//根据文件访问地址获取输入流//URL url = new URL(urlPath);inputStream=getInputStreamByUrl(urlPath);outputStream = new ByteArrayOutputStream();while (inputStream.read(data) != -1) {outputStream.write(data);}//当前时间字符创SimpleDateFormat timeName = new SimpleDateFormat("yyyyMMddhhmmss");//UUIDString uuidName = UUID.randomUUID().toString().replace("-", "");stringMap.put(timeName.format(new Date()) + uuidName + PDF, outputStream.toByteArray());}return stringMap;} catch (IOException e) {e.printStackTrace();} finally {if (outputStream != null) {try {outputStream.flush();outputStream.close();} catch (IOException e) {e.printStackTrace();}}if (inputStream != null) {try {inputStream.close();} catch (IOException e) {e.printStackTrace();}}}return null;}public static InputStream getInputStreamByUrl(String strUrl) {HttpURLConnection conn = null;try {URL url = new URL(strUrl);conn = (HttpURLConnection) url.openConnection();conn.setRequestMethod("GET");conn.setConnectTimeout(20 * 1000);final ByteArrayOutputStream output = new ByteArrayOutputStream();org.apache.commons.io.IOUtils.copy(conn.getInputStream(), output);return new ByteArrayInputStream(output.toByteArray());} catch (Exception e) {// logger.error(e + "");} finally {try {if (conn != null) {conn.disconnect();}} catch (Exception e) {//logger.error(e + "");}}return null;}}

这样就完成了通过流的方式下载

下面是调试步骤


2022.9.7回来补充

我又来更新了,uuid作为文件名称和压缩包名称需求觉得不合适,让我把文件换成原文件名称,标题作为压缩包名称

文件名称和标题从库里查,大家根据需求自行修改就完事了

代码稍微修改下

    private void downloadFile(Long signId,Long docType, HttpServletResponse response) throws Exception {Sign sign = signMapper.selectById(signId);// 签署标题 也就是压缩包名称String title = sign.getTitle()+".zip";// 编译成utf-8格式title = URLEncoder.encode(title,"UTF-8");// 根据signId查询签署文档List<SignDocumentVO> signDocumentVOS = signDocumentMapper.selectFilesBySignID(signId,docType);//清空输出流response.reset();//定义输出类型response.setContentType("application/octet-stream");response.setHeader("Content-disposition", "attachment;filename="+title+";"+"filename*=utf-8''"+title);// 打包下载ZipUtils.getZipFile(IOUtils.getByte(signDocumentVOS), response.getOutputStream(), response);}
    public static Map<String, byte[]> getByte(List<SignDocumentVO> SignDocumentVOS) {Map<String, byte[]> stringMap = new HashMap<String, byte[]>();byte[] data = new byte[1024];ByteArrayOutputStream outputStream = null;InputStream inputStream = null;try {for (SignDocumentVO signDocumentVO : SignDocumentVOS) {inputStream=getInputStreamByUrl(signDocumentVO.getLink());outputStream = new ByteArrayOutputStream();while (inputStream.read(data) != -1) {outputStream.write(data);}stringMap.put(signDocumentVO.getOriginalName(), outputStream.toByteArray());}return stringMap;} catch (IOException e) {e.printStackTrace();} finally {if (outputStream != null) {try {outputStream.flush();outputStream.close();} catch (IOException e) {e.printStackTrace();}}if (inputStream != null) {try {inputStream.close();} catch (IOException e) {e.printStackTrace();}}}return null;}

2022.9.9回来补充

又改需求了,如果只有一个文件就直接下载文件本身,多个文件才打包

代码如下:

 /*** @Author 魏一鹤* @Description  公共下载zip文件方法* @Date 14:00 2022/9/6**/private void downloadFile(Long signId,Long docType, HttpServletResponse response) throws Exception {Sign sign = signMapper.selectById(signId);Assert.notNull(sign, "该签署ID错误");// 签署标题 也就是压缩包名称String title = sign.getTitle()+".zip";// 编译成utf-8格式title = URLEncoder.encode(title,"UTF-8");// 根据signId查询签署文档List<SignDocumentVO> signDocumentVOS = signDocumentMapper.selectFilesBySignID(signId,docType);Assert.notEmpty(signDocumentVOS, "该签署下没有文件");if(signDocumentVOS.size()==1){// 如果文件只有一个就直接下载文件,无需打包downloadOnlyOne(signId,response);// 防止重复使用responsereturn ;}//清空输出流response.reset();//定义输出类型response.setContentType("application/octet-stream");response.setHeader("Content-disposition", "attachment;filename="+title+";"+"filename*=utf-8''"+title);// 打包下载ZipUtils.getZipFile(IOUtils.getByte(signDocumentVOS), response.getOutputStream(), response);}//只有一个文件就直接下载文件本身下载不打包private void downloadOnlyOne(Long signId, HttpServletResponse response) throws Exception {System.out.println("只有一个文件" );SignDocument signDocument =  this.query().eq("sign_id", signId).one();SignDocumentVO signDocumentVO = BeanUtil.copyProperties(signDocument, SignDocumentVO.class);// 文件名称String originalName = signDocument.getOriginalName();// 编译成utf-8格式originalName = URLEncoder.encode(originalName,"UTF-8");response.reset();//定义输出类型response.setContentType("application/octet-stream");response.setHeader("Content-disposition", "attachment;filename="+originalName+";"+"filename*=utf-8''"+originalName);// 下载文件ZipUtils.getFile(IOUtils.getByteFile(signDocumentVO), response.getOutputStream(), response);}

工具类

package com.dmyz.signature.util;import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.util.Arrays;
import java.util.Map;
import java.util.Set;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;public class ZipUtils {public static void getZipFile(Map<String, byte[]> stringByte, OutputStream outputStream, HttpServletResponse response) throws Exception {//将文件打包成压缩文件ZipOutputStream zipout = new ZipOutputStream(outputStream);Set<Map.Entry<String, byte[]>> dataEntrys = stringByte.entrySet();for (Map.Entry<String, byte[]> data : dataEntrys) {InputStream bufferIn = new BufferedInputStream(new ByteArrayInputStream(data.getValue()));byte[] bs = new byte[1024];Arrays.fill(bs, (byte) 0);//创建压缩文件内的文件zipout.putNextEntry(new ZipEntry(data.getKey()));int len = 0;while ((len = bufferIn.read(bs)) > 0) {zipout.write(bs, 0, len);zipout.flush();}response.flushBuffer();bufferIn.close();}try {zipout.close();outputStream.flush();} catch (IOException e) {}}public static void getFile(Map<String, byte[]> stringByte, OutputStream outputStream, HttpServletResponse response) throws Exception {//将文件打包成压缩文件Set<Map.Entry<String, byte[]>> dataEntrys = stringByte.entrySet();for (Map.Entry<String, byte[]> data : dataEntrys) {InputStream bufferIn = new BufferedInputStream(new ByteArrayInputStream(data.getValue()));byte[] bs = new byte[1024];Arrays.fill(bs, (byte) 0);//创建压缩文件内的文件int len = 0;while ((len = bufferIn.read(bs)) > 0) {outputStream.write(bs, 0, len);outputStream.flush();}response.flushBuffer();bufferIn.close();}try {outputStream.close();outputStream.flush();} catch (IOException e) {}}}

工具类

package com.dmyz.signature.util;import com.dmyz.signature.sign.vo.SignDocumentVO;import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.HashMap;
import java.util.List;
import java.util.Map;/*** @author Administrator*/
public class IOUtils {public static Map<String, byte[]> getByte(List<SignDocumentVO> SignDocumentVOS) {Map<String, byte[]> stringMap = new HashMap<String, byte[]>();byte[] data = new byte[1024];ByteArrayOutputStream outputStream = null;InputStream inputStream = null;try {for (SignDocumentVO signDocumentVO : SignDocumentVOS) {inputStream=getInputStreamByUrl(signDocumentVO.getLink());outputStream = new ByteArrayOutputStream();while (inputStream.read(data) != -1) {outputStream.write(data);}stringMap.put(signDocumentVO.getOriginalName(), outputStream.toByteArray());}return stringMap;} catch (IOException e) {e.printStackTrace();} finally {if (outputStream != null) {try {outputStream.flush();outputStream.close();} catch (IOException e) {e.printStackTrace();}}if (inputStream != null) {try {inputStream.close();} catch (IOException e) {e.printStackTrace();}}}return null;}public static Map<String, byte[]> getByteFile(SignDocumentVO signDocumentVO) {Map<String, byte[]> stringMap = new HashMap<String, byte[]>();byte[] data = new byte[1024];ByteArrayOutputStream outputStream = null;InputStream inputStream = null;try {inputStream=getInputStreamByUrl(signDocumentVO.getLink());outputStream = new ByteArrayOutputStream();while (inputStream.read(data) != -1) {outputStream.write(data);}stringMap.put(signDocumentVO.getOriginalName(), outputStream.toByteArray());return stringMap;} catch (IOException e) {e.printStackTrace();} finally {if (outputStream != null) {try {outputStream.flush();outputStream.close();} catch (IOException e) {e.printStackTrace();}}if (inputStream != null) {try {inputStream.close();} catch (IOException e) {e.printStackTrace();}}}return null;}public static InputStream getInputStreamByUrl(String strUrl) {HttpURLConnection conn = null;try {URL url = new URL(strUrl);conn = (HttpURLConnection) url.openConnection();conn.setRequestMethod("GET");conn.setConnectTimeout(20 * 1000);final ByteArrayOutputStream output = new ByteArrayOutputStream();org.apache.commons.io.IOUtils.copy(conn.getInputStream(), output);return new ByteArrayInputStream(output.toByteArray());} catch (Exception e) {} finally {try {if (conn != null) {conn.disconnect();}} catch (Exception e) {}}return null;}}

Java通过流的方式从OSS打压缩包下载或者直接下载文件,并返回输出流给前端(弹框选择下载路径)相关推荐

  1. 阿里云oss上传svg等格式的文件,返回的路径打开后是下载而不是预览

    在做的一个项目,阿里云oss上传svg等格式的文件,返回的路径打开后是下载而不是预览.之后web同事跟产品说不好处理,换回了使用jpg格式的文件.但是最终这个问题都是要解决的,产品要求下期也要上传sv ...

  2. java 打包zip下载_java web 将文件打包成 .zip后 肿么自动弹出下载框提示并下载?

    response.setContentType("application/zip"); response.setHeader("Location",fileNa ...

  3. HDFS使用流的方式上传下载

    主代码 package api;import java.io.FileInputStream; import java.io.InputStream; import java.io.OutputStr ...

  4. Java实现两种方式 RSA签名, RSA签名校验

    Java实现两种方式 RSA签名, RSA签名校验 通过 .keystore密钥文件实现 生成密钥文件 test2.keystore 相关使用 通过密钥生成器实现 Byte数据转换成 Hex字符串 相 ...

  5. JAVA打印流PrintStream 常用方式

    JAVA打印流PrintStream 常用方式 打印流:PrintStream : 继承于OutputStream ,可以使用OutputStream的方法 ***主要用于改变标准输出流方向. (1) ...

  6. Java复习第11天---11.2---Java8新特性---Stream流获取方式和常用方法1

    Java复习第11天---11.2---Java8新特性---Stream流获取方式和常用方法1 目录 文章目录 1.Stream流的2中获取方式 1.1.集合的stream方法 1.2.Stream ...

  7. Java 文件路劲获取(流的方式),适用与jar包或war包运行方式

    读取文件使用流的方式在基本的场合都不会发生错误! 以下是读取文件的几种方式: public static void main(String[] args) {//获取classpath路径,就是根目录 ...

  8. java http 流_java 模拟http请求,通过流(stream)的方式,发送json数据和文件

    发送端: /** * 以流的方式 * 发送文件和json对象 * * @return */ public static String doPostFileStreamAndJsonObj(String ...

  9. Java pcm/wav文件转mp3(流的方式)

    项目场景: pcm与wav文件是无损音质,几分钟的文件就高达20几M,要求将pcm/wav文件转mp3文件,既完成文件的压缩,又不影响使用. 解决方案 网上找了很多例子,大都是Lame与FFmpeg, ...

最新文章

  1. 大北农集团被指控授意窃取商业秘密
  2. 软件测试_APP测试_兼容性测试
  3. 软件系统架构师成长之路(一)
  4. STM32F4 HAL库开发 -- 工程模板解读
  5. kotlin之重载运算符(十一)
  6. 如何用css3实现简单旋转的风车
  7. day01_初识python
  8. GitHub政府用户破万:开源成重塑政府新手段
  9. 论文浅尝 | 利用机器翻译和多任务学习进行复杂的知识图谱问答
  10. php获取表单ip,PHP获取用户IP代码实现
  11. python切片习题与详细讲解
  12. 【Python实例第6讲】多标签分类
  13. 第九章:第九章:XML文档集成---Axd向导
  14. python report_python之reportlab
  15. 易语言超级列表框 网络图片_川足快报| 四川优必选为老将汪嵩庆生、遂宁市第三届高中男子足球超级联赛开赛...
  16. android 微博sdk 集成 文件不存在(8998) 您所访问的站点在新浪微博的认证失败,错误码 21322
  17. 锁定计算机时候的屏幕壁纸,电脑锁屏的时候屏幕壁纸怎么更改
  18. C语音数组数据从小到大排序
  19. 避免重要数据泄露的8种方式
  20. Kids Photography: At Home 儿童摄影:家庭摄影 Lynda课程中文字幕

热门文章

  1. php云函数实现注册,7.6.1 内部函数注册
  2. 如何提升BERT在下游任务中的性能
  3. 存储系统“数据之眼”的设计--数据探查服务
  4. windows2016 达梦8数据库实例初始化和卸载
  5. 《Python自然语言处理(第二版)-Steven Bird等》学习笔记:第11章 语言数据管理
  6. JAVA 18道基础循环练习题,带你了解循环是如何实现的(带答案)
  7. linux的网页口令相关,RedHat Linux常见有关问题集锦(一)
  8. pug模板引擎基本用法
  9. 攻防世界forgot——让人眼花目眩的一道题(详细菜鸡向)
  10. 轻松搞定ThinkPad T530蓝牙驱动