文档章节

一个简单的Java模板工具类(二)—简单表达式解析实现

德胜
 德胜
发布于 2015/06/23 19:13
字数 535
阅读 1600
收藏 16

以前写过一个, 用正则比较不高效, 所以用表达式解析方式又实现了一个, 练手.

以前的: http://my.oschina.net/haogrgr/blog/222349

现在的:

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Objects;

/**
 * 非常非常简单的模板实现
 * 
 * @author desheng.tu
 * @date 2015年6月23日 下午4:38:05
 *
 */
public class SimpleTmpl {

	public static void main(String[] args) {
		String t1 = "你好 $$name$$, 您的验证码是:$$code$$";
		String t2 = "你好 #{name}, 您的验证码是:${code}";
		
		Map<String, Object> param = MapBuilder.makeO("name", "haogrgr").build("code", "1314");
		for (int i = 0; i < 100; i++) {
			SimpleTempletUtil.render(t1, param);
			Templ.of(t2).render(param);
		}
		
		String result = "";
		long start = 0;
		
		start = System.currentTimeMillis();
		for (int i = 0; i < 100000; i++) {
			param.put("code", i);
			result = SimpleTempletUtil.render(t1, param);
		}
		System.out.println(System.currentTimeMillis() - start);
		System.out.println(result);
		
		start = System.currentTimeMillis();
		Templ templ = Templ.of(t2);
		for (int i = 0; i < 100000; i++) {
			param.put("code", i);
			result = templ.render(param);
		}
		System.out.println(System.currentTimeMillis() - start);
		System.out.println(result);
		
	}

}

abstract class Exp {

	abstract String resolve(Map<String, Object> context);

	static Exp of(String exp) {
		Objects.requireNonNull(exp);
		if (exp.startsWith("#{") || exp.startsWith("${")) {
			return new VarExp(exp);
		}
		return new StrExp(exp);
	}
}

class StrExp extends Exp {

	String value;

	StrExp(String exp) {
		this.value = exp;
	}

	@Override
	public String resolve(Map<String, Object> context) {
		return this.value;
	}

	@Override
	public String toString() {
		return "StrExp [value=" + value + "]";
	}

}

class VarExp extends Exp {

	String varName;
	String defaultValue;
	Boolean nullable = false;

	VarExp(String varName, String defaultValue, Boolean nullable) {
		this.varName = varName;
		this.defaultValue = defaultValue;
		this.nullable = nullable;
	}

	VarExp(String exp) {
		Objects.requireNonNull(exp);
		if (!(exp.startsWith("#{") || exp.startsWith("${")) || !exp.endsWith("}")) {
			throw new IllegalArgumentException("表达式[" + exp + "]必须类似于#{}或${}");
		}

		String[] nodes = exp.substring(2, exp.length() - 1).split(",");
		if (nodes.length > 2) {
			throw new IllegalArgumentException("表达式[" + exp + "]只能出现一个','");
		}

		this.varName = nodes[0].trim();
		this.defaultValue = nodes.length == 2 ? nodes[1].trim() : "";
		this.nullable = exp.startsWith("$");
	}

	@Override
	public String resolve(Map<String, Object> context) {
		Object value = context.get(varName);
		if (value == null && nullable) {
			value = defaultValue == null ? "" : defaultValue;
		}
		if (value == null) {
			throw new NullPointerException("上下文中没有指定的变量:var=" + varName + " map=" + context);
		}
		return value.toString();
	}

	@Override
	public String toString() {
		return "VarExp [varName=" + varName + ", defaultValue=" + defaultValue + ", nullable="
				+ nullable + "]";
	}

}

class Templ {

	List<Exp> exps = new ArrayList<>();

	static Templ of(String templStr) {
		Objects.requireNonNull(templStr, "模板为空");

		Templ templ = new Templ();
		StringBuilder sb = new StringBuilder();

		char[] chars = templStr.toCharArray();
		for (int i = 0; i < chars.length; i++) {
			switch (chars[i]) {
			case '#':
			case '$':
				if(i < chars.length - 1 && chars[i+1] == '{'){
					templ.addExp(Exp.of(sb.toString()));
					sb.setLength(0);
				}
				sb.append(chars[i]);
				break;
			case '}':
				sb.append('}');
				if(sb.length() > 1 && sb.charAt(1) == '{'){
					templ.addExp(Exp.of(sb.toString()));
					sb.setLength(0);
				}
				break;
			default:
				sb.append(chars[i]);
				break;
			}
		}
		
		if(sb.length() > 0){
			templ.addExp(Exp.of(sb.toString()));
		}

		return templ;
	}

