【Java】将数据导出到指定word模板当中,批量导出多个word并压缩成zip并加密(代码实现)

目录

1.模板文件:

2. 制作word模板

3.导出word效果

一、将数据导出到指定word模板当中

引入依赖

实体类

接口

接口测试

测试结果

二、批量导出多个word并压缩成zip(不加密版本)

引入依赖

接口

接口测试

测试结果

三、批量导出多个word并压缩成zip(加密版本)

接口

接口测试

测试结果


        业务场景:在平时的业务开发过程中,用户填写表单后,后台管理员需要将用户填写的数据导出到一个Word表单中。为了提高效率,管理员希望能够批量导出这些数据,而不是一个个地导出。然而,后续发现每个人登录管理员账户都有可能下载这些数据,这可能导致敏感信息的泄露。为了避免这种情况,需要对压缩包进行加密处理。

 参考文档:JAVA poi-tl 制作word模板 表格数据行循环 带有复选框勾选的表格_poi-tl 复选框-CSDN博客

        那么下述就对上述这三种情况提供接口实例代码实现:

1.模板文件:

2. 制作word模板

模板文件链接:https://pan.baidu.com/s/1Lvo43xkYp6ec2RonHpEeKA
提取码:0617

3.导出word效果

一、将数据导出到指定word模板当中

引入依赖

        <!--POI-TL实现数据导出到word模板-->
        <dependency>
            <groupId>cn.hutool</groupId>
            <artifactId>hutool-all</artifactId>
            <version>5.8.0.M2</version>
        </dependency>
        <dependency>
            <groupId>com.deepoove</groupId>
            <artifactId>poi-tl</artifactId>
            <version>1.9.1</version>
        </dependency>

实体类

Voteinfo

/**
 * 投票详情
 */
@Data
@AllArgsConstructor
@NoArgsConstructor
public class VoteInfo {

    /** 投票人名称 */
    private String voterName;

    /** 投票结果  1、同意  2、续议  3、拒绝  4、回避 */
    private String voteResult;

    /** 投票意见 */
    private String voteOpinion;
}

DataForm

/**
 *  word数据表单
 */
@Data
@AllArgsConstructor
@NoArgsConstructor
public class DataForm {

    /** 公司名称 */
    private String companyName;

    /** 时间-年 */
    private String year;

    /** 时间-月 */
    private String month;

    /** 时间-日 */
    private String day;

    /** 会议主题 */
    private String meetingTheme;

    /** 会议类型 1、股东会 2、董事会  3、合伙人会 4、其他 */
    private String meetingType;

    /** 是否通过  1、同意  2、续议  3、拒绝 */
    private String passFlag;

    /** 汇总意见 所有投票人的意见汇总 */
    private String allOpinion;

    /** 签名 */
    private String sign;

    /** 签名日期  yyyy-MM-dd */
    private String signDate;
    
}

接口

@RestController
@Slf4j
@RequestMapping("/")
public class WordController {

