JFinal Enjoy指令扩展管理常用文本模板
个人博客 地址:http://www.wenhaofan.com/article/20190304102258
平时在项目中使用短信模板 邮件模板以及 站内消息通知等文本模板一般都是通过手动的字符串拼接来完成,例如:"欢迎"+user.getName()+"加入俱乐部。"
然而这种方法不仅代码难看而且还不方便管理,因此为了更方便的在项目中管理使用这类文本模板,参考JFinal源码中的activerecord管理sql的代码来扩展了Enjoy的指令。
1.扩展代码
package com.autu.common.keys; import com.jfinal.kit.StrKit;
import com.jfinal.template.Directive;
import com.jfinal.template.Env;
import com.jfinal.template.expr.ast.Const;
import com.jfinal.template.expr.ast.Expr;
import com.jfinal.template.expr.ast.ExprList;
import com.jfinal.template.io.Writer;
import com.jfinal.template.stat.ParseException;
import com.jfinal.template.stat.Scope; /**
* KeysDirective
*/
public class KeysDirective extends Directive { static final String KEYS_DIRECTIVE="_KEYS_DIRECTIVE"; private String id; public void setExprList(ExprList exprList) {
if (exprList.length() == 0) {
throw new ParseException("The parameter of #keys directive can not be blank", location);
}
if (exprList.length() > 1) {
throw new ParseException("Only one parameter allowed for #keys directive", location);
}
Expr expr = exprList.getExpr(0);
if (expr instanceof Const && ((Const)expr).isStr()) {
} else {
throw new ParseException("The parameter of #keys directive must be String", location);
} this.id = ((Const)expr).getStr();
} public void exec(Env env, Scope scope, Writer writer) {
String beforeKey=(String)scope.get(KeysDirective.KEYS_DIRECTIVE); String key = StrKit.isBlank(beforeKey) ? id : beforeKey + "." + id;
scope.set(KEYS_DIRECTIVE, key); stat.exec(env, scope, writer); } public boolean hasEnd() {
return true;
}
}
package com.autu.common.keys; import java.util.Map; import com.jfinal.kit.StrKit;
import com.jfinal.template.Directive;
import com.jfinal.template.Env;
import com.jfinal.template.Template;
import com.jfinal.template.expr.ast.Const;
import com.jfinal.template.expr.ast.Expr;
import com.jfinal.template.expr.ast.ExprList;
import com.jfinal.template.io.Writer;
import com.jfinal.template.stat.ParseException;
import com.jfinal.template.stat.Scope; /**
* KeyDirective
*/
public class KeyDirective extends Directive { static final String KEY_DIRECTIVE="_KEY_DIRECTIVE"; private String id; public void setExprList(ExprList exprList) {
if (exprList.length() == 0) {
throw new ParseException("The parameter of #key directive can not be blank", location);
}
if (exprList.length() > 1) {
throw new ParseException("Only one parameter allowed for #key directive", location);
}
Expr expr = exprList.getExpr(0);
if (expr instanceof Const && ((Const)expr).isStr()) {
} else {
throw new ParseException("The parameter of #key directive must be String", location);
} this.id = ((Const)expr).getStr();
} @SuppressWarnings("unchecked")
public void exec(Env env, Scope scope, Writer writer) {
String nameSpace = (String)scope.get(KeysDirective.KEYS_DIRECTIVE);
String key = StrKit.isBlank(nameSpace) ? id : nameSpace + "." + id;
Map<String, Template> keyTemplateMap = (Map<String, Template>)scope.get(KeyKit.KEY_TEMPLATE_MAP_KEY);
if (keyTemplateMap.containsKey(key)) {
throw new ParseException("Key already exists with key : " + key, location);
} keyTemplateMap.put(key, new Template(env, stat));
} public boolean hasEnd() {
return true;
}
}
package com.autu.common.keys; import com.jfinal.template.source.ISource; /**
* 封装 key 模板源
*/
class KeySource { String file;
ISource source; KeySource(String file) {
this.file = file;
this.source = null;
} KeySource(ISource source) {
this.file = null;
this.source = source;
} boolean isFile() {
return file != null;
}
}
package com.autu.common.keys; import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map; import com.jfinal.kit.Kv;
import com.jfinal.kit.StrKit;
import com.jfinal.template.Engine;
import com.jfinal.template.Template;
import com.jfinal.template.source.ISource;
import com.jfinal.template.stat.ParseException; /**
* Email Kit
*/
public class KeyKit { static final String KEY_TEMPLATE_MAP_KEY = "_KEY_TEMPLATE_MAP_";
static final boolean DEFAULT_DEV_MODE=false;
public static final String MAIN_CONFIG_NAME = "keys";
public String configName;
private boolean devMode=false;
private Engine engine;
private List<KeySource> keySourceList = new ArrayList<KeySource>();
public Map<String, Template> keyTemplateMap; private static final Map<String,KeyKit> keyKitMap=new HashMap<>(); public static KeyKit use(String configName) {
return keyKitMap.get(configName);
} public static KeyKit use() {
return use(MAIN_CONFIG_NAME);
} private KeyKit(boolean devMode) {
this(MAIN_CONFIG_NAME, devMode);
} public static KeyKit load(String configName) { if(keyKitMap.containsKey(configName)) {
return keyKitMap.get(configName);
} return new KeyKit(configName,DEFAULT_DEV_MODE);
} public static KeyKit load(boolean devMode) {
if(keyKitMap.containsKey(MAIN_CONFIG_NAME)) {
return keyKitMap.get(MAIN_CONFIG_NAME);
}
return new KeyKit(devMode);
} public static KeyKit load(String configName, boolean devMode) {
if(keyKitMap.containsKey(configName)) {
return keyKitMap.get(configName);
}
return new KeyKit(configName, devMode);
} private KeyKit(String configName, boolean devMode) {
this.configName = configName;
this.devMode = devMode; if(keyKitMap.containsKey(configName)) {
throw new ParseException("Key already exists", null );
} engine = new Engine(configName);
engine.setDevMode(devMode);
engine.addDirective("key", KeyDirective.class);
engine.addDirective("keys", KeysDirective.class);
engine.addSharedMethod(new StrKit()); keyKitMap.put(configName, this);
} public KeyKit(String configName) {
this(configName, false);
} public Engine getEngine() {
return engine;
} public void setDevMode(boolean devMode) {
this.devMode = devMode;
engine.setDevMode(devMode);
} public KeyKit setBaseKeyTemplatePath(String baseKeyTemplatePath) {
engine.setBaseTemplatePath(baseKeyTemplatePath);
return this;
} public KeyKit addTemplate(String KeyTemplate) {
if (StrKit.isBlank(KeyTemplate)) {
throw new IllegalArgumentException("keyTemplate can not be blank");
}
keySourceList.add(new KeySource(KeyTemplate));
return this;
} public void addTemplate(ISource keyTemplate) {
if (keyTemplate == null) {
throw new IllegalArgumentException("keyTemplate can not be null");
}
keySourceList.add(new KeySource(keyTemplate));
} public synchronized KeyKit parseKeysTemplate() {
Map<String, Template> keyTemplateMap = new HashMap<String, Template>(512, 0.5F);
for (KeySource ss : keySourceList) {
Template template = ss.isFile() ? engine.getTemplate(ss.file) : engine.getTemplate(ss.source);
Map<Object, Object> data = new HashMap<Object, Object>();
data.put(KEY_TEMPLATE_MAP_KEY, keyTemplateMap);
template.renderToString(data);
}
this.keyTemplateMap = keyTemplateMap;
return this;
} private void reloadModifiedKeyTemplate() {
engine.removeAllTemplateCache(); // 去除 Engine 中的缓存,以免 get 出来后重新判断 isModified
parseKeysTemplate();
} private boolean isKeyTemplateModified() {
for (Template template : keyTemplateMap.values()) {
if (template.isModified()) {
return true;
}
}
return false;
} private Template getKeyTemplate(String key) {
Template template = keyTemplateMap.get(key);
if (template == null) { // 此 if 分支,处理起初没有定义,但后续不断追加 key 的情况
if (!devMode) {
return null;
}
if (isKeyTemplateModified()) {
synchronized (this) {
if (isKeyTemplateModified()) {
reloadModifiedKeyTemplate();
template = keyTemplateMap.get(key);
}
}
}
return template;
} if (devMode && template.isModified()) {
synchronized (this) {
template = keyTemplateMap.get(key);
if (template.isModified()) {
reloadModifiedKeyTemplate();
template = keyTemplateMap.get(key);
}
}
}
return template;
} /**
* 示例: 1:模板 定义 #key("key")
*
* #end
*
* 2:java 代码 getContent("key", Kv);
*/
public String getContent(String key, Kv kv) {
Template template = getKeyTemplate(key);
if (template == null) {
return null;
}
return template.renderToString(kv);
} public java.util.Set<java.util.Map.Entry<String, Template>> getKeyMapEntrySet() {
return keyTemplateMap.entrySet();
} public String toString() {
return "KeyTplKit for config : " + configName;
}
}
2.模板文件

