先来看一种正确的写法,然后逐个分析代码:
<#assign publishDt="2018-10-19">
style="display:none"#if>>
这段代码的意思是:
如果创建时间小于发布时间,隐藏这个div内容。
assign是freemarker的指令,可以用来在页面上创建一个变量,代码第一行使用这个指令创建了一个日期字符串publshDt。
if是条件指令。
重点看下if指令后的表达式(bean.createDt?date gt publishDt?date('yyyy-MM-dd'))
bean.createDt是后台传到前台的对象.属性的写法,createDt在后台是java.util.Date类型。
date是一个日期内建函数。
用来指定日期变量中的哪些部分被使用,包括date,总共三种:
date
:仅日期部分,没有一天当中的时间部分。
time
:仅一天当中的时间部分,没有日期部分。
datetime
:日期和时间都在
如果 ?
左边是字符串,那么date就是字符串的日期转换函数,用来将 将字符串转换成日期/时间/日期时间。
右边的publishDt?date('yyyy-MM-dd')写法就是这种情况
publishDt是用assign指令定义的字符串变量,publishDt?date('yyyy-MM-dd')中的date是字符串内建函数date,用于将字符串格式的日期转为日期类型。
虽然字面都是叫date,但是一个是日期函数,一个是字符串转日期的函数。
个人觉得这个设计还是比较坑的,开发者容易混淆,可以完全使用带前缀的名字区分嘛。
不能。
由于createDt是一个java.util.Date类型,所以你不能这么写:
bean.createDt?date('yyyy-MM-dd')
因为这里的date是日期函数,用来告诉freemarker取日期的哪个部分(日期、时间、日期时间)。
虽然freemarker知道createDt是一个java,util.Date类型,但是freemarker不知道这个类型是freemarker要的哪一种(日期、时间、日期时间),所以还是需要通过日期函数指定,否则会报错说,左边的是一个未知的日期类型,需要指定date、time、date-time中的一种:
lt是比较运算
string (当用于日期/时间/日期-时间值时)
<#assign publishDt="2018-10-19"?date>
style="display:none"#if>>
在使用assgin定义的时候,使用使用字符串转日期的函数date将publishDt转为日期类型。
比较的时候不需要写成bean.createDt?date gt publishDt?date('yyyy-MM-dd')。
但是注意不能这样写:
<#assign publishDt="2018/10/19"?date>
否则会报错:
freemarker需要的格式是yyyy-MM-dd。
这篇文章的由来,源于一个线上的bug,为了解决Activiti Workflow流程兼容的问题,在前端控制,老流程不走流程节点X。
工作流,一旦发起流程,流程定义信息都已经确定,新加流程节点并发布后,老流程是无法跑到新流程节点的,因为流程节点已经在运行的流程中确定,所以对于老流程,页面无须暴露新节点的入口。
freemarker的date函数和字符串date函数,还是比较坑的,开发人员需要对其熟悉才能用好,否则会花费你额外的时间debug。
目前想到的绕过这个坑的方法是,将比较的值在后台处理,返回给前台。
后台处理也有问题,兼容的逻辑耦合在代码里不够优雅,如果能够把兼容的标识,以时间或者版本存到某张表中,然后暴露一个接口