    //127.0.0.1:8080/generateWordForm
    @GetMapping("/generateWordForm")
    public void generateWordForm(HttpServletResponse response) throws IOException {

        
        /**
         *  1. 获取所有投票人的列表数据
         *    此处使用测试数据,实际项目中需要自己从数据库查询
         * */

        List<VoteInfo> infoList = new ArrayList<VoteInfo>() {{
            add(new VoteInfo("张三", "1", "没有意见"));
            add(new VoteInfo("李四", "1", "同意"));
            add(new VoteInfo("王五", "3", "拒绝,不同意"));
            add(new VoteInfo("赵六", "4", "我回避!不做任何评价"));
            add(new VoteInfo("刘七", "2", "我认为需要续议,日后再重新讨论"));
        }};

        StringBuffer allOpinion = new StringBuffer();
        for (VoteInfo info : infoList) {
            //拼接所有投票人的意见  并换行
            allOpinion.append(info.getVoterName() + ":" + info.getVoteOpinion() + "\n");
        }

        /**
         *  2. 获取并设置表单数据  此处为测试数据  meetingType和passFlag默认设置为1
         *  复选框 meetingType  会议类型 1、股东会 2、董事会  3、合伙人会 4、其他
         *  复选框 passFlag  是否通过 1、同意  2、续议  3、拒绝
         * */

        DataForm dataForm = new DataForm("大聪明集团", "2024", "1", "1",
                "如何成为大聪明", "2", "2",
                allOpinion.toString(), "大聪明老总", new SimpleDateFormat("yyyy-MM-dd").format(new Date()));


        /**
         * 3. 数据map  用于渲染word表单的数据 将表单数据对象存入map中
         */
        Map<String, Object> dataMap = BeanUtil.beanToMap(dataForm);
        //需要循环的表单数据
        dataMap.put("dataTable", infoList);

        /**
         * 4. Configure类是该库中的一个配置类,其作用是提供了一些全局的配置选项
         * (1) useSpringEL() 开启El表达式{{ }}  word模板中的数据就以这个表达式传递数据 例如:{{companyName}};也可以调用buildGramer("${", "}") 可以修改模板为${}
         * (2) bind()  绑定标记需要循环的数据
         * (3) 实现表格行循环的策略 HackLoopTableRenderPolicy 不同poi版本实现行循环的策略不一样;当前案例是poi-tl 1.9.1版本
         * 1.9.x版本:HackLoopTableRenderPolicy  1.10.x以后的版本:LoopRowTableRenderPolicy
         */
        ConfigureBuilder configureBuilder = Configure.builder().useSpringEL().bind("dataTable", new HackLoopTableRenderPolicy());
        Configure config = configureBuilder.build();
        InputStream is = null;
        try {
            /**
             *  5. word模板渲染数据  wordForm.docx为模板,本案例放在了项目根目录的wordTemplates下
             */
            is = new ClassPathResource("wordTemplates/wordForm.docx").getInputStream();
            XWPFTemplate template = XWPFTemplate.compile(is, config).render(dataMap);

            // 6.生成Word文件到内存中
            ByteArrayOutputStream out = new ByteArrayOutputStream();
            template.writeAndClose(out);
            out.flush();

            // 将Word文件转换为字节流并写入到响应对象的输出流中
            String fileName = URLEncodeUtil.encode("数据导出到word模板测试");
            byte[] data = out.toByteArray();
            response.setContentType("application/octet-stream;charset=utf-8");
            response.setHeader("Content-Disposition", "attachment;filename=" + fileName + ".docx");
            response.getOutputStream().write(data);
            response.getOutputStream().flush();
        } catch (IOException e) {
            log.error("生成意见反馈表失败!", e);
        } finally {
            if (null != is) {
                try {
                    //最后别忘记了关闭流
                    is.close();
                } catch (IOException e) {
                    log.error("关闭流失败!", e);
                }
            }
        }

    }
}

接口测试

postman进行接口调用或直接浏览器访问:

127.0.0.1:8080(你的ip地址:端口号)/generateWordForm

测试结果

二、批量导出多个word并压缩成zip(不加密版本)

引入依赖

        引入zip压缩包的依赖

        <!-- zip的依赖-->
        <dependency>
            <groupId>net.lingala.zip4j</groupId>
            <artifactId>zip4j</artifactId>
            <version>2.6.0</version>
        </dependency>

