关于用java编写生成word文档,动态添加数据到word文档的一些心得,经过翻阅了无数的有用的和无用的资料以后,总算找到了一种靠谱的方法

1.概述

经过反反复复的查阅资料,总算找到了一个靠谱的生成word的方案,这里分享给大家.

2.需求

首先我们的需求是通过一个指定的word模板来生成新的word并且填充内容,内容是我们在布局页面上面就写好的,比如说EditText,TextView,或者是图片ImageView,填充完内容之后,在页面上进行点击操作,生成新的word,可以指定路径,内容自动填充到新生成word文档中

3.方案

3.1 概述

上面所讲到的几种方案。
3.1.1 jadoc
3.1.2 apache poi
3.1.3 java2word
3.1.4 iText
3.1.5 jsp
3.1.6 xml的方式
最终得出结论,这几种方法 要么就是操作太简陋,没有实现我们这样复杂的需求,要么就是不太好用。期间还去研究过一个名为Jword的一个第三方,除去试用期只有30天,不是免费的之外,本身Jword自带的jar包内含方法太多,导致出现 65536的问题,需要我们分 dex,分jar,去除没用的方法,这里这种大费周章的搞,不是我们的目的。

4.实现

4.1使用freemarker实现我们的需求

4.4.1 自己新建一个 word的模板 模板中指定需要填写的内容的字段 如 name, type等

4.2.2.新建word文档模板之后,保存为xml格式的文件,保存之后打开编辑,在xml中修改我们的字段为${name}等,修改之后可以通过代码的方式来写入内容到wrod中

4.2.3.利用freemarker 来实现 生成word、动态添加数据到word中

5.demo运行项目

5.1 这里我们以 java项目为例,Android项目类似,只需要添加文件读写权限即可。

java workbook 写入到文件中 java往word文档中写入数据_java

5.2 这里新建的模板为 doc格式。

java workbook 写入到文件中 java往word文档中写入数据_xml_02

这里我们指定每一项的字段,有图片或者文件时不需要处理。

5.3 模板有了之后我们保存为*xml 文件 ,打开编辑xml文件,用crtl+f 的方法 去找我们对应的NAME、SEX 并且将其改为

${NAME}、${SEX}...

这里我们需要找到类似这样的标签

<w:t>.......</w:t>

,然后将其修改为

</w:t>${NAME}</w:t>

所有的字符串字段均作为修改,这里需要注意,当我们有图片时,我们需要找的标签是这样的

w:binData w:name="wordml://02000001.jpg" xml:space="preserve">${image}</w:binData> 

 //这里 ${image}  已经是修改之后的值,没修改之前为 一串很长的值,我们替换掉

这里我已经修改过,原来的里面是一堆很长很长的乱码,我们直接用我给的这个给替换掉,代码中用image去写一张新的图片进去。

5.4 至此,我们的xml修改成功,修改完成之后,我们需要修改生成的 xml后缀名 为 ftl 格式,生成之后放到我们的项目之下,这个模板就当做我们word的模板,下面的事情就是写代码进去,将我们的内容填充进去,main函数中申明我们的模板

public static void main(String[] args){
        Freemark freemark = new Freemark("template/");//这里如果放在了具体的包名下,需要修改为 "/com/test/template/"
        freemark.setTemplateName("简历-朱老师.ftl");
        freemark.setFileName("doc_"+new SimpleDateFormat("yyyy-MM-dd hh-mm-ss").format(new Date())+".doc");//生成的word名称
        freemark.setFilePath("D:/");//生成word存储路径
        freemark.createWord();//生成方法
    }

创建word的方法

