Java之模板实现

记得在02年学习php语言的时候第一次接触PhP模板技术,

觉得这种可以把程序代码和模板文件分开的结构很好.当时就是会使用,没有深入研究.(这种模板其实非常简单,就是字符串的处理和分析)
其实模板,就是字符串的替换处理.没有任何神秘的地方,最早是perl语言的模板,因为php和perl在字符串上同样强大,所以做个模板是非常容易的,我们通常用的模板类库有,phplibTemplate,FastTemplate,这两种类库使用上和方法上都非常相似.

java中有太多的mvc框架以及taglib了,所以很少有人去写一个关于字符串处理的模板.

最近公司做一个项目类似于php模板方式的结构,所以参考phplibTemplate写了一个java的模板类.

模板标记注释方式:

非循环标记如下注释:
<!–MyFLAG–>
//可以修改模板类中set_var()方法来更改标记,如果你习惯用php的模板标记可以修改为{MyFLAG}

循环标记:
<!–BEGIN MyFLAG–>

<!–END MyFLAG–>

PS:2006/04/27

增加对判断的处理
标记:
<!– IF your_assert_name == your_assert_value –>
//条件成立则显示
<!– END IF your_assert_name –>

后记:现在的开源社区已经有像FreeMark的工具了,该文章只用来记录。

/**
 * <P>Title:</P><P>Description:</P>
 * <P>Copyright: Copyright(c) 2005</P>
 *<P>Company: MNC</P>
 * 
 * @Author : cheung
 * @RCSfile : Templates.java
 * @Revision : 1.0
 * @Date : 2005-7-20
 * @Homepage : <a href="http://www.zhanglihai.com" target="_blank">ZhangLiHai.Com </a>
 * @Email : <a href="mailto:[email protected]">[email protected] </a>
 */
package com.zhanglihai.util;
 
import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
 
public class Templates {
 
	/**
	 * 模板替换公共类
	 */
	private HashMap files = new HashMap(4);
 
	private HashMap vars = new HashMap(64);
 
	private HashMap results = new HashMap(64);
 
	private HashMap assertVars = new HashMap(32);// 模板中定义的条件和对应成立的值
 
	private List block = new ArrayList(8); // 所有循环标记,执行后替换掉所有多余标记
 
	private PrintWriter out = null;
 
	public Templates(OutputStream output) {
		this(output, "UTF-8");
	}
 
	public Templates(OutputStream output, String charset) {
		if (output == null) {
			throw new NullPointerException("output = null");
		}
		try {
			out = new PrintWriter(new OutputStreamWriter(output, charset));
		} catch (Exception e) {
			out = new PrintWriter(output);
		}
 
	}
 
	/**
	 * 添加模板文件
	 * 
	 * @param handler
	 *            用户操作的句柄
	 * @param item
	 *            文件辅助类
	 */
	public void addFile(String handler, FileItem item) {
		files.put(handler, item);
		results.put(handler, item.getContent());
	}
 
	/**
	 * 设置循环处理区域
	 * 
	 * @param parentHandler
	 *            某个文本句柄
	 * @param mark
	 *            当前循环标记
	 * @param name
	 *            当前标记的操作名
	 */
	public void addBlock(String parentHandler, String mark, String name) {
		if (name == null) {
			name = mark;
		}
		results.remove(name);// remove old value;
		vars.remove(set_var(name));// remove old var value
		if (!block.contains(set_var(name)))
			block.add(set_var(name));
		String str = (String) results.get(parentHandler);
		if (str == null) {
			throw new NullPointerException("str = null");
		}
		String regx = "<!--\\s*BEGIN\\s+" + mark
				+ "\\s*-->([\\s\\S]*?)<!--\\s*END\\s+" + mark + "\\s*-->";
		// regx = "<!--\\s*" + mark + "\\s*-->([\\s\\S]*?)<!--\\s*" + mark +
		// "\\s*-->";
		Pattern p = Pattern.compile(regx);
		Matcher m = p.matcher(str);
		if (m.find()) {
			String markResult = m.group(1);
			str = replaceAll(str, markResult, set_var(name));
			str = str.replaceAll("<!--\\s*BEGIN\\s+" + mark + "\\s*-->", "");
			str = str.replaceAll("<!--\\s*END\\s+" + mark + "\\s*-->", "");
			// str = str.replaceAll("<!--\\s*" + mark + "\\s*-->", "");
			results.put(mark, markResult);
			results.put(parentHandler, str);// 覆盖掉
			vars.put(set_var(mark), markResult);// 标记区声明
		}
	}
 