接口



    /**
     * 批量下载word文件打成zip--不加密版本
     */
    @GetMapping("/batchGenerateWordForm")
    public void batchGenerateWordForm1(HttpServletResponse response) throws IOException {

        // 1. 获取所有投票人的列表数据
        List<VoteInfo> infoList = new ArrayList<VoteInfo>() {{
            add(new VoteInfo("张三", "1", "没有意见"));
            add(new VoteInfo("李四", "1", "同意"));
            add(new VoteInfo("王五", "3", "拒绝,不同意"));
            add(new VoteInfo("赵六", "4", "我回避!不做任何评价"));
            add(new VoteInfo("刘七", "2", "我认为需要续议,日后再重新讨论"));
        }};
        List<VoteInfo> infoList1 = new ArrayList<VoteInfo>() {{
            add(new VoteInfo("张三1", "1", "没有意见"));
            add(new VoteInfo("李四1", "1", "同意"));
            add(new VoteInfo("王五1", "3", "拒绝,不同意"));
            add(new VoteInfo("赵六1", "4", "我回避!不做任何评价"));
            add(new VoteInfo("刘七1", "2", "我认为需要续议,日后再重新讨论"));
        }};

        // 2. 获取并设置表单数据
        DataForm dataForm = new DataForm("大聪明集团", "2024", "1", "1",
                "如何成为大聪明", "2", "2",
                getAllOpinion(infoList), "大聪明老总", new SimpleDateFormat("yyyy-MM-dd").format(new Date()));
        DataForm dataForm1 = new DataForm("大聪明集团1", "2024", "1", "1",
                "如何成为大聪明1", "2", "2",
                getAllOpinion(infoList1), "大聪明老总1", new SimpleDateFormat("yyyy-MM-dd").format(new Date()));

        // 3. 数据map  用于渲染word表单的数据 将表单数据对象存入map中
        List<Map<String, Object>> mapList = new ArrayList<>();
        Map<String, Object> dataMap = BeanUtil.beanToMap(dataForm);
        Map<String, Object> dataMap1 = BeanUtil.beanToMap(dataForm1);
        mapList.add(dataMap);
        mapList.add(dataMap1);
        dataMap.put("dataTable", infoList);
        dataMap1.put("dataTable", infoList1);

        // 4. 配置全局选项
        ConfigureBuilder configureBuilder = Configure.builder().useSpringEL().bind("dataTable", new HackLoopTableRenderPolicy());
        Configure config = configureBuilder.build();

        // 5. 创建zip文件并加密
        String zipFilePath = "download/wordForms.zip";
        String password = "lock123";
        FileOutputStream fos = new FileOutputStream(zipFilePath);
        ZipOutputStream zipOut = new ZipOutputStream(fos);
        try {
            // 6. 循环渲染word表单数据并写入zip文件中
            for (Map<String, Object> data : mapList) {
                InputStream is = new ClassPathResource("wordTemplates/wordForm.docx").getInputStream();
                XWPFTemplate template = XWPFTemplate.compile(is, config).render(data);

                // 7. 将word文件写入zip文件中
                ByteArrayOutputStream out = new ByteArrayOutputStream();
                template.writeAndClose(out);
                out.flush();
                byte[] dataBytes = out.toByteArray();
                ZipEntry zipEntry = new ZipEntry(data.get("companyName") + ".docx");
                zipOut.putNextEntry(zipEntry);
                zipOut.write(dataBytes);
                zipOut.closeEntry();
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            // 8. 关闭zip文件输出流
            zipOut.close();
            fos.close();

            // 9. 下载zip文件
            String fileName = URLEncodeUtil.encode("数据导出到word模板测试");
            response.setContentType("application/octet-stream;charset=utf-8");
            response.setHeader("Content-Disposition", "attachment;filename=" + fileName + ".zip");
            FileInputStream fis = new FileInputStream(zipFilePath);
            IOUtils.copy(fis, response.getOutputStream());
            fis.close();
        }
    }
    private String getAllOpinion(List<VoteInfo> infoList) {
        StringBuffer allOpinion = new StringBuffer();
        for (VoteInfo info : infoList) {
            //拼接所有投票人的意见  并换行
            allOpinion.append(info.getVoterName() + ":" + info.getVoteOpinion() + "\n");
        }
        return allOpinion.toString();
    }

接口测试

postman进行接口调用或直接浏览器访问:

127.0.0.1:8080(你的ip地址:端口号)/batchGenerateWordForm

测试结果

三、批量导出多个word并压缩成zip(加密版本)

接口

/**
     * 批量下载word文件打成zip--加密版本
     */
    @GetMapping("/batchGenerateWordFormEncrypt")
    public void batchGenerateWordForm(HttpServletResponse response) throws IOException {

        // 1. 获取所有投票人的列表数据
        List<VoteInfo> infoList = new ArrayList<VoteInfo>() {{
            add(new VoteInfo("张三", "1", "没有意见"));
            add(new VoteInfo("李四", "1", "同意"));
            add(new VoteInfo("王五", "3", "拒绝,不同意"));
            add(new VoteInfo("赵六", "4", "我回避!不做任何评价"));
            add(new VoteInfo("刘七", "2", "我认为需要续议,日后再重新讨论"));
        }};
        List<VoteInfo> infoList1 = new ArrayList<VoteInfo>() {{
            add(new VoteInfo("张三1", "1", "没有意见"));
            add(new VoteInfo("李四1", "1", "同意"));
            add(new VoteInfo("王五1", "3", "拒绝,不同意"));
            add(new VoteInfo("赵六1", "4", "我回避!不做任何评价"));
            add(new VoteInfo("刘七1", "2", "我认为需要续议,日后再重新讨论"));
        }};

        // 2. 获取并设置表单数据
        DataForm dataForm = new DataForm("大聪明集团", "2024", "1", "1",
                "如何成为大聪明", "2", "2",
                getAllOpinion(infoList), "大聪明老总", new SimpleDateFormat("yyyy-MM-dd").format(new Date()));
        DataForm dataForm1 = new DataForm("大聪明集团1", "2024", "1", "1",
                "如何成为大聪明1", "2", "2",
                getAllOpinion(infoList1), "大聪明老总1", new SimpleDateFormat("yyyy-MM-dd").format(new Date()));

        // 3. 数据map  用于渲染word表单的数据 将表单数据对象存入map中
        List<Map<String, Object>> mapList = new ArrayList<>();
        Map<String, Object> dataMap = BeanUtil.beanToMap(dataForm);
        Map<String, Object> dataMap1 = BeanUtil.beanToMap(dataForm1);
        mapList.add(dataMap);
        mapList.add(dataMap1);
        dataMap.put("dataTable", infoList);
        dataMap1.put("dataTable", infoList1);

        // 4. 配置全局选项
        ConfigureBuilder configureBuilder = Configure.builder().useSpringEL().bind("dataTable", new HackLoopTableRenderPolicy());
        Configure config = configureBuilder.build();

        // 5. 创建临时目录并生成Word文件
        String tempDir = "download/temp/";
        String zipDir = "download/zip/";
        String zipFileName = zipDir + "wordForms.zip";
        String password = "lock123";

        File dir = new File(tempDir);
        if (!dir.exists()) {
            dir.mkdirs();
        }

        File zDir = new File(zipDir);
        if (!zDir.exists()) {
            zDir.mkdirs();
        }

        List<String> fileNames = new ArrayList<>();
        fileNames.add(dataForm.getCompanyName() + ".docx");
        fileNames.add(dataForm1.getCompanyName() + ".docx");

        try {
            // 6. 循环渲染word表单数据并写入临时目录中
            for (Map<String, Object> data : mapList) {
                InputStream is = new ClassPathResource("wordTemplates/wordForm.docx").getInputStream();
                XWPFTemplate template = XWPFTemplate.compile(is, config).render(data);

                // 7. 将word文件写入临时目录中
                String tmpPath = tempDir + data.get("companyName") + ".docx";
                FileOutputStream fos = new FileOutputStream(tmpPath);
                template.writeAndClose(fos);
                fos.close();
            }

            // 7. 创建加密的Zip文件
            File zipTemFile = new File(zipFileName);
            ZipFile zipFile = new ZipFile(zipTemFile,password.toCharArray());
            ZipParameters zipParams = new ZipParameters();
            zipParams.setCompressionMethod(CompressionMethod.DEFLATE); // 设置压缩方法为 DEFLATE
            zipParams.setCompressionLevel(CompressionLevel.NORMAL); // 设置压缩级别为 NORMAL
            zipParams.setEncryptFiles(true); // 设置为加密模式
            zipParams.setEncryptionMethod(EncryptionMethod.AES); // 设置加密算法为 AES
            zipParams.setAesKeyStrength(AesKeyStrength.KEY_STRENGTH_256); // 设置 AES 密钥长度为 256 位

            File srcFile = new File(tempDir);
            if (srcFile.isDirectory()) {
                for (File file : srcFile.listFiles()) {
                    zipFile.addFile(file, zipParams);
                }
            }

            // 8. 下载加密的zip文件
            String fileName = URLEncodeUtil.encode("数据导出到word模板测试");
            response.setContentType("application/octet-stream;charset=utf-8");
            response.setHeader("Content-Disposition", "attachment;filename=" + fileName + ".zip");
            FileInputStream encryptedFis = new FileInputStream(zipTemFile);
            IOUtils.copy(encryptedFis, response.getOutputStream());
            encryptedFis.close();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            // 9. 删除临时文件
            delFile(fileNames, zipFileName, tempDir);
            File file1 = new File(zipDir);
            file1.delete();
        }
    }


    private static void delFile(List<String> fileName, String zipFileName, String tempDir) {
        for (String name : fileName) {
            File file = new File(tempDir + name);
            file.delete();
        }
        File file = new File(zipFileName);
        file.delete();
        File file1 = new File(tempDir);
        file1.delete();
    }
    private String getAllOpinion(List<VoteInfo> infoList) {
        StringBuffer allOpinion = new StringBuffer();
        for (VoteInfo info : infoList) {
            //拼接所有投票人的意见  并换行
            allOpinion.append(info.getVoterName() + ":" + info.getVoteOpinion() + "\n");
        }
        return allOpinion.toString();
    }

接口测试

postman进行接口调用或直接浏览器访问:

127.0.0.1:8080(你的ip地址:端口号)/batchGenerateWordFormEncrypt

测试结果

通过上述的代码,我们就能实现将数据导出到指定word模板当中,批量导出多个word并压缩成zip并加密。

  • 12
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
首先,我们可以使用JSZip库来创建一个zip文件,并将表单数据加密后添加到zip文件中。然后,使用FileSaver.js库提供的`saveAs`函数将zip文件保存为文件并下载。具体实现步骤如下: 1. 安装依赖库: ```bash npm install jszip file-saver --save ``` 2. 在Vue组件中引入依赖库: ```javascript import JSZip from 'jszip' import { saveAs } from 'file-saver' ``` 3. 定义一个方法来加密表单数据并添加到zip文件中: ```javascript methods: { async exportZip() { // 获取表单数据 const formData = new FormData(this.$refs.form) // 将表单数据转换为JSON字符串,并进行加密 const encryptedData = await this.encrypt(JSON.stringify(formData)) // 创建一个JSZip实例 const zip = new JSZip() // 将加密后的表单数据添加到zip文件中 zip.file('data.json', encryptedData) // 生zip文件并下载 zip.generateAsync({ type: 'blob' }).then((content) => { saveAs(content, 'data.zip') }) }, async encrypt(data) { // TODO: 实现加密算法 return data } } ``` 4. 编写HTML代码,定义一个表单和一个按钮: ```html <template> <div> <form ref="form"> <!-- 表单内容 --> </form> <button @click="exportZip">导出数据</button> </div> </template> ``` 5. 在`exportZip`方法中调用加密算法来对表单数据进行加密,并将加密后的数据添加到zip文件中。这里的加密算法可以是对称加密算法如AES、DES等,也可以是非对称加密算法如RSA等。由于加密算法的实现需要考虑到数据安全性,这里只提供一个示例,具体实现需要根据实际情况进行调整。 ```javascript async encrypt(data) { // 将字符串转换为字节数组 const byteArray = new TextEncoder().encode(data) // 生一个随机密钥 const key = await window.crypto.subtle.generateKey( { name: 'AES-CBC', length: 256 }, true, ['encrypt', 'decrypt'] ) // 使用密钥对数据进行加密 const encryptedData = await window.crypto.subtle.encrypt( { name: 'AES-CBC', iv: new Uint8Array(16) }, key, byteArray ) // 将加密后的数据转换为Base64字符串 const base64Data = btoa(String.fromCharCode.apply(null, new Uint8Array(encryptedData))) return base64Data } ``` 上述代码中,我们使用`window.crypto.subtle` API来生一个随机密钥,并使用该密钥对表单数据进行AES-CBC加密。然后,将加密后的数据转换为Base64字符串并返回。注意,由于`window.crypto.subtle` API需要在HTTPS环境下才能使用,因此需要在HTTPS环境下进行测试。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

Mxin5

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

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

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

打赏作者

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

抵扣说明:

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

余额充值