根据模板动态生成word(一)使用freemarker生成word

打印 上一主题 下一主题

主题 941|帖子 941|积分 2823

@
目录

一、准备模板

1、创建模板文件

首先先建立一个word文件,输入模板内容freemaker的内容,下面是本次演示的word文件。

然后将word文件另存为 .xml 文件,然后再把文件后缀改成.ftl 。将项目的resource目录下建立一个templates目录(非必须步骤)将 模板文件放到templates目录下


打开模板文件按 Ctrl + Shift + L 将模板内容格式化。
2、处理模板

2.1 处理普通文本

处理文本比较简单,将需要替换文本中直接用占位符 ${} 替换即可。
这里发现一个问题因为之前在word格式时我就已经替换了变量,但是在ftl变量却被 拆分成多段了(见图1)。但是这样是freemaker是无法成功替换变量的,所以需要手动处理成到一个段里(如图2),关于这点实在太无语了,因为没有找到比较好的处理办法,只能手工处理,在实际的开发工作中曾经花了几个小时来做这件事情。
图1:

图2


2.2 处理表格

如果模板里需要用变量填充表格,建议模板里的表格像word文件一样建一个两行的表格。在模板中         表示一个表格 、 表示一行、 表示一列。因为FreeMarker 是利用列表一行一行循环填充的,所以我们可以根据关键字找到标签,因为第一个 是表头注意不要改到了,找到第二个在前后分别加上如下语句即可,后面的表格里后面的行需要删掉,建议模板里的表格像word文件一样建一个两行的表格即可这样就不用删了:
  1. [/code]替换后的模板如下:
  2. [img]https://img2023.cnblogs.com/blog/685402/202307/685402-20230709210852690-2082196356.png[/img]
  3. [size=4]2.3 处理图片[/size]
  4. 如果模板里需要用变量填充图片,建议先在word文件里插入一张图片,这样在模板文件里找到<a target="_blank" rel="noopener"pkg:binaryData/a>标签直接里面把里面的图片base64字符替换成变量即可,word里可以通过植入base64字符来展示图片:
  5. 替换前:
  6. [img]https://img2023.cnblogs.com/blog/685402/202307/685402-20230709210852692-1426306086.png[/img]
  7. 替换后:
  8. [code]<pkg:binaryData>${image1}</pkg:binaryData>
复制代码
到此模板已经调整完成,接下来就可以开始写代码了。
二、项目代码

1、引入依赖

在项目的pom文件里引入如下依赖
  1.         <dependency>
  2.           <groupId>org.freemarker</groupId>
  3.           <artifactId>freemarker</artifactId>
  4.           <version>2.3.31</version>
  5.       </dependency>
复制代码
2、生成代码

将图片转成Base64字符串的公共方法:
  1. public static String getImageBase64Str(String imgFile) {
  2.         try( InputStream in = new FileInputStream(imgFile)) {
  3.             byte[] data = new byte[in.available()];
  4.             in.read(data);
  5.             BASE64Encoder encoder = new BASE64Encoder();
  6.             return encoder.encode(data);
  7.         } catch (FileNotFoundException e) {
  8.             throw new RuntimeException(e);
  9.         } catch (IOException e) {
  10.             throw new RuntimeException(e);
  11.         }
  12.     }
