java基于easypoi实现对导出的excel文档加密

  • **项目背景

    随着项目日新月异的变化,对数据的安全性也越来越高,特别是政府类型的项目,数据安全往往是非常重要的,最近项目中导出的文件被要求需要密码才能打开,所以写下这篇文章,特此记录一下。


前言

本项目中使用的poi框架为easypoi,springboot版本为2.0.3

提示:以下是本篇文章正文内容,下面案例可供参考

一、文档

easypoi使用教程1.0

二、思考与实现

1.ModelMap方式导出

代码如下(示例):

  List<ExcelExportEntity> entityList = new ArrayList<>();
        entityList.add(new ExcelExportEntity("乡镇", "town", 15));
        entityList.add(new ExcelExportEntity("社区", "community", 15));
        entityList.add(new ExcelExportEntity("姓名", "name", 15));
        entityList.add(new ExcelExportEntity("手机号", "phone", 15));
        entityList.add(new ExcelExportEntity("身份证号码", "idcard", 15));
        entityList.add(new ExcelExportEntity("健康管理措施", "typeName", 15));
        entityList.add(new ExcelExportEntity("健康管理地址", "addr", 15));
        entityList.add(new ExcelExportEntity("健康管理开始时间", "startTime", 15));
        entityList.add(new ExcelExportEntity("健康管理结束时间", "endTime", 15));
        List<PersonImportant> dataResult = personImportantService.selectExcelList(para);
        modelMap.put(MapExcelConstants.ENTITY_LIST, entityList);
        modelMap.put(MapExcelConstants.MAP_LIST, dataResult);
        modelMap.put(MapExcelConstants.FILE_NAME, "重点人员健康管理人员信息");
        SessionUser sessionUser = ShiroUtils.getSessionUser();
        String password = sessionUser.getExcelPassword();
        if (StringUtils.isEmpty(password)) {
            password = "123456";
        }
        modelMap.put(MapExcelConstants.PASSWORD, password);
        modelMap.put(NormalExcelConstants.PARAMS, new ExportParams("重点人员健康管理人员信息", "重点人员健康管理人员信息", ExcelType.XSSF));
        return MapExcelConstants.EASYPOI_MAP_EXCEL_VIEW;

这种方式的导出,我们看到,官方是自带了文档加密功能,只需要我们通过参数的方式传递过去就好了,所以我们不细讲。

2.Workbook方式的导出

代码如下(示例):


	@KrtLog("下载导入失败数据")
    @RequiresPermissions("person:personImportantDetail:excelIn")
    @GetMapping("person/personImportant/downloadExcelErrorData")
    public void downloadExcelErrorData(String downErrorDataKey) {

        List<PersonImportantDetail> dataResult = personImportantService.getExcelErrorData(downErrorDataKey);
        Workbook workbook = ExcelExportUtil.exportExcel(new ExportParams("重点人员健康管理人员信息", "重点人员健康管理人员信息", ExcelType.XSSF), PersonImportantDetail.class, dataResult);
        ExportExcelUtil.exportExcel(workbook, "导入失败-重点人员健康管理人员信息", response);
    }

这种方式的导出,查阅了官方文档,没看到官方的加密功能。通过阅读ModelMap方式导出的源码发现了其加密的奥秘:

通过代码我们可以发现:
在这里插入图片描述
ModelMap方式的导出最后是会到这个控制层,而通过源码我们可以看到,最终是在这个controller中进行导出的:
在这里插入图片描述
那么让我们看看这个里面究竟做了些什么事情吧!继续追踪源码,我们可以发现,具体的实现都是在一个叫out()的方法中进行的:
在这里插入图片描述
让我们再次深入其中,为了更好的展现,我把这部分的源码单独粘贴出来了:

 public void out(Workbook workbook, String codedFileName, String password, HttpServletRequest request, HttpServletResponse response) throws Exception {
        if (workbook instanceof HSSFWorkbook) {
            codedFileName = codedFileName + ".xls";
        } else {
            codedFileName = codedFileName + ".xlsx";
        }

        if (password != null && !"".equals(password)) {
            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            workbook.write(baos);
            baos.flush();
            ByteArrayInputStream workbookInput = new ByteArrayInputStream(baos.toByteArray());
            EncryptionInfo info = new EncryptionInfo(EncryptionMode.agile);
            Encryptor enc = info.getEncryptor();
            enc.confirmPassword(password);
            POIFSFileSystem fs = new POIFSFileSystem();
            OPCPackage opc = OPCPackage.open(workbookInput);
            OutputStream os = enc.getDataStream(fs);
            opc.save(os);
            os.close();
            opc.close();
            baos = new ByteArrayOutputStream();
            fs.writeFilesystem(baos);
            baos.flush();
            response.setHeader("content-disposition", WebFilenameUtils.disposition(codedFileName));
            byte[] buff = new byte[1024];
            BufferedInputStream bis = null;

            try {
                OutputStream os = response.getOutputStream();
                bis = new BufferedInputStream(new ByteArrayInputStream(baos.toByteArray()));

                for(int i = bis.read(buff); i != -1; i = bis.read(buff)) {
                    os.write(buff, 0, buff.length);
                    os.flush();
                }
            } catch (IOException var24) {
                var24.printStackTrace();
            } finally {
                if (bis != null) {
                    try {
                        bis.close();
                    } catch (IOException var23) {
                        var23.printStackTrace();
                    }
                }

            }
        } else {
            response.setHeader("content-disposition", WebFilenameUtils.disposition(codedFileName));
            ServletOutputStream out = response.getOutputStream();
            workbook.write(out);
            out.flush();
        }

    }

至此,我们便发现了他的庐山真面目,我们可以参照他的源码,自己写一个导出工具类。

3.封装导出工具类:

package com.krt.common.util;

import lombok.extern.slf4j.Slf4j;
import org.apache.poi.openxml4j.opc.OPCPackage;
import org.apache.poi.poifs.crypt.EncryptionInfo;
import org.apache.poi.poifs.crypt.EncryptionMode;
import org.apache.poi.poifs.crypt.Encryptor;
import org.apache.poi.poifs.filesystem.POIFSFileSystem;
import org.apache.poi.ss.usermodel.Workbook;

import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.net.URLEncoder;

/**
 * @author: lyp
 * @Date: 2022/1/24 10:38
 * @Description: excel导出工具类
 */
@Slf4j
public class ExportExcelUtil {
    /**
     * 导出Excel
     *
     * @param workbook workbook流
     * @param fileName 文件名
     * @param response 响应
     */
    public static void exportExcel(Workbook workbook, String fileName, HttpServletResponse response) {
        // 输出文件
        try (OutputStream out = response.getOutputStream()) {
            // 获取文件名并转码
            String name = URLEncoder.encode(fileName, "UTF-8");
            // 编码
            response.setCharacterEncoding("UTF-8");
            // 设置强制下载不打开
            response.setContentType("application/force-download");
            // 下载文件的默认名称
            response.setHeader("Content-Disposition", "attachment;filename=" + name + ".xlsx");
            // 输出表格
            workbook.write(out);
        } catch (IOException e) {
            log.error("文件导出异常,详情如下:{}", e);
        } finally {
            try {
                if (workbook != null) {
                    // 关闭输出流
                    workbook.close();
                }
            } catch (IOException e) {
                log.error("文件导出关闭输出流失败,详情如下:{}", e);
            }
        }
    }


