【问题
】当渲染文章数据时,由于文章的数据很多,直接去查询文章内容表的话,效率比较低。
【解决
】使用freemarker将文章的内容通过模板技术生成静态的html文件存储到minio中,这样用户就只需要拿着minio的url去minio里获取静态页面即可。效率大大提高

模板引擎
Freemarker是一种模板引擎:一种基于模板和要改变的数据,并用来生成输出文本(html网页、电子邮件、配置文件、源代码…)的通用工具。不是面向最终用户的,而是一个Java类库。

步骤
- 导入依赖
<dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-freemarker</artifactId> </dependency> </dependencies>
|
- 添加application.yml配置
server: port: 8881 spring: application: name: freemarker-demo freemarker: cache: false settings: template_update_delay: 0 suffix: .ftl
|
suffix的属性也可以是.html、.xml、.jsp等,但是一般是以ftl作为扩展名
- 在resources下创建templates,此目录为
freemarker的默认模板存放目录
。在templates下创建模板文件basic.ftl
,模板中的插值表达式
最终会被freemarker替换成具体的数据。
basic.ftl文件
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>Hello World!</title> </head> <body> <b>普通文本 String 展示:</b><br><br> Hello ${name} <br> <hr> <b>对象Student中的数据展示:</b><br/> 姓名:${stu.name}<br/> 年龄:${stu.age} <hr> </body> </html>
|
- 往模板里填数据,返回模板文件
@Controller public class HelloController { @GetMapping("/basic") public String hello(Model model) { model.addAttribute("name", "xiaolin"); Student stu = new Student("03", 18); model.addAttribute("stu", stu); return "basic"; } }
|
Freemarker指令语法
基础语法种类
1. 注释<#-- -->
介于其之间的内容会被Freemarker忽视
2. 插值表达式${...}
Freemarker会用真实的值替代${…}
3. FTL指令<#> </#>
名字前加#
区分,Freemarker会解析标签中的表达式或逻辑。
例如:
<#list stus as stu>${stu.name}</#list>
|
4. 文本
仅文本信息,不是freemarker的注释、插值、FTL指令的内容会被Freemarker忽略解析,直接输出内容。
<#--freemarker中的普通文本--> 我是一个普通的文本
|
集合指令(List、Map)
List
<table> <tr> <td>序号</td> <td>姓名</td> <td>年龄</td> <td>钱包</td> </tr> <#--遍历数据 stu指的是集合里的每一个数据--> <#list stus as stu> <tr> <#--获取当前集合的下标--> <td>${stu_index + 1}</td> <td>${stu.name}</td> <td>${stu.age}</td> <td>${stu.money}</td> </tr> </#list> </table>
|
Map
获取map中某个key对应的值
- 通过
map['keyname'].property
姓名:${stuMap['stu1'].name}<br/> 年龄:${stuMap['stu1'].age}<br/>
|
- 通过
map.keyname.property
姓名:${stuMap.stu2.name}<br/> 年龄:${stuMap.stu2.age}<br/>
|
遍历map
<table> <tr> <td>序号</td> <td>姓名</td> <td>年龄</td> <td>钱包</td> </tr> <#--遍历数据 key指的是map中的每一个key--> <#list stuMap?keys as key> <tr> <#--获取当前集合的下标--> <td>${key_index + 1}</td> <td>${stuMap[key].name}</td> <td>${stuMap[key].age}</td> <td>${stuMap[key].money}</td> </tr> </#list> </table>
|
if指令
【例】:姓名为小红的数据字体显示为红色
<#if name = '小红'> <span style = "color: red">${name}</span> <#else> <span>${name}</span> </if>
|
在Freemarker中,=
与 ==
是一样的
运算符
数值运算符
- 加法:+
- 减法:-
- 乘法:*
- 除法:/
- 求余:%
比较运算符

= 和 != 可以用于字符串、数值、日期来比较是否相等
= 和 != 两边必须是相同类型的值,否则会产生错误
字符串”x”和”x “和”X”比较是不相等的
gt
代替>
,因为Freemarker会把>解析成FTL标签结束的字符串,可以用括号避免这种情况,如:<#if (x > y)>
逻辑运算符
- 逻辑与:&&
- 逻辑或:||
- 逻辑非:!
空值处理
- 判断某个变量是否存在使用:”??”
用法:变量??
<#if stus??> <#list stus as stu> ... <#list> </#if>
|
- 缺失的变量使用:
!
用法:!默认值
- 使用
!
要指定一个默认值,当变量为空时显示默认值
- 如果是嵌套对象,要使用
()
括起来
<#--如果name为空显示空字符串''--> ${name!''} <#--如果stu或name为空,默认显示空字符串''--> ${(stu.name)!''}
|
内建函数
语法格式:变量 + ? + 函数名称
- 集合大小
- 日期格式化
显示日期+时间:${today?datetime}
自定义格式化:${today?string("yyyy年MM月")}
显示时分秒:${today?time}
显示年月日:${today?date}
- 内建函数c
【场景】:point是数值类型,使用${point}
会显示这个数字的数值,每三位使用逗号分隔。如果不想显示为每隔三位分割的数字,可以使用c函数将数字型转成字符串输出。

model.addAttribute("poin", 123456780L);
|
使用内建函数c:
- 将json字符串转为对象
<#--assign标签的作用:定义一个变量--> <#assign text="{'bank':'工商银行','account':'10101920201920212'}" /> <#--把json转成变量--> <#assign data=text?eval /> 开户行:${data.bank} 账号:${data.account}
|
注意:eval的使用可能不安全,如果传入的字符串内容不可控(比如来自用户输入),可能会导致安全问题(例如代码注入)
输出静态化文件

@SpringBootTest public class FreemarkerTest { @Autowired private Configuration configuration; @Test public void test() throws IOException, TemplateException { Template template = configuration.getTemplate("test.ftl");
Map<String, Object> mp = new HashMap<>(); mp.put("name", "xiaolin"); template.process(mp, new FileWriter("d:/list.html")); } }
|