zoukankan      html  css  js  c++  java
  • java基于feemarker 生成word文档(超级简单)

    问题由来:

    开发个新需求,需要按规定导出word文档,文档截图如下

    因为之前没做过这个,一脸懵B啊,导出excel和txt倒是经常接触到,对于这个word这种格式不严谨的文件怎么处理呢?

    技术选型:可协助实现的技术很多,但是本人极力推荐feemarker,简直太好用了。

    具体实施:

    步骤一:maven项目 先添加如下依赖:

    <!--freemarker 协助word 导出-->
            <dependency>
                <groupId>org.freemarker</groupId>
                <artifactId>freemarker</artifactId>
                <version>2.3.20</version>
            </dependency>

    不是maven的,去下载feemarker.jar 导入就好了

    步骤二原理就是先做一个word模板, 该模板中变量数据用${xxx}这种方式填写, 然后再导出时只需读取模板然后用相应的数据替换其中的${xxx}即可. 

    我们这里设置了三个变量;

    步骤三把该word文档 另存为xml文件(是另存为,不是改扩展名为xml),然后再改扩展名为ftl,步骤不能错。随便放在一个地方,我们这里先放在D盘根目录 名为 测试.ftl;

    步骤四:上代码

    try {
                    Map<String,String> dataMap = new HashMap<String,String>();
                    dataMap.put("account", "123456");
                    dataMap.put("name", "张三");
                    dataMap.put("idNumber", "123123");
                    Configuration configuration = new Configuration();
                    configuration.setDefaultEncoding("utf-8");
                    //指定模板路径的第二种方式,我的路径是D:/      还有其他方式
                    configuration.setDirectoryForTemplateLoading(new File("D:/"));
    
                    // 输出文档路径及名称
                    File outFile = new File("D:/test.doc");
                    //以utf-8的编码读取ftl文件
                    Template t =  configuration.getTemplate("测试.ftl","utf-8");
                    Writer out = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(outFile), "utf-8"),10240);
                    t.process(dataMap, out);
                    out.close();
                } catch (IOException e) {
                    e.printStackTrace();
                } catch (Exception e) {
                    e.printStackTrace();
                }

    跑起来,大兄弟。

    步骤四:跑完,发现在我的D盘  有个test.doc,点开看看

    完美啊,发现数据进去了。

    技术扩展(循环列表):

    其实到这里,已经可以满足很多的场景需要了。

    但是我们这里还欠缺了点,因为我们的数据列表是循环的,因为可能不止一条数据。

    那怎么办呢?

    其实feemarker已经为我们考虑了这一点了, 先上代码

    Map<String,String> map1 = new HashMap<String,String>();
                    map1.put("account", "123456");
                    map1.put("name", "张三");
                    map1.put("idNumber", "123123");
                    Map<String,String> map2 = new HashMap<String,String>();
                    map2.put("account", "456789");
                    map2.put("name", "李四");
                    map2.put("idNumber", "123");
    
                    List<Map<String,String>> newlist = new ArrayList<>();
                    newlist.add(map1);
                    newlist.add(map2);
                    Map<String, Object> dataMap = new HashMap<>();
                    dataMap.put("userList", newlist);
    
                    Configuration configuration = new Configuration();
                    configuration.setDefaultEncoding("utf-8");
                    //指定模板路径的第二种方式,我的路径是D:/      还有其他方式
                    configuration.setDirectoryForTemplateLoading(new File("D:/"));
    
                    // 输出文档路径及名称
                    File outFile = new File("D:/test.doc");
                    //以utf-8的编码读取ftl文件
                    Template t =  configuration.getTemplate("测试.ftl","utf-8");
                    Writer out = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(outFile), "utf-8"),10240);
                    t.process(dataMap, out);
                    out.close();

    代码里我们对数据的封装做了改动,我们传了list进去,list里面都是key相同的map;

    还得对我们的 ftl 文件内容改动一下

    搜索  w:tr 可以找到行的起点与结束点(注意第一对w:tr 是表头,应找第二对 w:tr), 如图(网上摘录的图,因为我自己的ftl文件内容太大,截不了): 

     用<#list userList as user> </#list>标签将第二对 w:tr 标签包围起来(userList是集合的key, user是集合中的每个元素, 类似<c:forEach items='userList' var='user'>), 如图: 

    当然,这里的user.a   要换  user随便写,和上面的as user对应起来就好,这里需要改成user.account, user.name,user.idNumber;

    现在看看文件变成什么样了

     完美解决list循环读取的问题;

    扩展二(直接导出):

    显然我们这里处理文件的方式是直接生成文件放在了D盘里,更多的时候,我们需要直接导出;

                    Map<String,String> dataMap = getData();  //获取数据
                    //Configuration用于读取ftl文件
                    Configuration configuration = new Configuration();
                    configuration.setDefaultEncoding("utf-8");
    
                    //获取模板所在的路径
                    configuration.setDirectoryForTemplateLoading(new File(pathHelper.getWebClassesPath()+"/template"));
    
                    //以utf-8的编码读取ftl文件
                    Template t =  configuration.getTemplate("测试.ftl","utf-8");
    
                    String fileName = URLEncoder.encode("客户信息-","UTF-8") + dataMap.get("formCode")+".doc";
                    //1.设置文件ContentType类型,这样设置,会自动判断下载文件类型
                    response.setContentType("multipart/form-data");
                    //2.设置文件头:最后一个参数是设置下载文件名(假如我们叫a.pdf)
                    response.setHeader("Content-Disposition", "attachment;fileName=" + fileName);
                    Writer out = new BufferedWriter(new OutputStreamWriter(response.getOutputStream(), "utf-8"),10240);
                    t.process(dataMap, out);
                    out.close();

    这样就可以直接导出了。

    可能遇到的bug:

    就是获取模板的那步可能会出问题,提示找不到模板。feemarker为我们提供了三种方法

    第一种:基于类路径,HttpWeb包下的framemaker.ftl文件
      configuration.setClassForTemplateLoading(this.getClass(), "/HttpWeb");


    第二种:基于文件系统

    configuration.setDirectoryForTemplateLoading(new File("/template"))

    第三种:基于Servlet Context,指的是基于WebRoot下的template下的framemaker.ftl文件

    HttpServletRequest request = ServletActionContext.getRequest();

    configuration.setServletContextForTemplateLoading(request.getSession().getServletContext(), "/template");

    因为放在项目中,肯定想设置个相对路径,我就选择了第一种,

    项目存放路径

    注意:configuration.setClassForTemplateLoading(this.getClass(),"/jasperreports");   
    这样就可以了,千万别写什么 /resources/jasperreports,因为maven项目打包的时候,resources文件夹就不存在了。



    好了到这里,介绍完毕,是不是很简单又美观呢。
  • 相关阅读:
    Linux内核分析作业六
    课本第三章读书笔记
    课本第十八章读书笔记
    Linux内核分析作业五
    课本第五章读书笔记
    MSF MS11-050/10-087/Adobe攻击实践及内存保护技术
    Linux课题实践五——字符集总结与分析
    Linux课题实践四——ELF文件格式分析
    Linux课题实践三——程序破解
    实践二——内核模块
  • 原文地址:https://www.cnblogs.com/xinde123/p/8581963.html
Copyright © 2011-2022 走看看