最近對(duì)echarts的使用很多,并且做了很多有意思的,很無解的需求,本文主要講述如何實(shí)現(xiàn)將echarts輸出到word。
- 實(shí)現(xiàn)方式:
前端:echarts轉(zhuǎn)base64,將base64傳遞給后端
后端:接受base64,配置xml文件,將xml傳遞給前端
前端:接受xml,通過瀏覽器下載,導(dǎo)出word文檔
首先,前端echarts轉(zhuǎn)base64
- echarts的實(shí)現(xiàn)原理其實(shí)就是通過canvas繪制的,canvas提供了api,可將canvas轉(zhuǎn)換為base64。
前端需要設(shè)置echarts的背景色,否則導(dǎo)出的圖片為白色背景,在word文件中不易查看數(shù)據(jù)。
// 找到繪制echarts的canvas節(jié)點(diǎn)
let canvas = $('#mychart').find('canvas')[0]
// 調(diào)用toDataURL,將canvas轉(zhuǎn)換為base64
let myBase64 = canvas.toDataURL('png')
-----
調(diào)用接口,將base64傳遞給后臺(tái)。base64的有效長(zhǎng)度需要去除前22位,前端/后端都可單獨(dú)處理
-----
后端接收base64資源,配置xml
- 在項(xiàng)目中添加freemarker的依賴,或者引入jar包
- 使用word做一個(gè)需要的文件模版,并將其中需要改變的部分編程變量(圖片建議先貼上大小相等的其他圖片)
- 制作完成之后,將其另存為xml格式。
- 將轉(zhuǎn)存的 xml 文件使用文本編輯器例如 notepad++ 等打開,將其中紅色區(qū)域的刪除掉,那些是圖片的base64編碼后的信息,然后替換為一個(gè)圖片變量,傳入新的圖片的 base64 編碼即可導(dǎo)出你所要的圖片,一般來說導(dǎo)出的圖片都是由前臺(tái) echarts 等工具生成的
- 導(dǎo)出列表的話還需要在 xml 中找到 <w:tr> ,在其前加入 <#list list as list> (注意第一個(gè)list 不能變,第二個(gè)list 為變量名,第三個(gè)list 為別名),和</w:tr> 后加入 </#list> ,此外需將 name 改成 list.name,gender 改成 list.gender 。
- 復(fù)制 xml 粘貼至項(xiàng)目文件中,并將后綴名更改為 .ftl
- 編寫導(dǎo)出 Word 工具類
//加載模板(路徑)數(shù)據(jù),也可使用setServletContextForTemplateLoading()方法放入到web文件夾下
config.setClassForTemplateLoading(this.getClass(), "/templates");
//設(shè)置異常處理器 這樣的話 即使沒有屬性也不會(huì)出錯(cuò) 如:${list.name}...不會(huì)報(bào)錯(cuò)
config.setTemplateExceptionHandler(TemplateExceptionHandler.IGNORE_HANDLER);
try {
if(templateName.endsWith(".ftl")) {
templateName = templateName.substring(0,
templateName.indexOf(".ftl"));
}
Template template = config.getTemplate(templateName + ".ftl");
response.setContentType("application/msword");
response.setHeader("Content-disposition", "attachment;filename="+ URLEncoder.encode(fileName, StandardCharsets.UTF_8));
OutputStream outputStream = response.getOutputStream();
Writer out = new BufferedWriter(new OutputStreamWriter(outputStream));
//將模板中的預(yù)先的代碼替換為數(shù)據(jù)
template.process(dataMap, out);
log.info("由模板文件:" + templateName + ".ftl" + " 生成Word文件 " + fileName + " 成功??!");
out.flush();
} catch (TemplateNotFoundException e) {
log.info("模板文件未找到");
e.printStackTrace();
} catch (MalformedTemplateNameException e) {
log.info("模板類型不正確");
e.printStackTrace();
} catch (TemplateException e) {
log.info("填充模板時(shí)異常");
e.printStackTrace();
} catch (IOException e) {
log.info("IO異常");
e.printStackTrace();
}
}
- 編寫簡(jiǎn)單的Controller方法
/**
* @param image 注意該image參數(shù)為前臺(tái)傳過來圖片
*/
@PostMapping("/exportWord")
public void exportWord(HttpServletResponse response, @RequestParam("image") MultipartFile image){
ExportWordUtil ewUtil = new ExportWordUtil();
Map<String, Object> dataMap = new HashMap<>();
dataMap.put("title", "導(dǎo)出word文檔");
Base64.Encoder base64 = Base64.getEncoder();
try {
dataMap.put("image", base64.encodeToString(image.getBytes()));
} catch (Exception e){
}
List<User> userList = new ArrayList<>();
userList.add(new User("張三","男"));
userList.add(new User("李四","男"));
userList.add(new User("王五","女"));
dataMap.put("list", userList);
ewUtil.exportWord(dataMap, "test.ftl", response, "導(dǎo)出word文檔");
}
- 啟動(dòng)項(xiàng)目,傳入某個(gè)圖片進(jìn)行測(cè)試,這里選用的是前端傳圖片的 base64 編碼的字符串。
- 讀取.ftl文件,返回給前端。
前端接收返回的xml,輸出word文檔
$.get('../url', function (res){
let xml = res.data // 后端返回的xml。
let blob = new Blob([xml], {
type: `application/msword` //word文檔為msword,pdf文檔為pdf,msexcel 為excel
});
let objectUrl = URL.createObjectURL(blob);
let link = document.createElement("a");
let fname = `echarts.doc`; //下載文件的名字+后綴名
link.href = objectUrl;
link.setAttribute("download", fname);
link.click();
})
本文只是敘述了一種比較簡(jiǎn)易的方式,其實(shí)關(guān)于echarts轉(zhuǎn)圖片或者base64,有echarts自帶的api,以及后端配置xml時(shí)也有其他方式。后續(xù)會(huì)補(bǔ)充一些更加簡(jiǎn)易,正規(guī)的方式。如有錯(cuò)誤,還望指正,如有不懂,可評(píng)論留言,小編一定盡力解答。