集成
HTTL已内置集成常用MVC框架,你也可以自行使用HTTL的API进行集成。
API集成
API一览表
Engine: (加载后不可变,线程安全,请复用单例)
- Engine.getEngine() 获取引擎单例
- Engine.getTemplate(name) 基于模板名查询模板实例
- Engine.parseTemplate(src) 解析模板源码为模板实例
- Engine.getResource(name) 获取资源文件
- Engine.hasResource(name) 判断资源文件是否存在
- Engine.getProperty(key) 获取配置项属性值
- Engine.getName() 获取配置文件名
- Engine.getVersion() 获取HTTL版本
Template: (继承于Node和Resource,每模板原型实例,加载后不可变类,线程安全,热加载将产生不同实例)
- Template.render(map,writer) 基于参数渲染模板内容到输出中
- Template.evaluate(map) 基于参数求值模板内容
- Template.getVariables() 获取需要的参数类型
- Template.getMacros() 获取模板中的宏
- Template.isMacro() 当前模板是否为宏
- Node.accept(Visitor) 访问语法树
- Node.getOffset() 获取片断源位置偏移量
- Node.getParent() 获取父节点
- Node.getChildren() 获取子节点
- Resource.openReader() 获取模板源读取器
- Resource.openStream() 获取模板源输入流
- Resource.getSource() 获取模板源代码
- Resource.getName() 获取模板源名称
- Resource.getEncoding() 获取模板源编码
- Resource.getLastModified() 获取模板源最后修改时间
- Resource.getLocale() 获取模板本地化区域
- Resource.getLength() 获取模板源长度
Context: (继承于Map,线程绑定实例,线程栈内无竞争使用,线程安全,请不要跨线程传递)
- Context.getContext() 获取当前线程上下文
- Context.getParent() 获取上一级上下文
- Context.getTemplate() 获取当前执行的模板
- Context.getEngine() 获取当前执行的引擎
- Context.getOut() 获取当前输出
- Context.getLevel() 获取当前上下文层级
- Map.get(String) 获取上下文变量
- Map.put(String,Object) 写法上下文变量
API集成示例
import httl.*; import java.util.*; Map<String, Object> parameters = new HashMap<String, Object>(); parameters.put("user", user); parameters.put("books", books); Engine engine = Engine.getEngine(); Template template = engine.getTemplate("/books.httl"); template.render(parameters, response.getOutputStream());
注:缺省配置下,HTTL不依赖任何三方库,只需JDK1.5+即可。
注:缺省必须要用JDK运行,如果只有JRE,请配置为JavassistCompiler。
多份配置:
Engine engine = Engine.getEngine("xxx.properties"); // 不同配置产生不同Engine实例
编程配置:
Properties properties = new Properties(); properties.setProperty("loaders", "com.your.YourLoader"); Engine engine = Engine.getEngine("xxx", properties); // 不同ID产生不同Engine实例
获取属性:
// 如果只配了单 Loader,可以通过这种方式获取属性实例: Loader loader = engine.getProperty("loaders", Loader.class); // 如果你配了多个Loader,可以: Loader[] loaders = engine.getProperty("loaders", Loader[].class); // 如果是文本,可以直接获取: String encoding = engine.getProperty("output.encoding");
下面的调用只是演示集成中你能获取到的信息:
// 你可以传入Template对象,在模板中直接调用:$!{template} // 注意:HTTL在发现Template对象时,会直接把output往下传,而不是拷贝结果。 parameters.put("template", template); // 基于参数渲染到输出: // parameters可以是Map,或者Pojo对象,或者Object[],或者JSON串。 // out可以是OutputStream或Writer。 template.render(parameters, out); // 你也可以执行模板拿到渲染结果: String result = (String) template.evaluate(parameters); // 注意:如果你只是为了把A模板的结果传给B模板,请不要用这种先求值,再传变量的方式。 // 因为这会浪费一次内存拷贝,请直接将template传入,可以减少result中间变量的内存占用。 parameters.put("template", result); // 错误用法,应直接传入template对象 // 你可以拿到模板中的set赋值: // 注意:如果要在模板渲染完之后拿到变量,要用#set(title :="foo")写到上级Context中。 // 因为模板渲染完时会弹出Context栈,模板Context中的变量都会消失,只有写到上级Context中变量保留。 String title = (String) Context.getContext().get("title"); // 你也可以拿到模板中的宏:(你可以把宏理解为片断模板) Template macro = template.getMacros().get("menus"); // 如果你要写测试工具,你可以获取到模板所需的变量和类型,去Mock数据。 Map<String, Class<?>> variables = template.getVariables();
ScriptEngine集成
你也可以使用JDK标准的脚本API,这样可以不显式依赖HTTL的任何类:
import javax.script.* ScriptEngineManager manager = new ScriptEngineManager(); ScriptEngine engine = manager.getEngineByName("httl"); Bindings bindings = engine.createBindings(); bindings.put("hello","world"); CompiledScript script = engine.compile("${hello}"); String result = (String) script.eval(bindings);
配置pom.xml依赖:
<project> <dependencies> <dependency> <groupId>com.github.httl</groupId> <artifactId>httl-script</artifactId> <version>1.0.11</version> </dependency> </dependencies> <project>
扩展集成
扩展约定
- 1. 通过setter注入配置项及依赖,如:setEncoding(String), setCompiler(Compiler)
- 2. 属性用大写分隔,对应配置用点号分隔,如:setFooBar(String),配置:foo.bar=val
- 3. 当注入类型为数组时,以逗号分隔多个值,如:setFoo(String[]),配置:foo=v1,v2
- 4. 如果值int或boolean等基本类型,将自动转换,如:setFoo(boolean),配置:foo=true
- 5. 如果值为空或字符串null时,注入的setter方法不会被执行,在setter内不用判断null值。
- 6. 如果有init()初始化方法,将在属性注入完成后执行。
- 7. 如果有inited()事件方法,将在所有扩展点初始化完后执行,以初始化先后逆序执行。
- 8. 如果setter以@Reqiured标注,表示如果该属性没有注入,当前扩展点不加载。
- 9. 如果setter以@Optional标注,表示如果没有任意一个Optional属性被注入,当前扩展点不加载。
- 10. 基于同类型构造函数进行AOP包装,并用^=配置,如:public XxxWrapLoader(Loader) {},配置:loader^=XxxWrapLoader
配置注入
public MyFilter implements Filter { private String outputEncoding; // 将注入httl.properties中的output.encoding=UTF-8配置项 public void setOutputEncoding(String outputEncoding) { this.outputEncoding = outputEncoding; } private Compiler compiler; // 将注入httl.properties中的compiler配置项 // 并且将实例化和初始化好compiler的属性 public void setCompiler(Compiler compiler) { this.compiler = compiler; } private Engine engine; // 将注入Engine本身 public void setEngine(Engine engine) { this.engine = engine; } // 当属性注入完后执行 public void init() { } public String filter(String value) { // ... } }
支持的扩展点
# 方法扩展 import.methods=StaticMethodClass # 模板加载器 loaders=httl.spi.Loader # 模板语法解析器 template.parser=httl.spi.Parser # 表达式语法解析器 expression.parser=httl.spi.Parser # 模板编译转换器 translator=httl.spi.Translator # JAVA编译器 compiler=httl.spi.Compiler # 日志输出 loggers=httl.spi.Logger # 属性决策器 resolvers=httl.spi.Resolver # 模板缓存 template.cache=java.util.Map # render参数转换器,返回值必须是Map map.converters=httl.spi.Converter # render输出转换器,返回值必须是Writer或OutputStream out.converters=httl.spi.Converter # 插值格式化器 formatters=httl.spi.Formatter # 对象编解码器 codecs=httl.spi.Codec # HTML动态插值过滤 value.filters=httl.spi.Filter # HTML静态文本过滤 text.filters=httl.spi.Filter # 动态插值位置切换器 value.filter.switchers=httl.spi.Switcher # 静态文本位置切换器 text.filter.switchers=httl.spi.Switcher # JS动态插值过滤 script.value.filters=httl.spi.Filter # JS静态文本过滤 script.text.filters=httl.spi.Filter # CSS动态插值过滤 style.value.filters=httl.spi.Filter # CSS静态文本过滤 style.text.filters=httl.spi.Filter
MVC集成
HTTL在MVC中的定位:
配置查找顺序
(1) 首先查找/WEB-INF/web.xml中的context-param指定的配置:
<context-param> <param-name>httl.properties</param-name> <param-value>/WEB-INF/httl.properties</param-value> </context-param>
(注:如果配置路径以 / 开头则表示在Web应用目录下,否则在ClassPath下查找)
(2) 如果未配置,则查找默认WEB-INF路径:/WEB-INF/httl.properties
(3) 如果WEB-INF中没有,则查找ClassPath根目录:httl.properties
(4) 如果ClassPath根目录也没有,则使用标准配置。
变量查找顺序
以${foo}为例:
(1) 首先查找当前模板内#set赋值的变量。
(2) 再查找业务Controller返回的变量。
(3) 然后查找请求属性:request.getAttribute("foo")
(4) 然后查找请求参数:request.getParameter("foo")
(5) 然后查找请求头:request.getHeader("foo")
(6) 然后查找临时会话属性:session.getAttribute("foo")
(7) 然后查找持外会话属性:cookie.get("foo")
(8) 然后查找应用属性:servletContext.getAttribute("foo")
也可以指定访问的域:
(1) ${request.foo} 返回请求属性:request.getAttribute("foo")
(2) ${parameter.foo} 返回请求参数:request.getParameter("foo")
(3) ${header.foo} 返回请求头:request.getHeader("foo")
(4) ${session.foo} 返回临时会话属性:session.getAttribute("foo")
(5) ${cookie.foo} 返回持久会话属性:cookie.get("foo")
(6) ${application.foo} 返回应用属性:servletContext.getAttribute("foo")
Servlet集成
你需要在你的业务Servlet中,处理完业务后,将业务参数都写到request.setAttribute()中。
HttlFilter会在业务Servlet执行后,从模板目录下读取与请求path同名,后缀换成.httl的模板,然后以request中的变量进行渲染。
如需执行非同名模板,可将请求forward到指定模板,HttlServlet会在模板目录下读取forward过来的path同名的模板,然后以request中的变量进行渲染。 比如:request.getRequestDispatcher("foo.httl").forward(request, response);
配置/WEB-INF/web.xml:
<?xml version="1.0" encoding="UTF-8" ?> <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" version="2.5"> <servlet> <servlet-name>yourServlet</servlet-name> <servlet-class>com.foo.YourServlet</servlet-class> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>yourServlet</servlet-name> <url-pattern>*.do</url-pattern> </servlet-mapping> <servlet> <servlet-name>httlServlet</servlet-name> <servlet-class>httl.web.servlet.HttlServlet</servlet-class> <load-on-startup>2</load-on-startup> </servlet> <servlet-mapping> <servlet-name>httlServlet</servlet-name> <url-pattern>*.httl</url-pattern> </servlet-mapping> <filter> <filter-name>httlFilter</filter-name> <filter-class>httl.web.servlet.HttlFilter</filter-class> </filter> <filter-mapping> <filter-name>httlFilter</filter-name> <url-pattern>*.do</url-pattern> </filter-mapping> </web-app>
配置/WEB-INF/httl.properties:
import.packages+=com.your.domain template.directory=/WEB-INF/templates message.basename=/WEB-INF/messages input.encoding=UTF-8 output.encoding=UTF-8 reloadable=false precompiled=false localized=false
配置pom.xml依赖:
<project> <dependencies> <dependency> <groupId>com.github.httl</groupId> <artifactId>httl-servlet</artifactId> <version>1.0.11</version> </dependency> </dependencies> <project>
示例源码仓库:httl-servlet-demo
示例包下载参见:下载
SpringMVC集成
配置/WEB-INF/web.xml:
<?xml version="1.0" encoding="UTF-8" ?> <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" version="2.5"> <listener> <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> </listener> <servlet> <servlet-name>springmvc</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>springmvc</servlet-name> <url-pattern>/*</url-pattern> </servlet-mapping> </web-app>
配置/WEB-INF/springmvc-servlet.xml:
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE beans PUBLIC"-//SPRING//DTD BEAN 2.0//EN" "http://www.springframework.org/dtd/spring-beans-2.0.dtd"> <beans> <bean id="viewResolver" class="httl.web.springmvc.HttlViewResolver"> <property name="contentType" value="text/html; charset=UTF-8" /> </bean> </beans>
配置pom.xml依赖:
<project> <dependencies> <dependency> <groupId>com.github.httl</groupId> <artifactId>httl-springmvc</artifactId> <version>1.0.11</version> </dependency> </dependencies> <project>
示例源码仓库:httl-springmvc-demo
示例包下载参见:下载
Struts集成
配置/WEB-INF/web.xml:
<?xml version="1.0" encoding="UTF-8" ?> <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" version="2.5"> <filter> <filter-name>struts</filter-name> <filter-class>org.apache.struts2.dispatcher.FilterDispatcher</filter-class> </filter> <filter-mapping> <filter-name>struts</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> </web-app>
配置classpath:struts.xml:
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE struts PUBLIC "-//Apache Software Foundation//DTD Struts Configuration 2.0//EN" "http://struts.apache.org/dtds/struts-2.0.dtd"> <struts> <package name="hello" extends="httl-default"> <action name="helloWorld" class="com.hello.HelloWorld"> <result type="httl">/hello_world.httl</result> </action> </package> </struts>
配置/WEB-INF/httl.properties:
import.packages+=com.your.domain template.directory=/WEB-INF/templates message.basename=/WEB-INF/messages input.encoding=UTF-8 output.encoding=UTF-8 reloadable=false precompiled=false localized=false
配置pom.xml依赖:
<project> <dependencies> <dependency> <groupId>com.github.httl</groupId> <artifactId>httl-struts</artifactId> <version>1.0.11</version> </dependency> </dependencies> <project>
示例源码仓库:httl-struts-demo
示例包下载参见:下载
Webx集成
配置/WEB-INF/web.xml:
<?xml version="1.0" encoding="UTF-8" ?> <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" version="2.5"> <filter> <filter-name>webx</filter-name> <filter-class>com.alibaba.citrus.webx.servlet.WebxFrameworkFilter</filter-class> <init-param> <param-name>excludes</param-name> <param-value>*.css, *.js, *.jpg, *.gif, *.png</param-value> </init-param> </filter> <filter-mapping> <filter-name>webx</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> </web-app>
配置/WEB-INF/webx.xml:
<?xml version="1.0" encoding="UTF-8" ?> Webx Root Context Configuration. <beans:beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:beans="http://www.springframework.org/schema/beans" xmlns:p="http://www.springframework.org/schema/p" xmlns:services="http://www.alibaba.com/schema/services" xmlns:engines="http://www.alibaba.com/schema/services/template/engines" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.alibaba.com/schema/services http://localhost:8080/schema/services.xsd http://www.alibaba.com/schema/services/template/engines http://localhost:8080/schema/services/template/engines.xsd"> <services:template> <engines:httl-engine /> </services:template> </beans:beans>
配置/WEB-INF/httl.properties:
import.packages+=com.your.domain template.directory=/WEB-INF/templates message.basename=/WEB-INF/messages input.encoding=UTF-8 output.encoding=UTF-8 reloadable=false precompiled=false localized=false
配置pom.xml依赖:
<project> <dependencies> <dependency> <groupId>com.github.httl</groupId> <artifactId>httl-webx</artifactId> <version>1.0.11</version> </dependency> </dependencies> <project>