文件批量下载

背景
随着数字媒体的发展,每天产生的媒体文件越来越多。日常使用系统的过程中,涉及到文件下载的场景也得越来常见。这对文件下载,这个功能的体验提出了新的要求。 为了提升对文件下载功能的友好型,很有必要提供文件打包下载这个功能。

主要功能
● 对多个文件进行打包压缩:针对需要下载的多个文件,进行打包压缩(提供7z、tar、zip格式)。并且可以对压缩文件进行下载操作。

代码地址
[email protected]:gts-compress/compress-parent.git
example
示例代码
📎compress-sample.zip
setting.xml
📎settings.xml
使用说明
引入依赖

<dependency>
		<groupId>com.aliyun.gts</groupId>
    <artifactId>compress-starter</artifactId>
    <version>1.0.0-SNAPSHOT</version>
</dependency>

添加配置

gts:
  compress:
    path:
      file-path: "D:\\test\\result\\"       # 文件缓存路径
      compress-path: "D:\\test\\result2\\"  # 压缩文件缓存路径

配置文件中如果不添加该配置,那么会使用默认的路径。默认的路径分别为:
jar所在路径\file\source # 文件缓存路径
jar所在路径\file\compress-path # 压缩文件缓存路径
相关适配代码如下

        ApplicationHome ah = new ApplicationHome(GtsCompressProperty.class);
        String docStorePath = ah.getSource().getParentFile().toString();

        logger.info("jar包所在路径:{}", docStorePath);
        
        if(StringUtils.isBlank(filePath)){
            this.filePath = docStorePath + "\\file\\source\\";
        }

        if(StringUtils.isBlank(compressPath)){
            this.compressPath = docStorePath + "\\file\\compress\\";
        }

        logger.info("文件缓存路径:{}", this.filePath);
        logger.info("压缩文件缓存路径:{}", this.compressPath);

接口介绍

public interface FileService {

    /**
     * 调用方式一、接受多个输入流,返回压缩文件的输出流
     *
     * @param inputStreams 文件输入流列表
     * @param fileNames 文件名称列表
     * @param targetName 批量下载的目标文件名称
     * @param compressEnum 文件打包压缩的策略
     */
    InputStream batchDownloadsByInputStream(List<InputStream> inputStreams, List<String> fileNames, String targetName,
                                            CompressEnum compressEnum)
            throws IOException, CompressExcetpion;


    /**
     * 调用方式二、接受consumer函数,返回压缩文件的输出流
     *
     * @param consumer 回调方法,在该接口的实现类中,将文件下载到文件缓存目录
     * @param targetName 批量下载的目标文件名称
     * @param compressEnum 文件打包压缩的策略
     */
    InputStream batchDownloadsByConsumer(Consumer<String> consumer, String targetName, CompressEnum compressEnum)
            throws IOException, CompressExcetpion;
}

● 接口一,通过接收多个文件流,将文件对应的文件打包成压缩文件,并将压缩文件对应的输入流返回。
● 接口二,通过接收consumer,回调consumer的accept()方法,会将文件缓存的路径回传给accept()方法的参数。调用者在consumer完成将文件下载到对应的路径即可。
调用示例
1、通过接受多个输入流,返回压缩文件的输出流

