是否可以通过编程方式创建 Freemarker 宏?
Is it possible to create a Freemarker macro programmatically?
Freemarker 被用作 ninja web 框架中的默认模板引擎。该框架将一些默认值分配给模板,这些默认值在使用 ninja web 框架时全局可用。我已经为启用 CSRF 保护的模板创建了一个扩展。该扩展提供了一个可以在模板中使用的功能,例如
${foo(bar)}
目前调用函数需要指定参数,不太直观。使用宏我可以简化对
的调用
@{foo}
并且用户无需担心传递正确的(例如 "bar")参数。但是要在 ninja web 框架中使用它,我必须以编程方式定义一个宏。这可能吗?
更新
抱歉造成混淆。意思是 <@foo/> 而不是 @{foo} ...
查看 Freemarker 文档,我也许可以更清楚地了解我想要实现的目标:http://freemarker.org/docs/ref_directive_macro.html
就像我上面解释的那样,我将一个自定义函数传递给模板,使我能够调用
${foo("bar")}
我想做的是通过像
这样的宏来调用它
@<myMacro/>
但是定义的宏像
<#macro myMacro>
${foo("bar")}
</#macro>
不应在模板中定义,而应以编程方式定义。希望这能让它更清楚。
更新2/解决方案
我最终使用了推荐的 TemplateDirectiveModel。
public class TemplateEngineFreemarkerAuthenticityTokenDirective implements TemplateDirectiveModel {
private String authenticityToken;
public TemplateEngineFreemarkerAuthenticityTokenDirective(Context context) {
this.authenticityToken = context.getSession().getAuthenticityToken();
}
@Override
public void execute(Environment env, Map params, TemplateModel[] loopVars, TemplateDirectiveBody body) throws TemplateException, IOException {
if (!params.isEmpty()) {
throw new TemplateException("This directive doesn't allow parameters.", env);
}
if (loopVars.length != 0) {
throw new TemplateException("This directive doesn't allow loop variables.", env);
}
Writer out = env.getOut();
out.append(this.authenticityToken);
}
}
FreeMarker 宏调用看起来不像 @{...}
。那是某种 Ninja 特定的扩展吗?
无论如何,如果你知道数据模型中有一个bar
,那么你的方法可以像Environment.getCurrentEnvironment().getDataModel().get("bar")
一样获取它,所以不需要传入它。
此外,了解 FTL 有两种 "subroutines",类函数的和类指令的可能很有用。两者都可以在 FTL(#function
、#macro
)和 Java(普通 Java 方法、TemplateMethodModelEx
、TemplateDirectiveModel
)中实现。真正的区别在于,类似函数的用于计算值,而类似指令的用于将值直接打印到输出(因此绕过自动转义)和副作用。但是这些都可以达到Environment
,所以没有区别
您可以调用宏"dynamically"。假设您有一个宏:
<#macro myMacro>
${foo("bar")}
</#macro>
你可以这样称呼它:
<@myMacro />
或
<@.vars["myMacro"] />
那么你可以做...
<#assign someVar = "myMacro" />
<@.vars[someVar] />
Freemarker 被用作 ninja web 框架中的默认模板引擎。该框架将一些默认值分配给模板,这些默认值在使用 ninja web 框架时全局可用。我已经为启用 CSRF 保护的模板创建了一个扩展。该扩展提供了一个可以在模板中使用的功能,例如
${foo(bar)}
目前调用函数需要指定参数,不太直观。使用宏我可以简化对
的调用@{foo}
并且用户无需担心传递正确的(例如 "bar")参数。但是要在 ninja web 框架中使用它,我必须以编程方式定义一个宏。这可能吗?
更新
抱歉造成混淆。意思是 <@foo/> 而不是 @{foo} ...
查看 Freemarker 文档,我也许可以更清楚地了解我想要实现的目标:http://freemarker.org/docs/ref_directive_macro.html
就像我上面解释的那样,我将一个自定义函数传递给模板,使我能够调用
${foo("bar")}
我想做的是通过像
这样的宏来调用它@<myMacro/>
但是定义的宏像
<#macro myMacro>
${foo("bar")}
</#macro>
不应在模板中定义,而应以编程方式定义。希望这能让它更清楚。
更新2/解决方案
我最终使用了推荐的 TemplateDirectiveModel。
public class TemplateEngineFreemarkerAuthenticityTokenDirective implements TemplateDirectiveModel {
private String authenticityToken;
public TemplateEngineFreemarkerAuthenticityTokenDirective(Context context) {
this.authenticityToken = context.getSession().getAuthenticityToken();
}
@Override
public void execute(Environment env, Map params, TemplateModel[] loopVars, TemplateDirectiveBody body) throws TemplateException, IOException {
if (!params.isEmpty()) {
throw new TemplateException("This directive doesn't allow parameters.", env);
}
if (loopVars.length != 0) {
throw new TemplateException("This directive doesn't allow loop variables.", env);
}
Writer out = env.getOut();
out.append(this.authenticityToken);
}
}
FreeMarker 宏调用看起来不像 @{...}
。那是某种 Ninja 特定的扩展吗?
无论如何,如果你知道数据模型中有一个bar
,那么你的方法可以像Environment.getCurrentEnvironment().getDataModel().get("bar")
一样获取它,所以不需要传入它。
此外,了解 FTL 有两种 "subroutines",类函数的和类指令的可能很有用。两者都可以在 FTL(#function
、#macro
)和 Java(普通 Java 方法、TemplateMethodModelEx
、TemplateDirectiveModel
)中实现。真正的区别在于,类似函数的用于计算值,而类似指令的用于将值直接打印到输出(因此绕过自动转义)和副作用。但是这些都可以达到Environment
,所以没有区别
您可以调用宏"dynamically"。假设您有一个宏:
<#macro myMacro>
${foo("bar")}
</#macro>
你可以这样称呼它:
<@myMacro />
或
<@.vars["myMacro"] />
那么你可以做...
<#assign someVar = "myMacro" />
<@.vars[someVar] />