版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/fenfenguai/article/details/78731331
之前写过一篇利用Freemarker模板生成doc的博客,不过那个博客有点缺陷,不支持生成docx格式的文档。所以,这里补充一篇,生成docx或doc格式的文档以具体的docx模板或者doc模板为主。这里以docx为例。
具体思路:
把docx文档修改为ZIP格式(修改.docx后缀名为.zip)
获取zip里的document.xml文档以及_rels文件夹下的document.xml.rels文档
把内容填充到document.xml里,以及图片配置信息填充至document.xml.rels文档里
在输入docx文档的时候把填充过内容的的 document.xml、document.xml.rels用流的方式写入zip(详见下面代码)。
把图片写入zip文件下word/media文件夹中
输出docx文档
docx模板修改成zip格式后的信息如下(因为word文档本身就是ZIP格式实现的)
这里写图片描述
这里写图片描述
document.xml里存放主要数据
media存放图片信息
_rels里存放配置信息
注意:如果docx模板里的图片带有具体路径的话,则图片的格式不受限制。
这里写图片描述
如果docx模板里里图片信息不带路径,则模板仅支持和模板图片类型一致的图片。
这里写图片描述
交代了这么多,下面就可以干货。
准备好docx模板
这里写图片描述
这里写图片描述
把docx文档修改为ZIP格式(修改.docx后缀名为.zip)
获取zip文件里的word文件夹下的document.xml以及_rels文件夹里的document.xml.rels文件作为模板。
这里写图片描述
这里写图片描述
这里写图片描述
注意:这里图片配置信息是根据 rId来获取的。docx模板总的${img_warn}就是rId的具体值。
为了避免重复,我的图片rId从17开始(在我没有修改之前,里面最大的rId是rId17)。
填充模板信息、写入图片信息。
String temp_path = File.separator+"template"+File.separator+"test";
// HttpServletRequest request = new MockHttpServletRequest();
// String base_path = request.getSession().getServletContext().getRealPath(File.separator)+temp_path+File.separator;
// System.out.println(base_path);
Map data_map = new HashMap<>();
// 1) 总体环比分析
List res = new ArrayList<>();
res.add("本周报警总数环比上周上升5.62%,上周报警数20882,本周报警数22055。");
data_map.put("data_all_summary_title",res);
res = new ArrayList<>();
res.add("本周高架总数环比上周上升16.55%,上周报警数2405,本周报警数2803。");
data_map.put("data_all_content_title",res);
res = new ArrayList<>();
res.add("\uF06C\t本周断面环比上周上升12.8%,上周报警数547,本周报警数617。");
res.add("\uF06C\t本周上匝道环比上周上升17.5%,上周报警数1834,本周报警数2155。");
res.add("\uF06C\t本周下匝道环比上周上升29.17%,上周报警数24,本周报警数31。");
data_map.put("data_all_content",res);
res = new ArrayList<>();
res.add("本周路口环比上周上升4.19%,上周报警数18477,本周报警数19252。");
data_map.put("data_all_end",res);
String output_path = "D:/export/";
String output_file_name = System.currentTimeMillis()+"_freemarker_word.docx";
// FreemarkerWordUtils.createDocx(data_map,file_name,"document.xml",output_path, output_path+file_name);
/**
*
* @param dataMap 参数数据
* @param docxTemplate docx模板名称
* @param xmltemplateName xml模板名称
* @param xmltConfigemplateName xml配置主模板名称 一般用来配置图片、样式信息
* @param temp_path 模板存放路径
* @param output_path 产出路径
* @param template_rir 模板文件下的子文件夹
* @param output_file_name 产出文件名称
*/
List picNameList = new ArrayList<>();
picNameList.add("pic1.png");
Map picFiles = new HashMap<>();
picFiles.put("pic1.png","D:\\export\\png\\pic1.png");
picNameList.add("pic2.png");
picFiles.put("pic2.png","D:\\export\\png\\pic2.png");
picNameList.add("pic3.png");
picFiles.put("pic3.png","D:\\export\\png\\pic3.png");
picNameList.add("pic4.png");
picFiles.put("pic4.png","D:\\export\\png\\pic4.png");
picNameList.add("pic5.png");
picFiles.put("pic5.png","D:\\export\\png\\pic5.png");
picNameList.add("pic6.png");
picFiles.put("pic6.png","D:\\export\\png\\pic6.png");
picNameList.add("summary_pic7.png");
picFiles.put("summary_pic7.png","D:\\export\\png\\summary_pic7.png");
picNameList.add("summary_pic8.png");
picFiles.put("summary_pic8.png","D:\\export\\png\\summary_pic8.png");
picNameList.add("summary_pic9.png");
picFiles.put("summary_pic9.png","D:\\export\\png\\summary_pic9.png");
data_map.put("picNameList",picNameList);
data_map.put("picFiles",picFiles);
String base_path = "D:\\idea_workspace\\alarm\\alarm\\src\\main\\resources\\template\\test\\";
FreemarkerWordUtils.createDocx(data_map, "ptbjjcxbg.doc", "document.xml","document.xml.rels", temp_path,base_path, output_path, output_file_name);
/**
* 生成主数据模板xml
* @param dataMap 数据参数
* @param templateName 模板名称
* @param pathPrefix 模板路径
* @param filePath 生成路径
*/
public static void createTemplateXml(Map dataMap, String templateName, String pathPrefix ,String filePath){
try {
//创建配置实例
Configuration configuration = new Configuration();
//设置编码
configuration.setDefaultEncoding("UTF-8");
//ftl模板文件统一放至 com.lun.template 包下面
// configuration.setDirectoryForTemplateLoading(new File("D:/idea_workspace/alarm/alarm/src/main/resources/template/"));
// configuration.setClassForTemplateLoading(FreemarkerWordUtils.class,"/template/doc");
configuration.setClassForTemplateLoading(FreemarkerWordUtils.class,pathPrefix);
//获取模板
Template template = configuration.getTemplate(templateName);
//输出文件
File outFile = new File(filePath);
//如果输出目标文件夹不存在,则创建
if (!outFile.getParentFile().exists()){
outFile.getParentFile().mkdirs();
}
//将模板和数据模型合并生成文件
Writer out = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(outFile),"UTF-8"));
//生成文件
template.process(dataMap, out);
//关闭流
out.flush();
out.close();
} catch (Exception e) {
e.printStackTrace();
}
}
/**
*
* @param dataMap 参数数据
* @param docxTemplate docx模主板名称
* @param xmltemplateName xml主模板名称
* @param xmltConfigemplateName xml配置主模板名称 一般用来配置图片、样式信息
* @param temp_path 模板存放路径
* @param base_path 模板实际路径
* @param output_path 产出路径
* @param output_file_name 产出文件名称
*/
public static void createDocx(Map dataMap,String docxTemplate, String xmltemplateName,String xmltConfigemplateName,String temp_path,String base_path,String output_path,String output_file_name){
try {
try {
//================================拼装生成xml配置文档================================
String xml_config_output_path = output_path+System.currentTimeMillis()+".xml.rels";
createTemplateXml(dataMap,xmltConfigemplateName,temp_path,xml_config_output_path);
File xmlConfigFile = new File(xml_config_output_path);
//读取 xmlConfigFile 文件 并获取rId 与 图片的关系
String xmlConfigFile_content = getFreemarkerContent(dataMap,xmltConfigemplateName,temp_path);
System.out.println("===========================xmlConfigFile_content================================");
System.out.println(xmlConfigFile_content);
System.out.println("===========================xmlConfigFile_content================================");
Document document = DocumentHelper.parseText(xmlConfigFile_content);
Element rootElt = document.getRootElement(); // 获取根节点
Iterator iter = rootElt.elementIterator() ;// 获取根节点下的子节点head
List warn_img_list = new ArrayList<>();
List warn_summary_img_list = new ArrayList<>();
// 遍历Relationships节点
while (iter.hasNext()) {
Element recordEle = (Element) iter.next();
String id = recordEle.attribute("Id").getData().toString();
String target = recordEle.attribute("Target").getData().toString();
if(target.indexOf("media")==0){
// System.out.println("id>>>"+id+" >>>"+target);
// id>>>rId18 >>>media/pic1
if(target.indexOf("summary")>0){
warn_summary_img_list.add(id);
}else{
warn_img_list.add(id);
}
}
}
dataMap.put("warn_img_list",warn_img_list);
if(!warn_summary_img_list.isEmpty()){
dataMap.put("img_sum_warn_o",warn_summary_img_list.get(0));
dataMap.put("img_sum_warn_t",warn_summary_img_list.get(1));
dataMap.put("img_sum_warn_tt",warn_summary_img_list.get(2));
}
// dataMap.put("","");
//================================拼装生成xml配置文档================================
//================================拼装生成主模板xml文档================================
String xml_output_path = output_path+System.currentTimeMillis()+".xml";
createTemplateXml(dataMap,xmltemplateName,temp_path,xml_output_path);
File xmlFile = new File(xml_output_path);
//================================拼装生成主模板xml文档================================
File docxFile = new File(base_path+docxTemplate);
if(!docxFile.exists()){
docxFile.createNewFile();
}
ZipFile zipFile = new ZipFile(docxFile);
Enumeration extends ZipEntry> zipEntrys = zipFile.entries();
ZipOutputStream zipout = new ZipOutputStream(new FileOutputStream(output_path+output_file_name));
int len = -1;
byte[] buffer = new byte[1024];
//------------------追加新图片------------------
// List picList = new ArrayList<>();
Map picFiles = (Map) dataMap.get("picFiles");
if(picFiles!=null && !picFiles.isEmpty()){
for(String fileName :picFiles.keySet()){
ZipEntry next = new ZipEntry("word"+File.separator+"media"+File.separator+fileName);
zipout.putNextEntry(new ZipEntry(next.toString()));
InputStream in = new FileInputStream(picFiles.get(fileName));
while ((len = in.read(buffer)) != -1) {
zipout.write(buffer, 0, len);
}
in.close();
}
}
//------------------追加新图片------------------
len = -1;
while (zipEntrys.hasMoreElements()) {
ZipEntry next = zipEntrys.nextElement();
InputStream is = zipFile.getInputStream(next);
// 把输入流的文件传到输出流中 如果是word/document.xml由我们输入
zipout.putNextEntry(new ZipEntry(next.toString()));
System.out.println(">>>>>>>>>"+next.isDirectory());
System.out.println(">>>>>>>>>>>>>>>>>"+next.toString());
System.out.println(">>>>>>>>>>>>>>>>>"+next.isDirectory());
if ("word/document.xml".equals(next.toString())) {
InputStream in = new FileInputStream(xmlFile);
while ((len = in.read(buffer)) != -1) {
zipout.write(buffer, 0, len);
}
in.close();
} else if(next.toString().indexOf("document.xml.rels")>0){
InputStream in = new FileInputStream(xmlConfigFile);
while ((len = in.read(buffer)) != -1) {
zipout.write(buffer, 0, len);
}
in.close();
}else{
while ((len = is.read(buffer)) != -1) {
zipout.write(buffer, 0, len);
}
is.close();
}
}
zipout.close();
} catch (Exception e) {
e.printStackTrace();
}
} catch (Exception e) {
e.printStackTrace();
}
}
public static String getFreemarkerContent(Map dataMap, String templateName,String temp_path){
String ret_str = "";
try {
//创建配置实例
Configuration configuration = new Configuration();
//设置编码
configuration.setDefaultEncoding("UTF-8");
//ftl模板文件统一放至 com.lun.template 包下面
// configuration.setDirectoryForTemplateLoading(new File("D:/idea_workspace/alarm/alarm/src/main/resources/template/"));
configuration.setClassForTemplateLoading(FreemarkerWordUtils.class,temp_path);
//获取模板
Template template = configuration.getTemplate(templateName);
//输出文件
//File outFile = new File(filePath);
//如果输出目标文件夹不存在,则创建
// if (!outFile.getParentFile().exists()){
// outFile.getParentFile().mkdirs();
// }
//将模板和数据模型合并生成文件
// Writer out = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(outFile),"UTF-8"));
StringWriter swriter = new StringWriter();
//生成文件
template.process(dataMap, swriter);
ret_str = swriter.toString();
} catch (Exception e) {
e.printStackTrace();
}
return ret_str;
}
/**
* 删除文件
* @param listFiles
*/
public static void delFiles(List listFiles){
if(listFiles!=null && !listFiles.isEmpty()){
for(String file_temp_path:listFiles){
File file_temp = new File(file_temp_path);
if(file_temp.exists()){
file_temp.delete();
}
}
}
}