使用Freemarker生成Word文档并在文档内添加Echarts图形报表或循环添加表格、图片数据

转载:https://blog.csdn.net/Alexshi5/article/details/84437300

一、制作.ftl后缀的word模板文件

1、新建一个word文档模板

        

使用其他文本编辑器编写表达式,如:Editplus

 

 2、将word文档另存为xml并改名为.ftl后缀的文件

另存完之后关闭word文档,将demo.xml的后缀修改为.ftl,然后使用文本编辑器打开demo.ftl文件

3、修改.ftl文件并生成最终的模板文件

① 修改图片的数据内容使用表达式代替

替换之后如下:

② 在数据表格中添加循环标签

 二、通过模板文件生成word文档

1、添加pom.xml的依赖


   
   
  1. <dependency>
  2. <groupId>org.freemarker </groupId>
  3. <artifactId>freemarker </artifactId>
  4. <version>2.3.23 </version>
  5. </dependency>

2、index.jsp中添加一个Echarts图形报表


   
   
  1. var option = {
  2. angleAxis: {
  3. type: 'category',
  4. data: [ '周一', '周二', '周三', '周四', '周五', '周六', '周日'],
  5. z: 10
  6. },
  7. radiusAxis: {
  8. },
  9. polar: {
  10. },
  11. series: [{
  12. type: 'bar',
  13. data: [ 1, 2, 3, 4, 3, 5, 1],
  14. coordinateSystem: 'polar',
  15. name: 'A',
  16. stack: 'a'
  17. }, {
  18. type: 'bar',
  19. data: [ 2, 4, 6, 1, 3, 2, 1],
  20. coordinateSystem: 'polar',
  21. name: 'B',
  22. stack: 'a'
  23. }, {
  24. type: 'bar',
  25. data: [ 1, 2, 3, 4, 1, 2, 5],
  26. coordinateSystem: 'polar',
  27. name: 'C',
  28. stack: 'a'
  29. }],
  30. legend: {
  31. show: true,
  32. data: [ 'A', 'B', 'C']
  33. }
  34. };
  35. var myChart = echarts.init( document.getElementById( "content"));
  36. myChart.setOption(option);
  37. //获取Echart图形报表生成的Base64编码格式的数据
  38. var imgData = myChart.getConnectedDataURL();
  39. $.post( '/demo/word',{ 'imgData':imgData}, function (data) {
  40. alert(data);
  41. }, 'json');

3、后台处理请求并设置模板数据


   
   
  1. @Controller
  2. @RequestMapping("/demo")
  3. public class DemoController {
  4. @RequestMapping("/word")
  5. @ResponseBody
  6. public String generateWord(String imgData){
  7. // 传递过程中 "+" 变为了 " " ,所以需要替换
  8. String newImageInfo = imgData.replaceAll( " ", "+");
  9. // 数据中:data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAABI4AAAEsCAYAAAClh/jbAAA ...
  10. // 在"base64,"之后的才是图片信息
  11. String[] arr = newImageInfo.split( "base64,");
  12. //添加模板数据
  13. Map<String,Object> dataMap = new HashMap<>();
  14. dataMap.put( "userName", "张三");
  15. dataMap.put( "imgData",arr[ 1]);
  16. Person person1 = new Person( "李四", "男", 36, "18811240001");
  17. Person person2 = new Person( "王五", "女", 22, "18811240002");
  18. Person person3 = new Person( "赵六", "男", 46, "18811240003");
  19. List<Person> personList = new ArrayList<>();
  20. personList.add(person1);
  21. personList.add(person2);
  22. personList.add(person3);
  23. dataMap.put( "personList",personList);
  24. //文件生成路径
  25. String wordFilePath = "E:\\ftl";
  26. //文件生成名称(因为是2003版本的xml模板,这里使用.doc后缀,如果使用.docx后缀生成的文件有问题)
  27. String wordFileName = "演示文档.doc";
  28. //模板路径
  29. String templatePath = "E:\\ftl";
  30. //模板文件名称
  31. String templateFileName = "demo.ftl";
  32. //生成word文档
  33. Boolean result = WordUtil.writeWordReport(wordFilePath, wordFileName, templatePath, templateFileName, dataMap);
  34. if(result){
  35. return "success";
  36. } else {
  37. return "error";
  38. }
  39. }
  40. }

