Los archivos de Spring Boot se descargan en lotes a través del paquete de compresión zip

Recientemente, se ha agregado un nuevo requisito al proyecto: se requiere descargar por lotes los archivos de Word exportados a partir de la información anterior, es decir, descargar por lotes.

Los datos se guardan en ES y también se escribe la función de exportar palabra.

Mis pensamientos:

  1. El ID de datos entrantes exporta respectivamente archivos de Word a una carpeta en el servidor.
  2. Empaque todos los archivos en un archivo zip de acuerdo con la dirección del archivo a una determinada dirección en el servidor
  3. Descarga de acuerdo con la dirección del archivo zip

Hay un problema:

La exportación de documentos de Word en lotes puede llevar mucho tiempo debido a la gran cantidad de datos.

resolver:

Se adopta el método asincrónico para exportar cada archivo de Word por separado, lo que ahorra en gran medida la eficiencia de la exportación de archivos.

Referencia de método específico: tutorial introductorio de Spring Boot: uso de grupo de subprocesos asíncronos

Aunque este método mejora la eficiencia de la exportación de archivos, no se puede controlar el tiempo de finalización de todas las exportaciones de archivos.

El siguiente método se utiliza aquí


            List<CompletableFuture<Map<String, String>>> list = new ArrayList<>();
            for (String sourceCode : sourceCodes.split(",")) {
                CompletableFuture<Map<String, String>> future = favoriteService.exportFavoriteItemWordFile(sourceCode);
                list.add(future);
            }
            CompletableFuture<Map<String, String>>[] completableFutures = list.toArray(new CompletableFuture[list.size()]);
            CompletableFuture.allOf(completableFutures).join();

 CompletableFuture.allOf (). Join (); Espere el final de todas las tareas del hilo

Llamada al método de exportación de archivos:

 @Async
    @Override
    public CompletableFuture<Map<String, String>> exportFavoriteItemWordFile(String sourceCode) throws IOException, URISyntaxException, InterruptedException {
       
        Map<String, String> result = esDetailedService.exportDetailInfoDoc(sourceCode);
        
        return CompletableFuture.completedFuture(result);
    }

Aquí el resultado devuelve la ruta de almacenamiento del archivo en el servidor. Se puede obtener a través de future.get (). Get ("url").

Referencia de implementación de exportación de Word: use POI para exportar archivos de plantilla de Word

El resto es la solución de empaquetar el archivo en un zip, aquí hay una clase de herramienta:


import java.io.*;
import java.util.ArrayList;
import java.util.List;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;

/**
 * @BelongsProject: exchange
 * @BelongsPackage: com.elens.util
 * @Author: xuweichao
 * @CreateTime: 2019-06-04 15:51
 * @Description: 文件压缩工具类
 */

public class ZipUtil {


    private static final int BUFFER_SIZE = 2 * 1024;

