java实现生成word文档

本文介绍了如何利用Freemarker根据数据库数据生成Word文档,包括定义模板、转换XML、处理表格和单元格合并,以及图片插入的方法。还提到了Freemarker不支持null值和处理表格数据时的注意事项。
摘要由CSDN通过智能技术生成

简介

之前项目中有一个生成word文档的功能,根据数据库的数据进行word文档的生成,当时实现了该功能,但没有打笔记忘记了,特此打个笔记记录一下

我使用的freemarker的技术来实现word的生成,网上也都比较推荐该方式,他是通过根据一个模板,进行填充的方式实现word的生成

准备工作

定义word模板

我们要使用freemarker生成word,首先要自己去定义一个doc模板,模板中要填充的数据使用字符串模板的方式定义  ${ 字段名 } 

定义完我们的模板之后,我们要将文档保存为xml的格式

修改保存的xml文件

保存完的xml文件是一行的不好查看,我们可以提前复制到idea中,使用ctrl + alt  + l  进行格式化,就变成标准的xml格式了

保存为xml常见的问题就是${name}被拆开了,我们要进行修改

 修改为下面这样(多余的wr直接删除即可)

 

基础信息的定义

基础信息的定义只要保证我们转化成的xml文件中的${name} , ${age}格式没错误即可

表格的定义

遍历实现,表格的数据填充

在xml文件中我们的 <w:tbl>  代表是我们的表格 ,<w:tr>  代表的是我们的行  ,<w:tc>  代表我们的列

我们要想使用表格的方式,肯定大部分是要使用我们的list集合进行数据填充的,我们可以通过下面的方式进行遍历填充数据

我们在表格的表头下的<w:tr>上添加

 <#list bookList as book>

在我们</w:tr>下添加

</#list>

其中bookList代表我们要遍历的集合,book代表出来的结果,book.month代表book中的字段

 实现单元格的合并

有两个标签

该标签表示,从这个开始进行合并

<w:vMerge w:val="restart"/>

 该标签表示,只要带这个标签他就与上面的这个标签合并

<w:vMerge/>

我们将这两个标签定义到我们要合并的单元格的<w:tcPr>中

<w:tcPr>
	<w:tcW w:w="2765" w:type="dxa"/>
    <#-- 表示居中-->
	<w:vAlign w:val="center"/>
	<#-- 将month 等于1 和 2的进行合并-->
	<#if book.month == 1>
		<w:vMerge w:val="restart"/>
	</#if>
	<#if book.month == 2>
		<w:vMerge/>
	</#if>
</w:tcPr>

图片的插入

首先我们要在指定位置添加一个图片,我们保存为xml文件后,我们的图片信心会变为base64转码的字符串,将这部分进行删除,替换为${images},所以我们进行填充时也要是base64转码后的数据

 

修改xml文件为ftl文件

最后将我们的文件修改为 .ftl   格式的文件复制到我们 templates文件夹下

 代码实现

首先要导入我们的freemarker依赖

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-freemarker</artifactId>
        </dependency>

定义我们要填充的数据

    public Map<String,Object> dataMap() throws IOException {
        //获取基础数据
        Map<String , Object> map = new HashMap<>();
        map.put("name","qtt");
        map.put("age","25");

        //获取表格数据
        List<Map<String,Object>> bookList = new ArrayList<>();
        for (int i = 0; i < 5; i++) {
            Map<String, Object> map1 = new HashMap<>();
            map1.put("month",i);
            map1.put("income", i);
            map1.put("expense", i +100);
            bookList.add(map1);
        }
        map.put("bookList",bookList);

        //获取图片流且进行base64转码
        File file = new File("C:\\Users\\Administrator\\Desktop\\teacher\\01.jpg");
        FileInputStream fileInputStream = new FileInputStream(file);
        byte[] bytes = new byte[fileInputStream.available()];
        fileInputStream.read(bytes);
        BASE64Encoder base64Encoder = new BASE64Encoder();
        String encode = base64Encoder.encode(bytes);
        map.put("images",encode);
        //关闭流
        fileInputStream.close();
        
        return map;
    }

定义我们我们的填充方法

    @Test
    public void insertWord() throws IOException, TemplateException {
        //定义我们的编码方式
        Configuration configuration = new Configuration();
        configuration.setDefaultEncoding("UTF-8");

        //指定我们word的目录
        configuration.setDirectoryForTemplateLoading(new File("src/main/resources/templates"));

        //指定我们要使用的word模板.ftl
        Template template = configuration.getTemplate("模板.ftl", "UTF-8");

        //指定输出流到的位置
        BufferedWriter bufferedWriter = new BufferedWriter(new OutputStreamWriter(new FileOutputStream("E:/222/demo.doc"), "UTF-8"));

        //执行填充输出
        template.process(this.dataMap(),bufferedWriter);

        //关闭io流
        bufferedWriter.flush();
        bufferedWriter.close();
    }

我们还可以直接定义为下载,不用使用输出流指定下载地址,直接通过下载的方式指定地址

    @GetMapping("/upload")
    public void upload(HttpServletResponse response){
        try {

            //定义我们的编码方式
            Configuration configuration = new Configuration();
            configuration.setDefaultEncoding("UTF-8");
            //指定我们word的目录
            configuration.setDirectoryForTemplateLoading(new File("src/main/resources/templates"));
            //指定我们要使用的word模板.ftl
            Template template = configuration.getTemplate("模板.ftl", "UTF-8");

            //返回word文档
            SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyyMMddHHmmss");
            String format = simpleDateFormat.format(new Date());
            String fileName = URLEncoder.encode("接口文档" + format, "UTF-8");
            response.setCharacterEncoding("UTF-8");
            //请求头定义为下载
            response.setHeader("Content-Disposition","attachment;filename="+fileName+".doc");

            //获取apiDoc所需要的数据
            Map<String, Object> map = dataMap();

            //渲染模板
            template.process(map, response.getWriter());
            //response的Writer不需要我们手动关,tomcat会帮我们关的
        } catch (Exception e) {
            log.error("导出word异常:", e);
        }
    }

遇到的坑

1.优为注意:freemarker是不支持  null 的,所以我们的数据要么全部附上值,要么给为空的值设置为 " " ,否则会报错

2.我们在定义表格l遍历填充的时候,一定要注意传入的表格字段类型是list,不能是map,否则会报错

3.和并单元格的时候,查看的文章,它定义的标签是m是小写,实现不了合并,看其他文章都为大写M,修改实现了合并,有大小写区分

无法合并的情况

<w:vmerge w:val="restart"/>
<w:vmerge/>

修改后可以合并

<w:vMerge w:val="restart"/>
<w:vMerge/>

  • 10
    点赞
  • 50
    收藏
    觉得还不错? 一键收藏
  • 5
    评论
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值