freemark从数据库读取模板且实时更新
本例子只是简单的实现,如有问题请指出。
转载请注明出处:https://blog.csdn.net/u014508380/article/details/88226855
freemark加载模板
框架提供的读取模板的方式
1.void setDirectoryForTemplateLoading(File dir);//从磁盘的文件系统上的目录加载模板
2.void setClassForTemplateLoading(Class cl, String prefix);//从类路径下加载模板
3.void setServletContextForTemplateLoading(Object servletContext, String path);//从Web应用目录开始加载模板
从多个位置加载模板
如果需要从多个位置加载模板,那就不得不为每个位置都实例化模板加载器对象, 将它们包装到一个称为 MultiTemplateLoader 的特殊模板加载器, 最终将这个加载器传递给 Configuration 对象的 setTemplateLoader(TemplateLoader loader)方法。 下面给出一个使用类加载器从两个不同位置加载模板的示例:
FileTemplateLoader ftl1 = new FileTemplateLoader(new File("/tmp/templates"));
FileTemplateLoader ftl2 = new FileTemplateLoader(new File("/usr/data/templates"));
ClassTemplateLoader ctl = new ClassTemplateLoader(getClass(), "");
TemplateLoader[] loaders = new TemplateLoader[] { ftl1, ftl2, ctl };
MultiTemplateLoader mtl = new MultiTemplateLoader(loaders);
cfg.setTemplateLoader(mtl);
自定义加载方式
因为内建的类加载器无法从数据库中读取模板,于是编写自己的类加载器, 这个类需要实现 freemarker.cache.TemplateLoader 接口, 然后将它传递给 Configuration 对象的 setTemplateLoader(TemplateLoader loader)方法。
1、DbTemplateLoader:自定义的模板加载器
2、DbTemplateSource:模板加载的资源类
3、FreemarkerTransformEngine:模板的配置类
4、FreemarkController:调用的示例类
DbTemplateLoader
public class DbTemplateLoader implements TemplateLoader {
private FreemarkRecordMapper mapper;
DbTemplateLoader(FreemarkRecordMapper mapper) {
this.mapper = mapper;
}
@Override
public Object findTemplateSource(String name) {
int lastUnderscore = name.lastIndexOf('_');
if (lastUnderscore != -1) {
name = name.substring(0, lastUnderscore);
}
return new DbTemplateSource(mapper, name);
}
/**
* 最后修改的版本,用于判断是否直接读取缓存
* @param templateSource
* @return
*/
@Override
public long getLastModified(Object templateSource) {
return ((DbTemplateSource) templateSource).lastModified();
}
@Override
public Reader getReader(Object templateSource, String encoding) throws IOException {
return new InputStreamReader(
((DbTemplateSource) templateSource).getInputStream(),
encoding);
}
@Override
public void closeTemplateSource(Object templateSource) throws IOException {
((DbTemplateSource) templateSource).close();
}
}
DbTemplateSource
@Slf4j
public class DbTemplateSource {
private FreemarkRecordMapper mapper;
private FreemarkRecord freemarkRecord;
private InputStream inputStream;
DbTemplateSource(FreemarkRecordMapper mapper, String name) {
this.mapper = mapper;
this.freemarkRecord = FreemarkRecord.builder().recordCode(name).build();
}
long lastModified() {
if (Objects.isNull(mapper)) {
return 0;
}
//优化建议:可以设置缓存,库表修改后更新缓存
FreemarkRecord freemarkRecordTemp = mapper.selectOne(freemarkRecord);
if (Objects.isNull(freemarkRecordTemp)) {
return 0;
}
return freemarkRecordTemp.getVersion();
}
InputStream getInputStream() {
if (inputStream != null) {
try {
inputStream.close();
} catch (IOException e) {
log.info("异常={}", e);
}
}
if (Objects.isNull(mapper)) {
return new StringInputStream("");
}
FreemarkRecord freemarkRecordTemp = mapper.selectOne(freemarkRecord);
String jsonData = "";
if (Objects.nonNull(freemarkRecordTemp)) {
jsonData = freemarkRecordTemp.getJsonResource();
}
inputStream = new StringInputStream(jsonData);
return inputStream;
}
void close() throws IOException {
try {
if (inputStream != null) {
inputStream.close();
}
} finally {
inputStream = null;
}
}
/**
* 比较两个templateSource是否相同,用于判断是否直接读取缓存
*/
@Override
public boolean equals(Object o) {
if (o instanceof DbTemplateSource) {
return Objects.equals(freemarkRecord.getRecordCode(), ((DbTemplateSource) o).getFreemarkRecord().getRecordCode());
} else {
return false;
}
}
@Override
public int hashCode() {
return freemarkRecord.getRecordCode().hashCode();
}
private FreemarkRecord getFreemarkRecord() {
return freemarkRecord;
}
}
FreemarkerTransformEngine
@Slf4j
@Component
public class FreemarkerTransformEngine implements InitializingBean {
@Resource
private FreemarkRecordMapper mapper;
private Configuration cfg;
public FreemarkerTransformEngine() {
}
private void initConfiguration() {
cfg = new Configuration(Configuration.VERSION_2_3_23);
cfg.setDefaultEncoding("UTF-8");
cfg.setLocale(Locale.CHINESE);
cfg.setNumberFormat("#");
extendCfg();
}
/**
* 设置template加载方式
*/
private void extendCfg() {
TemplateLoader[] loaders = new TemplateLoader[]{new DbTemplateLoader(mapper)};
MultiTemplateLoader mtl = new MultiTemplateLoader(loaders);
cfg.setTemplateLoader(mtl);
}
public String transform2String(String templateName, Map<String, Object> input) {
Template template = this.getTemplate(templateName);
StringWriter stringWriter = new StringWriter();
if (Objects.isNull(template)) {
return "";
}
try {
template.process(input, stringWriter);
} catch (TemplateException | IOException e) {
log.error(e.getMessage(), e);
}
return stringWriter.toString();
}
private Template getTemplate(String templateName) {
try {
return cfg.getTemplate(templateName);
} catch (IOException e) {
log.error(e.getMessage(), e);
}
return null;
}
@Override
public void afterPropertiesSet() {
this.initConfiguration();
}
}
FreemarkController
@Slf4j
@RestController
public class FreemarkController {
@Autowired
private FreemarkerTransformEngine engine;
@RequestMapping("/transform2String")
public String transform2String(String templateName) {
HashMap<String, Object> input = Maps.newHashMap();
input.put("phone", "13644441111");
return engine.transform2String(templateName, input);
}
}
通过http://localhost:8081/transform2String?templateName=test可调用,获取响应的数据;
templateName:表示数据库里模板的编码【唯一标识】
响应的数据例子:
{
"name": "",
"sign": "",
"key": "",
"payload": {
"phone": "13644441111",
"idCard": "",
"name": "",
"ip": "",
"deviceId": "",
"productCode": ""
}
}
FreemarkRecord对应的数据库脚本
说明:只要在修改了json_resource,同时修改version字段的值【可累加】,则前端调用接口后,返回的json_resource即是修改后的数据。
create table freemark_record
(
id bigint auto_increment
primary key,
record_code varchar(50) default '' not null
comment '记录的编码',
json_resource varchar(1000) default '' not null
comment 'json格式的数据',
version int default '0' null
comment '版本',
create_time datetime null
comment '创建时间'
)
comment 'freemark_json记录表';
# 数据例子:
INSERT INTO zxytest.freemark_record (id, record_code, json_resource, version, create_time) VALUES (1, 'test', '{
"name":"${name!}",
"sign": "${sign!}",
"key": "${key!}",
"payload":{
"phone": "${phone!}",
"idCard": "${idCard!}",
"name": "${name!}",
"ip": "${ip!}",
"deviceId": "${deviceId!}",
"productCode": "${productCode!}"
}
}', 2, '2019-03-04 01:56:04');