前段时间接到一个Web应用自动生成Word的需求,现整理了下一些关键步骤拿来分享一下。
思路:(注:这里只针对WORD2003版本,其它版本大同小异。)
因为WORD文件内部的数据及格式等是通过XML文件的形式存储的,所以WORD文件可以很方便的实现由DOC到XML格式的相互转换,而操作XML文件就方便的多了,这样就实现了与平台无关的各种操作,通过节点的查询、替换、删除、新增等生成Word文件。所以,根据模板生成WORD文件实质就是由用户数据替换XML文件中特殊标签,然后另存为一个DOC文件的过程。
下面列举涉及到的一些关键步骤(以介绍信为例)
第一步:根据需求制作WORD模板
新建一个DOC格式的WORD文件,根据需要填写好模板内容,设置好模板的格式,包括字体,样式,空行等等,需要填充的数据使用特殊标签(如:【※单位名称※】)预先占位,然后将新建的WORD文件另存为XML格式文件。这样, WORD模板就制作完成了,代码如下:
第二步:在配置文件中配置好模板信息
新增名为template-rule.xml的配置文件,每个template节点对应一个模板类型。每个template中有一个taglist节点,该节点包含的所有子节点包含了模板所有将要替换、删除节点信息,节点信息包括:节点值,节点属性英文名称,中文描述,字段类型,可否删除等信息。在设置这个配置文件时候,需要注意desc属性的值必须与模板XML中的占位符一致。比如:模板XML中设置的年份这个录入项【※年※】需与template-rule.xml中的desc="年"名称对应,代码如下:
<?xml version="1.0" encoding="GB2312"?> <!-- 模板定义 --> <templates> <!-- 说明: S-字符串; D-日期; E-金额; M-大写金额; ifEmptyDelete: T-值为空删除父节点,默认为F --> <template name="RECOMMEND-LETTER" desc="介绍信" templateFile="template4.xml"> <taglist remark="单值标签列表"> <tag id="1" name="ToPartment" desc="接收部门" type="S" ifEmptyDelete="T">#ToPartment</tag><!--接收部门--> <tag id="2" name="OwnerName" desc="姓名" type="S">#OwnerName</tag><!--姓名--> <tag id="3" name="CountNum" desc="人数" type="S">#CountNum</tag><!--人数--> <tag id="4" name="Business" desc="内容" type="S">#Business</tag><!--内容--> <tag id="5" name="UsefulDays" desc="有效期" type="S">#UsefulDays</tag><!--有效期--> <tag id="6" name="Year" desc="年" type="S">#Year</tag><!--年--> <tag id="7" name="Month" desc="月" type="S">#Month</tag><!--月--> <tag id="8" name="Day" desc="日" type="S">#Day</tag><!--日--> </taglist> </template> </templates>
第三步:编写java代码
/** * 参数及规则 */ public class RuleDTO { /** * tag名称 */ private String parmName; /** * tag描述 */ private String parmDesc; /** * tag序号 */ private String parmSeq; /** * tag值类型 */ private String parmType; /** * tag参数名称 */ private String parmRegular; /** * tag值 */ private String parmValue; /** * tag值为空删除该属性 */ private String ifEmptyDelete;
/** * 描述: Word模板信息 */ public class Template { private String name;//模板名 private String desc;//模板描述 private String templateFile;//模板文件 private Vector<RuleDTO> rules;//模板规则 }
public class WordBuilder { /** * 根据模板读取替换规则 * @param templateName 模板ID */ @SuppressWarnings("unchecked") public Template loadRules(Map<String, String> ruleValue) { InputStream in = null; Template template = new Template(); // 规则配置文件路径 String ruleFile = "template-rule.xml"; // 模板规则名称 String templateRuleName = ""; try { templateRuleName = ruleValue.get("ruleName"); // 读取模板规则文件 in = this.getClass().getClassLoader().getResourceAsStream(ruleFile); // 解析模板规则 SAXBuilder sb = new SAXBuilder(); Document doc = sb.build(in); Element root = doc.getRootElement(); // 得到根元素 List<Element> templateList = root.getChildren();// 所有模板配置 Element element = null; Vector<RuleDTO> rules = null; for (int i = 0; i < templateList.size(); i++) {// 遍历所有模板 element = (Element) templateList.get(i); String templateName = element.getAttributeValue("name"); if (templateRuleName.equalsIgnoreCase(templateName)) {// 查找给定的模板配置 template.setName(templateName); template.setDesc(element.getAttributeValue("desc")); template.setTemplateFile(element .getAttributeValue("templateFile")); List<Element> tagList = ((Element) element.getChildren() .get(0)).getChildren();// tag列表 Element tag = null; RuleDTO ruleDTO = null; rules = new Vector<RuleDTO>(); for (int j = 0; j < tagList.size(); j++) { tag = (Element) tagList.get(j); ruleDTO = new RuleDTO(); ruleDTO.setParmName(tag.getAttributeValue("name")); ruleDTO.setParmDesc("【※" + tag.getAttributeValue("desc") + "※】"); ruleDTO.setParmSeq(tag.getAttributeValue("id")); ruleDTO.setParmType(tag.getAttributeValue("type")); if ("T".equalsIgnoreCase(tag .getAttributeValue("ifEmptyDelete"))) {// 是否可删除标记 ruleDTO.setIfEmptyDelete("T"); } else { ruleDTO.setIfEmptyDelete("F"); } ruleDTO.setParmRegular(tag.getText()); // 值 // 判断参数类型 String value = (String) ((Map<String, String>) ruleValue) .get(ruleDTO.getParmRegular().replaceAll("#", "")); ruleDTO.setParmValue(value); rules.add(ruleDTO); } template.setRules(rules); break; } } } catch (FileNotFoundException e) { e.printStackTrace(); } catch (JDOMException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } finally { try { in.close(); } catch (Exception e) { e.printStackTrace(); } } return template; } /** * 查找父节点 */ public Element findElement(Element currNode, String parentNodeId) { // 节点标示为空 if (currNode == null || parentNodeId == null) { return null; } Element pNode = null; do { pNode = currNode.getParent(); currNode = pNode; } while (parentNodeId.equalsIgnoreCase(pNode.getName())); return pNode; } /** * 生成Word文件 */ @SuppressWarnings("unchecked") public String build(Template template) { InputStream in = null; OutputStream fo = null; // 生成文件的路径 String file = "d:\\test\\" + template.getDesc() + ".doc"; try { // 读取模板文件 in = this.getClass().getClassLoader() .getResourceAsStream(template.getTemplateFile()); SAXBuilder sb = new SAXBuilder(); Document doc = sb.build(in); Element root = doc.getRootElement(); // 得到根元素 Namespace ns = root.getNamespace();// NameSpace // word 03模板存在<wx:sect>元素 List<Element> sectList = root.getChild("body", ns).getChildren(); Element sectElement = (Element) sectList.get(0); // <w:p>下的标签集合 List<Element> pTagList = sectElement.getChildren("p", ns); // <w:tbl>下的标签集合 List<Element> tblTagList = sectElement.getChildren("tbl", ns); if (pTagList != null && pTagList.size() > 0) { changeValue4PTag(pTagList, template.getRules(), ns, null); } if (tblTagList != null && tblTagList.size() > 0) { changeValue4TblTag(tblTagList, template.getRules(), ns); } // 写文件 XMLOutputter outp = new XMLOutputter(" ", true, "UTF-8"); fo = new FileOutputStream(file); outp.output(doc, fo); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (JDOMException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } finally { try { in.close(); fo.close(); } catch (Exception e) { e.printStackTrace(); } } return file; } /** * 针对<w:body><wx:sect><w:p>这种层级的WORD模板, 查找及替换<w:p>下的标签。 * @param pTagList :<w:p>集合 * @param rulesValue :RuleDTO集合 * @param ns :NameSpace对象 * @param trChildren :<w:tbl>的子节点<w:tr>集合 */ @SuppressWarnings("unchecked") private boolean changeValue4PTag(List<Element> pTagList, Vector<RuleDTO> rulesValue, Namespace ns, List<Element> trChildren) { Element p = null; boolean delFlag = false; for (int i = 0; i < pTagList.size(); i++) { boolean delCurrNode = false;// 删除当前节点 boolean delCurrNode4TabWR = false;// 删除table中单行节点 p = (Element) pTagList.get(i); List<Element> pChild = p.getChildren("r", ns); for (int j = 0; pChild != null && j < pChild.size(); j++) { Element pChildren = (Element) pChild.get(j); Element t = pChildren.getChild("t", ns); if (t != null) { String text = t.getTextTrim(); if (text.indexOf("【※") != -1) { for (int v = 0; v < rulesValue.size(); v++) { RuleDTO dto = (RuleDTO) rulesValue.get(v); if (text.indexOf(dto.getParmDesc().trim()) != -1) { // 判断属性值是否为可空删除 if ("T".equals(dto.getIfEmptyDelete()) && StringUtils.isBlank(dto .getParmValue())) { // 删除该节点顶级节点 text = ""; if (trChildren != null) {// 针对<w:tbl>删除该行 Element element = ((Element) p .getParent()).getParent(); trChildren.remove(element); delCurrNode4TabWR = true; } else {// 针对<w:r>删除段 // pTagList.remove(p); pTagList.remove(pChildren); delCurrNode = true; } break; } else { text = text.replaceAll(dto.getParmDesc() .trim(), dto.getParmValue()); } } } t.setText(text); } if (delCurrNode4TabWR) {// <w:tbl>TABLE下的行节点已删除 delFlag = true; break; } else if (delCurrNode) {// <w:p>下的节点已删除 i--; delFlag = true; break; } } } } return delFlag; } /** * 针对含有表格的WORD模板, 查找及替换<w:tbl>下的标签。 * @param tblTagList :<w:tbl>集合 * @param rulesValue :RuleDTO集合 * @param ns :NameSpace对象 */ @SuppressWarnings("unchecked") private void changeValue4TblTag(List<Element> tblTagList, Vector<RuleDTO> rulesValue, Namespace ns) { Element p = null; for (int i = 0; tblTagList != null && i < tblTagList.size(); i++) { p = (Element) tblTagList.get(i); List<Element> trChildren = p.getChildren("tr", ns); for (int j = 0; trChildren != null && j < trChildren.size(); j++) {// 循环<w:tr> Element pChildren = (Element) trChildren.get(j); List<Element> tcTagList = pChildren.getChildren("tc", ns); for (int c = 0; tcTagList != null && c < tcTagList.size(); c++) {// 循环<w:tc>取<w:p>集合 Element tcChildren = (Element) tcTagList.get(c); List<Element> pTagList = tcChildren.getChildren("p", ns); boolean delFlag = changeValue4PTag(pTagList, rulesValue, ns, trChildren); if (delFlag) {// 删除行后需要改变trChildren的指针位置 j--; } } } } } public static void main(String[] args) throws Exception { WordBuilder word = new WordBuilder(); Map<String, String> map = new HashMap<String, String>(); //填充参数 map.put("ToPartment", "XXX公司"); map.put("OwnerName", "张三"); map.put("CountNum", "5"); map.put("Business", "例行检查"); map.put("UsefulDays", "15"); map.put("Year", "2014"); map.put("Month", "5"); map.put("Day", "13"); map.put("ruleName", "RECOMMEND-LETTER"); Template template = word.loadRules(map); //直接打开文件 Runtime.getRuntime().exec("explorer " + word.build(template)); } }
第四步:大功告成
几点总结及注意事项:
1. 定义的元素name必须与template_rule.xml中对应相同的name的值一致,否则需要设置转换规则。
2. 模板xml中定义的占位符【※※】中的文字必须与template_rule.xml中对应的desc相同,否则需要设置转换规则.
3. 在配置好模板XML后,需要检查<w:body>标签下的子节点是否是<wx:sect>标签(与WORD版本有关),如果没有,则必须加上该标签。
4. 如果要动态删除<w:p>标签节点,则这个节点的内容需要在模板中的同一行,如果不是,则可以手动调整模板XML。
5. 如果需要实现WORD自动换行功能(关于模板中换行的方案暂没有想到更好的),则需要首先计算出对应模板该行的字数,然后采用空格填充来实现。
相关推荐
综上所述,JS操作Word生成表格涉及到的技术包括ActiveXObject、Office.js、XML解析以及文件操作。理解这些知识点,能够帮助开发者构建强大的文档处理工具,提升工作效率。在实际开发中,需要注意兼容性问题,因为...
5. **Web应用程序**:文件名`WordTest.aspx`和`Default.aspx`暗示这可能是一个ASP.NET Web应用程序,用于处理用户的请求并生成Word文档。`.cs`文件是C#代码的后端部分,处理逻辑主要在这里实现。`Web.Config`是配置...
在Web开发中,有时我们需要为用户提供将数据导出为Word文档的功能,这在报表生成、合同制作或报告撰写等场景非常常见。本教程主要讲解如何使用Java后台来实现这一功能,特别是结合Word2003的模板进行数据填充。我们...
VUE动态生成Word文档的实现是一个涉及前端技术与文档处理技术的复杂过程,适用于Web开发领域中对文档生成功能的需求。通过使用Vue.js框架,开发者可以利用其响应式和组件化的特点,轻松构建出动态的用户界面。结合...
在现代Web应用中,有时我们需要在前端生成文档,例如Word文件,以便用户可以直接下载或进行进一步处理。"用js生成word"这个主题涉及到的技术就是利用JavaScript在浏览器端创建Microsoft Word文档。这种技术对于那些...
在IT行业中,生成二维码并将其整合到Word文档中是一项实用的技术,尤其在数据分享、信息传递和自动化流程中。这个任务涉及到三个主要技术领域:二维码生成、PHP编程语言以及Microsoft Word文档处理。以下是对这些...
ASP.NET和C#是开发Web应用程序的常用技术组合,它们可以用来创建动态网页并处理各种数据操作,包括生成和导出Word文档。在本场景中,我们主要关注如何使用这两种技术来实现Word文档的生成与下载。 首先,ASP.NET...
这个库使得在Web应用中创建、编辑和更新Word文档变得简单易行。在本篇文章中,我们将深入探讨`phpWord`库的使用方法以及如何通过它来生成和替换Word文档内容。 首先,我们需要安装`phpWord`库。通常,我们可以通过...
5. **集成Web应用**:PageOffice可以无缝集成到Java Web应用中,如Spring Boot、Struts、JSF等框架,实现Web应用中的Word文档生成和下载功能。 6. **安全机制**:PageOffice提供了一些安全机制,如防止内存泄漏、...
### Web应用测试知识点详解 #### 一、实验背景与目的 **实验背景:** 随着互联网技术的迅猛发展,Web应用程序已成为人们日常生活中不可或缺的一部分。为了确保Web应用的稳定性和用户体验,进行系统的Web应用测试至...
### 使用JSP实现Word、Excel格式报表打印 #### 一、使用JSP生成Word文档 在JSP中生成Word文档可以通过设置正确的`...通过合理配置和适当的技术选择,开发者可以轻松地实现在Web应用程序中生成和输出这些文档的目标。
综上所述,实现“二维码生成并打印到Word上”的功能需要跨领域的技术知识,包括二维码编码、批量处理、Word自动化、文本解析、Web开发以及安全性考量。开发者需要具备多种编程技能,并对这些技术有深入的理解。
通过理解以上技术点,你可以构建一个能够动态生成包含图片的Word文档的Java Web应用。这个过程涉及到对Freemarker模板的理解,Java对象数据的准备,以及利用Apache POI来处理Word文档结构。在实际应用中,这种能力...
在实际应用中,POI可以配合Spring框架和其他Java技术栈一起使用,例如结合Spring MVC来实现Web应用中的文档生成和下载功能。同时,POI还支持Apache Commons Lang和Apache Commons IO等常用的Java库,方便处理文本和I...
首先,加载模板文件,然后使用`process`方法将数据模型应用到模板上,得到生成的文本。接下来,我们需要将这个文本转换为Word文档。这里可以借助于Apache POI库,它提供了操作Microsoft Office格式文件的能力。 6. ...
ASP(Active Server Pages)是一种微软开发的服务器端脚本环境,用于在Web服务器上动态生成HTML、XML或其他格式的网页。在ASP中生成Word文档,主要是为了将网页内容转化为可编辑、可保存的文档格式,这在数据报告、...
.NET Core是微软推出的新一代开源、跨平台的.NET开发框架,用于构建桌面应用、Web应用、云服务和物联网应用。它支持Windows、Linux和macOS操作系统,并且可以使用C#、F#或VB.NET进行开发。在本项目中,.NET Core被...
FreeMarker 是一个强大的模板引擎,常用于Web应用中动态生成HTML或其他类型的文本。在Java开发中,它也可以用来生成Word文档,提供了一种简洁的方式来构建结构化的文档内容。以下是关于如何使用FreeMarker生成Word...
对于VS2012的Web模式,这是Visual Studio的一种工作环境,主要用于Web应用开发。在这种模式下,开发者可以创建ASP.NET Web Forms、MVC或Web API项目。虽然VBWordOperation可能是一个桌面应用项目,但理解Web模式的...