`
小码哥BASE64
  • 浏览: 122126 次
社区版块
存档分类
最新评论

Web应用Word生成

阅读更多

    前段时间接到一个Web应用自动生成Word的需求,现整理了下一些关键步骤拿来分享一下。

 

思路:(注:这里只针对WORD2003版本,其它版本大同小异。)

因为WORD文件内部的数据及格式等是通过XML文件的形式存储的,所以WORD文件可以很方便的实现由DOCXML格式的相互转换,而操作XML文件就方便的多了,这样就实现了与平台无关的各种操作,通过节点的查询、替换、删除、新增等生成Word文件。所以,根据模板生成WORD文件实质就是由用户数据替换XML文件中特殊标签,然后另存为一个DOC文件的过程。

 

下面列举涉及到的一些关键步骤(以介绍信为例)

第一步:根据需求制作WORD模板

新建一个DOC格式的WORD文件,根据需要填写好模板内容,设置好模板的格式,包括字体,样式,空行等等,需要填充的数据使用特殊标签(如:【※单位名称※】)预先占位,然后将新建的WORD文件另存为XML格式文件。这样, WORD模板就制作完成了,代码如下:

 template4.xml
 

第二步:在配置文件中配置好模板信息

新增名为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自动换行功能(关于模板中换行的方案暂没有想到更好的),则需要首先计算出对应模板该行的字数,然后采用空格填充来实现。

 

分享到:
评论
1 楼 Tomcat911 2014-05-13  
受教了

相关推荐

    一个JAVA小项目--Web应用自动生成Word

    前段时间接到一个Web应用自动生成Word的需求,现整理了下一些关键步骤拿来分享一下。

    freemarker生成复杂word

    在Web应用中,有时需要按照固定的模板将数据导出到Word,如流程审批单,在流程处理完成后将处理过程按照流程单的要求导出,有时程序中需要实现生成标准Word文档,要求能够打印,并且保持页面样式不变,常见的方案有...

    ASP.NET生成WORD文档服务器部署注意事项

    ASP.NET生成WORD文档服务器部署注意事项 配置详情请下载附件图解 1、Asp.net 2.0在配置Microsoft Excel、Microsoft Word应用程序权限时 error: 80070005 和8000401a 的解决总 2007-11-01 11:30 检索 COM 类...

    easyjweb 开发文档

    EasyJWeb是基于java技术,用于企业级Java Web应用程序快速开发的MVC框架。框架设计构思来源于国内众多项目实践,框架的设计及实现借鉴当前主要流行的开源Web框架,如Rails、Struts、JSF、Tapestry等,吸取其优点及...

    word使用技巧大全

    二、使WORD里面的文章自动生成目录 1 (一) 设置标题格式 1 (二) 自动生成目录 1 (三) 更新目录的方法 2 三、自动生成目录图片演示 2 4.用标题1,2,3分别去定义文中的每一章节 4 四、如何自动生成目录? 6 五、奇偶...

    点聚weboffice7

    WEBOFFICE是标准的ACTIVEX组件,支持在应用开发平台中嵌入整合。 C/S平台:VB、VC、Delphi … … B/S平台:ASP、PHP、Java、ASP.Net、C#.Net … … 功能项 详细说明 文件格式 支持大多数的文件格式,如Word、Excel...

    适合web应用的帮助文档制作系统(helppad online author 1.1.35)

    7.支持多种帮助内容敏感设置,便于快速定位帮助内容 ,从而实现在WEB应用中按F1键快速获取联系帮助功能 8.支持flash,avi等多媒体内容 9.具备index,keyword等多种灵活的内容检索方式。 url:[url=...

    java2word:Java2word是一个库,可从Java代码生成MS Word文档,而无需任何特殊组件

    #Java2word# 缺少的库无法从Java代码生成MS ... 您可以在Web或非Web应用程序中使用它。 ##只需简单品尝一下Java2word ## IDocument myDoc = new Document2004(); myDoc.addEle(Heading1.with("Heading01").create

    wallstor Chm-Web帮助文档制作软件

    支持多种帮助内容敏感设置,便于快速定位帮助内容 ,从而实现在WEB应用中按F1键快速获取联系帮助功能。 .支持flash,avi等多媒体内容。 .具备index,keyword等多种灵活的内容检索方式。 注意:免费版功能有限制,有...

    Lotus Domino WEB详细 学习笔记

    26. 视图---excel,表单---word 32 27. 关于Web上的检索问题 35 28. 如何使用Notes与关系数据库进行信息交互? 37 29. 如何在IE里面实现notes中的 对话框列表? 39 30. LotusDomino环境下编写Web浏览器多...

    Java_Web开发实战1200例第1卷.part2

    20.1 应用JavaScript导出到Word 765 20.2 应用响应流导出到Word 766 20.3 应用POI组件导出到Word 772 第21章 JSP操作Excel 775 21.1 应用JXL组件操作Excel 776 21.2 应用POI组件操作Excel 807 第22章 报表与打印 829...

    Java_Web开发实战1200例第1卷.part3

    20.1 应用JavaScript导出到Word 765 20.2 应用响应流导出到Word 766 20.3 应用POI组件导出到Word 772 第21章 JSP操作Excel 775 21.1 应用JXL组件操作Excel 776 21.2 应用POI组件操作Excel 807 第22章 报表与打印 829...

    Web性能测试模型与性能提升策略研究(论文)

    2.4 Web应用程序性能测试方法 18 2.4.1虚拟用户方法 18 2.4.2 WUS方法 18 2.4.3 对象驱动法 19 第三章 Web性能测试程序设计 20 3.1 系统建设的目标 20 3.2系统功能结构分析 20 3.3 系统功能的设计 20 3.3.1 URL生成...

    word_cloud:在Jupyter Notebook和Python应用程序中使用的Python词云库

    在Jupyter笔记本中,从Web应用程序等中使用。 产品特点 生成单个文档的词云 使用文档列表生成词云 为已经定义分数的单词或短语生成词云 嵌入Jupyter笔记本 在HTML页面上显示 随机颜色 快速开始 用pip安装 pip ...

    基于SSM+Mysql的Word自动出题系统.zip

    系统的后端设计采用了SSM框架,该框架是一个广泛应用于Java Web开发的开源框架组合。Spring框架提供了强大的IoC(控制反转)和AOP(面向切面编程)功能,简化了系统的配置和开发过程。SpringMVC作为一个基于MVC...

    JSP论文格式化系统_java_格式化_数据库_web_移植性_

    本系统是基于Java平台的Web应用程序。采用JSP作为后台开发语言,HTML和JavaScript作为前台开发语言,MYSQL5.0作为后台数据库系统具有稳定性高、可移植性强等特点。本系统中文档数据的传输和存储均使用XML形式,以XML...

    基于XML标准vml作图包

    在一些比较简单的情况下,可在Microsoft Word中直接把文件另存为web页,必要时也可把word生成的图片作为素材取出,用于网页制作。 即便如此,还是有一些问题不易解决:用word等生成的网页与网站融合得不是很好,...

    Lotus Domino WEB 开发技术积累-DOC(313页)

    26. 视图---excel,表单---word 32 27. 关于Web上的检索问题 35 28. 如何使用Notes与关系数据库进行信息交互? 37 29. 如何在IE里面实现notes中的 对话框列表? 39 30. LotusDomino环境下编写Web浏览器多数据库检索...

    0826-wordweb-app:Wordweb项目

    如果您更改任何源文件,该应用程序将自动重新加载。 代码脚手架 运行ng generate component component-name生成一个新的组件。 您还可以使用ng generate directive|pipe|service|class|guard|interface|enum|module...

Global site tag (gtag.js) - Google Analytics