js將文件流轉為文件
需求:
前端通過ajax請求后端,根據接收前端的參數生成相應的文件,並將文件返回到前端提供下載。
方案1:
通過ajax請求后端,將生成的文件直接通過response.write的方式直接將生成的文返回。
該方案失敗,由於ajax請求返回的數據需要在回調函數中獲取,返回的data沒法直接轉為文件下載。
方案2:
通過ajax請求后端,將生成的文件轉為文件字符流返回到前端,前端使用Blob的方式將文件字符流數據寫入文件,再下載。
具體實現代碼如下
- 后端代碼
- 文件生成使用freemarker模版引擎
/** * * @param dataMap * word中需要展示的動態數據 * @param templateName * word模板名稱 eg:test.ftl * @param filePath * 文件生成的目標路徑,eg:D:/wordFile/ * @param fileName * 生成的文件名稱,eg:test.doc */
public File createWord(Map<String, Object> dataMap, String templateName, String filePath, String fileName) {
// 輸出文件
File outFile = null;
try {
// 創建配置實例
Configuration configuration = new Configuration();
// 設置編碼
configuration.setDefaultEncoding(encode);
// ftl模板文件統一放至 com.lun.template 包下面
configuration.setClassForTemplateLoading(FreemarkService.class, templatePath);
//設置錯誤顯示方式
configuration.setTemplateExceptionHandler(TemplateExceptionHandler.RETHROW_HANDLER);
// 設置對象包裝器
configuration.setObjectWrapper(new DefaultObjectWrapper());
//處理空值
configuration.setClassicCompatible(true);
// 獲取模板
Template template = configuration.getTemplate(templateName);
// 輸出文件
outFile = new File(filePath + File.separator + fileName);
// 如果輸出目標文件夾不存在,則創建
if (!outFile.getParentFile().exists()) {
outFile.getParentFile().mkdirs();
}
// 將模板和數據模型合並生成文件
Writer out = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(outFile), encode));
// 生成文件
template.process(dataMap, out);
// 關閉流
out.flush();
out.close();
} catch (Exception e) {
e.printStackTrace();
}
return outFile;
}
- 將生成的文件調用FileUtils工具類將文件轉為字節流數據
byte[] fileBuff = null;
try {
fileBuff = FileUtils.readFileToByteArray(file);
} catch (IOException e) {
e.printStackTrace();
}
- 將字節流數據轉為字符流數據
/** * 字節流轉字符流 * @param bytes * @return */
private char[] getChars(byte[] bytes) {
Charset cs = Charset.forName("UTF-8");
ByteBuffer bb = ByteBuffer.allocate(bytes.length);
bb.put(bytes).flip();
CharBuffer cb = cs.decode(bb);
return cb.array();
}
以上完成將文件轉為字符流后,可以直接返回到前端。
- 前端代碼
// 下載文件方法
var downloadDoc = function(content, filename) {
var eleLink = document.createElement('a');
eleLink.download = filename;
eleLink.style.display = 'none';
// 字符內容轉變成blob地址
var blob = new Blob([content]);
eleLink.href = URL.createObjectURL(blob);
// 自動觸發點擊
document.body.appendChild(eleLink);
eleLink.click();
// 然后移除
document.body.removeChild(eleLink);
};
@content:后端返回的文件字符流數據
@filename:下載時顯示的默認文件名
在ajax請求的回調函數中調用該方法即可觸發文件下載的操作事件。
二次優化(兼容IE11):
后端優化改進為返回base64字符串:
return Base64.encodeBase64String(fileBuff);
前端調整:
// 下載文件方法 var downloadDoc = function(fileData, filename) { var content = base64ToUint8Array(fileData); var blob = new Blob([content]); if (window.navigator.msSaveOrOpenBlob) { navigator.msSaveBlob(blob, filename); } else { var a = document.createElement('a'); var url = window.URL.createObjectURL(blob); if (!url) { url = window.webkitURL.createObjectURL(blob); } a.href = url; a.download = filename; a.click(); window.URL.revokeObjectURL(url); } }; //base64字符串轉array var base64ToUint8Array = function(base64String) { var rawData = window.atob(base64String); var len = rawData.length; var buffer = new ArrayBuffer(len); var outputArray = new Uint8Array(buffer); while (--len) { outputArray[len] = rawData.charCodeAt(len); } return outputArray; }