欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

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

程序员文章站 2024-02-29 08:42:40
前段时间接到一个web应用自动生成word的需求,现整理了下一些关键步骤拿来分享一下。 思路:(注:这里只针对word2003版本,其它版本大同小异。) 因为word文...

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

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

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

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

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

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

一个JAVA小项目--Web应用自动生成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;//模板规则

}</ruledto>

复制代码 代码如下:

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));
    }
}</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,>

第四步:大功告成

几点总结及注意事项:

1. 定义的元素name必须与template_rule.xml中对应相同的name的值一致,否则需要设置转换规则。

2. 模板xml中定义的占位符【※※】中的文字必须与template_rule.xml中对应的desc相同,否则需要设置转换规则.

3. 在配置好模板xml后,需要检查标签下的子节点是否是标签(与word版本有关),如果没有,则必须加上该标签。

4. 如果要动态删除标签节点,则这个节点的内容需要在模板中的同一行,如果不是,则可以手动调整模板xml。

5. 如果需要实现word自动换行功能(关于模板中换行的方案暂没有想到更好的),则需要首先计算出对应模板该行的字数,然后采用空格填充来实现。