700字范文,内容丰富有趣,生活中的好帮手!
700字范文 > java导出版word(docx格式)freemarker + xml 实现

java导出版word(docx格式)freemarker + xml 实现

时间:2020-04-18 00:29:48

相关推荐

java导出版word(docx格式)freemarker + xml 实现

Freemarker+xml生成docx

原理概述:word从版就支持xml格式,而freemarker是java封装的模板工具,两者结合也就是在xml中需要动态生成的部分调用freemarker的指令(类似于EL表达式),来生成我们需要的数据,再用流输出文件,就达到了写word的效果。

生成word的基本流程图如下:

1.生成docx模板和xml模板

生成docx模板

按照项目需要生成固定格式的docx格式的模板。

为方便测试做了个简单的例子,docx模板的内容如下图:

生成xml模板

从docx模板中取出word/document.xml,由于docx属于zip格式,可以用winrar打开,如图:

除word文件夹外其它文件为基本配置文件,取出word/document.xml(存放word文件的文本内容)如下图:

需要把document.xml解压出来,修改里面需要从数据库导出的数据用freemarker的指令代替,例如${test} 同时可以用遍历函数

替换完成后相当于生成了xml模板

生成的Xml模板:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?><w:document xmlns:wpc="/office/word//wordprocessingCanvas" xmlns:mc="/markup-compatibility/" xmlns:o="urn:schemas-microsoft-com:office:office" xmlns:r="/officeDocument//relationships" xmlns:m="/officeDocument//math" xmlns:v="urn:schemas-microsoft-com:vml" xmlns:wp14="/office/word//wordprocessingDrawing" xmlns:wp="/drawingml//wordprocessingDrawing" xmlns:w10="urn:schemas-microsoft-com:office:word" xmlns:w="/wordprocessingml//main" xmlns:w14="/office/word//wordml" xmlns:wpg="/office/word//wordprocessingGroup" xmlns:wpi="/office/word//wordprocessingInk" xmlns:wne="/office/word//wordml" xmlns:wps="/office/word//wordprocessingShape" mc:Ignorable="w14 wp14"><w:body><w:p w:rsidR="009175C2" w:rsidRDefault="005B5FB3" w:rsidP="005B5FB3"><w:pPr><w:pStyle w:val="1"/><w:jc w:val="center"/><w:rPr><w:rFonts w:hint="eastAsia"/></w:rPr></w:pPr><w:bookmarkStart w:id="0" w:name="_GoBack"/><w:bookmarkEnd w:id="0"/><w:r><w:rPr><w:rFonts w:hint="eastAsia"/></w:rPr><w:t>这是一个测试Word</w:t></w:r></w:p><w:p w:rsidR="005B5FB3" w:rsidRDefault="005B5FB3" w:rsidP="005B5FB3"><w:pPr><w:rPr><w:rFonts w:hint="eastAsia"/></w:rPr></w:pPr></w:p><w:p w:rsidR="005B5FB3" w:rsidRDefault="005B5FB3" w:rsidP="005B5FB3"><w:pPr><w:rPr><w:rFonts w:hint="eastAsia"/></w:rPr></w:pPr></w:p><w:p w:rsidR="005B5FB3" w:rsidRDefault="005B5FB3" w:rsidP="005B5FB3"><w:pPr><w:pStyle w:val="a3"/><w:numPr><w:ilvl w:val="0"/><w:numId w:val="1"/></w:numPr><w:ind w:firstLineChars="0"/><w:rPr><w:rFonts w:hint="eastAsia"/></w:rPr></w:pPr><w:r><w:rPr><w:rFonts w:hint="eastAsia"/></w:rPr><w:t>${test}</w:t></w:r><w:r><w:rPr><w:rFonts w:hint="eastAsia"/></w:rPr><w:t xml:space="preserve"></w:t></w:r></w:p><#list students as s><w:p w:rsidR="005B5FB3" w:rsidRDefault="005B5FB3" w:rsidP="005B5FB3"><w:pPr><w:pStyle w:val="a3"/><w:numPr><w:ilvl w:val="0"/><w:numId w:val="1"/></w:numPr><w:ind w:firstLineChars="0"/><w:rPr><w:rFonts w:hint="eastAsia"/></w:rPr></w:pPr><w:r><w:rPr><w:rFonts w:hint="eastAsia"/></w:rPr><w:t>${s}</w:t></w:r></w:p></#list><w:sectPr w:rsidR="005B5FB3" w:rsidRPr="005B5FB3"><w:pgSz w:w="11906" w:h="16838"/><w:pgMar w:top="1440" w:right="1800" w:bottom="1440" w:left="1800" w:header="851" w:footer="992" w:gutter="0"/><w:cols w:space="425"/><w:docGrid w:type="lines" w:linePitch="312"/></w:sectPr></w:body></w:document>

2.利用freemarker填充数据并生成word文件