	/**
	 * 分析字符串str中的判断标记
	 * 
	 * @param str
	 */
	protected String parserAssert(String str) {
		if (str == null)
			return "";
		String str_ = str;
		// <!-- IF aaa = 1 -->
		String regex = "<!--\\s*IF\\s+(.*?)\\s*==\\s*(.*?)\\s*-->";
		Pattern p = Pattern.compile(regex, Pattern.CASE_INSENSITIVE);
		Matcher m = p.matcher(str);
		while (m.find()) {
			this.assertVars.put(m.group(1), m.group(2));
		}
		String key = "", value = "", tmpValue = "";
 
		for (Iterator i = assertVars.keySet().iterator(); i.hasNext();) {
			key = (String) i.next();
			value = (String) assertVars.get(key);
			tmpValue = (String) vars.get(set_var(key));
			// 模板中设置的变量、值 和程序中设置的一直,说明要显示该判断
			if (tmpValue != null && tmpValue.equals(value)) {
				str_ = str_.replaceAll("<!--\\s*IF\\s+" + key
						+ "\\s*==\\s*(.*?)\\s*-->", "");
				str_ = str_.replaceAll("<!--\\s*END\\s+IF\\s+" + key
						+ "\\s*-->", "");
			} else {
				str_ = str_
						.replaceAll(
								"<!--\\s*IF\\s+"
										+ key
										+ "\\s*==\\s*(.*?)\\s*-->([\\s\\S]*?)<!--\\s*END\\s+IF\\s+"
										+ key + "\\s*-->", "");
			}
		}
		return str_;
	}
 
	/**
	 * 添加模板中的标记和对应要替换的值
	 * 
	 * @param mark
	 *            标记
	 * @param value
	 *            标记对应的值
	 */
	public void addVar(String mark, String value) {
		vars.put(set_var(mark), value);
	}
 
	public void addVar(String mark) {
		addVar(mark, "");
	}
 
	/**
	 * 为所有的标记加一个前,后缀
	 * 
	 * @param flag
	 * @return
	 */
	private String set_var(String flag) {
		return "{" + flag + "}";
	}
 
	/**
	 * 解析某个指定的代码
	 * 
	 * @param target :
	 *            当前代码名称
	 * @param handler :
	 *            某个文本的句柄,可能是整个模板文件,也可能是指定某个标记快的句柄
	 * @param append
	 */
	public void parser(String target, String handler, boolean append) {
		String str = subst(handler);
 
		if (append) {
			String old = (String) results.get(target);
			String tmp = old == null ? "" : old;
			results.put(target, tmp + str);
			old = (String) vars.get(set_var(target));
			tmp = old == null ? "" : old;
			vars.put(set_var(target), new StringBuffer(tmp).append(str)
					.toString());
		} else {
			results.put(target, str);
			vars.put(set_var(target), str);
		}
	}
 
	/**
	 * 是否清理注释等信息
	 * 
	 * @param html
	 * @return
	 */
	private String finish(String html) {
		for (int i = 0; i < block.size(); i++) {
			String str = (String) block.get(i);
			html = replaceAll(html, str, "");
		}
		return html;
	}
 
	/**
	 * 输出某个指定的目标
	 * 
	 * @param target
	 */
	public void print(String target) {
		String html = (String) results.get(target);
		html = finish(html);
		if (out == null) {
			throw new NullPointerException("out = null");
		}
		out.println(html);
		out.flush();
	}
 
	/**
	 * 清除所有内存数据
	 */
	public void destroy() {
		vars.clear();
		results.clear();
		files.clear();
		block.clear();
		assertVars.clear();
		try {
			out.flush();
			out.close();
		} catch (Exception e) {
		}
	}
 
