新需求html
最近接到一個新的需求,說是以前直接下載的PDF文件或者是Excel文件,如今不能直接下載,須要實如今線預覽功能。前端
前端人員拿到這個需求後,去看了一下之前的代碼,之前調用的下載接口和PDF文件預覽接口都是直接將文件成二進制java
流的形式,而後響應到前端。有的接口即便是動態生成PDF文件或者是Excel文件都是一樣的操做,也是將動態生成的對spring
象的二進制流寫入到響應對象中。前端人員遇到的問題是,若是直接將二進制流返回給前端,前端調用的時候,會直接apache
載而不能作其餘處理。而後找我協商,看看後端人員有沒有好的解決辦法,我去百度裏面查找,找到一個靠譜的方法,後端
大體意思就是將文件轉爲Base64格式的字符串數據,而後返回給前端,前端在去作響應的處理。安全
解決方案async
肯定方案後,而後我繼續去百度裏面查找如何將文件轉爲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的字符串數據,就能夠拿到整個文件的全部數據。因此對於安全要求比較嚴格的業務來講,這個是不達標的。不過對於咱們來講,已經知足要求了。