使用其他文本编辑器编写表达式,如:Editplus
另存完之后关闭word文档,将demo.xml的后缀修改为.ftl,然后使用文本编辑器打开demo.ftl文件
替换之后如下:
org.freemarker
freemarker
2.3.23
var option = {
angleAxis: {
type: 'category',
data: ['周一', '周二', '周三', '周四', '周五', '周六', '周日'],
z: 10
},
radiusAxis: {
},
polar: {
},
series: [{
type: 'bar',
data: [1, 2, 3, 4, 3, 5, 1],
coordinateSystem: 'polar',
name: 'A',
stack: 'a'
}, {
type: 'bar',
data: [2, 4, 6, 1, 3, 2, 1],
coordinateSystem: 'polar',
name: 'B',
stack: 'a'
}, {
type: 'bar',
data: [1, 2, 3, 4, 1, 2, 5],
coordinateSystem: 'polar',
name: 'C',
stack: 'a'
}],
legend: {
show: true,
data: ['A', 'B', 'C']
}
};
var myChart = echarts.init(document.getElementById("content"));
myChart.setOption(option);
//获取Echart图形报表生成的Base64编码格式的数据
var imgData = myChart.getConnectedDataURL();
$.post('/demo/word',{'imgData':imgData},function (data) {
alert(data);
},'json');
@Controller
@RequestMapping("/demo")
public class DemoController {
@RequestMapping("/word")
@ResponseBody
public String generateWord(String imgData){
// 传递过程中 "+" 变为了 " " ,所以需要替换
String newImageInfo = imgData.replaceAll(" ", "+");
// 数据中:data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAABI4AAAEsCAYAAAClh/jbAAA ...
// 在"base64,"之后的才是图片信息
String[] arr = newImageInfo.split("base64,");
//添加模板数据
Map dataMap = new HashMap<>();
dataMap.put("userName","张三");
dataMap.put("imgData",arr[1]);
Person person1 = new Person("李四", "男", 36, "18811240001");
Person person2 = new Person("王五", "女", 22, "18811240002");
Person person3 = new Person("赵六", "男", 46, "18811240003");
List personList = new ArrayList<>();
personList.add(person1);
personList.add(person2);
personList.add(person3);
dataMap.put("personList",personList);
//文件生成路径
String wordFilePath = "E:\\ftl";
//文件生成名称(因为是2003版本的xml模板,这里使用.doc后缀,如果使用.docx后缀生成的文件有问题)
String wordFileName = "演示文档.doc";
//模板路径
String templatePath = "E:\\ftl";
//模板文件名称
String templateFileName = "demo.ftl";
//生成word文档
Boolean result = WordUtil.writeWordReport(wordFilePath, wordFileName, templatePath, templateFileName, dataMap);
if(result){
return "success";
}else {
return "error";
}
}
}
/**
* 根据freemarker生成word文档并存到指定目录
* @param wordFilePath word文件生成的目录
* @param wordFileName word文件名
* @param templatePath 模板文件所在的目录
* @param templateFileName 模板文件名
* @param beanParams 生成word文件所需要的模板数据
* @return
*/
public static Boolean writeWordReport(String wordFilePath,String wordFileName,
String templatePath,String templateFileName, Map beanParams) {
Configuration config = new Configuration(Configuration.getVersion());
Writer out = null;
try {
config.setDirectoryForTemplateLoading(new File(templatePath));
Template template = config.getTemplate(templateFileName, "UTF-8");
//获取文件目录,如果不存在则创建
String filePath = "";
int index = wordFilePath.lastIndexOf(File.separator);
if(index != wordFilePath.length()-1){
filePath = wordFilePath+ File.separator;
}else {
filePath = wordFilePath;
}
File file1 = new File(filePath);
if(!file1.exists()){
file1.mkdirs();
}
//输出文件
File file = new File(filePath+wordFileName);
FileOutputStream fos = new FileOutputStream(file);
out = new OutputStreamWriter(fos, "UTF-8");
template.process(beanParams, out);
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}finally{
try {
if(out != null) {
out.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
如果生成文档时报如下错误:
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('')}这种形式,这个表达式的意思是如果为空值就替换成'', 这样即便不小心传了空值也不会导致程序出错。
实际开发中会遇到有一些图形报表导出图片时不完整,比如:折线图导出时只有点却没有线条,这是由于折线图有动画,而生成的图片是在动画还未结束时就生成的。解决方法就是在配置项中关闭动画效果。
按照上面的思路,既然可以循环添加数据,那肯定也可以循环添加图片,但是当我们使用循环标签添加图片时,却发现生成的多张图片都是一样的,这是由于我们没有修改模板文件中的图片标签的属性导致的。需要修改的地方有两个一个是:
上面这个属性的含义指的是当前文档的第几张图片,如果我们的图片集合数据从下标0开始则这里的后缀要修改成"下标+1"的形式。伪代码示例如下:
<#list dataList as obj>
${obj.imgUrl?default('')}
<#/list>
如果文档前面已经有一张图片了,然后才开始循环图片呢?那循环开始的图片就是当前文档的第二张图片,那后缀就要改成“下标+2”的形式,以此类推。示例如下:
参考:
1、制作freemarker模板文件生成word文档
2、前端EChart图表转换为图片保存到服务器路径
3、使用JFreeChart做成柱状图写入word的总结
4、freemarker教程之list循环
5、FreeMarker 对null值的处理技巧
6、freemarker 图片输出、多张图片输出(图片重复原因及解决)