Web应用Word生成

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

Web应用Word生成

时间: 2024-10-08 02:28:40

Web应用Word生成的相关文章

C#操作Word生成目录

C#代码   OperateWord ow = new OperateWord(); Microsoft.Office.Interop.Word.ApplicationClass ss = ow.WordApplication; AddContent(ref ss); void AddContent(ref   Microsoft.Office.Interop.Word.ApplicationClass app) { Object oMissing = System.Reflection.Mis

百度Web App在线生成平台Site App体验

最近收到百度开发者中心邮件,告知之前的百度移动建站服务已经升级为Site App了,Site  App顾名思义是可以创建APP的站点,之前想建立一个APP要么是自己制作,要么是选用国外的在线Web APP工具来实现,现在百度推出的Site  App极大的解决了中小网站无法建立APP站点的事实. 下图为电脑站.移动建站.Web APP的图示: 通过图例我们可以看到,之前通过把电脑版通过百度移动建站后在手机上的显示效果,界面显得如此凌乱,而使用Site App后,界面则整洁了许多,也像一个Web  

word生成pdf保留书签设置

word生成pdf保留书签设置 点击"另存为"选项: 在另存为界面选择保存为pdf,如下,会出现"选项"设置项,点击进入: 在选项中,设置需要的设置,若要将pdf保留word中的标题作为书签,则需设置如下图,"创建标签时使用"选项勾选即可. word生成pdf保留书签设置

asp.net.web如何简单生成和保存二维码图片的例子

首先,要有生成二维码图片,需要二维码生成的类库,到官网下载thoughtWorks.QRCode.dll 例子的步骤: 1.创建项目QRCodeTest1,选择asp.net.web窗体应用程序 2.添加引用,引入支持生成二维码图片类库,thoughtWorks.QRCode.dll 3.右键项目QRCodeTest1,选择添加web窗体,生成WebForm1.aspx, 并添加新文件夹photos,存放生成的二维码图片 4.打开webForm1.aspx,可以选择两种方式编写页面(熟悉的话,用

Java中将word生成缩略图

解决思路是: 1.先将word生成pdf,这个采用openoffice或者jacob 2.然后将pdf生成图片 具体代码如下: private void officeToPdf(){ OpenOfficeConnection connection = new SocketOpenOfficeConnection(8100); try { connection.connect(); } catch (ConnectException e) { e.printStackTrace(); } Docu

使用python在WEB页面上生成EXCEL文件

来自:http://blog.sina.com.cn/s/blog_5d18f85f0101bxo7.html 近日写的一个程序需要在WEB服务器上生成EXCEL文件供用户下载,研究了一下找到了以下比较可行的实现方案,下面以web.py为例,把相关代码贴出来供大家参考: 首先需要下载生成EXCEL的模块,推荐使用xlwt import xlwt import StringIO import web urls = ( '/rim_request','rim_request', '/rim_expo

在.net core web项目中生成二维码

原文:在.net core web项目中生成二维码 1.添加QRCoder包引用 2. public IActionResult MakeQrCode()        { string url="https://www.baidu.com"; var generator = new QRCodeGenerator(); var codeData = generator.CreateQrCode(str,QRCodeGenerator.ECCLevel.M,true); var qrc

Java Web用Freemarker生成带图片的Word文档

步骤一:模板制作 用world2003做一个导出模板,如果有图片则加入一张图片占位,将world另存为xml,将xml中需要导出的内容用Freemarker标签表示,最后另存为.ftl结尾的模板: 步骤二:后台代码 1.获取导出的数据: @RequestMapping(value = "/exportDoc") public void exportDoc(String resumeId,HttpServletResponse response,HttpServletRequest re

【Web】Java生成中文GIF动态验证码-集成SpringMVC

转载请注明出处:http://blog.csdn.net/qq_26525215 本文源自[大学之旅_谙忆的博客] 说明 GIF验证码相对于JPG图片验证码来说,要更难破解一些,加大了破解的代价. 从昨天到现在,写了一个小小的GIF验证码项目(中文成语). 当然,你可以自己修改成字母数字的.我只是单纯的觉得中文验证码的破解代价更高一点~ 我在这里生成GIF图片的类,用到了国外牛人的三个类,也就是: AnimatedGifEncoder LZWEncoder 和NeuQuant,这三个类. 没办法