private void createWord(){

        Template t = null;
        try {
            t = configuration.getTemplate(templateName);
        } catch (IOException e) {
            e.printStackTrace();
        }

        File outFile = new File(filePath+fileName);
        Writer out = null;
        try {
            out = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(outFile), "UTF-8"));
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }

        Map map = new HashMap<String, Object>();

        map.put("NAME", "韩满义");
        map.put("image", getImageStr());

        map.put("SEX", "男");
        map.put("BIRTH", "1987-08");
        map.put("ZZMM", "党员");
        map.put("MZ", "汉");
        map.put("JG", "河北省");
        map.put("JKZK", "良好");
        map.put("SG", "173cm");
        map.put("HYZK", "已婚");
        map.put("XL", "本科");
        map.put("BYYX", "河北工业大学");
        map.put("ZY", "软件工程");
        map.put("ZP", "照片//todo");
        map.put("QZYX", "软件方向工作薪资1w上下");
        map.put("JYSH1", "06-09-01~10-06-20");
        map.put("JYYZ1", "河北工业大学 软件工程");
        map.put("JYXW1", "学士学位");
        map.put("JYKC1", "软件工程、微积分、软件过程管理、数据库原理等等");

        map.put("JYSH2", "10-07-01~至今");
        map.put("JYYZ2", "ABCDE大学");
        map.put("JYXW2", "XYZ学位");
        map.put("JYKC2", "POI课程");

        map.put("ZYJN", "软件开发、软件管理");

        map.put("GZSH1", "10-07-01~11-12-09");
        map.put("GZDZ1", "华信软件");
        map.put("GZGY1", "初级软件工程师");

        map.put("GZSH2", "11-12-15~14-4-05");
        map.put("GZDZ2", "北京久其");
        map.put("GZGY2", "高级软件工程师");

        map.put("JLQK", "二三等奖学金、富士通奖学金等");
        map.put("ZWPJ", "兴趣丰富、好奇心强、有研究精神。");

        map.put("DH", "0312-3132098");
        map.put("SJ", "15033768387");
        map.put("YJ", "hanmanyifengyi@163.com");
        map.put("DZ", "河北省保定市");
        map.put("YB", "071000");

        try {
            t.process(map, out);
            out.close();
        } catch (TemplateException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }

    }

下面是类里面的其余方法:

/**
     * freemark初始化
     * @param templatePath 模板文件位置
     */
    public Freemark(String templatePath) {
        configuration = new Configuration();
        configuration.setDefaultEncoding("utf-8");
        configuration.setClassForTemplateLoading(this.getClass(),templatePath);     
    }   
    /**
     * 得到图片
     * @return
     */
    private String getImageStr() {
        String imgFile = "D:/hanmanyi/pic/111.jpg";//需要在D盘下指定的目录下放一张图片
        InputStream in = null;
        byte[] data = null;
        try {
            in = new FileInputStream(imgFile);
            data = new byte[in.available()];
            in.read(data);
            in.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
        BASE64Encoder encoder = new BASE64Encoder();//这里会报错
        return encoder.encode(data);
    }

    /**
     * freemark模板配置
     */
    private Configuration configuration;
    /**
     * freemark模板的名字
     */
    private String templateName;
    /**
     * 生成文件名
     */
    private String fileName;
    /**
     * 生成文件路径
     */
    private String filePath;

    public String getFileName() {
        return fileName;
    }

    public void setFileName(String fileName) {
        this.fileName = fileName;
    }

    public String getFilePath() {
        return filePath;
    }

    public void setFilePath(String filePath) {
        this.filePath = filePath;
    }

    public String getTemplateName() {
        return templateName;
    }

    public void setTemplateName(String templateName) {
        this.templateName = templateName;
    }

6.需要注意的问题

6.1 word模板如果有图片或者是文件,需要有一张默认的图片,即要赋值,不能为空 ,如果不写,则编译不成功
6.2 BASE64ENCODE 出现的错误,这里需要修改我们的编译环境,以eclipse为例,我们需要 windows->preference-> java->compiler->Error/warning->

java workbook 写入到文件中 java往word文档中写入数据_freemarker_03

这里需要修改为warning,不要弄成error

6.4 如果我们想在安卓客户端实现此处功能,建议后台服务器写一个接口,客户端传递参数生成word文档,之后返回客户端,本项目为web应用的项目,尝试将项目改为Android项目,运行报错,Configration 在初始化过程中出错,无法执行下去。