js将文件流转为文件
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; }
初心回归,时光已逝!