@Documented
@Retention(value=RUNTIME)
@Target(value=FIELD)
public @interface ListField
四种使用方式:
static Map listFields 中;static Map listFields = Collections.EMPTY_MAP。如果列表中没有显示,一般和 enable、listable、visible、searchable 等配置有关,请参考对应的注释。
此外,可以设置一个 key 为 “*” 的 Map,用于禁用所有的 searchable、sortable、link,或者禁用未显式设置的属性的 enable、listable、visible。
如 ["*": [enable: false], foo: [..]] 表示除了 foo 外的其他所有属性都禁用。
| Modifier and Type | Required Element and Description |
|---|---|
java.lang.Class |
cellProps
设置单元格(td)的其他属性(如 style、class 等)的 Groovy 闭包
|
boolean |
checkbox
单元格是否显示为复选框,此时表头为一个全选/全不选的 checkbox
|
java.lang.String |
cssClass
单元格/表头的 css 样式类
|
boolean |
defaultLink
单元格中的链接是否是默认链接(会自动添加 o-default-link 的 css class)
|
boolean |
enable
属性是否启用
|
java.lang.String |
header
表头显示名
|
boolean |
i18n
是否要通过消息前缀来计算列表显示值/查询范围
|
java.lang.String |
i18nPrefix
用来计算列表显示值/查询范围的 i18n 消息前缀
|
int |
index
显示顺序
|
boolean |
link
单元格是否自动渲染为文档链接
|
boolean |
listable
是否将数据传送到前台列表
|
java.lang.String |
mappingField
关联的其他 Domain 对象可以在列表/查询项中显示的属性名列表
|
java.lang.String |
namespace
命名空间
|
boolean |
radiobox
单元格是否显示为单选框
|
java.lang.String |
render
单元格中,处理数据显示值的、DataTable 的 js 渲染器方法名
|
java.lang.Class |
renderClosure
单元格中,处理数据显示值的、后台的 Groovy 渲染闭包
|
boolean |
rownum
是否显示为查询结果中的行号
|
java.lang.Class |
rowProps
设置行(tr)的其他属性(如 style、class 等)的 Groovy 闭包
|
boolean |
rowTitle
单元格的值是否可作为行 tr 的 title 属性(鼠标悬浮提示)
|
boolean |
searchable
是否可以作为查询选项
|
java.lang.Class |
searchClosure
自定义渲染搜索输入框(下拉框等)的闭包。
|
java.lang.String |
searchCssClass
查询字段的 css 样式类
|
java.lang.String |
searchField
查询字段的名称
|
int |
searchIndex
查询项的显示顺序
|
int |
searchMethod
查询方式
|
java.lang.String[] |
searchRange
查询范围
|
java.lang.String |
searchTitle
查询字段显示名
|
java.lang.String |
searchWidth
查询输入框的宽度
|
boolean |
sortable
是否可排序
|
java.lang.String |
sortedDir
默认排序属性的排序方向,默认为升序
|
int |
sortedIndex
默认排序属性的优先级顺序,默认等于 index
|
java.lang.String |
sortField
用于排序的列
|
java.lang.String |
test
属性是否启用的测试脚本(Groovy)字符串
|
boolean |
visible
是否可以在列表中显示
|
java.lang.String |
width
显示列宽(css 的格式,如 10px、20em、30% 等)
|
| Modifier and Type | Optional Element and Description |
|---|---|
boolean |
sorted
是否是默认的排序属性
|
public abstract java.lang.String namespace
当一个 Domain 类有多种列表显示方式时,可以用命名空间来区分。如果命名空间为空,则表示在所有命名空间中都存在。
一般可通过 URL 参数 ns 自动切换列表;如果定义了多个命名空间,但 URL 并未置顶 ns 参数,会找名为 default 的默认定义。
public abstract boolean enable
比如 fullSequence 属性,可以用来排序,但是不应该在前台显示出来(列表、查询栏都没有),因此其值也无需传到前台,可以禁用。
默认情况下,除 fullSequence、fullIds、password、revd、creatorUid 外的所有属性均启用。
public abstract java.lang.String test
脚本中可以直接使用 params、emp、user、session、request、ctx 等对象。
public abstract boolean listable
默认情况下,未配置 renderClosure、且长度大于等于 500 的字符串属性或 hasMany 的属性不启用,其余属性均启用;
也就是说,对于长度大于 500 的字符串属性和 hasMany 的属性,需要配置 renderClosure、或显式的配置 listable 或 index,否则默认不显示。
public abstract boolean visible
比如 id 属性,一般用来拼链接,但并不会直接在列表中显示。
默认情况下,除了 id 和长度大于 500 的属性,只要配置了 listable 或 index,则为真;但根据 index 的值,初始化列表时可能暂不显示。
public abstract java.lang.String cssClass
如果不希望作用于表头,可以使用 cellProps 来设置单元格的样式,如:cellProps: ['class': 'center']。
public abstract boolean defaultLink
public abstract boolean rownum
通常配置在一个不存在的列名(如 i)上,并直接渲染为行号,并且禁用排序、搜索、renderClosure。
如:i: [index: 1, rownum: true, header: "序号"]。
public abstract java.lang.String render
会先于 checkbox、radiobox 的渲染器之前执行。
public abstract java.lang.Class renderClosure
可接收参数 item、value、[list],即当前数据行的 Map、当前列的值、[所有数据的 Map 列表]。
当不是用注解方式使用时(如在 gsp 中设置 request.listFields),可以用键 render 来代替 renderClosure, 除非 js、groovy 两个渲染器同时存在时,才严格区分 render 和 renderClosure。
闭包返回值可以包含 HTML 代码,否则需要手动转一下码、避免显示问题,如调用 StringUtils.escapeXML(text)。
如果列表定义在 list.gsp 中,并且要在闭包中为没条数据执行一次数据库查询(或类似的操作),建议优化:
一种是将其提取到外面、设置为一个变量,在闭包中引用;
一种是在闭包中仅执行一次,执行结果放在 request 属性中,以后每次判断 request 属性存在、则从 request 中取值。
public abstract java.lang.Class rowProps
可接收参数 item,即当前数据行的 Map,并返回一个键值对的 Map,如 rowProps: \{ Map item -> [class: (item.disabled ? 'deleted' : '')] \}。
设置在任何一个属性上都可以。
如果不是通过注解设置的,可以直接为一个 Map 对象,如 [class: "deleted", style: "xxx"]。
public abstract java.lang.Class cellProps
可接收参数 item、value、[list],即当前数据行的 Map、当前列的值、[所有数据的 Map 列表]。
如果不是通过注解设置的,可以直接为一个 Map 对象,如 cellProps: ['class': 'center', 'title': '']。
public abstract boolean sortable
默认情况下,长度大于 500 且未配置 sorted 的属性外,其余属性均可排序。
public abstract java.lang.String sortField
如前台显示为 sequence,而后台排序的时候 fullSequence。格式同 mappingField。 如果配置了 mappingField,则默认等于 mappingField。
public abstract java.lang.String mappingField
如 ".name";最多支持两级关联,如 ".foobar.name"。 其中前缀 “.” 为简写,即前面忽略的属性名称本身,如属性名为 employee,显示为 employee.name,则可简写为 “.name”。
如果要映射多个属性,请使用注解 ListFields 嵌套多个 ListField 注解。
通常情况下,如果只有一级关联,则可以为一对多的关系,如 ".groups.name",这样会自动取出关联的 groups*.name,并且可以支持查询。
特殊的,如果有两级关联,并且主类和第一级为一对一,而第二级为一对多的关系:
比如主类 Verification 和 Person 为一对一,Person 和 Groups 为一对多,需要在 Verification 的列表中显示、查询 person.groups*.name,
那么不能直接通过 mappingField 配置,但可以通过下面的方式实现。// 1、列表 listFields 的配置,如
request.listFields = [
....
// 取出 person 的 id,但是不在列表中显示
person : [mappingField: ".id", visible: false, listable: true],
// 新增一个纯粹依赖 renderClosure 闭包的 personGroups,用于输出到列表中
personGroups: [index: 110, render: { Map item, value, List<Map> data ->
if (request.groups == null) {
// 一次性将当前页的分组信息取出来,并根据 person.id 分组,缓存到 request 中
request.groups = CollectionUtils.groupBy(
DbUtils.executeQueryInList("select new map(vp.id as id, vpg.name as name) from foo.bar.Person vp inner join vp.groups vpg where vp.id in (??)",
data*.person_id, [clazz: Verification]), "id")
}
// 拼接分组名称,用于列表显示
return request.groups.get(item.person_id)*.name?.join(", ") ?: ""
}],
....
]
// 2、查询的实现:此时无法通过 o:searchFields 或 s:textField 标签来实现自动拼接查询条件,但是可以通过下列方法解决。
// 2.1 在查询栏上放一个输入控件(根据需求放 input、select 均可),这里放一个 input,用户可以输入多个分组名称进行模糊搜索
<g:textField name="personGroups"/>
// 2.2 如果是默认框架,那么提交查询时会自动将 personGroups 作为参数传给后台;如果用 layui 等框架,可以手动将 personGroups 的值取出来,拼接到 table.reload 的 where.personGroups 中。
// 2.3 在控制器的 list 或者 $beforeList 中,根据 group.name 拼接子查询,如下面的代码所示(注意 _person.id 的写法):
if (params.personGroups) {
String groups = ((String) params.personGroups).trim()
.replaceAll(/['"\\\/]/, "").split(/\s/) // 替换特殊字符
.join("%' or vpg.fzmc like '%") // 拼接多个 like 条件
params.'search.precondition' = (params.'search.precondition' ?: "1=1") +
" and _person.id in (select vp.id from foo.bar.Person vp inner join vp.groups vpg where vpg.fzmc like '%" + groups + "%')"
}
public abstract boolean i18n
如果没有设置 i18nPrefix,则前缀默认为 “domain类全名.属性名.”。
public abstract java.lang.String i18nPrefix
一般以 “.” 结束,然后拼上数据值进行显示值计算。
public abstract java.lang.Class searchClosure
默认情况下会根据字段类型等生成搜索输入框,若自动生成的输入框无法满足要求,可以采用自定义闭包。
配置后自定义闭包后,searchField、searchMethod、searchRange、searchWidth、searchCssClass 将失效。
例如:searchClosure: { s.booleanSelect(name: "disabled", from: ['', '0', '!0'], type: "number") }。
public abstract java.lang.String searchField
正常情况下,查询字段为当前显示的字段(或 mappingField);但如果实际搜索的是其他字段、或多个字段,可以配置 searchField 属性。
注:需要配置完整的查询名称,比如 "d.name;_employee.name",同时查询文档的 name 字段和文档关联的 employee.name 字段,中间以分号分隔。
public abstract int searchMethod
日期默认是 range;布尔默认是 equal;字符串默认是 like; 数字的 constraints 里有 inList 或 ext.inList 则默认为 equal,否则默认为 range。
如果为 equal 且设置了 searchRange、或者为 range 且不是字符串,则会渲染为下拉列表;
public abstract java.lang.String[] searchRange
如果查询方式为 range 或 equal,则可设置查询范围。
默认情况下,查询范围会自动从 constraints 的 range、inList、ext.inList 中取值,并尝试国际化。
如果不是注解形式的定义、且配合 searchMethod 渲染为下拉列表时,可以为对象或 Map 列表,如果为 Map 列表,会自动取 value、text 作为下拉列表选项(Option)的值和文本。