SpringBoot使用freemarker动态生成word文档

最近做项目有个需求,在动态生成word文档的同时插入电子签名图片,这里使用freemarker来实现。

首先引入freemarker依赖:

<!-- freemarker -->
<dependency>
	<groupId>org.freemarker</groupId>
	<artifactId>freemarker</artifactId>
	<version>2.3.28</version>
</dependency>

首先模板要自己先画好,打开word自己制作一个模板:

然后将它另存为xml,修改相关内容后再另存为ftl文件,这样就可以使用了(抓取重要的几个部分)

//如果想要打出多个要是用list标签
<#list signs as sign>
<w:body>
....
//文字部分的替换
<w:r>
	<w:rPr>
		<w:rFonts w:hint="fareast"/>
		<w:b/>
		<w:b-cs/>
		<w:sz w:val="32"/>
		<w:sz-cs w:val="32"/>
		<w:lang w:val="EN-US" w:fareast="ZH-CN"/>
	</w:rPr>
	<w:t>作战部队:${sign.army}</w:t>
</w:r>
...
//图片部分(二维码也是一样的)
<#if (sign.signImage != "")>
<w:pict>
	<w:binData w:name="wordml://${sign_index}_1.png">${sign.signImage}</w:binData>
	<v:shape id="图片 1" o:spid="_x0000_s1026" o:spt="75" alt="qm" type="#_x0000_t75" style="position:absolute;left:0pt;margin-left:41.1pt;margin-top:7.45pt;height:53.2pt;width:329.25pt;mso-wrap-distance-left:9pt;mso-wrap-distance-right:9pt;z-index:-251658240;mso-width-relative:page;mso-height-relative:page;" filled="f" o:preferrelative="t" stroked="f" coordsize="21600,21600" wrapcoords="0 0 0 20950 21492 20950 21492 0 0 0">
		<v:path/>
		<v:fill on="f" focussize="0,0"/>
		<v:stroke on="f"/>
		<v:imagedata src="wordml://${sign_index}_1.png" o:title=""/>
		<o:lock v:ext="edit" aspectratio="t"/>
		<w10:wrap type="tight"/>
	</v:shape>
</w:pict>
</#if>
...
</w:body>
</#list>

项目结构大致如下:

编写一个文件处理工具类:

@Component
public class DocumentUtil {
   /**
     * 生成word或excel文件
     * @param dataMap word或excel中需要展示的动态数据,用map集合来保存
     * @param templateName word或者excel模板名称,例如:test.ftl
     * @param fileFullPath 要生成的文件全路径
     */
    @SuppressWarnings("unchecked")
    public static void createWordOrExcel(Map dataMap, String templateName, String fileFullPath) {
        logger.info("[createWord]:==>方法进入");
        logger.info("[fileFullPath]:==>" + fileFullPath);
        logger.info("[templateName]:==>" + templateName);

        try {
            // 创建配置实例
            Configuration configuration = new Configuration();
            logger.info("[创建配置实例]:==>");

            // 设置编码
            configuration.setDefaultEncoding("UTF-8");
            logger.info("[设置编码]:==>");

            // 设置处理空值
            configuration.setClassicCompatible(true);

            // 设置ftl模板文件加载方式
            configuration.setClassForTemplateLoading(DocumentUtil.class,"/template/ftl");

            //创建文件
            File file = new File(fileFullPath);
            // 如果输出目标文件夹不存在,则创建
            if (!file.getParentFile().exists()) {
                file.getParentFile().mkdirs();
            }

            // 将模板和数据模型合并生成文件
            Writer out = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(file), "UTF-8"));
            // 获取模板
            Template template = configuration.getTemplate(templateName);
            // 生成文件
            template.process(dataMap, out);

            // 清空缓存
            out.flush();
            // 关闭流
            out.close();

        } catch (Exception e) {
            logger.info("[生成word或excel文件出错]:==>" + e.getMessage());
            e.printStackTrace();
        }
    }
}

二维码和图片的工具类:

public class QRCodeUtil {

