仅供自己学习、参考
reemarker.ext.beans.BeansWrapper 是一个对象包装器**, 最初加到FreeMarker中是为了将任意的POJO(Plan Old Java Objects,普通的Java对象) 包装成 TemplateModel 接口类型。** 这样它就可以以正常的方式来进行处理,事实上 DefaultObjectWrapper 本身是 BeansWrapper 的扩展类。
这里描述的所有东西对 DefaultObjectWrapper 都是适用的,
除了 DefaultObjectWrapper 会用到 freemarker.template.SimpleXxx 类包装的String,Number, Date,array,
Collection(如List), Map,Boolean 和 Iterator对象,会用 freemarker.ext.dom.NodeModel 来包装W3C的DOM结点(更多关于包装的W3C DOM 可以参考这里…), 所以上述这些描述的规则不适用。
模板方法模型功能(TemplateMethodModel functionality)
一个对象的所有方法作为 TemplateMethodModelEx 对象的表述, 它们在对象模型的方法名中使用哈希表的键来访问。
当使用 model.method(arg1, arg2, …) 来调用方法时,形参被作为模板模型传递给方法。 **方法首先不会包装它们,**后面我们会说到解包的详细内容。
这些不被包装的参数之后被实际方法来调用。以防止方法被重载, 许多特定的方法将会被选择使用相同的规则,也就是Java编译器从一些重载的方法中选择一个方法。 以防止没有方法签名匹配传递的参数,或者没有方法可以被无歧义地选择, 将会抛出 TemplateModelException 异常。
返回值类型为 void 的方法返回 TemplateModel.NOTHING,那么它们就可以使用 ${obj.method(args)} 形式的语法被安全地调用。
java.util.Map 实例的模型仍然实现了 TemplateMethodModelEx 接口,作为调用它们 get() 方法的一种方式。正如前面所讨论的那样, 你可以使用哈希表功能来访问"get"方法,但是它有一些缺点: 因为第一个属性和方法名会被键名来检查,所以执行过慢; 属性,方法名相冲突的键将会被隐藏;最终这种方法中你只可使用 String 类型的键。对比一下,调用 model(key) 方法,将直接翻译为 model.get(key):因为没有属性和方法名的查找, 速度会很快;不容易被隐藏;最终对非字符串的键也能正常处理, 因为参数没有被包装,只是被普通的方法调用。实际上, Map 中的 model(key) 和 model.get(key) 是相等的,只是写起来很短罢了。
java.util.ResourceBundle 类的模型也实现了 TemplateMethodModelEx 接口, 作为一种访问资源和信息格式化的方便形式。对资源包的单参数调用, 将会取回名称和未包装参数的 toString() 方法返回值一致的资源。 对资源包的多参数调用的情况和单参数一样,但是它会将参数作为格式化的模式传递给 java.text.MessageFormat,在第二个和后面的作为格式化的参数中使用未包装的值。 MessageFormat 对象将会使用它们原本的本地化资源包来初始化。
解包规则
如果目标对象是 boolean Map List Set 类型将会返回对应的模型对象
如果 目标对象 是 java.util.Collection 或 java.lang.Iterable 类型 除外,模型实现了 TemplateCollectionModel 或 TemplateSequenceModel 接口, 那么集合或序列模型(各自地)一个特殊的Set或List表示对象将会返回。
如果 T 是Java数组类型,模型实现了 TemplateSequenceModel 接口, 那么一个新的指定类型的数组将会创建, 它其中的元素使用数组的组件类型作为 T, 递归展开到数组中。
如果 T 是 char 或 java.lang.Character 类型,模型实现了 TemplateScalarModel 接口, 它的字符串表示中包含精确的一个字符,那么一个 java.lang.Character 类型的值将会返回。
如果 T 定义的是 java.util.Date 类型,模型实现了 TemplateDateModel 接口, 而且它的日期值是 T 的实例, 那么这个日期值将会返回。
字符串插入指南:不要忘了转义!
如果插值在 文本 区 (也就是说,不在 字符串表达式 中),如果 escape 指令 起作用了,那么将被插入的字符串会被自动转义。
freemarker 定义使用宏
macro可以有多个参数,参数的次序是无关的,在macro指令中只能使用定义的参数,并且必须对所有参数赋值,可以在定义参数时指定缺省值:
自定义指令嵌套内容 <#nested> ;<#nested>就相当于占位符
freemarker 中变量的使用 数据模型的变量【root中的变量】直接从模型中给模板传值的变量就是数据模型的变量,它把变量的值放在一个map中,在模板中直接可以用
【模板中的变量】:是使用<#assign定义的变量,如果模板中定义的变量和模型中的变量名称一致,不是覆盖,而是隐藏
局部变量【在指令中的变量】:使用local可以声明局部变量
循环变量【在循环中的变量】:在list循环中定义的变量,循环中的变量只在循环中有效,也是一种临时的变量定义方式
一:[#if list?? && (list?size gt 0)] 内容 [/#if]//list不为空并且list的size大于0
二:[#if list?? && list?size gt 0 ] 内容 [#elseif list?? && list?size == 0 ] 内容[/#if] //elseif部分判断
三:[#list list as current] //相当于for循环current为当前list中的对象
四:[#if hlist?? && hlist?size gt 0]
[#list hlist as h]${h.name}[#if h_has_next]内容[/#if][/#list]//判断list还有下一个
[/#if]
五:[#include ‘inc/inc_column_head.ftl’ /] //相当于html中的include
六:<#if str == “1”> </#if> //等于判断
<#if str !== “1”> </#if> //非等于判断
七:[#list list as current] ${current_index} </#list> list遍历中的下标序号
– <#if> <#list> 里不需要用 KaTeX parse error: Expected 'EOF', got '#' at position 8: 获取 -- <#̲assign bm = "{param}" >
用 $ 获取的参数一般 前后加 “”
要用数字 则可以转换 eg:<#assign bm = “${param}” ?number>
– <#if> 比较大小
里面比较大小,eg:<#if (3>5)></#if>
– 获取session
${Session[“userSession”]?default(“Session”)}
获取session里 实体的值
${userSession.nickname}
– 变量自定义值
<#assign hh="${userSession.roles}" >
判断 roles 包含3 <#if roles?contains(“3”)>
<#assign ctx=request.contextPath>
– 获取 url 上带的参数如 msgEmail=56464@qq.com
${RequestParameters[“msgEmail”]?default("")}
– 获取request 传来的值 包括request.setAttribute("","")
<#if Request[“shoppingCart”]?exists>
– 判断数值存在与否
<#if Session[“userSession”]?exists>
666
<#else>
777
</#if>
– 获取绑定的key
model.addAttribute(“oneOne”,oneoneList);
页面获取 ${}获取即可
<#list oneOne as one>
– 获取实体里的 自定义 集合属性
one 代表 实体,childList是自定义的一个集合
<#list one.childList() as child>
</#list
</#list
list
– freemarker 数字输出中的逗号问题
model.put(“t”,i);
在freemarker中显示为100,000,000
想按原样输出时${t} 显示为100,000,000
${t?c} 显示为100000000
如果不加?c 默认情况下freemarker会将数字用逗号分隔
如何去掉",“逗号呢.,加上”?c"就可以了。
– 自定义list循环及终止
<#list [1,2,3] as x>
${x}
<#if x == 3>
<#break>
</#if>
</#list>
– 获取国际化文件
引入spring.ftl
页面输出
<@spring.message “handle.reSubmit”/>
– 国际化 动态传值
home.teaching.experience=${0}年工作经验
直接用如下:[ ] 必须要 且里面是字符串
${springMacroRequestContext.getMessage(“home.teaching.experience”,[“9”])}
– contains 包含用法
<#–声明一个序列,包含若干个元素–>
<#assign x = [“red”, 16, “blue”, “cyan”]>
如果不是map <#if roles?contains(“3”)>
<#–使用seq_contains判断序列中的元素是否存在–>
“blue”: ${x?seq_contains(“blue”)?string(“yes”, “no”)}
“yellow”: ${x?seq_contains(“yellow”)?string(“yes”, “no”)}
– list标签遍历map:
<#list avertisementTypeMap?keys as key>
– 五星好评
<#assign avgScore=item.avgScore?default(0)>
<#list 1…5 as xx>
<#if (xx <= avgScore)>
<#else>
</#if>
</#list>
– string 用于将数字转换为字符串
Freemarker 中预订义了三种数字格式:number,currency(货币)和percent(百分比)其中number为默 认的数字格式转换
例如:
<#assign tempNum=20>
${tempNum}
t e m p N u m ? s t r i n g . n u m b e r 或 {tempNum? string .number}或tempNum?string.number或{tempNum? string (“number”)} 结果为20
t e m p N u m ? s t r i n g . c u r r e n c y 或 {tempNum? string .currency}或tempNum?string.currency或{tempNum? string (“currency”)} 结果为¥20.00
t e m p N u m ? s t r i n g . p e r c e n t 或 {tempNum? string . percent}或tempNum?string.percent或{tempNum? string (“percent”)} 结果为2,000%
– 字符串转数字
<#assign test="${param}"?number>
${“60.60”?number} 结果为60.60
– 日期 (后台传的是秒)
${item.createTime?string(“yyyy-MM-dd HH:mm:ss”)}
– macro 自定义标签
自定义标签,其中 bm是自定义标签 param是参数 可以是多个参数
<#macro bm param>
this is ${param}
</#macro>
调用的时候:
<@bm param="90"/> 输出为:this is "90"
空值判断及简单写法
.判断是否存在,通过exists关键字或者"??"运算符。都将返回一个布尔值
<#if list ?exists>和${listone?if_exists} 及其简化写法
<#if list ?exists> 用作逻辑判断,返回的是true或者false
${listone?if_exists} 用于输出的时候 如果存在输出,不存在就输出孔字符串
list ?exists 简化成 list??
listone?if_exists 简化成 listone!
listone.name?default("dn") 简化成 listone!dn