FreeMarker动态模板

前言

当我们开发功能时,不仅要考虑当前,也要考虑之后的迭代.

对于邮件正文内容,有时候需要配置HTML格式,所以选择了FreeMarker

准备工作

  • FreeMarker的依赖
        <dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-freemarker</artifactId>
</dependency>
  • 其余Spring相关依赖
        <dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency> <dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>

FreeMarker

官方文档 http://freemarker.foofun.cn/

最简单的模板通常是普通的HTML文件,当然也可以用来写word,pdf之类

对于FreeMarker的模板语言,和动态sql有些相似

既然是动态模板,那么是要传入数据的

http://freemarker.foofun.cn/dgui_datamodel_types.html

常用的传参类型有List,Map,自定义对象 在上方的官方文档中你可以查看支持的全部类型

代码构建

项目结构

创建 Configuration 实例

参考官方文档中步骤 http://freemarker.foofun.cn/pgui_quickstart.html

package com.lizi.util;

import freemarker.template.Configuration;
import freemarker.template.Template;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import org.springframework.ui.freemarker.FreeMarkerTemplateUtils; import javax.annotation.PostConstruct;
import java.util.Locale; /**
* @author lizi
* @description FreeMarkerUtil
* @date 2022/01/01
*/
@Component
@Slf4j
public class FreeMarkerUtil { private static Configuration configuration = null; @PostConstruct
public void init() {
if (null == configuration) {
// 设置版本号
configuration = new Configuration(Configuration.VERSION_2_3_23); // ”/template“为模板文件来源
configuration.setClassForTemplateLoading(FreeMarkerTemplateUtils.class, "/template"); // 设置编码格式
configuration.setEncoding(Locale.CHINA, "UTF-8");
}
} /**
* @param file template文件路径
* @param data 数据
* @return String
*/
public static String getResult(String file, Object data) {
String result = "";
try {
// 获取通用模板
Template template = configuration.getTemplate(file); // 通过模板创建动态数据
result = FreeMarkerTemplateUtils.processTemplateIntoString(template, data);
} catch (Exception e) {
log.error("processTemplateIntoString error : {} ", e.getMessage());
}
return result;
}
}

调用

package com.lizi.controller;

import com.lizi.Entity.Pokemon;
import com.lizi.util.FreeMarkerUtil;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RestController; import java.util.HashMap;
import java.util.Map; /**
* @author lizi
* @description FreeMarkerController
* @date 2022/01/01
*/
@RestController
public class FreeMarkerController { @PostMapping("/getTemplate")
public String getTemplate() { // 创建数据模型
Map<String, Object> dataMap = new HashMap<>(16); Map<String, Object> map = new HashMap<>(16);
map.put("珍珠", "pearl");
map.put("钻石", "diamond"); Pokemon pokemon=new Pokemon();
pokemon.setName("ground_dragon");
pokemon.setRace("108,130,95,80,85,102"); dataMap.put("strong",pokemon);
dataMap.put("pokemon", map);
dataMap.put("ground_dragon","108,130,95,80,85,102");
return FreeMarkerUtil.getResult("template.ftl", dataMap);
}
}

模板文件

对于模板语言,可以更多的去参考官方文档,

<html>
<#-- 传入类型是Map ${ground_dragon} 表示对Map.get("ground_dragon") -->
<td>${ground_dragon}</td>
<#-- 我传入的类型是Map 这里pokemon 表示Map.get("pokemon")之后获取的value 代码中也是一个Map -->
<#if pokemon?exists>
<#-- list,表示遍历 -->
<#list pokemon?keys as key>
<tr>
<td>${key}</td>
<td>${pokemon[key]}</td>
</tr>
</#list>
</#if>
<#-- Map.get("strong") 是一个自定义类 访问属性可以直接用.的方式获取 -->
<td>${strong.name}</td>
<td>${strong.race}</td>
</body>
</html>

调用结果

<html>
<td>108,130,95,80,85,102</td>
<tr>
<td>钻石</td>
<td>diamond</td>
</tr>
<tr>
<td>珍珠</td>
<td>pearl</td>
</tr> <td>ground_dragon</td>
<td>108,130,95,80,85,102</td>
</body>
</html>

Tips

  1. 对于传入的数据模型,需要用Map做一层包装,不然会出错
  2. 如果对象可能不存在,需要做一层判断,不然会出错