    /**
     * 生成BASE64格式的二维码
     * @param contents
     * @param width
     * @param height
     * @return
     */
    public static String creatRrCode(String contents, int width, int height) {
        String binary = null;
        Hashtable hints = new Hashtable();
        hints.put(EncodeHintType.CHARACTER_SET, "utf-8");
        try {
            BitMatrix bitMatrix = new MultiFormatWriter().encode(contents, BarcodeFormat.QR_CODE, width, height, hints);
            // 1、读取文件转换为字节数组
            ByteArrayOutputStream out = new ByteArrayOutputStream();
            BufferedImage image = toBufferedImage(bitMatrix);
            //转换成png格式的IO流
            ImageIO.write(image, "png", out);
            byte[] bytes = out.toByteArray();

            // 2、将字节数组转为二进制
            binary = new String(Base64.encodeBase64(bytes));
        } catch (WriterException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return binary;
    }

    /**
        * image流数据处理
        */
    public static BufferedImage toBufferedImage(BitMatrix matrix) {
        int width = matrix.getWidth();
        int height = matrix.getHeight();
        BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
        for (int x = 0; x < width; x++) {
            for (int y = 0; y < height; y++) {
                image.setRGB(x, y, matrix.get(x, y) ? 0xFF000000 : 0xFFFFFFFF);
            }
        }
        return image;
    }


    /**
     * 根据图片url转成图片文件
     * @param url
     * @return
     */
    public static File dealUrlToImage(String url) {
        ByteArrayOutputStream outStream = new ByteArrayOutputStream();
        BufferedOutputStream stream = null;
        InputStream inputStream = null;
        File file = null;
        try {
            URL imageUrl = new URL(url);
            HttpURLConnection conn = (HttpURLConnection) imageUrl.openConnection();
            conn.setRequestProperty("User-Agent", "Mozilla/4.0 (compatible; MSIE 5.0; Windows NT; DigExt)");
            inputStream = conn.getInputStream();
            byte[] buffer = new byte[1024];
            int len = 0;
            while ((len = inputStream.read(buffer)) != -1) {
                outStream.write(buffer, 0, len);
            }
            file = File.createTempFile("pattern", "." + "jpg");
            FileOutputStream fileOutputStream = new FileOutputStream(file);
            stream = new BufferedOutputStream(fileOutputStream);
            stream.write(outStream.toByteArray());
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                if (inputStream != null) {
                    inputStream.close();
                }
                if (stream != null) {
                    stream.close();
                }
                outStream.close();
            } catch (Exception e) {
            }
            return file;
        }
    }

    public static 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);
    }

}

controller

@Api(tags = "文件管理")
@RestController
@RequestMapping("/document")
public class FileController {
    @ApiOperation(value="生成word文件测试")
    @RequestMapping(value = "/createWord", method = RequestMethod.POST)
    public String createWord() throws IOException {
        Map<String, Object> resultMap = new HashMap<>();
        List<Map<String, Object>> mapList = new ArrayList<>();
        Map<String, Object> map1 = new HashMap<>();
        map1.put("army", "八路军独立团一营");
        map1.put("speciality", "三八大盖");
        File file = QRCodeUtil.dealUrlToImage("这里是你想要的图片的地址");
        map1.put("signImage", QRCodeUtil.getImageStr(file.getAbsolutePath()));
        map1.put("img", QRCodeUtil.creatRrCode("20201986606-001-sfasfasfsdgfs", 100, 100));
        mapList.add(map1);
        Map<String, Object> map2 = new HashMap<>();
        map2.put("army", "八路军独立团二营");
        map2.put("speciality", "意大利炮");
        map2.put("signImage", QRCodeUtil.getImageStr(file.getAbsolutePath()));
        map2.put("img", QRCodeUtil.creatRrCode("20201986606-002-sdsdafafafasafa", 100, 100));
        mapList.add(map2);
        resultMap.put("signs", mapList);

        //模板名称
        String templateName = "签名.ftl";
        String fileFullPaths = "C:\\Users\\Administrator\\Desktop\\电子签名.docx";

        DocumentUtil.createWordOrExcel(resultMap,templateName, fileFullPaths);
        return "操作成功!";
    }
}

最终结果展示

如果你要生产成excel步骤也是和上面一样的

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
SpringBoot_Freemarker生成Word_多个表格+两层嵌套循环; 步骤说明: 1.用Microsoft Office Word打开word原件;将文档中需要动态生成的内容,替换为属性名 ${name} 2.另存为,选择保存类型Word 2003 XML 文档(*.xml) 3.用Firstobject free XML editor打开文件,选择Tools下的Indent【或者按快捷键F8】格式化文件内容。左边是文档结构,右边是文档内容; 4. 文档生成后有时需要手动修改,查找第一步中设置的属性名,可能会产生类似${n.....ame}类似的样子,我们将将名字中间的标签删掉,恢复为${name} 5. word模板中有表格,需要循环的位置, 用 标签将第二对 标签(即除表头的w:tr标签后的一对)包围起来 同时表格内的属性例如${name},在这里需要修改为${user.name} (userList是集合在dataMap中的key, user是集合中的每个元素, 类似), 如图: PLUS:若表格之外还有嵌套的循环,也需要用,注意这里的标签不要和某对其他标签交叉,不可以出现这种 6. 标识替换完之后,另存为.ftl后缀文件即可。 代码里是相对有一丢丢复杂的,两层嵌套循环; 总(dataMap) deptName 部门名 list(Table)表的集合 table1(map) table-名字 ${map.table} tableName-中文名 ${map.tableName} columnCount-字段数 ${map.columnCount} recordCount-记录数 ${map.recordCount} listA-List--表格1 map.listA column Model属性——字段名 ${model.column} columnName Model属性——字段中文名 ${model.column} rate Model属性——字段占比 ${model.rate} nullValueCount Model属性——字段空值数 ${model.nullValueCount} listB-List--表格2 map.listB …… listC-List--表格3 map.listC …… table2 table-名字 ${map.table} tableName-中文名 ${map.tableName} columnCount-字段数 ${map.columnCount} recordCount-记录数 ${map.recordCount} listA-List--表格1 map.listA column Model属性——字段名 ${model.column} columnName Model属性——字段中文名 ${model.column} rate Model属性——字段占比 ${model.rate} nullValueCount Model属性——字段空值数 ${model.nullValueCount} listB-List--表格2 map.listB …… listC-List--表格3 map.listC …… table3 ……

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值