1. 程式人生 > 實用技巧 >PDF/Excel檔案預覽功能完整實現-java版本

PDF/Excel檔案預覽功能完整實現-java版本

新需求

最近接到一個新的需求,說是之前直接下載的PDF檔案或者是Excel檔案,現在不能直接下載,需要實現線上預覽功能。

前端人員拿到這個需求後,去看了一下以前的程式碼,以前呼叫的下載介面和PDF檔案預覽介面都是直接將檔案成二進位制

流的形式,然後響應到前端。有的介面即使是動態生成PDF檔案或者是Excel檔案都是同樣的操作,也是將動態生成的對

象的二進位制流寫入到響應物件中。前端人員遇到的問題是,如果直接將二進位制流返回給前端,前端呼叫的時候,會直接

載而不能做其他處理。然後找我協商,看看後端人員有沒有好的解決辦法,我去百度裡面查詢,找到一個靠譜的方法,

大致意思就是將檔案轉為Base64格式的字串資料,然後返回給前端,前端在去做響應的處理。

解決方案

確定方案後,然後我繼續去百度裡面查詢如何將檔案轉為Base64格式的資料,找到一個可行的方法,網址如下:

https://blog.csdn.net/dbeautifullife/article/details/77650713

使用裡面的方法寫成了一個工具類,然後在根據業務的需要,添加了動態生成PDF檔案和動態生成Excel

檔案的方法,很好的解決了檔案轉換為Base64的方式。

import lombok.extern.slf4j.Slf4j;
import org.apache.poi.ss.usermodel.Workbook;
import org.springframework.context.annotation.Scope;

import sun.misc.BASE64Encoder;

import java.io.*;

/**
* @Description: 檔案轉 base64 工具類
* @ClassName: ToBase64Utils
* @author: dengchao
* @date: 2020/11/24 9:27
*/

@Slf4j
@Scope(value = "singleton")//單例
public class ToBase64Utils {

//私有化構造方法
private ToBase64Utils(){}

/* @Description: ava 自帶的轉換base64物件
* @author: dengchao

* @date: 2020-10-24 10:10
*/
private final static BASE64Encoder encoder = new BASE64Encoder();

/* @Description: 讀取實體檔案轉 Base64
* @author: dengchao
* @date: 2020/11/24 9:29
* @param: file 檔案物件
* @return: String 字串
*/
public static String PDFToBase64(File file) {
if(file == null || !file.exists()){
throw new BaseException(MessageConstant.A000001, "傳入的file物件為null或者檔案不存在");
}

if(file.isDirectory()){
throw new BaseException(MessageConstant.A000001, "傳入的file物件是一個路徑,不是具體的檔案");
}

ToBase64Utils.log.error("PDFToBase64-開始讀取檔案!");

try ( FileInputStream fin = new FileInputStream(file);
BufferedInputStream bin = new BufferedInputStream(fin);
ByteArrayOutputStream baos = new ByteArrayOutputStream();
BufferedOutputStream bout = new BufferedOutputStream(baos);
){
byte[] buffer = new byte[1024];
int len = bin.read(buffer);
while(len != -1){
bout.write(buffer, 0, len);
len = bin.read(buffer);
}
//重新整理此輸出流並強制寫出所有緩衝的輸出位元組
bout.flush();
return ToBase64Utils.byteArrayToBase64(baos);

} catch (FileNotFoundException e) {
ToBase64Utils.log.error("PDFToBase64-檔案未找到!");
e.printStackTrace();
} catch (IOException e) {
ToBase64Utils.log.error("PDFToBase64-讀取檔案異常!");
e.printStackTrace();
}

return "";
}


/* @Description: 動態生成 Excel物件 轉 Base64
* @author: dengchao
* @date: 2020/11/24 9:37
* @param: No such property: code for class: Script1
* @return:
*/
public static String workToBase64(Workbook workbook){
if(workbook == null){
throw new BaseException(MessageConstant.A000001, "傳入Excel檔案物件錯誤");
}

String excelBase64 = "";
try(ByteArrayOutputStream bos = new ByteArrayOutputStream()){
workbook.write(bos);
bos.flush();
excelBase64 = ToBase64Utils.byteArrayToBase64(bos);
}catch(Exception e){
excelBase64 = "";
ToBase64Utils.log.error("EXCEL檔案轉Base64錯誤!", e);
}

return excelBase64;
}


/* @Description: 位元組輸出流轉 Base64
* @author: dengchao
* @date: 2020/11/24 9:48
* @param: No such property: code for class: Script1
* @return:
*/
public static String byteArrayToBase64(ByteArrayOutputStream bos){
if(bos == null){
throw new BaseException(MessageConstant.A000001, "傳入的位元組輸入流物件錯誤");
}else{
byte[] byteArray = bos.toByteArray();
String resultString = ToBase64Utils.encoder.encodeBuffer(byteArray).trim();
return resultString;
}
}
}
核心原理就是將二進位制的輸出流轉換為Base64字串即可。

實際操作

工具類寫好之後,立馬和前端人員進行除錯,測試通過,能夠正常返回Base64的字串,並且前端人員拿到資料後,可以進一步做其他操作。

前端人員的程式碼能看懂一大半,使用的VUE元件。大致意思就是引用VUE元件生成一個excel檔案物件,然後在動態的拼接資料,最後顯示

在頁面中。

const workbook = await XLSX.read(res.responseBody, { type: 'base64', cellDates: true })
workbook.SheetNames.map(async item => {
if (item) {
const title = item
let html = await XLSX.utils.sheet_to_html(workbook.Sheets[item]).match(/<table>.*<\/table>/)[0]
const totalTr = html.match(/<\/tr>/g).length
const totalEmptyTd = html.match(/<td><\/td><\/tr>/g).length
// 如果每行結尾都是空 td,則過濾掉
if (totalTr === totalEmptyTd) {
html = html.replace(/<td><\/td><\/tr>/g, '</tr>')
}
this.xlsxHtml.push({title, html})
}
})

最終完成這個功能,PDF也是同樣的處理方式。對於一般人來說,這完全能夠滿足需求,實現線上預覽的功能,而且效果也很好。
可是對於專業人士來說,這種操作方式還是存在問題的,只要拿到檔案的Base64的字串資料,就可以拿到整個檔案的所有數
據。所以對於安全要求比較嚴格的業務來說,這個是不達標的。不過對於我們來說,已經滿足要求了。