	/**
	 * 从某个指定的handler获得指定的字符串, 用当前vars中的标记替换掉
	 * 
	 * @param handler
	 * @return
	 */
	private String subst(String handler) {
		String str = (String) results.get(handler);
		if (str == null)
			return "";
		str = parserAssert(str);
		Iterator iterator = vars.keySet().iterator();
		String key = null;
		String value = null;
		String tmp = str;
		while (iterator.hasNext()) {
			key = (String) iterator.next();
			value = (String) vars.get(key);
			if (key != null && value != null)
				tmp = replaceAll(tmp, key, value);
		}
		return tmp;
	}
 
	public static void main(String[] args) {
		Templates tpl = new Templates(System.out, "GBK");
		tpl
				.addFile(
						"test",
						new Templates.FileItem(
								"E:/downloads/zhanglihai_templates/ihtml/complex_phplib.ihtml"));
		tpl.addBlock("test", "row", "rows");
		tpl.addBlock("row", "row_s", "s_row");
		tpl.addBlock("row", "row_ss", "ss_row");
		for (int i = 0; i < 5; i++) {
 
			tpl.addVar("s_row");
			if (i != 1) {
				for (int j = 0; j < 3; j++) {
					tpl.addVar("VAR_0", "J_" + j);
					//assert
					tpl.addVar("assert_1", "1");
					tpl.parser("s_row", "row_s", true);
				}
			}
 
			tpl.addVar("ss_row");
			if (i != 2) {
				for (int k = 0; k < 3; k++) {
					tpl.addVar("VAR_0", "SS_" + k);
					tpl.parser("ss_row", "row_ss", true);
				}
			}
 
			for (int v = 0; v < 5; v++) {
				tpl.addVar("VAR" + v, "V_" + v);
			}
			tpl.addVar("assert_0", "0");
			tpl.parser("rows", "row", true);
		}
		tpl.addVar("KAO_K", "啊,@");
//		assert
		tpl.addVar("assert_2", "3");
		tpl.parser("out", "test", false);
		tpl.print("out");
		tpl.destroy();
	}
 
	/**
	 * 全局替换字符串 把字符串strSource中的所有strFrom都替换为strTo
	 * 
	 * @param strSource
	 * @param strFrom
	 * @param strTo
	 * @return
	 */
	public static String replaceAll(String strSource, String strFrom,
			String strTo) {
		if (strFrom == null || strFrom.equals("")) {
			return strSource;
		}
		StringBuffer strDest = new StringBuffer();
		int intFromLen = strFrom.length();
		int intPos;
		while ((intPos = strSource.indexOf(strFrom)) != -1) {
			strDest.append(strSource.substring(0, intPos)).append(strTo);
			strSource = strSource.substring(intPos + intFromLen);
		}
		strDest.append(strSource);
		return strDest.toString();
	}
 
	/**
	 * 模板文件辅助类 com.mnc.webunion.tools.Templates.java
	 */
	public static class FileItem {
		private String charset = "GBK";
 
		private String tplContent = null;
 
		private String file = null;
 
		public FileItem(String file) {
			this(file, "GBK");
		}
 
		public FileItem(String file, String charset) {
			this.file = file;
			this.charset = charset;
			load_file();
		}
 
		public String getFile() {
			return file;
		}
 
		public String getEncoding() {
			return charset;
		}
 
		/**
		 * 开始读文件
		 */
		private void load_file() {
			BufferedReader reader = null;
			try {
				reader = new BufferedReader(new InputStreamReader(
						new FileInputStream(file), charset));
				StringBuffer buffer = new StringBuffer();
				String line = null;
				while ((line = reader.readLine()) != null) {
					buffer.append(line).append("\r\n");
				}
				reader.close();
				tplContent = buffer.toString();
			} catch (Exception e) {
				throw new IllegalArgumentException(e);
			} finally {
				if (reader != null) {
					try {
						reader.close();
					} catch (IOException e) {
					}
				}
			}
		}
 
		/**
		 * 返回模板文件内容
		 * 
		 * @return
		 */
		public String getContent() {
			return tplContent;
		}
 
	}
 
}
分享到: 更多