    /**
     * 压缩成ZIP 方法1
     *
     * @param srcDir           压缩文件夹路径
     * @param out              压缩文件输出流
     * @param keepDirStructure 是否保留原来的目录结构,true:保留目录结构;
     *                         false:所有文件跑到压缩包根目录下(注意:不保留目录结构可能会出现同名文件,会压缩失败)
     * @throws RuntimeException 压缩失败会抛出运行时异常
     */
    public static void toZip(String srcDir, OutputStream out, boolean keepDirStructure)
            throws RuntimeException {

        long start = System.currentTimeMillis();
        ZipOutputStream zos = null;
        try {
            zos = new ZipOutputStream(out);
            File sourceFile = new File(srcDir);
            compress(sourceFile, zos, sourceFile.getName(), keepDirStructure);

            long end = System.currentTimeMillis();
            System.out.println("压缩完成,耗时:" + (end - start) + " ms");
        } catch (Exception e) {
            throw new RuntimeException("zip error from ZipUtils", e);
        } finally {
            if (zos != null) {
                try {
                    zos.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }

    }

    /**
     * 压缩成ZIP 方法2
     *
     * @param srcFiles 需要压缩的文件列表
     * @param out      压缩文件输出流
     * @throws RuntimeException 压缩失败会抛出运行时异常
     */
    public static void toZip(List<File> srcFiles, OutputStream out) throws RuntimeException {
        long start = System.currentTimeMillis();
        ZipOutputStream zos = null;

        try {
            zos = new ZipOutputStream(out);
            for (File srcFile : srcFiles) {
                byte[] buf = new byte[BUFFER_SIZE];
                zos.putNextEntry(new ZipEntry(srcFile.getName()));
                int len;
                FileInputStream in = new FileInputStream(srcFile);
                while ((len = in.read(buf)) != -1) {
                    zos.write(buf, 0, len);
                }
                zos.closeEntry();
                in.close();
            }
            long end = System.currentTimeMillis();
            System.out.println("压缩完成,耗时:" + (end - start) + " ms");
        } catch (Exception e) {
            throw new RuntimeException("zip error from ZipUtils", e);
        } finally {
            if (zos != null) {
                try {
                    zos.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    /**
     * 递归压缩方法
     *
     * @param sourceFile       源文件
     * @param zos              zip输出流
     * @param name             压缩后的名称
     * @param keepDirStructure 是否保留原来的目录结构,true:保留目录结构;
     *                         false:所有文件跑到压缩包根目录下(注意:不保留目录结构可能会出现同名文件,会压缩失败)
     * @throws Exception
     */
    private static void compress(File sourceFile, ZipOutputStream zos, String name,
                                 boolean keepDirStructure) throws Exception {
        byte[] buf = new byte[BUFFER_SIZE];
        if (sourceFile.isFile()) {
            // 向zip输出流中添加一个zip实体,构造器中name为zip实体的文件的名字
            zos.putNextEntry(new ZipEntry(name));
            // copy文件到zip输出流中
            int len;
            FileInputStream in = new FileInputStream(sourceFile);
            while ((len = in.read(buf)) != -1) {
                zos.write(buf, 0, len);
            }
            // Complete the entry
            zos.closeEntry();
            in.close();
        } else {
            File[] listFiles = sourceFile.listFiles();
            if (listFiles == null || listFiles.length == 0) {
                // 需要保留原来的文件结构时,需要对空文件夹进行处理
                if (keepDirStructure) {
                    // 空文件夹的处理
                    zos.putNextEntry(new ZipEntry(name + "/"));
                    // 没有文件,不需要文件的copy
                    zos.closeEntry();
                }

            } else {
                for (File file : listFiles) {
                    // 判断是否需要保留原来的文件结构
                    if (keepDirStructure) {
                        // 注意:file.getName()前面需要带上父文件夹的名字加一斜杠,
                        // 不然最后压缩包中就不能保留原来的文件结构,即:所有文件都跑到压缩包根目录下了
                        compress(file, zos, name + "/" + file.getName(), keepDirStructure);
                    } else {
                        compress(file, zos, file.getName(), keepDirStructure);
                    }

                }
            }
        }
    }

    public static void main(String[] args) throws Exception {
        /** 测试压缩方法1  */
        FileOutputStream fos1 = new FileOutputStream(new File("H:\\xuweichao.zip"));
        ZipUtil.toZip("H:\\docTmp", fos1, true);

//        /** 测试压缩方法2  */
//        List<File> fileList = new ArrayList<>();
//        fileList.add(new File("H:\\docTmp\\36c194f1-6d69-4114-a26e-c6170af.doc"));
//        fileList.add(new File("H:\\docTmp\\303e9dd9-6270-4968-95c8-13c660a.doc"));
//        fileList.add(new File("H:\\docTmp\\545a857a-2f3b-487c-8b21-a58da9d.doc"));
//        fileList.add(new File("H:\\docTmp\\ce608bff-f00d-4436-9c30-da73f70.doc"));
//        FileOutputStream fos2 = new FileOutputStream(new File("H:\\docTmp\\xuweichao.zip"));
//        ZipUtil.toZip(fileList, fos2);
    }
}

transferir

            String zipFileName = "收藏夹人物信息打包-" + System.currentTimeMillis() + ".zip";
            String zipFilePathName = words2ZipTmpDir + zipFileName;
            File zipfile = new File(zipFilePathName);

            if (!zipfile.getParentFile().exists()) {
                zipfile.getParentFile().mkdirs();
            }

            FileOutputStream fos = new FileOutputStream(zipfile);
            ZipUtil.toZip(zipFiles, fos);
List<File> zipFiles = new ArrayList<>();

zipFiles: una colección de archivos que deben empaquetarse.

Luego descargue el archivo zip de acuerdo con zipFilePathName.

Aquí solo se proporcionan las ideas de implementación y los códigos clave, y los comentarios e intercambios son bienvenidos si tiene alguna pregunta.

Supongo que te gusta

Origin blog.csdn.net/qq_27828675/article/details/90898140
Recomendado
Clasificación