3.1 all_emails.tpl
#keys("comment")
#include("innerKeys.tpl")
#end
3.2 comment.tpl
#key("comment_title")
[#(config.title)评论通知] Re:#(title)
#end
3.3 inner.tpl
#keys("inner")
#include("comment.tpl")
#end
3.创建管理工具
KeyKit.load(p.getBoolean("devMode", false))
.setBaseKeyTemplatePath(PathKit.getRootClassPath() + "/email")
.addTemplate("all_emails.tpl")
.parseKeysTemplate();
4.使用
String keyContent= KeyKit.use().getContent("comment.inner.comment_title",
Kv.by("config",new Config().setTitle("test")).set("title", "title1"));
System.out.println(keyContent);
输出结果
[test评论通知] Re:title1
5.说明
此处演示的为多层嵌套keys的使用,单层和jfinal的sql管理一样使用
JFinal Enjoy指令扩展管理常用文本模板的更多相关文章
- T4文本模板转换过程
T4文本模板转换过程将文本模板文件作为输入,生成一个新的文本文件作为输出. 例如,可以使用文本模板生成 Visual Basic 或 C# 代码,还可以生成 HTML 报告. 有三个组件参与这一过程: ...
- T4 文本模板编写准则
如果要在 Visual Studio 中生成程序代码或其他应用程序资源,遵守以下一般准则可能非常有帮助. 它们并不是一成不变的规则. 设计时 T4 模板准则 设计时 T4 模板是在设计时在 Visua ...
- 编写 T4 文本模板
文本模板由以下部件组成: 1)指令 - 控制模板处理方式的元素. 2)文本块 - 直接复制到输出的内容. 3)控制块 - 向文本插入可变值并控制文本的条件或重复部件的程序代码. 指令: 指令是控制模板 ...
- 使用 T4 文本模板生成设计时代码
使用设计时 T4 文本模板,您可以在 Visual Studio 项目中生成程序代码和其他文件. 通常,您编写一些模板,以便它们根据来自模型的数据来改变所生成的代码. 模型是包含有关应用程序要求的 ...
- MVC开发T4代码生成之一----文本模板基础
T4文本模板 T4全写为Text Template Transformation Toolkit,是一种编程辅助工具,用来使程序代码自(懒)动(猿)生(福)成(利)的工具.MVC开发中大量使用了T4模 ...
- T4文本模板
<#...#> 可以包含语句 <#=...#> 用于表达式,提供“输出”操作 <#+ ...> 使用类功能控制块向文本模板添加方法.属性.字段,必须作为文件中最后 ...
- 第3章-Vue.js 指令扩展 和 todoList练习
一.学习目标 了解Vue.js指令的实现原理 理解v-model指令的高级用法 能够使用Vue.js 指令完成 todoList 练习(重点+难点) 二.todoList练习效果展示 2.1.效果图展 ...
- T4模板之文本模板
网址:https://docs.microsoft.com/en-us/visualstudio/modeling/design-time-code-generation-by-using-t4-te ...
- 【翻译】Scriban README 文本模板语言和.NET引擎
scriban Scriban是一种快速.强大.安全和轻量级的文本模板语言和.NET引擎,具有解析liquid模板的兼容模式 Github https://github.com/lunet-io/sc ...
随机推荐
- Edge Chromium 中如何始终允许运行 Flash 内容
众所周知,由于 Adobe Flash 控件历史久远,积累了许多漏洞.早在2017年7月,Adobe就宣布了要在2020年底终止对 Flash 的支持.微软称其浏览器移除 Flash 插件的最后期限是 ...
- Tomcat 项目部署、账户配置、状态监测
tomcat部署项目 方式一.自动部署(最常用) 直接把war包或部署的文件夹放到webapps下. tomcat启动后会自动监听webapps下的文件|目录,放入打包好的项目会自动部署,移除打包好的 ...
- CentOS安装图解及配置
CentOS-7-x86_64-Minimal安装图解 界面说明: Install CentOS 7 安装CentOS 7 Test this media & install CentOS ...
- 解决Python3.7安装pygame报错You are using pip version 10.0.1, however version 19.1 is available.
背景: 学习python开发中,需要用到pygame插件,因此按照参考书<Python编程实践,从入门到实践>指引安装Pygame包. 但是利用pip 命令安装 .whl 文件时,报错(如 ...
- 面试想拿 10K,HR 说你只值 7K,该怎样回答或者反驳?
当HR压你价,说你只值7K时,你可以流畅地回答,记住,是流畅,不能犹豫. 礼貌地说:"7K是吗?了解了.嗯~其实我对贵司的面试官印象很好.只不过,现在我的手头上已经有一份11K的offer. ...
- Maven国内镜像配置(阿里云)-sunziren
<?xml version="1.0" encoding="UTF-8"?> <settings xmlns="http://mav ...
- 计蒜客 UCF 2015
#A.Find the twins # 题意 找出每个序列是否有特定的值 # 题解 坑,原始序列输出的时候每一行最后一个不能有空格 #include<bits/stdc++.h> #def ...
- Markdown 的效果
这是一级标题 这是二级标题 这是三级标题 这是四级标题 这是五级标题 这是六级标题 这是加粗的文字 这是倾斜的文字 这是斜体加粗的文字 这是加删除线的文字 这是引用的内容 这是引用的内容 这是引用的内 ...
- 吴裕雄--天生自然HADOOP操作实验学习笔记:hdfs简单的shell命令
实验目的 了解bin/hadoop脚本的原理 学会使用fs shell脚本进行基本操作 学习使用hadoop shell进行简单的统计计算 实验原理 1.hadoop的shell脚本 当hadoop集 ...
- Tomcat + mysql + myeclipse 启动遇到的问题
1. 问题: Tomcat启动时报错如下:Table 'performance_schema.session_variables' doesn't exist 2. 网络上普遍找到的解决办法: 控制台 ...