    /**
     * 导出一个需要密码打开的Excel
     *
     * @param workbook workbook流
     * @param fileName 文件名
     * @param response 响应
     */
    public static void exportEncryptExcel(Workbook workbook, String fileName, HttpServletResponse response, String password) throws Exception {
        //
        if (password != null && !"".equals(password)) {
            // 文件名
            fileName = fileName + ".xlsx";

            // 创建一个字节数组输出流
            ByteArrayOutputStream workbookOutput = new ByteArrayOutputStream();
            workbook.write(workbookOutput);
            workbookOutput.flush();

            // 创建一个字节数组输入流
            ByteArrayInputStream workbookInput = new ByteArrayInputStream(workbookOutput.toByteArray());

            // 加密
            EncryptionInfo info = new EncryptionInfo(EncryptionMode.agile);
            Encryptor enc = info.getEncryptor();
            enc.confirmPassword(password);

            // 创建一个POIFS 文件系统
            POIFSFileSystem poifsFileSystem = new POIFSFileSystem();
            OPCPackage opc = OPCPackage.open(workbookInput);
            OutputStream outputStream = enc.getDataStream(poifsFileSystem);
            opc.save(outputStream);
            outputStream.close();
            opc.close();
            workbookOutput = new ByteArrayOutputStream();
            poifsFileSystem.writeFilesystem(workbookOutput);
            workbookOutput.flush();

            // 获取文件名并转码
            String name = URLEncoder.encode(fileName, "UTF-8");
            // 编码
            response.setCharacterEncoding("UTF-8");
            // 设置强制下载不打开
            response.setContentType("application/force-download");
            // 下载文件的默认名称
            response.setHeader("Content-Disposition", "attachment;filename=" + name);
            byte[] buff = new byte[1024];
            BufferedInputStream bufferedInputStream = null;

            try {
                OutputStream responseOutputStream = response.getOutputStream();
                bufferedInputStream = new BufferedInputStream(new ByteArrayInputStream(workbookOutput.toByteArray()));

                for (int i = bufferedInputStream.read(buff); i != -1; i = bufferedInputStream.read(buff)) {
                    responseOutputStream.write(buff, 0, buff.length);
                    responseOutputStream.flush();
                }
            } catch (IOException e) {
                log.error("文件导出失败,详情如下:{}", e);
            } finally {
                if (bufferedInputStream != null) {
                    try {
                        bufferedInputStream.close();
                    } catch (IOException e) {
                        log.error("文件导出关闭输出流失败,详情如下:{}", e);
                    }
                }

            }
        }

    }

}

至此,功能已完成

  • 8
    点赞
  • 24
    收藏
    觉得还不错? 一键收藏
  • 7
    评论
以下是使用EasyPoi导出ExcelJava代码示例[^1]: 1. 首先,确保你已经引入了EasyPoi的依赖库。 2. 创建一个实体类,用于存储导出的数据。例如,创建一个名为"ExcelExport"的类,并使用@Excel注解来指定Excel中的列名和属性名。 ```java import cn.afterturn.easypoi.excel.annotation.Excel; import lombok.Data; @Data public class ExcelExport { @Excel(name = "姓名") private String name; @Excel(name = "年龄") private int age; // 其他属性... } ``` 3. 编写导出方法,使用EasyPoi提供的工具类进行导出操作。例如,创建一个名为"ExcelUtils"的工具类,并在其中编写导出方法。 ```java import cn.afterturn.easypoi.excel.ExcelExportUtil; import cn.afterturn.easypoi.excel.entity.ExportParams; import cn.afterturn.easypoi.excel.entity.enmus.ExcelType; import org.apache.poi.ss.usermodel.Workbook; import java.io.FileOutputStream; import java.io.IOException; import java.util.ArrayList; import java.util.List; public class ExcelUtils { public static void exportExcel() throws IOException { // 创建导出的数据列表 List<ExcelExport> dataList = new ArrayList<>(); dataList.add(new ExcelExport("张三", 20)); dataList.add(new ExcelExport("李四", 25)); dataList.add(new ExcelExport("王五", 30)); // 创建导出参数 ExportParams exportParams = new ExportParams(); exportParams.setType(ExcelType.XSSF); // 导出Excel文件 Workbook workbook = ExcelExportUtil.exportExcel(exportParams, ExcelExport.class, dataList); FileOutputStream fos = new FileOutputStream("导出文件路径"); workbook.write(fos); fos.close(); } } ``` 4. 调用导出方法进行导出操作。 ```java public class Main { public static void main(String[] args) { try { ExcelUtils.exportExcel(); System.out.println("导出成功!"); } catch (IOException e) { e.printStackTrace(); } } } ``` 请注意,上述代码中的"导出文件路径"需要替换为你希望导出Excel文件的路径。
评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值