由於項目需要,要做一個導出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;
}
}
以上便是我導出的過程。請多指教