使用FreeMarker配置动态模板的更多相关文章

  1. vert.x学习(六),动态模板与静态文件的结合

    这篇学习在动态模板里面引入css,把动态模板与静态文件结合起来使用. 编写DynamicReference.java package com.javafm.vertx.helloworld; impo ...

  2. SpringBoot下配置FreeMarker配置远程模版

    需求产生原因 要求在同一个接口中,根据不同的参数,返回不同的视图结果 所有的视图中的数据基本一致 要求页面能静态化,优化SEO 例如:A接口返回客户的信息 客户A在调用接口时,返回其个性化定制的页面A ...

  3. 如何通过Spring Boot配置动态数据源访问多个数据库

    之前写过一篇博客<Spring+Mybatis+Mysql搭建分布式数据库访问框架>描述如何通过Spring+Mybatis配置动态数据源访问多个数据库.但是之前的方案有一些限制(原博客中 ...

  4. 使用freemarker生成xml模板

    今天在java交流群里有个人问我如何用freemarker生成xml模板文件,可以手动配置参数,于是我到网上百度了一下.发现有一位同行的博文写的很nice,于是我就照着他的代码敲了一遍,最后实现了,本 ...

  5. 迷你MVVM框架 avalonjs 沉思录 第3节 动态模板

    模板的发明是编程史上的一大里程碑,让我们摆脱了烦锁且易出错的字符串拼接,维护性大大提高. 都在JSP,ASP时代,人们已经学会使用include等语句,将多个页面片断拼接成一个页面. 此外,为了将数据 ...

  6. FreeMarker之根据模板生成Java代码

    FreeMarker根据模板生成Java代码,光这句话,大家想必也知道它的应用了,比如流行的DRY原则,该原则的意思,可简单概述为"不要写重复的代码". 比如Java中三层架构,数 ...

  7. spark写入ES(动态模板)

    使用es-hadoop插件,主要使用elasticsearch-spark-20_2.11-6.2.x.jar 官网:https://www.elastic.co/guide/en/elasticse ...

  8. SpringBoot整合MyBatisPlus配置动态数据源

    目录 SpringBoot整合MyBatisPlus配置动态数据源 SpringBoot整合MyBatisPlus配置动态数据源 推文:2018开源中国最受欢迎的中国软件MyBatis-Plus My ...

  9. Logstash动态模板映射收集Nginx的Json格式日志

    Logstash传输给ES的数据会自动映射为5索引,5备份,字段都为text的的索引.这样基本上无法进行数据分析.所以必须将Logstash的数据按照既定的格式存储在ES中,这时候就要使用到ES模板技 ...

随机推荐

  1. Odoo14 rpc

    odoo14中rpc调用分为两种. 一种是外部调用rpc来访问odoo数据,这个时候你需要登录授权. 另一种是我们自己编写的widget小部件或者自定义视图时候通过js通过rpc去获取数据. 这里说的 ...

  2. Auto.js 特殊定位控件方法 不能在ui线程执行阻塞操作,请使用setTimeout代替

    本文所有教程及源码.软件仅为技术研究.不涉及计算机信息系统功能的删除.修改.增加.干扰,更不会影响计算机信息系统的正常运行.不得将代码用于非法用途,如侵立删! Auto.js 特殊定位控件方法 操作环 ...

  3. Python 实现列表与二叉树相互转换并打印二叉树16-详细注释+完美对齐-OK

    # Python 实现列表与二叉树相互转换并打印二叉树16-详细注释+完美对齐-OK from binarytree import build import random # https://www. ...

  4. 优雅退出在Golang中的实现

    背景 为什么需要优雅关停 在Linux下运行我们的go程序,通常有这样2种方式: 前台启动.打开终端,在终端中直接启动某个进程,此时终端被阻塞,按CTRL+C退出程序,可以输入其他命令,关闭终端后程序 ...

  5. Hi3516开发笔记(十):Qt从VPSS中获取通道图像数据存储为jpg文件

    前言   上一篇已经将himpp套入qt的基础上进行开发.那么qt中拿到frame则是很关键的交互,这是qt与海思可能编解码交叉开发的关键步骤.   受限制   因为直接配置sample的vi比较麻烦 ...

  6. Luogu[YNOI2019]排序(DP,线段树)

    要最优?就要一步到位,不能做"马后炮",走"回头路",因此将序列映射到一个假定最优序列,发现移动原序列等价于删除原序列元素,以便生成最大不下降子序列.可线段树维 ...

  7. 图片系列(6)不同版本上 Bitmap 内存分配与回收原理对比

    请点赞关注,你的支持对我意义重大. Hi,我是小彭.本文已收录到 GitHub · AndroidFamily 中.这里有 Android 进阶成长知识体系,有志同道合的朋友,关注公众号 [彭旭锐] ...

  8. Spring源码 21 Bean生命周期

    参考源 https://www.bilibili.com/video/BV1tR4y1F75R?spm_id_from=333.337.search-card.all.click https://ww ...

  9. C++ 漫谈哈夫曼树

    1. 前言 什么是哈夫曼树? 把权值不同的n个结点构造成一棵二叉树,如果此树满足以下几个条件: 此 n 个结点为二叉树的叶结点 . 权值较大的结点离根结点较近,权值较小的结点离根结点较远. 该树的带权 ...

  10. 理解 Flutter 的基础概念:Widget

    Widget 的本意是组件的意思,熟悉 Web 应用开发的人在后期必定会接触到 Vue.React 等框架,这些框架都有一个核心的概念 -- 组件.组件的目的也很简单,那就是重复率用一段代码,并且能够 ...