这里把数据库中的数据放到map中,把map和xml模板交给freemarker来生成(填充完数据)的xml具体实现方法如下:

package com.hannet.yigehui;import java.io.File;import java.io.FileOutputStream;import java.io.IOException;import java.io.OutputStreamWriter;import java.io.Writer;import java.util.HashMap;import java.util.Map;import freemarker.template.Configuration;import freemarker.template.Template;import freemarker.template.TemplateException;public class XmlToExcel {private static XmlToExcel tplm = null;private Configuration cfg = null;private XmlToExcel() {cfg = new Configuration();try {//注册tmlplate的load路径cfg.setClassForTemplateLoading(this.getClass(), "/template/");} catch (Exception e) {}}private static Template getTemplate(String name) throws IOException {if(tplm == null) {tplm = new XmlToExcel();}return tplm.cfg.getTemplate(name);}/*** * @param templatefile 模板文件* @param param 需要填充的内容* @param out填充完成输出的文件* @throws IOException* @throws TemplateException*/public static void process(String templatefile, Map param ,Writer out) throws IOException, TemplateException{//获取模板Template template=XmlToExcel.getTemplate(templatefile);template.setOutputEncoding("UTF-8");//合并数据template.process(param, out);if(out!=null){out.close();}}}

利用freemarker生成数据

调用freemarker中的process方法(上图中的方法)来填充数据。

例(用1中生成的xml为模板填充数据):

//xml的模板路径 template/test.xml

String xmlTemplate = "test.xml";

//填充完数据的临时xml

String xmlTemp = "d:\\temp.xml";

Writer w = new FileWriter(new File(xmlTemp));

//1.需要动态传入的数据

Map<String,Object> p = new HashMap<String,Object>();

List<String> students = new ArrayList<String>();

students.add("张三");

students.add("李四");

students.add("王二");

p.put("test", "测试一下是否成功");

p.put("students", students);

//2.把map中的数据动态由freemarker传给xml

XmlToExcel.process(xmlTemplate, p, w);

注:下文中会给出源码这里只是方便理解。

导出word文件

利用java的zipFile 和 ZipOutputStream 及zipFile.getInputStream() 来根据docx模板导出 (需要把word/document.xml文件替换成(填充完数据)的xml)具体操作流程如下:

package com.hannet.yigehui;import java.io.File;import java.io.FileInputStream;import java.io.FileNotFoundException;import java.io.FileOutputStream;import java.io.FileWriter;import java.io.IOException;import java.io.InputStream;import java.io.Writer;import .URISyntaxException;import java.util.ArrayList;import java.util.Enumeration;import java.util.HashMap;import java.util.List;import java.util.Map;import java.util.zip.ZipEntry;import java.util.zip.ZipException;import java.util.zip.ZipFile;import java.util.zip.ZipOutputStream;import freemarker.template.TemplateException;/*** 其实docx属于zip的一种,这里只需要操作word/document.xml中的数据,其他的数据不用动* @author yigehui**/public class XmlToDocx {/*** * @param documentFile 动态生成数据的docunment.xml文件* @param docxTemplatedocx的模板* @param toFileName需要导出的文件路径* @throws ZipException* @throws IOException*/public void outDocx(File documentFile,String docxTemplate,String toFilePath) throws ZipException, IOException {try {String fileName = XmlToDocx.class.getClassLoader().getResource("").toURI().getPath()+docxTemplate;File docxFile = new File(fileName);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()));if("word/document.xml".equals(next.toString())){//InputStream in = new FileInputStream(new File(XmlToDocx.class.getClassLoader().getResource("").toURI().getPath()+"template/test.xml"));InputStream in = new FileInputStream(documentFile);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 (URISyntaxException e) {e.printStackTrace();}catch (FileNotFoundException e) {e.printStackTrace();}}}

这里输出的文件即为完整的docx格式的word文件

测试调用的代码:

public static void main(String[] args) throws IOException, TemplateException {//xml的模板路径*/*String xmlTemplate = "test.xml";//设置docx的模板路径 和文件名String docxTemplate = "template/test.docx";String toFilePath = "d:\\test.docx";//填充完数据的临时xmlString xmlTemp = "d:\\temp.xml";Writer w = new FileWriter(new File(xmlTemp));//1.需要动态传入的数据Map<String,Object> p = new HashMap<String,Object>();List<String> students = new ArrayList<String>();students.add("张三");students.add("李四");students.add("王二");p.put("test", "测试一下是否成功");p.put("students", students);//2.把map中的数据动态由freemarker传给xmlXmlToExcel.process(xmlTemplate, p, w);//3.把填充完成的xml写入到docx中XmlToDocx xtd = new XmlToDocx();xtd.outDocx(new File(xmlTemp), docxTemplate, toFilePath);}

调用成功后生成的test.docx如下图:

注:

测试项目的目录结构:

需要引入的包:

链接:/s/18_koWw1rx5fPTchl0UUMvA 密码:9nb2

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。