先看依赖的包:
<dependency>
<groupId>org.freemarker</groupId>
<artifactId>freemarker</artifactId>
<version>2.3.28</version>
</dependency>
整体思路:
1.先构建一个需要生成的word报告模板,我只需要把里边关键位置的文件和图片替换掉就可以了,那就必须要求word样式固定,里边的格式必须是这样
2.把word文件用压缩包工具打开,解压出这个xml文件,后边主要操作这个文件,把内容替换掉就可以,必须是07以后的版本,03的word不支持
处理办法:
把文件用xml编辑器打开,我用的是notepad++,必须要有xml的格式化插件,要不然里边格式是乱的,格式化之后,看到这样的东西
处理号这个xml之后,就可以开始写代码了,
```java
static Template template;
static{
//创建配置实例
Configuration configuration = new Configuration();
//设置编码
configuration.setDefaultEncoding("UTF-8");
//ftl模板文件统一放至/包下面
configuration.setClassForTemplateLoading(CreatWordService.class,"/");
// 获取模板
try {
template = configuration.getTemplate("document.xml");
template.setOutputEncoding("UTF-8");
} catch (IOException e) {
log.error("[加载模板xml失败:{}]",e.getMessage());
e.printStackTrace();
}
}
下来使用它
主方法,生成报告的流程
```Writer out = null;
try {
out = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(xmlTemp),"UTF-8"));
//1.需要动态传入的数据
Map<String, Object> root = initRootData(c3Entiy);
template.process(root, out);
out.close();
//3.把填充完成的xml写入到docx中
log.info("[把填充完成的xml写入到docx中]");
String reportPath = outDocx(new File(xmlTemp), Const.DOCX_TEMPLATE, toFilePath,c3Entiy);
log.info("[生成报告路径:{}]",reportPath);
return reportPath;
} catch (IOException e) {
log.info("[生成报告异常:{}]",e.getMessage());
e.printStackTrace();
return "";
} catch (TemplateException e) {
log.info("[生成报告异常:{}]",e.getMessage());
e.printStackTrace();
return "";
}
主要的两个方法:
private Map<String, Object> initRootData(C3ot c3Entiy) {
Map<String, Object> root= new HashMap<>();
root.clear();
root.put("cheCiHao", c3Entiy.getTrainnum()); //车次号
Calendar cal = Calendar.getInstance();
cal.setTime(c3Entiy.getPreDisctime());
root.put("guZhangShiJian_Nian", String.valueOf(cal.get(Calendar.YEAR))); //故障时间年份
root.put("guZhangShiJian_Yue", cal.get(Calendar.MONTH) + 1); //故障时间月份
List<Abislayer3message> abislayer3messageList = abislayer3messageMapper.selectRecordByC3ot(c3Entiy);
//这个list里边放map,map的key就是xml里表格配置的key,value是需要写在报告里的内容,这个方法不全,我只是举个例子,
List<Map<String,String>> MT1_PRI_1_List = initDataListService.getMT1_PRI_1_List(c3Entiy);
root.put("MT1_PRI_1_List",MT1_PRI_1_List);
return root;
}
这个方法也比较重要,遍历word模板的解压包,找到对应的文件,替换掉
/**
*
* @param documentFile 动态生成数据的docunment.xml文件
* @param docxTemplate docx的模板
* @param toFilePath 需要导出的文件路径
* @param c3Entiy
* @throws ZipException
* @throws IOException
*/
public String outDocx(File documentFile, String docxTemplate, String toFilePath, C3ot c3Entiy)
{
try {
//String fileName = CreatWordService.class.getClassLoader().getResource(docxTemplate).toURI().getPath();
File docxFile = new File(docxTemplate);
ZipFile zipFile = new ZipFile(docxFile);
Enumeration<? extends ZipEntry> zipEntrys = zipFile.entries();
ZipOutputStream zipout = new ZipOutputStream(new FileOutputStream(toFilePath));
int len=-1;
byte[] buffer=new byte[1024];
while(zipEntrys.hasMoreElements()) {
ZipEntry next = zipEntrys.nextElement();
InputStream is = zipFile.getInputStream(next);
//把输入流的文件传到输出流中 如果是word/document.xml由我们输入
zipout.putNextEntry(new ZipEntry(next.toString()));
switch(next.toString()){
case "word/media/image1.png" :
//生成图表
log.info("[准备生成图表:{}]","chart1");
String image1Path = createChartService.createChart(c3Entiy,"chart12");
if(null == image1Path || "".equals(image1Path)){
break;
}
File file1 = new File(image1Path);
System.out.println("path----------->" + file1.getAbsolutePath());
InputStream in1 = new FileInputStream(file1);
while((len = in1.read(buffer))!=-1){
zipout.write(buffer,0,len);
}
in1.close();
file1.delete();
break;
case "word/media/image2.png" :
log.info("[准备生成图表:{}]","chart2");
String image2Path = createChartService.createChart(c3Entiy,"chart34");
if(null == image2Path || "".equals(image2Path)){
break;
}
File file2 = new File(image2Path);
InputStream in2 = new FileInputStream(file2);
while((len = in2.read(buffer))!=-1){
zipout.write(buffer,0,len);
}
in2.close();
file2.delete();
break;
case "word/document.xml" :
InputStream in = new FileInputStream(documentFile);
while((len = in.read(buffer))!=-1){
zipout.write(buffer,0,len);
}
in.close();
break;
default :
while((len = is.read(buffer))!=-1){
zipout.write(buffer,0,len);
}
is.close();
}
}
zipout.close();
log.info("[准备删除模板文件:{}]",documentFile.getAbsolutePath());
documentFile.delete();
}catch (FileNotFoundException e) {
log.info("[压缩文件时异常:{}]",e.getMessage());
e.printStackTrace();
return "";
} catch (ZipException e) {
log.info("[压缩文件时异常:{}]",e.getMessage());
e.printStackTrace();
return "";
} catch (IOException e) {
log.info("[压缩文件时异常:{}]",e.getMessage());
e.printStackTrace();
return "";
}
return toFilePath;
}
里边有个替换图片的方法,如果在word文件中有图片,解压后的word文件下,按照代码中的对应目录路径,就能找到图片,替换掉就可以了,很好理解。
至此就大功告成了