一個(gè)JAVA小項(xiàng)目--Web應(yīng)用自動(dòng)生成Word
前段時(shí)間接到一個(gè)Web應(yīng)用自動(dòng)生成Word的需求,現(xiàn)整理了下一些關(guān)鍵步驟拿來(lái)分享一下。
思路:(注:這里只針對(duì)WORD2003版本,其它版本大同小異。)
因?yàn)閃ORD文件內(nèi)部的數(shù)據(jù)及格式等是通過(guò)XML文件的形式存儲(chǔ)的,所以WORD文件可以很方便的實(shí)現(xiàn)由DOC到XML格式的相互轉(zhuǎn)換,而操作XML文件就方便的多了,這樣就實(shí)現(xiàn)了與平臺(tái)無(wú)關(guān)的各種操作,通過(guò)節(jié)點(diǎn)的查詢、替換、刪除、新增等生成Word文件。所以,根據(jù)模板生成WORD文件實(shí)質(zhì)就是由用戶數(shù)據(jù)替換XML文件中特殊標(biāo)簽,然后另存為一個(gè)DOC文件的過(guò)程。
下面列舉涉及到的一些關(guān)鍵步驟(以介紹信為例)
第一步:根據(jù)需求制作WORD模板
新建一個(gè)DOC格式的WORD文件,根據(jù)需要填寫(xiě)好模板內(nèi)容,設(shè)置好模板的格式,包括字體,樣式,空行等等,需要填充的數(shù)據(jù)使用特殊標(biāo)簽(如:【※單位名稱(chēng)※】)預(yù)先占位,然后將新建的WORD文件另存為XML格式文件。這樣, WORD模板就制作完成了,代碼如下:
![]() |
新增名為template-rule.xml的配置文件,每個(gè)template節(jié)點(diǎn)對(duì)應(yīng)一個(gè)模板類(lèi)型。每個(gè)template中有一個(gè)taglist節(jié)點(diǎn),該節(jié)點(diǎn)包含的所有子節(jié)點(diǎn)包含了模板所有將要替換、刪除節(jié)點(diǎn)信息,節(jié)點(diǎn)信息包括:節(jié)點(diǎn)值,節(jié)點(diǎn)屬性英文名稱(chēng),中文描述,字段類(lèi)型,可否刪除等信息。在設(shè)置這個(gè)配置文件時(shí)候,需要注意desc屬性的值必須與模板X(qián)ML中的占位符一致。比如:模板X(qián)ML中設(shè)置的年份這個(gè)錄入項(xiàng)【※年※】需與template-rule.xml中的desc="年"名稱(chēng)對(duì)應(yīng),代碼如下:
<!--?xml version="1.0" encoding="GB2312"?-->
<!-- 模板定義 -->
<templates>
<!-- 說(shuō)明: S-字符串; D-日期; E-金額; M-大寫(xiě)金額; ifEmptyDelete: T-值為空刪除父節(jié)點(diǎn),默認(rèn)為F -->
<template name="RECOMMEND-LETTER" desc="介紹信" templatefile="template4.xml">
<taglist remark="單值標(biāo)簽列表">
<tag id="1" name="ToPartment" desc="接收部門(mén)" type="S" ifemptydelete="T">#ToPartment</tag><!--接收部門(mén)-->
<tag id="2" name="OwnerName" desc="姓名" type="S">#OwnerName</tag><!--姓名-->
<tag id="3" name="CountNum" desc="人數(shù)" type="S">#CountNum</tag><!--人數(shù)-->
<tag id="4" name="Business" desc="內(nèi)容" type="S">#Business</tag><!--內(nèi)容-->
<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>
第三步:編寫(xiě)java代碼
/**
* 參數(shù)及規(guī)則
*/
public class RuleDTO {
/**
* tag名稱(chēng)
*/
private String parmName;
/**
* tag描述
*/
private String parmDesc;
/**
* tag序號(hào)
*/
private String parmSeq;
/**
* tag值類(lèi)型
*/
private String parmType;
/**
* tag參數(shù)名稱(chēng)
*/
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;//模板規(guī)則
}</ruledto>
public class WordBuilder {
/**
* 根據(jù)模板讀取替換規(guī)則
* @param templateName 模板ID
*/
@SuppressWarnings("unchecked")
public Template loadRules(Map<string, string=""> ruleValue) {
InputStream in = null;
Template template = new Template();
// 規(guī)則配置文件路徑
String ruleFile = "template-rule.xml";
// 模板規(guī)則名稱(chēng)
String templateRuleName = "";
try {
templateRuleName = ruleValue.get("ruleName");
// 讀取模板規(guī)則文件
in = this.getClass().getClassLoader().getResourceAsStream(ruleFile);
// 解析模板規(guī)則
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"))) {// 是否可刪除標(biāo)記
ruleDTO.setIfEmptyDelete("T");
} else {
ruleDTO.setIfEmptyDelete("F");
}
ruleDTO.setParmRegular(tag.getText());
// 值
// 判斷參數(shù)類(lèi)型
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;
}
/**
* 查找父節(jié)點(diǎn)
*/
public Element findElement(Element currNode, String parentNodeId) {
// 節(jié)點(diǎn)標(biāo)示為空
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>下的標(biāo)簽集合
List<element> pTagList = sectElement.getChildren("p", ns);
// <w:tbl>下的標(biāo)簽集合
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);
}
// 寫(xiě)文件
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;
}
/**
* 針對(duì)<w:body><wx:sect><w:p>這種層級(jí)的WORD模板, 查找及替換<w:p>下的標(biāo)簽。
* @param pTagList :<w:p>集合
* @param rulesValue :RuleDTO集合
* @param ns :NameSpace對(duì)象
* @param trChildren :<w:tbl>的子節(jié)點(diǎn)<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;// 刪除當(dāng)前節(jié)點(diǎn)
boolean delCurrNode4TabWR = false;// 刪除table中單行節(jié)點(diǎn)
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())) {
// 刪除該節(jié)點(diǎn)頂級(jí)節(jié)點(diǎn)
text = "";
if (trChildren != null) {// 針對(duì)<w:tbl>刪除該行
Element element = ((Element) p
.getParent()).getParent();
trChildren.remove(element);
delCurrNode4TabWR = true;
} else {// 針對(duì)<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下的行節(jié)點(diǎn)已刪除
delFlag = true;
break;
} else if (delCurrNode) {// <w:p>下的節(jié)點(diǎn)已刪除
i--;
delFlag = true;
break;
}
}
}
}
return delFlag;
}
/**
* 針對(duì)含有表格的WORD模板, 查找及替換<w:tbl>下的標(biāo)簽。
* @param tblTagList :<w:tbl>集合
* @param rulesValue :RuleDTO集合
* @param ns :NameSpace對(duì)象
*/
@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++) {// 循環(huán)<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++) {// 循環(huán)<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="">();
//填充參數(shù)
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);
//直接打開(kāi)文件
Runtime.getRuntime().exec("explorer " + word.build(template));
}
}</string,></string,></element></w:p></w:tc></element></w:tr></element></ruledto></element></w:tbl></w:tbl></w:p></w:tbl></w:r></w:tbl></element></element></ruledto></element></w:tr></w:tbl></w:p></w:p></w:p></wx:sect></w:body></element></w:tbl></element></w:p></element></wx:sect></string,></ruledto></element></ruledto></element></string,>
第四步:大功告成
幾點(diǎn)總結(jié)及注意事項(xiàng):
1. 定義的元素name必須與template_rule.xml中對(duì)應(yīng)相同的name的值一致,否則需要設(shè)置轉(zhuǎn)換規(guī)則。
2. 模板xml中定義的占位符【※※】中的文字必須與template_rule.xml中對(duì)應(yīng)的desc相同,否則需要設(shè)置轉(zhuǎn)換規(guī)則.
3. 在配置好模板X(qián)ML后,需要檢查標(biāo)簽下的子節(jié)點(diǎn)是否是標(biāo)簽(與WORD版本有關(guān)),如果沒(méi)有,則必須加上該標(biāo)簽。
4. 如果要?jiǎng)討B(tài)刪除標(biāo)簽節(jié)點(diǎn),則這個(gè)節(jié)點(diǎn)的內(nèi)容需要在模板中的同一行,如果不是,則可以手動(dòng)調(diào)整模板X(qián)ML。
5. 如果需要實(shí)現(xiàn)WORD自動(dòng)換行功能(關(guān)于模板中換行的方案暫沒(méi)有想到更好的),則需要首先計(jì)算出對(duì)應(yīng)模板該行的字?jǐn)?shù),然后采用空格填充來(lái)實(shí)現(xiàn)。
- idea創(chuàng)建JAVA Class時(shí)自動(dòng)生成頭部文檔注釋的方法
- Java利用Swagger2自動(dòng)生成對(duì)外接口的文檔
- eclipse中自動(dòng)生成javadoc文檔的方法
- 利用json2POJO with Lombok 插件自動(dòng)生成java類(lèi)的操作
- 利用JAVA反射,讀取數(shù)據(jù)庫(kù)表名,自動(dòng)生成對(duì)應(yīng)實(shí)體類(lèi)的操作
- Java反射 JavaBean對(duì)象自動(dòng)生成插入,更新,刪除,查詢sql語(yǔ)句操作
- android自動(dòng)生成dimens適配文件的圖文教程詳解(無(wú)需Java工具類(lèi))
- java自動(dòng)生成編號(hào)的實(shí)現(xiàn)(格式:yyMM+四位流水號(hào))
- Java中自動(dòng)生成構(gòu)造方法詳解
- Eclipse下編寫(xiě)java程序突然不會(huì)自動(dòng)生成R.java文件和包的解決辦法
- java自動(dòng)生成ID號(hào)的方法
- java 自動(dòng)生成略縮圖示例代碼
- 教你怎么用java一鍵自動(dòng)生成數(shù)據(jù)庫(kù)文檔
相關(guān)文章
springboot集成shiro權(quán)限管理簡(jiǎn)單實(shí)現(xiàn)
這篇文章主要介紹了springboot集成shiro權(quán)限管理簡(jiǎn)單實(shí)現(xiàn),文章圍繞主題展開(kāi)詳細(xì)的內(nèi)容介紹,具有一定的參考價(jià)值,需要的小伙伴可以參考一下2022-08-08Java利用遞歸算法實(shí)現(xiàn)查詢斐波那契數(shù)
今天小編就為大家分享一篇關(guān)于Java利用遞歸算法實(shí)現(xiàn)查詢斐波那契數(shù),小編覺(jué)得內(nèi)容挺不錯(cuò)的,現(xiàn)在分享給大家,具有很好的參考價(jià)值,需要的朋友一起跟隨小編來(lái)看看吧2018-12-12使用IDEA異常斷點(diǎn)來(lái)定位java.lang.ArrayStoreException的問(wèn)題
這篇文章主要介紹了使用IDEA異常斷點(diǎn)來(lái)定位java.lang.ArrayStoreException的問(wèn)題,平常開(kāi)發(fā)過(guò)程中面對(duì)這種描述不夠清楚,無(wú)法定位具體原因的問(wèn)題該如何處理,下面我們來(lái)一起學(xué)習(xí)一下吧2019-06-06Java線程池必知必會(huì)知識(shí)點(diǎn)總結(jié)
這篇文章主要給大家介紹了關(guān)于Java線程池必知必會(huì)知識(shí)點(diǎn)的相關(guān)資料,文中通過(guò)圖文以及實(shí)例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2022-02-02