欢迎光临我的博客[http://poetize.cn],前端使用Vue2,聊天室使用Vue3,后台使用Spring Boot
Spring Boot整合
添加pom依赖
<!-- springboot整合freemarker -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-freemarker</artifactId>
</dependency>
在application.yml中添加相关配置
spring:
# 配置freemarker
freemarker:
# 设置模板后缀名
suffix: .ftl
# 设置文档类型
content-type: text/html
# 设置页面编码格式
charset: UTF-8
# 设置页面缓存
cache: false
# 设置ftl文件路径
template-loader-path:
- classpath:/templates
# 设置静态文件路径,js,css等
mvc:
static-path-pattern: /static/**
# FREEMARKER (FreeMarkerAutoConfiguration)
spring.freemarker.allow-request-override=false
spring.freemarker.allow-session-override=false
spring.freemarker.cache=false
spring.freemarker.charset=UTF-8
spring.freemarker.check-template-location=true
spring.freemarker.content-type=text/html
spring.freemarker.enabled=true
spring.freemarker.expose-request-attributes=false
spring.freemarker.expose-session-attributes=false
spring.freemarker.expose-spring-macro-helpers=true
spring.freemarker.prefer-file-system-access=true
spring.freemarker.suffix=.ftl
spring.freemarker.settings.template_update_delay=0
spring.freemarker.settings.default_encoding=UTF-8
spring.freemarker.settings.classic_compatible=true
spring.freemarker.order=1
# spring boot 默认的页面模板存放目录
spring.freemarker.template-loader-path=classpath:/templates/
自定义函数(继承 TemplateMethodModelEx 接口)
1 创建自定义函数类
public class TemplateMethd implements TemplateMethodModelEx {
@Override
public Object exec(List list) throws TemplateModelException {
SimpleSequence simpleSequence = (SimpleSequence) list.get(0);
List<BigDecimal> list1 = simpleSequence.toList();
Collections.sort(list1, (a, b) -> { return a.intValue() - b.intValue();});
return list1;
}
}
2 将自定义函数对象传到模版中
modelAndView.setViewName("index");
modelAndView.addObject("sort_int_list", new TemplateMethd());
return modelAndView;
3 在模版中使用
<#assign myList=[1,4,5,2,3,7,5,9,0]/>
<#list sort_int_list(myList) as item>
${item}
</#list>
自定义标签(解决公共数据集合的重复代码问题)
在 freemarker 中实现自定义的标签,主要就是靠 TemplateDirectiveModel 类。
如字面意思:模板指令模型,主要就是用来扩展自定义的指令。
public interface TemplateDirectiveModel extends TemplateModel {
public void execute(Environment env, Map params, TemplateModel[] loopVars,
TemplateDirectiveBody body) throws TemplateException, IOException;
}
TemplateDirectiveModel 是一个接口,类中只有一个 execute 方法供使用者实现,而我们要做的就是通过实现 execute 方法,实现自定义标签的功能。
当页面模板中使用自定义标签时,会自动调用该方法。
execute 方法的参数含义:
env :
表示模板处理期间的运行时环境。
该对象会存储模板创建的临时变量集、模板设置的值、对数据模型根的引用等等,通常用它来输出相关内容,如Writer out = env.getOut()。
params :
传递给自定义标签的参数(如果有的话)。其中map的key是自定义标签的参数名,value值是TemplateModel实例。
loopVars :
循环替代变量(未发现有什么用)
body :
表示自定义标签中嵌套的内容。说简单点就是自定义标签内的内容体。
如果指令调用没有嵌套内容:
例如,就像<@myDirective/>或者<@myDirective></mydirective>
那么这个参数就会为空。
一、实现 TemplateDirectiveModel 接口
@Component
public class CustomTagDirective implements TemplateDirectiveModel {
private static final String METHOD_KEY = "method";
@Autowired
private BizTagsService bizTagsService;
@Override
public void execute(Environment environment, Map map, TemplateModel[] templateModels, TemplateDirectiveBody templateDirectiveBody) throws TemplateException, IOException {
if (map.containsKey(METHOD_KEY)) {
DefaultObjectWrapperBuilder builder = new DefaultObjectWrapperBuilder(Configuration.VERSION_2_3_25);
String method = map.get(METHOD_KEY).toString();
switch (method) {
case "tagsList":
// 将数据对象转换成对应的TemplateModel
TemplateModel tm = builder.build().wrap(bizTagsService.listAll())
environment.setVariable("tagsList", tm);
break;
case other...
default:
break;
}
}
templateDirectiveBody.render(environment.getOut());
}
}
二、创建 freemarker 的配置类
@Configuration
public class FreeMarkerConfig {
@Autowired
protected freemarker.template.Configuration configuration;
@Autowired
protected CustomTagDirective customTagDirective;
/**
* 添加自定义标签
*/
@PostConstruct
public void setSharedVariable() {
/*
* 向freemarker配置中添加共享变量;
* 它使用 Configurable.getObjectWrapper() 来包装值,因此在此之前设置对象包装器是很重要的。(即上一步的builder.build().wrap操作)
*/
configuration.setSharedVariable("zhydTag", customTagDirective);
}
}
三、ftl模板中使用自定义标签
<@zhydTag method="tagsList">
<#if tagsList?? && (tagsList?size > 0)>
<#list tagsList as item>
<li>
<a href="${config.siteUrl}/tag/${item.id}" title="${item.name!}">
${item.name!}
</a>
</li>
</#list>
</#if>
</@zhydTag>
自定义标签的使用方法跟自定义宏(macro)用法一样,直接使用<@标签名>${值}</@标签名>即可。
注:ftl中通过@调用自定义标签时,后面可以跟任意参数,所有的参数都可以在execute方法的第二个参数(map)中获取,
由此可以根据一个特定的属性开发一套特定的自定义标签,比如上面代码中通过method参数判断调用不同的处理方式。
@Component
public class MenuTagDirective implements TemplateDirectiveModel {
private static final String METHOD_KEY = "method";
private final MenuService menuService;
public MenuTagDirective(Configuration configuration, MenuService menuService) {
this.menuService = menuService;
configuration.setSharedVariable("menuTag", this);
}
@Override
public void execute(Environment env, Map params, TemplateModel[] loopVars, TemplateDirectiveBody body) throws TemplateException, IOException {
final DefaultObjectWrapperBuilder builder = new DefaultObjectWrapperBuilder(Configuration.VERSION_2_3_25);
if (params.containsKey(HaloConst.METHOD_KEY)) {
String method = params.get(HaloConst.METHOD_KEY).toString();
switch (method) {
case "list":
env.setVariable("menus", builder.build().wrap(menuService.listAll()));
break;
case "tree":
env.setVariable("menus", builder.build().wrap(menuService.listAsTree(Sort.by(DESC, "priority"))));
break;
case "listTeams":
env.setVariable("teams", builder.build().wrap(menuService.listTeamVos(Sort.by(DESC, "priority"))));
break;
case "listByTeam":
String team = params.get("team").toString();
env.setVariable("menus", builder.build().wrap(menuService.listByTeam(team, Sort.by(DESC, "priority"))));
break;
case "count":
env.setVariable("count", builder.build().wrap(menuService.count()));
break;
default:
break;
}
}
body.render(env.getOut());
}
}
TemplateModel
TemplateModel 是一个接口类型,代表 FreeMarker 模板语言(FTL)数据类型的接口的公共超接口,
即所有的数据类型都会被 freemarker 转成对应的 TemplateModel。
通常我们都使用TemplateScalarModel接口来替代它获取一个String 值,如:TemplateScalarModel.getAsString()。
TemplateNumberModel 获取 number。
类型 |
FreeMarker接口 |
FreeMarker实现 |
字符串 |
TemplateScalarModel |
SimpleScalar |
数值 |
TemplateNumberModel |
SimpleNumber |
日期 |
TemplateDateModel |
SimpleDate |
布尔 |
TemplateBooleanModel |
TemplateBooleanModel.TRUE |
哈希 |
TemplateHashModel |
SimpleHash |
序列 |
TemplateSequenceModel |
SimpleSequence |
集合 |
TemplateCollectionModel |
SimpleCollection |
节点 |
TemplateNodeModel |
NodeModel |
扩展 FreeMarkerConfig
上面提到的自定义标签,都是通过<@tagName>xxx</@tagName>方式调用的。
针对我们系统中一些类环境变量的数据(全局的配置类属性等):
@Configuration
public class FreeMarkerConfig {
@Autowired
protected freemarker.template.Configuration configuration;
@Autowired
private SysConfigService configService;
/**
* 添加自定义标签
*/
@PostConstruct
public void setSharedVariable() {
try {
configuration.setSharedVariable("config", configService.get());
} catch (TemplateModelException e) {
e.printStackTrace();
}
}
}
如此而已,在使用的时候我们可以直接在页面上通过 ${config.siteName} 调用 config 的参数即可。