subchen / jetbrick-template-1x Goto Github PK
View Code? Open in Web Editor NEWJava template engine, quickly and easily.
Home Page: http://subchen.github.io/jetbrick-template/
License: Apache License 2.0
Java template engine, quickly and easily.
Home Page: http://subchen.github.io/jetbrick-template/
License: Apache License 2.0
目前的 #put 一次只能保持一个变量, 如 #put(key, value)
可以修改为如下:
#put (key1, value1, key2, value2, ...)
如果模板对应的 outputEncoding 变了,如果 jdk 版本变了,如果模板内引用的对象实现变了...
针对这些问题,增加一个选项 compile.always
,第一次访问模板的时候,强制编译,而不是尝试从磁盘中读取以前编译的 class。
默认 compile.always
为 true
比如模板:
#if (true) abc
0123
#end 999
AAA
结果输出:
0123
AAA
正确的输出应该是:
abc
0123
999
AAA
提供 Annotation Class
@JetMethods
@JetFunctions
@JetTags
然后在对应的 Class 上面增加 Annotation 就会生效。
@JetMethods
public class StringMethods {
public static String link(String text, String url) {
return "<a href=\"" + url + "\">" + text + "</a>";
}
...
}
不过由于扫描 classpath 需要一些时间,准备加一个配置选项是否开启,默认是关闭的。
import.autoscan = false
代码和文档不一致。
应该默认关闭 compile.debug
getXXX() 方法比直接读取 Field 更通用,所以优先级应该更高。
调整如下:
Should change default number format
DEFAULT_NUMBER_FORMAT = "###,##0.00";
${@Long.MAX_VALUE}
${@Long.valueOf(12345)}
${@(java.lang.Long).MAX_VALUE}
模板:
<!-- #set(String title = "") -->
开启
trim.directive.comments = true
出现 NullPointerException
java.lang.NullPointerException: null
at jetbrick.template.parser.code.TextCode.trimEmptyLine(TextCode.java:62) ~[bin/:na]
at jetbrick.template.parser.JetTemplateCodeVisitor.visitBlock(JetTemplateCodeVisitor.java:201) ~[bin/:na]
at jetbrick.template.parser.JetTemplateCodeVisitor.visitBlock(JetTemplateCodeVisitor.java:1) ~[bin/:na]
at jetbrick.template.parser.grammer.JetTemplateParser$BlockContext.accept(JetTemplateParser.java:154) ~[bin/:na]
at jetbrick.template.parser.JetTemplateCodeVisitor.visitTemplate(JetTemplateCodeVisitor.java:148) ~[bin/:na]
at jetbrick.template.parser.JetTemplateCodeVisitor.visitTemplate(JetTemplateCodeVisitor.java:1) ~[bin/:na]
at jetbrick.template.parser.grammer.JetTemplateParser$TemplateContext.accept(JetTemplateParser.java:104) ~[bin/:na]
at jetbrick.template.JetTemplate.generateJavaSource(JetTemplate.java:135) ~[bin/:na]
at jetbrick.template.JetTemplate.compileAndLoadClass(JetTemplate.java:101) ~[bin/:na]
at jetbrick.template.JetTemplate.<init>(JetTemplate.java:68) ~[bin/:na]
at jetbrick.template.JetEngine$ConcurrentTemplateCache.doGetValue(JetEngine.java:179) ~[bin/:na]
at jetbrick.template.JetEngine$ConcurrentTemplateCache.doGetValue(JetEngine.java:1) ~[bin/:na]
at jetbrick.template.utils.ConcurrentCache.get(ConcurrentCache.java:44) ~[bin/:na]
at jetbrick.template.JetEngine.getTemplate(JetEngine.java:92) ~[bin/:na]
模板
abc
#end
123
结果输出
abc
没有任何的报错
main.jetx
#tag block("bodyContent1")
BODY 1111
#end
#tag block("bodyContent2")
BODY 2222
#end
#include ("layout.jetx")
layout.jetx
This is a header.
<div>
${bodyContent1}
</div>
<div>
${bodyContent2}
</div>
This is a footer.
输出结果:
This is a header.
<div>
BODY 1111
</div>
<div>
BODY 2222
</div>
This is a footer.
java code:
JetContext context = new JetContext();
context.put("flag", Boolean.FALSE);
jetx:
========
IF语句:#if(flag)flag为true#else()flag为false#end
========
output
========
IF语句:flag为false========
version
1.1.0
谢谢你贡献了jetbrick,函数/方法扩展特性思路很棒。
不过在试用时,出现 java.lang.NoSuchMethodError: javax.servlet.http.HttpServletRequest.getServletContext 异常
(可见附件内详细信息)。我试着将依赖改为servlet-api-3.0.1,还是有这个异常。不知是否和容器有关?!
(我用的是jetty-maven-plugin 7.2.0).
期待您的回复。
songlei.
java.lang.NoSuchMethodError: javax.servlet.http.HttpServletRequest.getServletContext()Ljavax/servlet/ServletContext;
at jetbrick.template.web.JetWebContext.(JetWebContext.java:65)
at jetbrick.template.web.springmvc.JetTemplateView.renderMergedTemplateModel(JetTemplateView.java:36)
at org.springframework.web.servlet.view.AbstractTemplateView.renderMergedOutputModel(AbstractTemplateView.java:167)
at org.springframework.web.servlet.view.AbstractView.render(AbstractView.java:264)
at org.springframework.web.servlet.DispatcherServlet.render(DispatcherServlet.java:1208)
at org.springframework.web.servlet.DispatcherServlet.processDispatchResult(DispatcherServlet.java:992)
at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:939)
at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:856)
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:915)
at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:811)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:707)
at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:796)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:820)
at org.eclipse.jetty.servlet.ServletHolder.handle(ServletHolder.java:533)
at org.eclipse.jetty.servlet.ServletHandler.doHandle(ServletHandler.java:475)
at org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:119)
at org.eclipse.jetty.security.SecurityHandler.handle(SecurityHandler.java:514)
at org.eclipse.jetty.server.session.SessionHandler.doHandle(SessionHandler.java:226)
at org.eclipse.jetty.server.handler.ContextHandler.doHandle(ContextHandler.java:920)
at org.eclipse.jetty.servlet.ServletHandler.doScope(ServletHandler.java:403)
at org.eclipse.jetty.server.session.SessionHandler.doScope(SessionHandler.java:184)
at org.eclipse.jetty.server.handler.ContextHandler.doScope(ContextHandler.java:856)
at org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:117)
at org.eclipse.jetty.server.handler.ContextHandlerCollection.handle(ContextHandlerCollection.java:247)
at org.eclipse.jetty.server.handler.HandlerCollection.handle(HandlerCollection.java:151)
at org.eclipse.jetty.server.handler.HandlerWrapper.handle(HandlerWrapper.java:114)
at org.eclipse.jetty.server.Server.handle(Server.java:352)
at org.eclipse.jetty.server.HttpConnection.handleRequest(HttpConnection.java:596)
at org.eclipse.jetty.server.HttpConnection$RequestHandler.headerComplete(HttpConnection.java:1049)
at org.eclipse.jetty.http.HttpParser.parseNext(HttpParser.java:590)
at org.eclipse.jetty.http.HttpParser.parseAvailable(HttpParser.java:212)
at org.eclipse.jetty.server.HttpConnection.handle(HttpConnection.java:426)
at org.eclipse.jetty.io.nio.SelectChannelEndPoint.handle(SelectChannelEndPoint.java:510)
at org.eclipse.jetty.io.nio.SelectChannelEndPoint.access$000(SelectChannelEndPoint.java:34)
at org.eclipse.jetty.io.nio.SelectChannelEndPoint$1.run(SelectChannelEndPoint.java:40)
at org.eclipse.jetty.util.thread.QueuedThreadPool$2.run(QueuedThreadPool.java:450)
at java.lang.Thread.run(Thread.java:662)
主要是这几个方法的返回值的使用方式问题:
request.getServletPath()
request.getPathInfo()
request.getRequestURI()
其中 request.getRequestURI()
的返回值包含了 request.getContextPath()
,所以是相对于网站的根目录的。
下面我们分析 request.getServletPath()
和 request.getPathInfo()
如果我们的 servlet-mapping 如下配置:
<servlet-mapping>
<servlet-name>jetbrick-template</servlet-name>
<url-pattern>*.jetx</url-pattern>
</servlet-mapping>
那么访问: /context/templates/index.jetx
request.getServletPath() == "/templates/index.jetx"
request.getPathInfo() == <null>
如果我们的 servlet-mapping 如下配置:
<servlet-mapping>
<servlet-name>jetbrick-template</servlet-name>
<url-pattern>/*</url-pattern>
</servlet-mapping>
那么访问: /context/templates/index.jetx
request.getServletPath() == ""
request.getPathInfo() == "/templates/index.jetx"
如果我们的 servlet-mapping 如下配置:
<servlet-mapping>
<servlet-name>jetbrick-template</servlet-name>
<url-pattern>/template/*</url-pattern>
</servlet-mapping>
那么访问: /context/templates/index.jetx
request.getServletPath() == "/templates"
request.getPathInfo() == "/index.jetx"
总结:
所以,我们要获取相对于 request.getContextPath()
的路径,我们可以使用如下的代码:
String uri = request.getServletPath();
String pathInfo = request.getPathInfo();
if (pathInfo != null && pathInfo.length() > 0) {
uri = uri + pathInfo;
}
或者:
String uri = request.getRequestURI();
String contextPath = request.getContextPath();
if (contextPath != null && contextPath.length() > 0) {
uri = uri.substring(contextPath.length());
}
目前在用户配置的 compile.path 后面会新建一个 jetx_x_x_x 的目录来存放编译的 java 和 class 文件
目前由于默认开启了 compile.always = true
,不会存在 class 版本的冲突问题,可以移除这个默认添加的 jetx_x_x_x 的目录。
用户配置什么目录,就是什么目录。
当然默认的还是在 System.getProperty("java.io.temp") + "/" + "jetx_" + version
===========================================================================
2013-12-13 16:56:00,054 com.jfinal.core.ActionHandler.handle(ActionHandler.java:123) com.jfinal.core.ActionHandler
ERROR: /
jetbrick.template.compiler.CompileErrorException: Compilation failed.
package jetbrick.template does not exist
2:
3: import java.util.*;
4: import jetbrick.template.JetContext;
^
package jetbrick.template.runtime does not exist
3: import java.util.*;
4: import jetbrick.template.JetContext;
5: import jetbrick.template.runtime.*;
^
cannot find symbol
symbol: class JetPage
6:
7: @SuppressWarnings({"all", "warnings", "unchecked", "unused", "cast"})
8: public final class a_html extends JetPage {
^
cannot find symbol
symbol: class JetPageContext
location: class default_.a_html
9:
10: @Override
11: public void render(final JetPageContext $ctx) throws Throwable {
^
cannot find symbol
symbol: class JetContext
location: class default_.a_html
10: @Override
11: public void render(final JetPageContext $ctx) throws Throwable {
12: final JetContext context = $ctx.getContext();
^
cannot find symbol
symbol: class JetWriter
location: class default_.a_html
11: public void render(final JetPageContext $ctx) throws Throwable {
12: final JetContext context = $ctx.getContext();
13: final JetWriter $out = $ctx.getWriter();
^
cannot find symbol
symbol: variable JetUtils
location: class default_.a_html
23: public static final String $ENC = "UTF-8";
24: private static final String $txt_1 = "<!DOCTYPE html>\r\n<meta http-equiv=\"content-type\" content=\"text/h
harset=utf-8\">\r\n<body>\r\n为什么受伤的总是我~~~~(>_<)~~~~\r\n</body>";
25: private static final byte[] $txt_1_bytes = JetUtils.asBytes($txt_1, $ENC);
^
method does not override or implement a method from a supertype
8: public final class a_html extends JetPage {
9:
10: @Override
^
method does not override or implement a method from a supertype
16: }
17:
18: @Override
^
9 error(s)
at jetbrick.template.compiler.jdk.JdkCompiler.generateJavaClass(JdkCompiler.java:146)
at jetbrick.template.compiler.jdk.JdkCompiler.compile(JdkCompiler.java:117)
at jetbrick.template.JetTemplate.compileAndLoadClass(JetTemplate.java:114)
at jetbrick.template.JetTemplate.<init>(JetTemplate.java:68)
at jetbrick.template.JetEngine$ConcurrentTemplateCache.doGetValue(JetEngine.java:179)
at jetbrick.template.JetEngine$ConcurrentTemplateCache.doGetValue(JetEngine.java:175)
at jetbrick.template.utils.ConcurrentCache.get(ConcurrentCache.java:44)
at jetbrick.template.JetEngine.getTemplate(JetEngine.java:92)
at jetbrick.template.web.jfinal.JetTemplateRender.render(JetTemplateRender.java:44)
at com.jfinal.core.ActionHandler.handle(ActionHandler.java:92)
at com.jfinal.ext.handler.ContextPathHandler.handle(ContextPathHandler.java:47)
at com.jfinal.core.JFinalFilter.doFilter(JFinalFilter.java:72)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:243)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:222)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:123)
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:502)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:171)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:100)
at org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:953)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:118)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:408)
可以在外部通过命令行调用,将所有的模板进行预编译,这样生成环境可以直接使用预编译好的 Class 文件,减少首次访问时候的延迟。
shell # JetxGenerateApp -all \
-src /webapp/templates \
-d /webapp/generatedClasses \
-config /webapp/WEB-INF/jetbrick-template.properties
options:
-all: compile all templates even if errors
-src <path>: template root directory
-d <path>: output directory
-config <file>: config file
允许 JetEngine
在初始化的时候,将所有的模板全部进行预编译(在独立线程中),同样是为了减少首次访问时候的延迟。
选项:
compile.strategy = [precompile, always, auto, none]
默认 always
说明:
precompile
: 第一次初始化 JetEngine 的时候,启动一个独立的线程把 template.path
下面的模板全部进行预编译。根据 template.suffix
过滤模板。always
:第一次访问模板的时候,进行编译auto
:在首次访问模板的时候,如果已经存在以前编译好的 class,那么直接加载,否则进行编译。none
:从不编译,只加载 classpath 下用户预先用工具编译好的模板 class,这种模式甚至可以不提供 jetx 源码。同时 compile.always
选项将被废弃。
配置如下:
<bean id="jetEngine" class="jetbrick.template.JetEngineFactoryBean" />
<bean id="jetEngine" class="jetbrick.template.JetEngineFactoryBean">
<property name="configFile" value="classpath:META-INF/jetbrick-template.properties" />
</bean>
<bean id="jetEngine" class="jetbrick.template.JetEngineFactoryBean">
<property name="configFile" value="file:/path/to/jetbrick-template.properties" />
</bean>
感谢 @应卓([email protected]) 贡献代码
同时还要考虑嵌入子模板的路径问题,如 #include() 指令, include() 和 read() 函数
允许在模板中定义一个宏,然后多次使用
模板定义方法: 比如 header
#macro header(String name)
Hello ${name}!
#end
然后使用: 使用宏就像使用函数一样。
${header("Sub")}
${header("Jetx")}
您好,在使用map时出现异常,代码如下:
Map<String, Object> map = Maps.newHashMap();
map.put("name", "测试");
map.put("age", 16);
JetWebContext context = new JetWebContext(request,response);
Map<String, Object> person = Maps.newHashMap();
person.put("person",map);
context.putAll(person);
//
${person["name"]}
异常信息:message: Operator [] is not applicable for the object (Object).
出现编译错误不容易排查错误,改为抛出 SyntaxErrorException,然后给出详细的错误提示
缓存模板内容还是比较有用的,可以提供一个默认的实现
#tag cache(5 * 60)
缓存 5 分钟
#end
#tag cache(5 * 60, true)
缓存 5 分钟 (Session 级别)
#end
cache 的 key 可以自动生成。
是否需要在外部 clear cache?
如果只有 jre, 可以 copy 一个 tools.jar 解决。
但是如果允许在第三方的云上面,比如 BAE, GAE,不允许使用 JDK 的 Compiler, 那么可以使用 JDT 来支持编译。
public final class JetTags
{
public static void layout(JetTagContext ctx, String name)
{
String bodyContext = ctx.getBodyContent();
ctx.getContext().put("bodyContext", bodyContext);
name = ctx.getPageContext().getAbsolutionName(name);
JetTemplate template = ctx.getEngine().getTemplate(name);
template.render(ctx.getContext(), ctx.getWriter());
}
}
需要修改为 bodyContent
, 和文档保持一致。
在HTML中,由于目前的指令直接嵌入在 HTML,对于一些使用可视化编辑器的用户来说,可能会造成一些干扰。如果能用注释语句将指令包裹起来就完美了。
如:
<!-- #if (...) -->
...
<!-- #end -->
支持注释的自定义:
trim.directive.comments = false
trim.directive.comments.prefix = <!--
trim.directive.comments.suffix = -->
默认不启用。
$('#form').submit();
如:${user?.id} id为int类型,如果user为null 得到的值是0 ,应该得到 空串 才对
UnsupportedClassVersionError found.
[main] INFO jetbrick.template.JetTemplate - Loading template class file:
C:\Windows\jetx_1_0_0\templates\jetx_html.class
Exception in thread "main" java.lang.UnsupportedClassVersionError:
templates/jetx_html : Unsupported major.minor version 51.0
at java.lang.ClassLoader.defineClass1(Native Method)
at java.lang.ClassLoader.defineClassCond(ClassLoader.java:631)
at java.lang.ClassLoader.defineClass(ClassLoader.java:615)
at java.security.SecureClassLoader.defineClass(SecureClassLoader.java:141)
at java.net.URLClassLoader.defineClass(URLClassLoader.java:283)
at java.net.URLClassLoader.access$000(URLClassLoader.java:58)
at java.net.URLClassLoader$1.run(URLClassLoader.java:197)
at java.security.AccessController.doPrivileged(Native Method)
at java.net.URLClassLoader.findClass(URLClassLoader.java:190)
at java.lang.ClassLoader.loadClass(ClassLoader.java:306)
at java.lang.ClassLoader.loadClass(ClassLoader.java:247)
at jetbrick.template.compiler.JetTemplateClassLoader.loadClass(JetTemplateClassLoader.java:53)
at jetbrick.template.JetTemplate.loadClassFile(JetTemplate.java:78)
at jetbrick.template.JetTemplate.<init>(JetTemplate.java:57)
at jetbrick.template.JetEngine$ConcurrentTemplateCache.doGetValue(JetEngine.java:172)
at jetbrick.template.JetEngine$ConcurrentTemplateCache.doGetValue(JetEngine.java:168)
at jetbrick.template.utils.ConcurrentCache.get(ConcurrentCache.java:45)
at jetbrick.template.JetEngine.getTemplate(JetEngine.java:92)
at org.boilit.ebm.engine.JetbrickTemplate.work(JetbrickTemplate.java:35)
at org.boilit.ebm.Executor.doByteStreamOut(Executor.java:93)
at org.boilit.ebm.Executor.doStreamOut(Executor.java:78)
at org.boilit.ebm.Executor.execute(Executor.java:53)
at org.boilit.ebm.Executor.run(Executor.java:23)
at org.boilit.ebm.Executor.main(Executor.java:142)
模板
${@System.getProperty(null)}
${obj.equals(null)}
结果
Exception in thread "main" java.lang.NullPointerException
at jetbrick.template.parser.VariableResolver.getPrivateCacheKeyName(VariableResolver.java:495)
at jetbrick.template.parser.VariableResolver.resolveStaticMethod(VariableResolver.java:463)
at jetbrick.template.parser.JetTemplateCodeVisitor.visitExpr_static_method_invocation(JetTemplateCodeVisitor.java:1057)
at jetbrick.template.parser.JetTemplateCodeVisitor.visitExpr_static_method_invocation(JetTemplateCodeVisitor.java:1)
at jetbrick.template.parser.grammer.JetTemplateParser$Expr_static_method_invocationContext.accept(JetTemplateParser.java:1607)
at jetbrick.template.parser.JetTemplateCodeVisitor.visitValue(JetTemplateCodeVisitor.java:249)
at jetbrick.template.parser.JetTemplateCodeVisitor.visitValue(JetTemplateCodeVisitor.java:1)
at jetbrick.template.parser.grammer.JetTemplateParser$ValueContext.accept(JetTemplateParser.java:288)
at jetbrick.template.parser.JetTemplateCodeVisitor.visitBlock(JetTemplateCodeVisitor.java:160)
at jetbrick.template.parser.JetTemplateCodeVisitor.visitBlock(JetTemplateCodeVisitor.java:1)
at jetbrick.template.parser.grammer.JetTemplateParser$BlockContext.accept(JetTemplateParser.java:153)
at jetbrick.template.parser.JetTemplateCodeVisitor.visitTemplate(JetTemplateCodeVisitor.java:148)
at jetbrick.template.parser.JetTemplateCodeVisitor.visitTemplate(JetTemplateCodeVisitor.java:1)
at jetbrick.template.parser.grammer.JetTemplateParser$TemplateContext.accept(JetTemplateParser.java:103)
at jetbrick.template.JetTemplate.generateJavaSource(JetTemplate.java:135)
at jetbrick.template.JetTemplate.compileAndLoadClass(JetTemplate.java:101)
at jetbrick.template.JetTemplate.<init>(JetTemplate.java:68)
at jetbrick.template.JetEngine$ConcurrentTemplateCache.doGetValue(JetEngine.java:178)
at jetbrick.template.JetEngine$ConcurrentTemplateCache.doGetValue(JetEngine.java:1)
at jetbrick.template.utils.ConcurrentCache.get(ConcurrentCache.java:45)
at jetbrick.template.JetEngine.getTemplate(JetEngine.java:92)
替换 1 个 '\t' 为 4 个空格,然后在重新计算 column
模板-1
${include("header.jetx", {"name": "jetbrick"})}
模板-2
#tag layout("layout.jetx", {"name": "jetbrick"})
hello from main
#end
出现的错误
Exception in thread "main" jetbrick.template.compiler.CompileErrorException: Compilation failed.
C:\Users\Sub\AppData\Local\Temp\jetx_1_0_0\template\ext_002dfunctions_002dinclude_jetx.java:18: cannot find symbol
symbol : method include(jetbrick.template.runtime.JetPageContext,java.lang.String,java.util.Map<capture#208 of ?,capture#811 of ?>)
location: class jetbrick.template.runtime.JetFunctions
17: $out.print($txt_1, $txt_1_bytes);
18: $out.print(JetFunctions.include($ctx,"header.jetx",JetUtils.asMap("name","jetbrick"))); // line: 3
^
1 error(s)
at jetbrick.template.compiler.jdk.JdkCompiler.generateJavaClass(JdkCompiler.java:131)
at jetbrick.template.compiler.jdk.JdkCompiler.compile(JdkCompiler.java:102)
at jetbrick.template.JetTemplate.compileAndLoadClass(JetTemplate.java:114)
at jetbrick.template.JetTemplate.<init>(JetTemplate.java:68)
at jetbrick.template.JetEngine$ConcurrentTemplateCache.doGetValue(JetEngine.java:179)
at jetbrick.template.JetEngine$ConcurrentTemplateCache.doGetValue(JetEngine.java:1)
at jetbrick.template.utils.ConcurrentCache.get(ConcurrentCache.java:44)
at jetbrick.template.JetEngine.getTemplate(JetEngine.java:92)
range 返回一个 array, 如果范围较大,会占用较大内存,改为 iterator 实现。
range(...) 标注为 @deprecated
在 layout.jetx 中,定义
#tag default_block("BLOCK")
DEFAULT BLOCK
#end
然后在 main.jetx 中可以对 BLOCK 进行重载
#tag block("BLOCK")
Override BLOCK
#end
#include("layout.jetx")
如果没有被重载,那么将默认输出 #tag default_block() 的内容。
${parameter.type.asDefaullt("123")}
等价于
${parameter.type ? parameter.type : "123"}
main.jetx
#tag layout("layout.jetx")
hello from main
#end
layout.jetx
header
${bodyContext}
footer
=> output
header
hello from main
footer
用法:
先用 Java 定义一个 Tag:比如 cache
public static void cache(JetTagContext ctx, String name) {
String value = CacheManager.get(name);
if (value == null) {
value = ctx.getBodyContent();
CacheManager.set(name, value);
}
ctx.getWriter().write(value);
}
然后在模板中使用:
#tag cache("1-1-1")
......
${header()} ${header()} ${header()}
... 其他内容...
#end
如果在 web.xml 配置了其他的 Filter, 并且使用了和模板不一致的 encoding,可能出现页面编码显示错误。
需要在 JetTemplateServlet 和 JetTemplateFilter 能够重置成正确的编码。
response.setCharacterEncoding(engine.getConfig().getOutputEncoding());
数据格式化器[接口]
package jetbrick.template.formatter;
/**
* 数据格式化器
*
* @author 应卓([email protected])
*
*/
public interface ObjectFormatter {
/**
* 格式化对象
*
* @param object 输入
* @return 输出
*/
public String format(Object object);
/**
* 当返回true时表示支持这种数据类型的格式化
*
* @param objectType
* @return
*/
public boolean supports(Class<?> objectType);
}
jetx-code
#set(double d = 0.1E-10D) ##OK
#set(double d = 0.1D) ##OK
#set(double d = 0.01D) ##NG
栈轨迹
Exception in thread "main" jetbrick.template.parser.SyntaxErrorException: Template parse failed.
E:\worspace-eclipse-sts\samples\target\classes\samples\templates\temp.jetx:61
message: missing ')' at '1D'
57: 8. 特殊字符转义
58: \#if
59:
60: ===============================================================================
61: #set(double d = 0.01D)
^^
at jetbrick.template.parser.JetTemplateErrorListener.syntaxError(JetTemplateErrorListener.java:47)
at org.antlr.v4.runtime.ProxyErrorListener.syntaxError(ProxyErrorListener.java:65)
at org.antlr.v4.runtime.Parser.notifyErrorListeners(Parser.java:473)
at org.antlr.v4.runtime.DefaultErrorStrategy.reportMissingToken(DefaultErrorStrategy.java:407)
at jetbrick.template.parser.JetTemplateErrorStrategy.recoverInline(JetTemplateErrorStrategy.java:32)
at org.antlr.v4.runtime.Parser.match(Parser.java:196)
at jetbrick.template.parser.grammer.JetTemplateParser.set_directive(JetTemplateParser.java:650)
at jetbrick.template.parser.grammer.JetTemplateParser.directive(JetTemplateParser.java:392)
at jetbrick.template.parser.grammer.JetTemplateParser.block(JetTemplateParser.java:209)
at jetbrick.template.parser.grammer.JetTemplateParser.template(JetTemplateParser.java:114)
at jetbrick.template.JetTemplate.generateJavaSource(JetTemplate.java:134)
at jetbrick.template.JetTemplate.compileAndLoadClass(JetTemplate.java:101)
at jetbrick.template.JetTemplate.<init>(JetTemplate.java:68)
at jetbrick.template.JetEngine$ConcurrentTemplateCache.doGetValue(JetEngine.java:178)
at jetbrick.template.JetEngine$ConcurrentTemplateCache.doGetValue(JetEngine.java:174)
at jetbrick.template.utils.ConcurrentCache.get(ConcurrentCache.java:45)
at jetbrick.template.JetEngine.getTemplate(JetEngine.java:92)
at samples.Main.main(Main.java:15)
目前的规则只是把非法字符替换成 "_", 但是没有区分不同的非法字符。
需要改成和 JSP 一样的处理规则。
如:
${ true ? "" : 0}
出现错误:
java.lang.NullPointerException
at jetbrick.template.parser.support.PromotionUtils.getResultClassForConditionalOperator(PromotionUtils.java:201)
at jetbrick.template.parser.JetTemplateCodeVisitor.visitExpr_conditional_ternary(JetTemplateCodeVisitor.java:1410)
at jetbrick.template.parser.JetTemplateCodeVisitor.visitExpr_conditional_ternary(JetTemplateCodeVisitor.java:99)
at jetbrick.template.parser.grammer.JetTemplateParser$Expr_conditional_ternaryContext.accept(JetTemplateParser.java:1640)
at jetbrick.template.parser.JetTemplateCodeVisitor.visitValue(JetTemplateCodeVisitor.java:232)
at jetbrick.template.parser.JetTemplateCodeVisitor.visitValue(JetTemplateCodeVisitor.java:99)
at jetbrick.template.parser.grammer.JetTemplateParser$ValueContext.accept(JetTemplateParser.java:287)
at jetbrick.template.parser.JetTemplateCodeVisitor.visitBlock(JetTemplateCodeVisitor.java:154)
at jetbrick.template.parser.JetTemplateCodeVisitor.visitBlock(JetTemplateCodeVisitor.java:99)
at jetbrick.template.parser.grammer.JetTemplateParser$BlockContext.accept(JetTemplateParser.java:153)
at jetbrick.template.parser.JetTemplateCodeVisitor.visitTemplate(JetTemplateCodeVisitor.java:142)
at jetbrick.template.parser.JetTemplateCodeVisitor.visitTemplate(JetTemplateCodeVisitor.java:99)
at jetbrick.template.parser.grammer.JetTemplateParser$TemplateContext.accept(JetTemplateParser.java:103)
at jetbrick.template.JetTemplate.generateJavaSource(JetTemplate.java:134)
at jetbrick.template.JetTemplate.compileAndLoadClass(JetTemplate.java:101)
at jetbrick.template.JetTemplate.checkLastModified(JetTemplate.java:77)
at jetbrick.template.JetEngine.getTemplate(JetEngine.java:93)
2013-12-03 14:23:26,176 [main] INFO jetbrick.template.JetConfig[103] - Load template from "/samples/templates/" by class jetbrick.template.resource.loader.ClasspathResourceLoader.
2013-12-03 14:23:26,180 [main] INFO jetbrick.template.JetConfig[107] - autoload off: template will NOT automatically reload.
2013-12-03 14:23:26,182 [main] INFO j.template.parser.VariableResolver[66] - import package: java.lang.*
2013-12-03 14:23:26,182 [main] INFO j.template.parser.VariableResolver[66] - import package: java.util.*
2013-12-03 14:23:26,185 [main] INFO j.template.parser.VariableResolver[122] - add method class: jetbrick.template.runtime.JetMethods
2013-12-03 14:23:26,186 [main] INFO j.template.parser.VariableResolver[156] - add function class: jetbrick.template.runtime.JetFunctions
2013-12-03 14:23:26,187 [main] INFO j.template.parser.VariableResolver[185] - add tag class: jetbrick.template.runtime.JetTags
2013-12-03 14:23:26,188 [main] INFO j.t.compiler.JetTemplateClassLoader[44] - Will compile template into C:\Users\yingzhuo\AppData\Local\Temp\jetx_1_1_0
2013-12-03 14:23:26,260 [main] INFO jetbrick.template.JetTemplate[98] - Loading template source file: E:\worspace-eclipse-sts\samples\target\classes\samples\templates\email.jetx
2013-12-03 14:23:26,391 [main] INFO jetbrick.template.JetTemplate[111] - generateJavaSource: C:\Users\yingzhuo\AppData\Local\Temp\jetx_1_1_0\email_jetx.java
===========================================================================
import java.util.*;
import jetbrick.template.JetContext;
import jetbrick.template.runtime.*;
@SuppressWarnings({"all", "warnings", "unchecked", "unused", "cast"})
public final class email_jetx extends JetPage {
@Override
public void render(final JetPageContext $ctx) throws Throwable {
final JetContext context = $ctx.getContext();
final JetWriter $out = $ctx.getWriter();
Boolean flag = (Boolean) context.get("flag"); // line: 1
$out.print($txt_1, $txt_1_bytes);
$out.print((flag?"flag为真":"flag为假")); // line: 3
$out.print($txt_2, $txt_2_bytes);
$out.flush();
}
@Override
public String getName() {
return "/email.jetx";
}
public static final String $ENC = "UTF-8";
private static final String $txt_1 = "========\nIF语句:";
private static final byte[] $txt_1_bytes = JetUtils.asBytes($txt_1, $ENC);
private static final String $txt_2 = "\n========\n";
private static final byte[] $txt_2_bytes = JetUtils.asBytes($txt_2, $ENC);
}
===========================================================================
此处生成的日志有点眼花缭乱啊! 但是关闭生成java代码的日志,把JetConfig配置信息log一并关闭了。 建议jetbrick.template.JetTemplate第111行的日志输出降低到DEBUG级别。
main.jetx
#tag layout("layout.jetx", {name: "jetbrick", age: 30})
XXX
#end
layout.jetx
header
Hello: ${name}, age is ${age}
<div>
${bodyContent}
</div>
footer
模板1:
#tag block("TEST")
1234567890
#include("test.jetx")
AAAAAAAAAAAAA
#end
#include("layout.jetx")
嵌入的 test.jetx
aaaaaaaaaaaa
布局 layout.jetx
XXXXXXXX
${TEST}
YYYYYYYY
结果:
aaaaaaaaaaaaXXXXXXXX
1234567890
AAAAAAAAAAAAA
YYYYYYYY
嵌入的 test.jetx 输出的内容在最前面,不正确。
新增配置选项: import.classes
import.classes = java.util.List, java.io.File
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.