由于项目需要,要做一个导出word文档。导出的文档里需要有多张图片和文字。
- 先找一个word文档做模板。我的模板里就只用图片和图片对应的名字。图片需要先在模板文档中随便插入一张图片,而图片对应的名字用${photoTitle}来表示(photoTitle是我给图名这个变量的名字)。如下图
- 之后将模板文档保存为xml文件,像这样。之后再将文件后缀改成ftl,即skrd1.ftl。
- 打开ftl的模板文件,找到文档里赛的那个图片,在ftl里显示的是图片的base64编码。
将那一串编码改成${photoCode}(使用个占位符,photoCode是我对那串编码起的名字)
4. 多张图片的话,需要对图片那里使用freemarker的一个list循环<#list photoList as ph></#list>,我用idea打开了ftl模板文件,方便查看。如图。添加list的位置找了好久,我是需要图片和图名一起循环添加的,所以就把${photoCode}和${photoTitle}的范围一起放在list中,photoList是循环list的名字,ph是别名。(注意,多张图片时需要修改<w:binData w:name="..">和<v:imagedata src="..">这两个的内容,如果是固定的,那么就只会显示第一张图片。可以按照下图来修改。)
我的ftl模板就配置了这么多。接下来就是代码了
使用freemarker先引入依赖
<dependency> <groupId>org.freemarker</groupId> <artifactId>freemarker</artifactId> <version>2.3.23</version> </dependency>
这是我后端接口,fileCode是前端将多张图片编码后以逗号隔开的字符串。最后文件就是直接被下载下来的,不会产生中间文件。
@GetMapping(value = "/export", produces = "application/json;charset=utf-8")
public ResponseEntity<byte[]> exportWord(String fileCode) {
return fileService.exportWord(fileCode);
}
@Override
public ResponseEntity<byte[]> exportWord(String fileCode) {
/** 拆分图片编码 */
List<String> imageCodeList = getImageCodeList(fileCode);
/** 组装模块数据 */
Map<String, Object> dataMap = FileUtil.getTemplateMap(imageCodeList);
/** word文档导出名字 */
//todo 导出word文档的命名 ---待定
String fileName = "123.docx";
byte[] b = null;
try {
b = FileUtil.export(dataMap);
} catch (Exception e) {
e.printStackTrace();
}
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_OCTET_STREAM);
try {
headers.setContentDispositionFormData("attachment", new String(fileName.getBytes("utf-8"), "ISO_8859_1"));
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
ResponseEntity<byte[]> responseEntity = new ResponseEntity<byte[]>(b, headers, HttpStatus.OK);
return responseEntity;
}
PACKAGE_PATH是我模板所在的目录,TEMPLATE是模板名称。dataMap是把模板中需要的数据组装进去的map,即使是多张图片用了list,最后用的也只是一个map。map中放的list的名字需要和模板中list的名字相同,我这里都是photoList,别名无所谓。
public class FileUtil {
/**
* 模板所在目录
*/
private static final String PACKAGE_PATH = "src/main/resources/templates/";
/**
* 模板名称
*/
private static final String TEMPLATE = "skrdModel.ftl";
public static byte[] export(Map<String, Object> dataMap) throws IOException {
/** 使用freemarker中的Configuration,处理模板 */
Configuration configuration = new Configuration(Configuration.VERSION_2_3_21);
configuration.setDefaultEncoding("utf-8");
/** 加载模板 */
configuration.setDirectoryForTemplateLoading(new File(PACKAGE_PATH));
/** 引用模板 */
Template t = configuration.getTemplate(TEMPLATE);
File outFile = new File(TEMPLATE);
Writer writer = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(outFile), "utf-8"));
try {
/** 将dataMap中的数据填入模板中 */
t.process(dataMap, writer);
} catch (TemplateException e) {
e.printStackTrace();
}
writer.close();
return FileUtils.readFileToByteArray(outFile);
}
/**
* 将图片的base64编码,以及图片的名称放入map中
*
* @return
*/
public static Map<String, Object> getTemplateMap(List<String> imageCodeList) {
Map<String, Object> dataMap = new HashMap<>(16);
List<Map<String, Object>> photo = new ArrayList<>();
for (String imageCode : imageCodeList) {
Map<String, Object> ph = new HashMap<>(16);
/** 图表的名称 */
//todo 图表名称 --待定
ph.put("photoTitle", "插入的图");
/** 图片的base64编码 */
//todo 需要插入的图片的base64编码
ph.put("photoCode", imageCode);
photo.add(ph);
}
dataMap.put("photoList", photo);
return dataMap;
}
}
以上便是我导出的过程。请多指教