4、生成word文档的工具类方法


   
   
  1. /**
  2. * 根据freemarker生成word文档并存到指定目录
  3. * @param wordFilePath word文件生成的目录
  4. * @param wordFileName word文件名
  5. * @param templatePath 模板文件所在的目录
  6. * @param templateFileName 模板文件名
  7. * @param beanParams 生成word文件所需要的模板数据
  8. * @return
  9. */
  10. public static Boolean writeWordReport(String wordFilePath,String wordFileName,
  11. String templatePath,String templateFileName, Map<String, Object> beanParams) {
  12. Configuration config = new Configuration(Configuration.getVersion());
  13. Writer out = null;
  14. try {
  15. config.setDirectoryForTemplateLoading( new File(templatePath));
  16. Template template = config.getTemplate(templateFileName, "UTF-8");
  17. //获取文件目录,如果不存在则创建
  18. String filePath = "";
  19. int index = wordFilePath.lastIndexOf(File.separator);
  20. if(index != wordFilePath.length()- 1){
  21. filePath = wordFilePath+ File.separator;
  22. } else {
  23. filePath = wordFilePath;
  24. }
  25. File file1 = new File(filePath);
  26. if(!file1.exists()){
  27. file1.mkdirs();
  28. }
  29. //输出文件
  30. File file = new File(filePath+wordFileName);
  31. FileOutputStream fos = new FileOutputStream(file);
  32. out = new OutputStreamWriter(fos, "UTF-8");
  33. template.process(beanParams, out);
  34. return true;
  35. } catch (Exception e) {
  36. e.printStackTrace();
  37. return false;
  38. } finally{
  39. try {
  40. if(out != null) {
  41. out.close();
  42. }
  43. } catch (IOException e) {
  44. e.printStackTrace();
  45. }
  46. }
  47. }

5、最终生成的word文档如下:

 

6、补充一:解决传空值导致程序报空指针异常的问题

        如果生成文档时报如下错误:

        Tip: If the failing expression is known to be legally refer to something that's sometimes null or missing, either specify a default value like myOptionalVar!myDefault, or use <#if myOptionalVar??>when-present<#else>when-missing</#if>. (These only cover the last step of the expression; to cover the whole expression, use parenthesis: (myOptionalVar.foo)!myDefault, (myOptionalVar.foo)??

        这有可能是你在传值过程中传了空值,导致模板引擎无法获取参数值,这时可以将表达式更改为${person.name?default('')}这种形式,这个表达式的意思是如果为空值就替换成'', 这样即便不小心传了空值也不会导致程序出错。

7、补充二:解决导出图片缺失或图片不完整问题

        实际开发中会遇到有一些图形报表导出图片时不完整,比如:折线图导出时只有点却没有线条,这是由于折线图有动画,而生成的图片是在动画还未结束时就生成的。解决方法就是在配置项中关闭动画效果。

8、补充三 :解决循环添加多张图片重复问题

        按照上面的思路,既然可以循环添加数据,那肯定也可以循环添加图片,但是当我们使用循环标签添加图片时,却发现生成的多张图片都是一样的,这是由于我们没有修改模板文件中的图片标签的属性导致的。需要修改的地方有两个一个是:<w:binData></w:binData>标签的w:name属性,一个是:<v:imagedata></v:imagedata>标签的src属性。示例如下:

         上面这个属性的含义指的是当前文档的第几张图片,如果我们的图片集合数据从下标0开始则这里的后缀要修改成"下标+1"的形式。伪代码示例如下:


   
   
  1. <#list dataList as obj> <!--循环开始,obj_index代表当前循环对象的索引,从下标0开始-->
  2. <!--伪代码-->
  3. <w:binData w:name="${"wordml://0300000"+ obj_index+1 +".png"}" xml:space="preserve">${obj.imgUrl?default('')} </w:binData>
  4. <v:imagedata src="${"wordml://0300000"+ obj_index+1 +".png"}" o:title=""/>
  5. <#/list> <!--循环结束-->

         如果文档前面已经有一张图片了,然后才开始循环图片呢?那循环开始的图片就是当前文档的第二张图片,那后缀就要改成“下标+2”的形式,以此类推。示例如下:

参考:

1、制作freemarker模板文件生成word文档

2、前端EChart图表转换为图片保存到服务器路径

3、使用JFreeChart做成柱状图写入word的总结

4、freemarker教程之list循环

5、FreeMarker 对null值的处理技巧

