zoukankan      html  css  js  c++  java
  • FreemarkerJavaDemo【Android将表单数据生成Word文档的方案之一(基于freemarker2.3.28,只能java生成)】

    版权声明:本文为HaiyuKing原创文章,转载请注明出处!

    前言

    这个方案只能在java中运行,无法在Android项目中运行。所以此方案是:APP将表单数据发送给后台,后台通过freemarker将表单数据根据模板ftl文件生成Word文件,然后返回给APP,由APP进行展现。

    前期准备

    1、下载freemarker.jar文件

    官网下载地址:https://freemarker.apache.org/freemarkerdownload.html

     

    后续将freemarker.jar文件添加到项目中。

    2、制作模板ftl文件

    (1)先用office2003或更高版本word软件编辑好word模版文件【版本要2003以上,2003以下的不支持另存为xml格式功能】

    注意:

    • 在word模板中写入相对真实的数据【注意,不要使用英文,尽量使用中文、数字,见附录1】;
    • 对于对勾样式的数据,在word模板文件中统一用安卓代替(后续需要通过java代码传入带有对勾样式的数据);
    • 需要设置图片的话,需要在word模板文件中放入真实的图片占位;请尽量选择小于50K的图片,并且把图片的大小和位置调整好。选择小图片的原因是避免xml文件过大导致打开时缓慢甚至卡死。

    例子:

     

    (2)另存为Word 2003 XML文档

    对于Word2016,另存为后会自动打开xml文件,所以需要先关闭xml文件,然后再使用FirstObject XML Editor软件打开xml文件!

    (3)下载FirstObject XML Editor软件

     下载FirstObject XML Editor软件(免安装版):下载地址:http://www.firstobject.com/dn_editor.htm

       

    官网下载的软件打开文件的时候可能会出现崩溃的问题建议使用foxe_CHS.exe软件进行编辑。下载地址见项目Demo下载地址。

    (4)使用FirstObject XML Editor软件将xml打开,将真实数据换成FreeMarker标记

    首先进行“缩进排版”

    查找真实数据,替换成FreeMarker标记,其实就是Map<String, Object>中key,如${writeDate},对应Map的key值就是writeDate。

    替换成:

    对于文本按照上面的方式进行替换,而对于图片需要这样替换:

    图片是以base64编码存在的,且这些编码放在<w:binData>标签之中。将这些base64编码使用占位符代替,然后java代码中将图片生成base64编码,传入值就能正常显示了。

    替换成

    (5)然后保存,直接将文件后缀修改为.ftl(FreeMarker模板)

     

    注意:一定不要用word打开ftl模板文件查看,否则xml内容会发生变化,导致前面的工作白做了;可以使用EditPlus打开查看。

    使用步骤

    一、项目组织结构图

    二、导入步骤

    1、在项目中引入freemarker.jar

    2、将制作的模板文件leaveTemplet.ftl和图片资源复制到D:/temp目录下

    3、将DocumentHandler.java文件复制到项目中

    package com.why.main;
    
    import java.io.BufferedWriter;
    import java.io.File;
    import java.io.FileInputStream;
    import java.io.FileNotFoundException;
    import java.io.FileOutputStream;
    import java.io.IOException;
    import java.io.InputStream;
    import java.io.OutputStreamWriter;
    import java.io.UnsupportedEncodingException;
    import java.io.Writer;
    import java.util.HashMap;
    import java.util.Map;
    
    import freemarker.template.Configuration;
    import freemarker.template.Template;
    import freemarker.template.TemplateException;
    import sun.misc.BASE64Encoder;
    
    /**
     * 生成Doc文档
     */
    public class DocumentHandler {
    
        //测试
        public static void main(String[] args) {
            DocumentHandler documentHandler = new DocumentHandler();
            documentHandler.createDoc();
        }
    
        // 配置实例:只需要一个实例(单例模式)
        private Configuration configuration = null;
    
        private String tempDirPath = "D:/temp";
    
        public DocumentHandler() {
            // 通过Freemaker的Configuration读取相应的ftl
            configuration = new Configuration(Configuration.VERSION_2_3_28);
            configuration.setDefaultEncoding("UTF-8");// 设置默认编码方式
        }
    
        /**
         * 生成DOC文档
         */
        public void createDoc() {
            // 要填入模本的数据文件
            Map<String,Object> dataMap = new HashMap<String,Object>();
            getData(dataMap);
            // 设置模本装置方法和路径,FreeMarker支持多种模板装载方法。可以重servlet,classpath,数据库装载,
            // 如果模板是放在程序代码的包下面
            //configuration.setClassForTemplateLoading(this.getClass(),"../");
            //如果放到服务器目录中,则使用下面的代码
            try {
                configuration.setDirectoryForTemplateLoading(new File(tempDirPath));
            } catch (IOException e2) {
                e2.printStackTrace();
            }
            //这里要设置取消使用Local语言环境
            configuration.setLocalizedLookup(false);
            Template template = null;
            try {
                // leaveTemplet.ftl为要装载的模板
                template = configuration.getTemplate("leaveTemplet.ftl","UTF-8");
            } catch (IOException e) {
                e.printStackTrace();
            }
            // 输出文档路径及名称
            File dir = new File(tempDirPath);
            File outFile = new File(tempDirPath + "/请假条.doc");
            if (!dir.isDirectory()) {
                dir.mkdir();
                if (!outFile.exists()) {
                    try {
                        outFile.createNewFile();
                    } catch (IOException e) {
                        System.out.println("创建文件失败");
                        e.printStackTrace();
                    }
                }
            }
            Writer out = null;
            try {
                try {
                    out = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(outFile), "UTF-8"));
                } catch (UnsupportedEncodingException e) {
                    e.printStackTrace();
                }
    
            } catch (FileNotFoundException e1) {
                System.out.println("输出文件失败");
                e1.printStackTrace();
            }
            try {
                template.process(dataMap, out);
                System.out.println("it's success!");
            } catch (TemplateException e) {
                System.out.println("生成失败");
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    
        /**
         * 注意dataMap里存放的数据Key值要与模板中的参数相对应
         */
        private void getData(Map<String,Object> dataMap) {
            String imgBase64Str = getImageStr(tempDirPath + "/leaderopinion_img.png");
    
            // 使用String的有参构造方法
            dataMap.put("writeDate","2018年10月13日");//填写日期
            dataMap.put("name","HaiyuKing");//姓名
            dataMap.put("dept","移动组");//部门
            dataMap.put("leaveType","☑倒休 √年假 ✔事假 ☐病假 ☐婚假 ☐产假 ☐其他");//请假类型
            dataMap.put("leaveReason","倒休休息两天");//请假理由
            dataMap.put("leaveStartDate","2018年10月13日上午");//请假开始日期
            dataMap.put("leaveEndDate","2018年10月14日下午");//请假结束日期
            dataMap.put("leaveDay","2");//请假天数
            dataMap.put("leaveLeader","同意");//直属领导意见
            dataMap.put("leaveDeptLeaderImg",imgBase64Str);//部门领导意见
    
        }
    
        /**
         * 获取图片的base64值*/
        private String getImageStr(String imgFile) {
            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);
        }
    }
    DocumentHandler.java

    注意:Map数据中的key值,对应ftl文件中的${xxxx}这里面的xxxx值。

    4、运行

    5、效果

    附录

    1、Word模板中输入真实数据的技巧

    1、不要使用英文;

    2、如果想要保证一个整体,不要将中文、数字、标点符号一起使用(这里指占位区域);

    3、日期想要作为一个整体,不要数字+中文输入,而是通过Enter键输入;

    下面记录的是不同输入的效果(使用FirstObject XML Editor软件打开xml文件)

    使用英文:

    使用数字:

    使用中文:

     日期采用数字+中文:

    日期采用Enter键输入:

    中文+标点符号:

    参考资料

    java生成word的几种方案

    沫沫金:使用Java模版引擎FreeMarker生成复杂的Word文档

    模板引擎freemarker的简单使用教程

    使用freemarker生成word,步骤详解并奉上源代码

    firstobject XML 编辑器

    freemarker官网

    用Freemarker导出word文档

    Android利用FreeMarker自动生成文件

    Freemarker入门案例

    freeMarker生成各类文件,含图片

    FreeMaker解析Word模板(含图片)生成Word文档

    项目demo下载地址

    链接:https://pan.baidu.com/s/19aPNIYWXt5GMN_KDQjFCRA 提取码:eo0n

  • 相关阅读:
    VS.NET2005中的源代码管理
    IE6升级后需要激活ActiveX控件的解决办法
    SQL Server的数据库开发工具
    今天更新了ActiveSync4.2
    永远等你先挂电话
    这回软设考试通过了!
    在Windows2003中FSO组件不能使用的问题
    七天的假期好长哟!
    发现博客园的一个Bug 存为草稿后就找不到了
    MySQL服务不能启动的解决方法
  • 原文地址:https://www.cnblogs.com/whycxb/p/9781839.html
Copyright © 2011-2022 走看看