	Templ addExp(Exp exp) {
		Objects.requireNonNull(exp, "表达式为空");
		exps.add(exp);
		return this;
	}

	String render(Map<String, Object> context) {
		StringBuilder sb = new StringBuilder(128);
		for (Exp exp : exps) {
			sb.append(exp.resolve(context));
		}
		return sb.toString();
	}

}


© 著作权归作者所有

德胜
粉丝 59
博文 31
码字总数 41512
作品 0
长沙
私信 提问
加载中

评论(1)

偿试
好厉害!交个朋友吧
Apache java项目全介绍

Jakarta项目是ASF(The Apache Software Foundation)的一部分。 ASF是一个非赢利组织,她鼓励基于开放的软件许可下进行合作、注重实效的开发,并提供各个领域的高质量软件,她涉及到 Http服务...

Sephiroth
2010/04/05
1K
1
【四 Twirl模板引擎】 1. 模板引擎

基于Scala的类型安全的模板引擎 Play提供了基于Scala的强大模板引擎Twirl。它的诞生灵感来自于 ASP.NET Razor。它有如下特点: 简洁、流畅、富于表现力:它能让你尽可能少的打字,同时提供了...

Landas
2018/11/02
73
0
精通Java设计模式从初见到相爱之命令解释器模式(15)

转载的:因为这中设计模式是在没法写,因为项目中基本没用到,也不想写,但是为了凑个数,.... https://www.cnblogs.com/chenpi/p/5222496.html 转载文章地址 一、什么是解释器模式 二、补充说...

木九天
2018/04/25
0
0
使用 Ruby 开发代码生成器

在软件开发工程中,源代码生成工具是提升生产效率的利器。在我的工作中,曾经使用过 XLST、FreeMaker 等多种技术开发源代码生成器,最终我还是选择了脚本语言 Ruby。Ruby 以其简洁有趣的语法...

IBMdW
2012/07/21
1K
0
Apache commons (Java常用工具包)简介

Apache Commons是一个非常有用的工具包,解决各种实际的通用问题,下面是一个简述表,详细信息访问http://jakarta.apache.org/commons/index.html BeanUtils Commons-BeanUtils 提供对 Java...

Coder小兵
2012/02/04
1K
1

没有更多内容

加载失败,请刷新页面

加载更多

OSChina 周二乱弹 —— 他只能用这个办法劝你注意身体了

Osc乱弹歌单(2019)请戳(这里) 【今日歌曲】 @-冰冰棒- :#今日歌曲推荐# Kodaline《High Hopes》 《High Hopes》- Kodaline 手机党少年们想听歌,请使劲儿戳(这里) @xiaoshiyue :仙女...

小小编辑
4分钟前
81
5
Spring Boot Actuator 整合 Prometheus

简介 Spring Boot 自带监控功能 Actuator,可以帮助实现对程序内部运行情况监控,比如监控状况、Bean加载情况、环境变量、日志信息、线程信息等。这一节结合 Prometheus 、Grafana 来更加直观...

程序员果果
13分钟前
3
0
Linux文件查找命令详解

对于文件查找,我们最好用的还是属于find命令了,在说find命令之前,先把另外几个查找命令介绍一下。 目录 0x01 查询命令介绍 0x02 find命令介绍 0x01 查询命令介绍 在介绍之前,首先先了解一...

无心的梦呓
13分钟前
3
0
快速掌握的测试用例优先级划分方法

怎么样的设计才能算测试用例 引自:IEEE Standard 610 (1990): A set of test inputs, execution conditions, and expected results developed for a particular objective, such as to exe......

测者陈磊
16分钟前
3
0
[mycat]Attribute value "roadNodeId,version" of type NMTOKEN must be a name token

不能逗号配两个字段的主键 primaryKey="roadNodeId,version" Caused by: io.mycat.config.util.ConfigException: org.xml.sax.SAXParseException; lineNumber: 7; columnNumber: 105; Attrib......

Danni3
22分钟前
4
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部