最近项目中需要根据模板生成word文档,模板文件也是word文档。当时思考一下想用POI API来做,但是觉得用起来相对复杂。后来又找了一种方式,使用freemarker模板生成word文件,经过尝试觉得还是相对简单易行的。
使用freemarker模板生成word文档主要有这么几个步骤
1、创建word模板:因为我项目中用到的模板本身是word,所以我就直接编辑word文档转成freemarker(.ftl)格式的。
2、将改word文件另存为xml格式,注意使用另存为,不是直接修改扩展名。
3、将xml文件的扩展名改为ftl
4、编写java代码完成导出
使用到的jar:freemarker.jar (2.3.28) ,其中Configuration对象不推荐直接new Configuration(),仔细看Configuration.class文件会发现,推荐的是 Configuration(Version incompatibleImprovements) 这个构造方法,具体这个构造方法里面传的就是Version版本类,而且版本号不能低于2.3.0
闲言碎语不再讲,直接上代码
1 public static void exportDoc() { 2 String picturePath = "D:/image.png"; 3 Map<String, Object> dataMap = new HashMap<String, Object>(); 4 dataMap.put("brand", "海尔"); 5 dataMap.put("store_name", "海尔天津"); 6 dataMap.put("user_name", "小明"); 7 8 //经过编码后的图片路径 9 String image = getWatermarkImage(picturePath); 10 dataMap.put("image", image); 11 12 //Configuration用于读取ftl文件 13 Configuration configuration = new Configuration(new Version("2.3.0")); 14 configuration.setDefaultEncoding("utf-8"); 15 16 Writer out = null; 17 try { 18 //输出文档路径及名称 19 File outFile = new File("D:/导出优惠证明.doc"); 20 out = new BufferedWriter(new OutputStreamWriter(new 21 FileOutputStream(new File("outFile")), "utf-8"), 10240); 22 } catch (UnsupportedEncodingException e) { 23 e.printStackTrace(); 24 } catch (FileNotFoundException e) { 25 e.printStackTrace(); 26 } 27 // 加载文档模板 28 Template template = null; 29 try { 30 //指定路径,例如C:/a.ftl 注意:此处指定ftl文件所在目录的路径,而不是ftl文件的路径 31 configuration.setDirectoryForTemplateLoading(new File("C:/")); 32 //以utf-8的编码格式读取文件 33 template = configuration.getTemplate("导出优惠证明.ftl", "utf-8"); 34 } catch (IOException e) { 35 e.printStackTrace(); 36 throw new RuntimeException("文件模板加载失败!", e); 37 } 38 39 // 填充数据 40 try { 41 template.process(dataMap, out); 42 } catch (TemplateException e) { 43 e.printStackTrace(); 44 throw new RuntimeException("模板数据填充异常!", e); 45 } catch (IOException e) { 46 e.printStackTrace(); 47 throw new RuntimeException("模板数据填充异常!", e); 48 } finally { 49 if (null != out) { 50 try { 51 out.close(); 52 } catch (IOException e) { 53 e.printStackTrace(); 54 throw new RuntimeException("文件输出流关闭异常!", e); 55 } 56 } 57 } 58 }
因为很多时候我们根据模板生成文件需要添加水印,也就是插入图片
1 /*** 2 * 处理图片 3 * @param watermarkPath 图片路径 D:/image.png 4 * @return 5 */ 6 private String getWatermarkImage(String watermarkPath) { 7 InputStream in = null; 8 byte[] data = null; 9 try { 10 in = new FileInputStream(watermarkPath); 11 data = new byte[in.available()]; 12 in.read(data); 13 in.close(); 14 } catch (Exception e) { 15 e.printStackTrace(); 16 } 17 BASE64Encoder encoder = new BASE64Encoder(); 18 return encoder.encode(data); 19 }
注意点:
插入图片后的word转化为ftl模板文件(ps:水印图片可以在word上调整到自己想要的大小,然后在执行下面的步骤)
1、先另存为xml
2、将xml扩展名改为ftl
3、打开ftl文件, 搜索w:binData 或者 png可以快速定位图片的位置,图片 已经编码成0-Z的字符串了, 如下:
5、 将上述0-Z的字符串全部删掉,写上${image}(变量名随便写,跟dataMap里的key保持一致)后保存
6、也是创建一个Map, 将数据存到map中,只不过我们要把图片用代码进行编码,将其也编成0-Z的字符串,代码请看上边
至此一个简单的按照模板生成word并插入图片(水印)功能基本完成。