@Autowired
private FileService fileService;

  /**
     * 1、调用示例一,根据多个文件流,生成压缩文件并完成下载功能
     *
     * @param type type可以传递 zip、tar、7z
     * @param response
     *
     * @throws IOException
     * @throws CompressExcetpion
     */
    @GetMapping("/donwloadByInputStream")
    public void batchDownloadsByInputStream(@RequestParam("type") String type, HttpServletResponse response)
            throws IOException, CompressExcetpion {
        // 构造模拟参数
        InputStream inputStream = new FileInputStream(new File("D:\\test\\file\\te\\1.xlsx"));
        InputStream inputStream2 = new FileInputStream(new File("D:\\test\\file\\te\\2.xlsx"));
        InputStream inputStream3 = new FileInputStream(new File("D:\\test\\file\\te\\3.xlsx"));

        List<InputStream> list1 = new ArrayList<>();
        list1.add(inputStream);
        list1.add(inputStream2);
        list1.add(inputStream3);

        List<String> list2 = new ArrayList<>();
        list2.add("1.xlsx");
        list2.add("2.xlsx");
        list2.add("3.xlsx");

        // 根据传递的type参数, 适配对应的压缩文件类型
        CompressEnum compressEnum = null;
        if ("tar".equals(type)) {
            compressEnum = CompressEnum.TAR;
        } else if ("7z".equals(type)) {
            compressEnum = CompressEnum.SEVEN_ZIP;
        } else if ("zip".equals(type)) {
            compressEnum = CompressEnum.ZIP;
        }

        // 模拟下载的文件名称
        String fileName = "compressFile";

        // 进行文件压缩调用
        InputStream resultInputStream = fileService.batchDownloadsByInputStream(list1, list2, fileName, compressEnum);

        fileName = fileName + compressEnum.getSuffix();

        response.setHeader("Content-Disposition", "attachment;filename=" + fileName);
        ServletOutputStream outputStream = response.getOutputStream();
        IOUtils.copy(resultInputStream, outputStream);

        outputStream.close();
        resultInputStream.close();
    }

引入FileService,调用batchDownloadsByInputStream()方法,对应的压缩文件流会返回。
2、通过接受函数,返回压缩文件的输出流

	@Autowired
	private FileService fileService;
   /**
     * 2、调用示例二,根据多个文件流,生成压缩文件并完成下载功能
     *
     * @param type type可以传递 zip、tar、7z
     * @param ids 待打包下载文件id列表
     * @param response
     *
     * @throws IOException
     * @throws CompressExcetpion
     */
    @GetMapping("/donwloadByConsumer")
    public void batchDownloadsByConsumer(@RequestParam("type") String type, @RequestParam("ids") String ids,
                                         HttpServletResponse response)
            throws IOException, CompressExcetpion {

        // 根据传递的type参数, 适配对应的压缩文件类型
        CompressEnum compressEnum = null;
        if ("tar".equals(type)) {
            compressEnum = CompressEnum.TAR;
        } else if ("7z".equals(type)) {
            compressEnum = CompressEnum.SEVEN_ZIP;
        } else if ("zip".equals(type)) {
            compressEnum = CompressEnum.ZIP;
        }

        //模拟文件名称
        String fileName = "compressFile";


        List<String> idList = Splitter.on(",").trimResults().splitToList(ids);

        if (CollectionUtils.isEmpty(idList)) {
            return;
        }

        // 进行文件压缩调用
        InputStream resultInputStream = fileService.batchDownloadsByConsumer((sourcePath) -> {
            /**
             * 此次模拟根据文件id列表,获取文件流,并将文件下载文件到 sourcePath 目录
             */
            idList.stream().forEach(id -> {
                // 1、根据id 查询当前文件的记录

                // 2、根据文件信息 到oss中获取当前的文件流

                // 3、将文件下载到 sourcePath 目录,完成后需要关闭文件输出流,否则会影响清理缓存功能
								

            });
        }, fileName, compressEnum);

        fileName = fileName + compressEnum.getSuffix();

        response.setHeader("Content-Disposition", "attachment;filename=" + fileName);
        ServletOutputStream outputStream = response.getOutputStream();
        IOUtils.copy(resultInputStream, outputStream);

        outputStream.close();
        resultInputStream.close();
    }

引入FileService,调用batchDownloadsByConsumer()方法,对应的压缩文件流会返回。
注意
● 对于第二种方式,通过接受函数,返回压缩文件的输出流的调用,可以在Consumer函数中进行高度自定义的操作。不仅仅是从oss中获取文件,也可以是从网络、磁盘,等地方获取文件。
参考链接
文件批量下载建设方案