iT邦幫忙

2024 iThome 鐵人賽

DAY 27
0

如果我們的Excel有一些敏感資料,那在文件匯出時加密是很重要的,Apache POI也有提供加密與讀取時解密的功能。
這篇同樣以學生成績資料表來作為實作範例。

加密

加密的步驟必須放在當我們將資料寫入Workbook之後,準備匯出Excel之前,拿文件的資料流ByteArrayOutputStream去進行加密。

// 略...

// 寫入ByteArrayOutputStream 匯出Excel
workbook.write(bos);
// 加密
ByteArrayResource resource = new ByteArrayResource(this.setEncrypt(bos));
return resource.getByteArray();

加密的步驟如下:

  • POIFSFileSystem: 在加密過程中,POIFSFileSystem可以用來存儲加密後的文件數據,並將其寫入輸出流
  • EncryptionInfo: 用來管理文件加密的類別,當處理加密文件時,EncryptionInfo能設定加密模式,API文件中有下圖這幾種選擇,範例中我選擇EncryptionMode.standard。不過我還沒有研究這些模式分別是用什麼標準或演算法,可以參考官方文件:Apache POI™ - Encryption support
  • Encryptor: 實際執行加密操作的類別,可以使用Encryptor設置文件的密碼,並將資料流加密後寫入加密的文件系統中
  • OPCPackage: 負責打開OOXML檔案,存取加密後的內容,再重新壓縮回OOXML格式
  • 這裡不使用try-with-resources是想要強調,匯出前一定要先關閉加密文件OutputStream,不然緩衝區中的內容可能未完全寫入到文件中,造成文件不完整或加密失敗,就會顯示匯出的文件損壞,關閉OutputStream則會強制將緩衝區的資料寫入文件,確保內容完整
private byte[] setEncrypt(ByteArrayOutputStream bos) throws IOException, InvalidFormatException, GeneralSecurityException {
    POIFSFileSystem fs = new POIFSFileSystem();
    EncryptionInfo info = new EncryptionInfo(EncryptionMode.standard);
    Encryptor encryptor = info.getEncryptor();
    // 設定加密密碼
    encryptor.confirmPassword("password");
    // 打開文件
    OPCPackage opc = OPCPackage.open(new ByteArrayInputStream(bos.toByteArray()));

    OutputStream os = encryptor.getDataStream(fs);
    // 儲存加密內容
    opc.save(os);
    opc.close();
    // 匯出前一定要先關閉加密文件OutputStream,不然會顯示匯出的文件損壞
    os.close();

    // 再將已加密的資料寫入ByteArrayOutputStream
    ByteArrayOutputStream encryptedStream = new ByteArrayOutputStream();
    fs.writeFilesystem(encryptedStream);
    encryptedStream.close();

    return encryptedStream.toByteArray();
}

加密結果

成功加密之後,打開文件查看內容之前,就會被要求要先輸入密碼囉

解密

如果用程式讀取被加密的文件,沒有解密的話會出現Exception:

想解密檔案的話可以在取得檔案FileInputStream之後進行。

public void readExcel(String filePath) {
    // 欄位名稱
    String[] columnNames = {"學號", "科系", "年級", "姓名", "課程", "成績", "考試日期"};

    List<StudentCourseScoreReportModel> modelList = new ArrayList<>();

    try {
        FileInputStream fileInputStream = new FileInputStream(Paths.get(filePath).toFile());
        // 解密
        Workbook workbook = this.decryptExcel(fileInputStream, "password");
        
        // 以下略...
  • 解密的步驟較簡單,同樣利用POIFSFileSystem讀取和打開文件,然後配合EncryptionInfo和Encryptor完成解密操作。
  • Decryptor: 驗證密碼並取得加密資料,利用getDataStream()能取得解密後的InputStream
private Workbook decryptExcel(FileInputStream fileInputStream, String password) throws IOException, GeneralSecurityException {
    POIFSFileSystem fs = new POIFSFileSystem(fileInputStream);
    EncryptionInfo encInfo = new EncryptionInfo(fs);
    Decryptor decryptor = Decryptor.getInstance(encInfo);
    decryptor.verifyPassword(password);
    Workbook workbook = new XSSFWorkbook(decryptor.getDataStream(fs));
    return workbook;
}

解密結果

解密成功後,就能順利讀取Excel拿到資料了。


Reference


上一篇
Apache POI-Excel資料驗證
下一篇
Apache POI-Excel公式與FormulaEvaluator
系列文
Java工程師的報表入門與實作30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言