6、freemarker 图片输出、多张图片输出(图片重复原因及解决)

  • 1
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
SpringBoot_Freemarker生成Word_多个表格+两层嵌套循环; 步骤说明: 1.用Microsoft Office Word打开word原件;将文档需要动态生成的内容,替换为属性名 ${name} 2.另存为,选择保存类型Word 2003 XML 文档(*.xml) 3.用Firstobject free XML editor打开文件,选择Tools下的Indent【或者按快捷键F8】格式化文件内容。左边是文档结构,右边是文档内容; 4. 文档生成后有时需要手动修改,查找第一步设置的属性名,可能会产生类似${n.....ame}类似的样子,我们将将名字间的标签删掉,恢复为${name} 5. word模板表格,需要循环的位置, 用 标签将第二对 标签(即除表头的w:tr标签后的一对)包围起来 同时表格内的属性例如${name},在这里需要修改为${user.name} (userList是集合在dataMap的key, user是集合的每个元素, 类似), 如图: PLUS:若表格之外还有嵌套的循环,也需要用,注意这里的标签不要和某对其他标签交叉,不可以出现这种 6. 标识替换完之后,另存为.ftl后缀文件即可。 代码里是相对有一丢丢复杂的,两层嵌套循环; 总(dataMap) deptName 部门名 list(Table)表的集合 table1(map) table-名字 ${map.table} tableName-文名 ${map.tableName} columnCount-字段数 ${map.columnCount} recordCount-记录数 ${map.recordCount} listA-List--表格1 map.listA column Model属性——字段名 ${model.column} columnName Model属性——字段文名 ${model.column} rate Model属性——字段占比 ${model.rate} nullValueCount Model属性——字段空值数 ${model.nullValueCount} listB-List--表格2 map.listB …… listC-List--表格3 map.listC …… table2 table-名字 ${map.table} tableName-文名 ${map.tableName} columnCount-字段数 ${map.columnCount} recordCount-记录数 ${map.recordCount} listA-List--表格1 map.listA column Model属性——字段名 ${model.column} columnName Model属性——字段文名 ${model.column} rate Model属性——字段占比 ${model.rate} nullValueCount Model属性——字段空值数 ${model.nullValueCount} listB-List--表格2 map.listB …… listC-List--表格3 map.listC …… table3 ……
非常抱歉,之前的回答有误,现在我会更全面地回答您的问题。 FreeMarker、POI 和 Poi-tl 都可以用于生成 Word 文档,但它们之间存在一些区别,主要体现在以下方面: 1. 生成方式 FreeMarker 是基于模板的生成方式,需要程序员先创建一个 Word 文档模板,然后使用 FreeMarker 引擎将数据模型数据填充到模板,并生成一个完整的 Word 文档。 POI 和 Poi-tl 则是使用代码直接对 Word 文档进行操作,可以读取、写入、修改、创建 Word 文档,并提供了针对 Word 模板操作的 API,例如修改样式、替换变量、插入图片等。 2. 操作方法 FreeMarker 和 Poi-tl 都是使用 API 对 Word 文档进行操作,例如修改样式、替换变量、插入图片等;而 POI 则是使用 POI API 操作 Word 文档。 3. 使用场景 由于 FreeMarker 和 Poi-tl 是基于模板的生成方式,因此适用于需要批量生成相似结构的 Word 文档的场景,例如生成合同、报告、简历等;而 POI 则适用于需要对 Word 文档进行灵活操作的场景,例如读取、修改、创建、删除等。 4. 功能 POI 和 Poi-tl 都提供了丰富的 API,可以对 Word 文档进行各种操作,例如读取、写入、修改、创建、删除、格式化等等;而 FreeMarker 则主要是通过填充模板来生成 Word 文档,并提供了一些基本的操作 API,例如对模板的变量进行替换、对模板的样式进行修改、插入图片等等。 5. 性能 由于 FreeMarker 和 Poi-tl 都是基于模板的生成方式,因此生成 Word 文档的性能相对较高,特别是在批量生成 Word 文档时更为明显;而 POI 则需要直接对文档进行操作,因此在生成 Word 文档时性能相对较低。 综上所述,FreeMarker、POI 和 Poi-tl 都是用于生成 Word 文档的工具,它们之间有着不同的生成方式、操作方法、使用场景、功能和性能。选择哪个工具应根据具体的需求和场景进行判断。如果需要批量生成相似结构的 Word 文档,可以选择 FreeMarker 或 Poi-tl;如果需要对 Word 文档进行灵活操作,可以选择 POI。
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值