把多个文件打包成ZIP下载的方法

把要压缩的文件保存到同一个文件夹下,然后使用ZipUtils对该文件夹打包,然后把数据流写入响应体中返回给前端下载即可

    public void downloadBatchWord(InspectLogQueryDto queryDto, HttpServletResponse response) {
        if(ObjectUtils.isNotEmpty(queryDto.getIds())&&queryDto.getIds().size()==1){
            queryDto.setId(queryDto.getIds().get(0));
            downloadSingleWord(queryDto, response);
        }
        List<InspectLog> inspectLogs = inspectLogMapper.selectList(queryDto);
        List<String> fileNames = new ArrayList<>();
        try {
            if(ObjectUtils.isNotEmpty(inspectLogs)){
                for (int i = 0; i < inspectLogs.size(); i++) {
                    InspectLog log = inspectLogs.get(i);
                    Map<String, Object> replaceMap = dataFilling(log);
                    OutputStream outputStream = null;

                        if (replaceMap != null) {
                            //把生成的word存到临时文件夹中
                            // 生成Word文档的临时路径
                            String year = replaceMap.get("year").toString();
                            String month = String.valueOf((Integer.valueOf(replaceMap.get("month").toString())+1));
                            String day = replaceMap.get("day").toString();
                            String s = year+"年"+month+"月"+day+"日";
                            String index = new DecimalFormat("000").format(i+1);
                            String fileName = "巡查日志"+s+"-"+index+".docx";
                            String docPath = System.getProperty("java.io.tmpdir") + "/" + fileName;
                            outputStream = new FileOutputStream(docPath);
                            // 加载Word模板并填充数据
                            Resource resource = resourceLoader.getResource("classpath:word/xcrz-template.docx");
                            InputStream tempFile = resource.getInputStream();
                            WordUtils.toWord(tempFile, replaceMap, outputStream);
                            outputStream.flush();
                            fileNames.add(fileName);

                }
            }
            response.setHeader("Access-Control-Expose-Headers", "Content-Disposition");
            response.addHeader("Content-type", "application/octet-stream");
            response.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode("巡查日志.zip", "UTF-8"));
            response.setCharacterEncoding("UTF-8");
            downloadObject(fileNames,response.getOutputStream());
        }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

 WordUtils

package com.ztjz.itp.hams.business.util;

import com.deepoove.poi.XWPFTemplate;
import com.forest.support.base.result.ItemCount;
import org.apache.poi.xwpf.usermodel.*;
import org.docx4j.jaxb.Context;
import org.docx4j.openpackaging.exceptions.Docx4JException;
import org.docx4j.openpackaging.packages.WordprocessingMLPackage;
import org.docx4j.openpackaging.parts.PartName;
import org.docx4j.openpackaging.parts.WordprocessingML.AlternativeFormatInputPart;
import org.docx4j.openpackaging.parts.WordprocessingML.MainDocumentPart;
import org.docx4j.org.apache.poi.util.IOUtils;
import org.docx4j.relationships.Relationship;
import org.docx4j.wml.CTAltChunk;
import org.springframework.util.ClassUtils;

import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

/**
 * @author HelloWord高级工程师
 * @describe:
 * @date 2023年03月24日 下午 03:48
 */

public class WordUtils {

    /**
     * 生成word
     *
     * @param tempfile
     * @param data
     * @param outfile
     * @return
     */
    public static boolean toWord(InputStream tempfile, Map<String, Object> data, String outfile) {
        return toWord(tempfile, data, new File(outfile));
    }

    /**
     * 生成word
     *
     * @param tempfile
     * @param data
     * @param outputStream
     * @return
     */
    public static boolean toWord(InputStream tempfile, Map<String, Object> data, OutputStream outputStream) {
        boolean result = false;
        XWPFTemplate template = null;
        try {
            template = XWPFTemplate.compile(tempfile).render(data);
            template.write(outputStream);
            outputStream.flush();
            result = true;
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                if (outputStream != null) {
                    outputStream.close();
                }
                if (template != null) {
                    template.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return result;
    }

    /**
     * 生成word
     *
     * @param tempfile
     * @param data
     * @param outfile
     * @return
     */
    public static boolean toWord(InputStream tempfile, Map<String, Object> data, File outfile) {
        boolean result = false;
        FileOutputStream out = null;
        XWPFTemplate template = null;
        try {
            template = XWPFTemplate.compile(tempfile).render(data);
            out = new FileOutputStream(outfile);
            template.write(out);
            out.flush();
            result = true;
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                if (out != null) {
                    out.close();
                    template.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return result;
    }

    public static void mergeDocxByFile(List<File> list, String path) {
        List<InputStream> inList = new ArrayList<InputStream>();
        for (int i = 0; i < list.size(); i++)
            try {
                inList.add(new FileInputStream(list.get(i)));
            } catch (FileNotFoundException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        try {
            InputStream inputStream = mergeDocx(inList);
            saveTemplate(inputStream, path);
        } catch (Docx4JException | IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }

    public static InputStream mergeDocx(final List<InputStream> streams)
            throws Docx4JException, IOException {

        WordprocessingMLPackage target = null;
        final File generated = File.createTempFile("generated", ".docx");

        int chunkId = 0;
        Iterator<InputStream> it = streams.iterator();
        while (it.hasNext()) {
            InputStream is = it.next();
            if (is != null) {
                if (target == null) {
                    // Copy first (master) document
                    OutputStream os = new FileOutputStream(generated);
                    os.write(IOUtils.toByteArray(is));
                    os.close();

                    target = WordprocessingMLPackage.load(generated);
                } else {
                    // Attach the others (Alternative input parts)
                    insertDocx(target.getMainDocumentPart(),
                            IOUtils.toByteArray(is), chunkId++);
                }
            }
        }

        if (target != null) {
            target.save(generated);
            return new FileInputStream(generated);
        } else {
            return null;
        }
    }

    // 插入文档
    private static void insertDocx(MainDocumentPart main, byte[] bytes, int chunkId) {
        try {
            AlternativeFormatInputPart afiPart = new AlternativeFormatInputPart(new PartName("/part" + chunkId + ".docx"));
            //afiPart.setContentType(new ContentType(CONTENT_TYPE));
            afiPart.setBinaryData(bytes);
            Relationship altChunkRel = main.addTargetPart(afiPart);
            CTAltChunk chunk = Context.getWmlObjectFactory().createCTAltChunk();
            chunk.setId(altChunkRel.getId());
            main.addObject(chunk);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public static void saveTemplate(InputStream fis, String toDocPath) {
        FileOutputStream fos;
        int bytesum = 0;
        int byteread = 0;
        try {
            fos = new FileOutputStream(toDocPath);
            byte[] buffer = new byte[1444];
            while ((byteread = fis.read(buffer)) != -1) {
                bytesum += byteread; //字节数 文件大小
                fos.write(buffer, 0, byteread);
            }
            fis.close();
            fos.close();
        } catch (FileNotFoundException e1) {
            e1.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public static InputStream readFile(String fileName) {
        InputStream inputStream = ClassUtils.class.getClassLoader().getResourceAsStream("templates/word/" + fileName + ".docx");
        return inputStream;
    }

    public synchronized static void download(HttpServletResponse response, File file) {
        BufferedInputStream bis = null;
        BufferedOutputStream bos = null;
        try {
            response.setContentType("application/octet-stream");
            // 下载文件能正常显示中文
            response.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(file.getName(), "UTF-8"));
            bis = new BufferedInputStream(new FileInputStream(file));
            bos = new BufferedOutputStream(response.getOutputStream());
            byte[] buff = new byte[10240];
            int bytesRead;
            while (-1 != (bytesRead = bis.read(buff, 0, buff.length))) {
                bos.write(buff, 0, bytesRead);
            }
            bis.close();
            bos.close();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            //这里为测试代码,可以自行封装
            String fileName = "D:\\test.docx";
            File f = new File(fileName);
            if (f.exists()) {
                f.delete();
            }
        }
    }

    /**
     * WordUtils.exportDataToWord(totalList, tempFile, replaceMap, outputStream, 3, 1);
     *
     * totalList 源数据
     * tempFile 是临时文件输入流,此时临时文件是空的
     * replaceMap 是替换word模板中的数据
     * outputStream 写数据
     *
     */


    public static boolean exportDataToWord(List<List<ItemCount>> totalList, InputStream templateFile, Map<String, Object> replaceMap, OutputStream outputStream, int tableIndex, int startRow) throws IOException {
        boolean result = false;
        XWPFTemplate template = null;
        try {
            template = XWPFTemplate.compile(templateFile).render(replaceMap);
            XWPFDocument document = template.getXWPFDocument();

            int currentTableIndex = tableIndex; // 保存当前表格的索引

            for (int j = 0; j < totalList.size(); j++) {
                List<ItemCount> itemList = totalList.get(j);

                // 获取指定索引的表格
                XWPFTable table = document.getTables().get(currentTableIndex);
                // 获取指定索引的起始行
                XWPFTableRow startTableRow = table.getRow(startRow);
                //获取表格行高
                int height = startTableRow.getHeight();

                // 填充数据
                for (int i = 0; i < itemList.size(); i++) {
                    ItemCount item = itemList.get(i);
                    XWPFTableRow dataRow;
                    if (i >= table.getNumberOfRows() - startRow) {
                        // 如果索引超过或等于剩余行数,创建新的行,新行行高和原表行高一样
                        dataRow = table.createRow();
                        dataRow.setHeight(height);

                    } else {
                        // 否则获取指定索引的行
                        dataRow = table.getRow(startRow + i);
                    }
                    List<XWPFTableCell> cells = dataRow.getTableCells();

                    // 填充 表格第一列 字段
                    XWPFTableCell cell = cells.get(0);
                    cell.setText(item.getIndex());
                    cell.getParagraphs().get(0).setAlignment(ParagraphAlignment.CENTER);

                    // 填充 表格第二列 字段
                    cell = cells.get(1);
                    cell.setText(item.getLabel());
                    cell.getParagraphs().get(0).setAlignment(ParagraphAlignment.CENTER);

                    // 填充 表格第三列 字段
                    cell = cells.get(2);
                    cell.setText(String.valueOf(item.getCount()));
                    cell.getParagraphs().get(0).setAlignment(ParagraphAlignment.CENTER);

                    // 填充 表格第四列 字段
                    if (4 <= cells.size()) {
                        cell = cells.get(3);
                        cell.setText(String.valueOf(item.getCode()));
                        cell.getParagraphs().get(0).setAlignment(ParagraphAlignment.CENTER);
                    }
                }
                currentTableIndex++; // 更新当前表格的索引
            }

            // 写入输出流
            document.write(outputStream);
            outputStream.flush();
            outputStream.close();

            result = true;
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (template != null) {
                template.close();
            }
        }
        return result;
    }

    /**
     * 所传totalList集合中对象超过四个元素情况
     *
     * @param totalList
     * @param templateFile
     * @param replaceMap
     * @param outputStream
     * @param tableIndex
     * @param startRow
     * @return
     * @throws IOException
     */
    public static boolean exportDataToWord(List<List<Word>> totalList, Boolean isContainMoreThanFourElement, InputStream templateFile, Map<String, Object> replaceMap, OutputStream outputStream, int tableIndex, int startRow) throws IOException {
        boolean result = false;
        XWPFTemplate template = null;
        try {
            template = XWPFTemplate.compile(templateFile).render(replaceMap);
            XWPFDocument document = template.getXWPFDocument();

            int currentTableIndex = tableIndex; // 保存当前表格的索引

            for (int j = 0; j < totalList.size(); j++) {
                List<Word> itemList = totalList.get(j);

                // 获取指定索引的表格
                XWPFTable table = document.getTables().get(currentTableIndex);
                // 获取指定索引的起始行
                XWPFTableRow startTableRow = table.getRow(startRow);
                //获取表格行高
                int height = startTableRow.getHeight();

                // 填充数据
                for (int i = 0; i < itemList.size(); i++) {
                    Word item = itemList.get(i);
                    XWPFTableRow dataRow;
                    if (i >= table.getNumberOfRows() - startRow) {
                        // 如果索引超过或等于剩余行数,创建新的行,新行行高和原表行高一样
                        dataRow = table.createRow();
                        dataRow.setHeight(height);

                    } else {
                        // 否则获取指定索引的行
                        dataRow = table.getRow(startRow + i);
                    }
                    List<XWPFTableCell> cells = dataRow.getTableCells();

                    // 填充 表格第一列 字段
                    XWPFTableCell cell = cells.get(0);
                    cell.setText(item.getName1());
                    cell.getParagraphs().get(0).setAlignment(ParagraphAlignment.CENTER);

                    // 填充 表格第二列 字段
                    cell = cells.get(1);
                    cell.setText(item.getName2());
                    cell.getParagraphs().get(0).setAlignment(ParagraphAlignment.CENTER);

                    // 填充 表格第三列 字段
                    cell = cells.get(2);
                    cell.setText(String.valueOf(item.getName3()));
                    cell.getParagraphs().get(0).setAlignment(ParagraphAlignment.CENTER);

                    // 填充 表格第四列 字段
                    if (4 <= cells.size()) {
                        cell = cells.get(3);
                        cell.setText(String.valueOf(item.getName4()));
                        cell.getParagraphs().get(0).setAlignment(ParagraphAlignment.CENTER);
                    }

                    // 填充 表格第五列 字段
                    if (5 <= cells.size()) {
                        cell = cells.get(4);
                        cell.setText(String.valueOf(item.getName5()));
                        cell.getParagraphs().get(0).setAlignment(ParagraphAlignment.CENTER);
                    }

                    // 填充 表格第六列 字段
                    if (6 <= cells.size()) {
                        cell = cells.get(5);
                        cell.setText(String.valueOf(item.getName6()));
                        cell.getParagraphs().get(0).setAlignment(ParagraphAlignment.CENTER);
                    }
                }
                currentTableIndex++; // 更新当前表格的索引
            }

            // 写入输出流
            document.write(outputStream);
            outputStream.flush();
            outputStream.close();

            result = true;
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (template != null) {
                template.close();
            }
        }
        return result;
    }
}

 

ZipUtils

package com.ztjz.itp.hams.business.util;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.io.IoUtil;
import cn.hutool.core.util.CharsetUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.ZipUtil;

import java.io.*;
import java.nio.charset.Charset;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.List;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;
/**
 * 通过Java的Zip输入输出流实现压缩和解压文件
 *
 * @author HelloWord高级工程师
 *
 */
public final class ZipUtils extends ZipUtil{

    private static final Charset DEFAULT_CHARSET = CharsetUtil.defaultCharset();

    /**
     *
     * 生成Zip压缩包 (注意是对hutool的二次封装,所以必须要有hutool依赖)
     *
     * @param zipFile 要生成的目标zip压缩包
     * @param sourceFiles   压缩包中包含的文件集合
     * @param dirWithFlag   是否将文件目录一同打包进去 (true:压缩包中包含文件目录,false:压缩包中不包含目录)
     * @author liukai
     */
    public static File zip(File zipFile, List<File> sourceFiles, boolean dirWithFlag) {
        File file = null;
        if (CollUtil.isNotEmpty(sourceFiles)) {
            File[] fileArr = sourceFiles.toArray(new File[]{});
            file = zip(zipFile, dirWithFlag, fileArr);
        }
        return file;
    }

    /**
     *
     * 生成Zip压缩包文件 (注意是对hutool的二次封装,所以必须要有hutool依赖)
     *
     * @param zipFile 要生成的目标zip压缩包路径
     * @param fileNames   待压缩文件路径名称
     * @param contents   待压缩文件输入流
     * @author kemi
     */
    public static void zip(File zipFile, List<String> fileNames, List<InputStream> contents) {
        FileOutputStream fos = null;
        try {
            fos = new FileOutputStream(zipFile);
            zip(fos, fileNames, contents);
        }catch (Exception e){
            e.printStackTrace();
        }finally {
            IoUtil.close(fos);
        }
    }

    /**
     *
     * 生成Zip压缩二进制包 (注意是对hutool的二次封装,所以必须要有hutool依赖)
     *
     * @param fileNames   待压缩文件路径名称
     * @param contents   待压缩文件输入流
     * @author kemi
     */
    public static void zip(OutputStream outputStream, List<String> fileNames, List<InputStream> contents) {
        ZipOutputStream zos = null;
        if (CollUtil.isNotEmpty(fileNames) && CollUtil.isNotEmpty(contents)) {
            if (fileNames.size() != contents.size()) {
                throw new IllegalArgumentException("fileNames length is not equals to contents length !");
            } else {
                try {
                    zos = getZipOutputStream(outputStream, DEFAULT_CHARSET);
                    ZipEntry zipEntry;
                    InputStream ios;
                    for(int i = 0, size = fileNames.size(); i< size; i++) {
                        zipEntry = new ZipEntry(fileNames.get(i));
                        zos.putNextEntry(zipEntry);
                        ios = contents.get(i);
                        IOUtils.copy(ios, zos);
                        IoUtil.close(ios);
                        zos.closeEntry();
                    }
                    zos.finish();;
                } catch (Exception e) {
                    throw new RuntimeException(e);
                } finally {
                    IoUtil.close(zos);
                }
            }
        } else {
            throw new IllegalArgumentException("fileNames or contents is empty !");
        }
    }

    /**
     *
     * 生成Zip压缩二进制包 (注意是对hutool的二次封装,所以必须要有hutool依赖)
     *
     * @param fileNames   待压缩文件路径名称
     * @param contents   待压缩文件输入流
     * @author kemi
     */
    public static byte[] zip(List<String> fileNames, List<InputStream> contents) {
        ByteArrayOutputStream bos = null;
        try {
            bos = new ByteArrayOutputStream();
            zip(bos, fileNames, contents);
            return bos.toByteArray();
        }catch (Exception e){
            e.printStackTrace();
        }finally {
            IoUtil.close(bos);
        }
        return null;
    }

    public static ZipOutputStream getZipOutputStream(OutputStream out, Charset charset) {
        return out instanceof ZipOutputStream ? (ZipOutputStream)out : new ZipOutputStream(out, ObjectUtil.defaultIfNull(charset, DEFAULT_CHARSET));
    }

    public static void main(String[] args) {
        String filePath ="D:\\opt\\nginx-1.24.0\\html\\upload\\zip\\";
        List<String> files = new ArrayList<>();
        files.add("15af21e188d0464b9b5aac128d907208.png");
        files.add("83f39c83bcd341f2b5127fb80598fd5c.png");
        files.add("86cb00db6a82406e88dca77097e6814e.png");
        files.add("307e91bba89345ddb9547e4b27959a02.png");
        List<InputStream> iss = new ArrayList<>();

        OutputStream os = null;
        try {
            for(String file : files){
                iss.add(Files.newInputStream(Paths.get(filePath + file)));
            }
            os = new FileOutputStream("D:\\opt\\nginx-1.24.0\\html\\upload\\zip\\zip.zip");
            byte[] zip = zip(files, iss);
            os.write(zip);
        }catch (Exception e){
            e.printStackTrace();
        }finally {
            IoUtil.close(os);
        }
    }
}

downloadObject

    private void downloadObject(List<String> objectNames, OutputStream outputStream) {
        if (ObjectUtils.isNotEmpty(objectNames)) {
            List<InputStream> iss = null;
            try {
                iss = new ArrayList<>();
                InputStream inputStream;
                for (String objectName : objectNames) {
                String word = System.getProperty("java.io.tmpdir") + "/" + objectName;
                inputStream = new FileInputStream(word);
                    if (inputStream != null) {
                        iss.add(inputStream);
                    }
                }
                if (ObjectUtils.isNotEmpty(iss)) {
                    ZipUtils.zip(outputStream, objectNames, iss);
                }
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                if(iss != null) {
                    for (InputStream is : iss) {
                        IOUtils.close(is);
                    }
                }
            }
        }
    }

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

HelloWorld高级工程师

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值