之前写过一篇利用Freemarker模板生成doc的博客,不过那个博客有点缺陷,不支持生成docx格式的文档。所以,这里补充一篇,生成docx或doc格式的文档以具体的docx模板或者doc模板为主。这里以docx为例。
具体思路:

  1. 把docx文档修改为ZIP格式(修改.docx后缀名为.zip)
  2. 获取zip里的document.xml文档以及_rels文件夹下的document.xml.rels文档
  3. 把内容填充到document.xml里,以及图片配置信息填充至document.xml.rels文档里
  4. 在输入docx文档的时候把填充过内容的的 document.xml、document.xml.rels用流的方式写入zip(详见下面代码)。
  5. 把图片写入zip文件下word/media文件夹中
  6. 输出docx文档

docx模板修改成zip格式后的信息如下(因为word文档本身就是ZIP格式实现的)

  • document.xml里存放主要数据
  • media存放图片信息
  • _rels里存放配置信息

注意:如果docx模板里的图片带有具体路径的话,则图片的格式不受限制。

如果docx模板里里图片信息不带路径,则模板仅支持和模板图片类型一致的图片。


交代了这么多,下面就可以干货。

  1. 准备好docx模板

  2. 把docx文档修改为ZIP格式(修改.docx后缀名为.zip)

  3. 获取zip文件里的word文件夹下的document.xml以及_rels文件夹里的document.xml.rels文件作为模板。



    注意:这里图片配置信息是根据 rId来获取的。docx模板总的${img_warn}就是rId的具体值。
    为了避免重复,我的图片rId从17开始(在我没有修改之前,里面最大的rId是rId17)。

  4. 填充模板信息、写入图片信息。

        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<String,Object> data_map = new HashMap<>();//        1) 总体环比分析List<String> 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<String> picNameList  = new ArrayList<>();picNameList.add("pic1.png");Map<String,String> 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() ;// 获取根节点下的子节点headList<String> warn_img_list = new ArrayList<>();List<String> 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/pic1if(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<String> picList = new ArrayList<>();Map<String,String> picFiles = (Map<String, String>) 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<String> 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();}}}}
  1. 输出具体的docx文档。

项目地址:https://gitee.com/wahnn/JavaUtilsProject
主工具类是:
https://gitee.com/wahnn/JavaUtilsProject/blob/master/src/main/java/com/sl/utils/office/word/WordUtils.java

java利用Freemarker模板生成格式友好的doc或者docx文档相关推荐

  1. java利用Freemarker模板生成docx格式的word文档(全过程)

    参考汇总: wordexport: JAVA生成并导出Word文档技术论证 java利用Freemarker模板生成docx格式的word文档(全过程) - 旁光 - 博客园 # 参考资料 - 其他项 ...

  2. java生成docx_java利用Freemarker模板生成docx格式的word文档

    之前写过一篇利用Freemarker模板生成doc的博客,不过那个博客有点缺陷,生成的word占用的空间很大,几百页的word有将近100M了.所以,后面需求必须是生成的docx文档,结果导出后正常才 ...

  3. freemarker 生成java_半自动化Java代码生成器[利用freemarker模板生成]

    rapid-generator 半自动化Java代码生成器[利用freemarker模板生成] 增加一些定制和扩展, 修改为基于MAVEN的格式. 整体架构保持不变. 增加的特性为: 支持表名前缀去除 ...

  4. 利用 freemarker 模板生成 word 小结

    在企业级开发时,不可避免的会遇到生成 word 文档的需求,有两种常用的方案,1.使用 Apache POI 在后台通过代码生成 word 文档:2.使用模板生成 word 文档.第二种方法比较简单, ...

  5. java 转换xml格式的doc或docx文档为docx以及docx转PDF

    转换xml格式的doc或docx文档为docx import org.docx4j.Docx4J; import org.docx4j.openpackaging.packages.Wordproce ...

  6. 利用Freemarker模板生成doc或者docx文档(转载整理)

    可以直接看主要代码实现 doc作为模板文件生成指定格式的doc文件 实现逻辑 1.把作为模板的doc文件另存为xml文件 2.凡是需要填充的数据用${xxxx}替代 3.利用Template类将数据填 ...

  7. 如何使用freeMarker生成doc、docx文档

    如何使用freeMarker生成doc.docx.pdf文件 freeMarker是什么 doc和docx有什么区别 如何生成doc文档(带图片) 如何生成docx文档,以及将其生成pdf文档 fre ...

  8. java 使用 freemarker模板 生成 word 并用 aspose 转换成PDF

    添加依赖: <!-- freemarker生成word文件--><dependency><groupId>org.springframework.boot</ ...

  9. java利用freemarker动态生成word文档及动态表格

    这里写自定义目录标题 目标 准备 实现 处理模板 java实现 验证 目标 根据给定word模板,动态填充指定内容,并输出为新的word文档. 准备 1.模板: 准备一份目标格式的word文档,如:w ...

最新文章

  1. 去除ios input部分默认样式
  2. 2016 、12 、11本周
  3. 2018年计算机相关学术会议,2018年信息与计算机技术国际学术会议(IEEE出版)
  4. 基于netty实现mq
  5. mysql8.0新用户无法连接_mysql 8.0.16 Linux新建用户无法登录
  6. python默认安装地址_python多版本下设置python3为默认的方法
  7. 大改革,GNOME 3.x将直接跳到GNOME 40
  8. 莓良心(第二类斯特林数)
  9. Ubuntu16.04通过GPT挂载硬盘
  10. 当实在受不了了,就开干吧!
  11. string类的构造函数,拷贝构造函数,析构函数和赋值函数
  12. 化工企业数据分析平台项目之应收款分析
  13. java几次,java兑现限制用户几次登录
  14. 图森未来高层动荡:CEO侯晓迪被突然免职 公开喊冤
  15. 福大软工1816 · 第四次作业 - 团队展示
  16. 计算机ABC分类法的步骤,ABC分类法的具体步骤
  17. springboot实战,实现发送邮件,gmail邮件,包括发送附件还有正文,以及注意覆盖问题
  18. 文字识别——检测部分 CTPN论文翻译
  19. oracle bpm 表单,Oracle BPM 安全认证
  20. Spring Boot+JSP

热门文章

  1. 二级米勒补偿运算放大器设计教程
  2. 第二章(1):Python入门:语法基础、面向对象编程和常用库介绍
  3. jsp,javaweb在线考试系统
  4. NVIDIA Drive PX2 使用笔记
  5. 调研分析-全球与中国三硼酸锂(LBO)晶体市场现状及未来发展趋势
  6. bzoj 3730: 震波 动态点分治+树链剖分+线段树
  7. 详谈简略式购物车代码
  8. CDO基础教程(二) 文件信息查询
  9. 北邮计算机学院二组,北邮信息与通信工程学院导师组介绍(二)
  10. ByteBuffer.allocateDirect()