使用freemarker 模塊,導出word文檔(多圖帶圖名導出)

由於項目需要,要做一個導出word文檔。導出的文檔裏需要有多張圖片和文字。 

  1.     先找一個word文檔做模板。我的模板裏就只用圖片和圖片對應的名字。圖片需要先在模板文檔中隨便插入一張圖片,而圖片對應的名字用${photoTitle}來表示(photoTitle是我給圖名這個變量的名字)。如下圖
  2. 之後將模板文檔保存爲xml文件,像這樣。之後再將文件後綴改成ftl,即skrd1.ftl。
  3. 打開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;
    }
}

 

以上便是我導出的過程。請多指教

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章