复制代码
根据模板文件生成word,主要生成的word的文件后缀必须是doc不能是docx,不然生成的文件无法打开。
  1. public static void crateWord(Map<String, Object> dataMap, String templatePath, String targetFile){
  2.         String path = templatePath.substring(0,templatePath.lastIndexOf("/"));
  3.         String templateName = templatePath.substring(templatePath.lastIndexOf("/") + 1);
  4.         try (FileOutputStream out = new FileOutputStream(targetFile);
  5.              Writer writer = new BufferedWriter(new OutputStreamWriter(out, "utf-8"))){
  6.             Configuration configuration = new Configuration(Configuration.DEFAULT_INCOMPATIBLE_IMPROVEMENTS);
  7.             configuration.setDefaultEncoding("utf-8");
  8.             configuration.setClassForTemplateLoading(FreeMakerTest.class, path);
  9.             //除了ClassForTemplateLoading外,另一种模板加载方式DirectoryForTemplateLoading,也可用
  10.             //ClassPathResource resource = new ClassPathResource(path);
  11.             //configuration.setDirectoryForTemplateLoading(resource.getFile());
  12.             //加载模板
  13.             Template template = configuration.getTemplate(templateName);
  14.             //渲染模板
  15.             template.process(dataMap, writer);
  16.         } catch (FileNotFoundException e) {
  17.             throw new RuntimeException(e);
  18.         } catch (UnsupportedEncodingException e) {
  19.             throw new RuntimeException(e);
  20.         } catch (IOException e) {
  21.             throw new RuntimeException(e);
  22.         } catch (TemplateException e) {
  23.             throw new RuntimeException(e);
  24.         }
  25.     }
复制代码
三、验证生成word

新建的列表数据实体类:
  1. public class Arrears{
  2.     private String name;
  3.     private Integer num;
  4.     private String endDay;
  5.     public String getName() {
  6.         return name;
  7.     }
  8.     public void setName(String name) {
  9.         this.name = name;
  10.     }
  11.     public Integer getNum() {
  12.         return num;
  13.     }
  14.     public void setNum(Integer num) {
  15.         this.num = num;
  16.     }
  17.     public String getEndDay() {
  18.         return endDay;
  19.     }
  20.     public void setEndDay(String endDay) {
  21.         this.endDay = endDay;
  22.     }
  23. }
复制代码
准备模板填充数据
  1. private static Map<String, Object> prepareParam(){
  2.         LocalDate currentDate = LocalDate.now();
  3.         LocalDate endDate = currentDate.plusYears(1L);
  4.         List<Arrears> arrearsList = new ArrayList<>();
  5.         arrearsList.add(new Arrears(){{setName("一顿老魏");setNum(1);setEndDay("三月内");}});
  6.         arrearsList.add(new Arrears(){{setName("贵州大黄牛");setNum(1);setEndDay("一年内");}});
  7.         arrearsList.add(new Arrears(){{setName("v我50");setNum(1);setEndDay("一月内");}});
  8.         //填充所需要的数据
  9.         Map<String, Object> dataMap = new HashMap<>();
  10.         dataMap.put("debtor", "陈有楚");
  11.         dataMap.put("nowYear", String.valueOf(currentDate.getYear()));
  12.         dataMap.put("nowMonth", String.valueOf(currentDate.getMonthValue()));
  13.         dataMap.put("nowDay", String.valueOf(currentDate.getDayOfMonth()));
  14.         dataMap.put("arrears", "一顿老魏、贵州大黄牛、v我50");
  15.         dataMap.put("endYear", String.valueOf(endDate.getYear()));
  16.         dataMap.put("endMonth", String.valueOf(endDate.getMonthValue()));
  17.         dataMap.put("endDay", String.valueOf(endDate.getDayOfMonth()));
  18.         dataMap.put("arrearsList", arrearsList);
  19.         dataMap.put("image1", getImageBase64Str("D:\\picture\\其他\\24-05-23-142418.png"));
  20.         dataMap.put("creditor", "知北游");
  21.         return dataMap;
  22.     }
复制代码
测试代码:
  1. public static void main(String[] args) throws IOException {
  2.         //准备参数
  3.         Map<String, Object> dataMap = prepareParam();
  4.         crateWord(dataMap,"/templates/qiantiao.ftl","D:\\test\\qiantiao.doc");
  5.     }
复制代码
测试结果:


免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

我可以不吃啊

金牌会员
这个人很懒什么都没写!

标签云

快速回复 返回顶部 返回列表