传统的Module配置一般采用XML - 这种繁杂的东西就不去说它了。
随着脚本语言在Java中的引入,我们有了更简洁更易维护的Module配置方式。
subclass一个Groovy的BuilderSupport先:
package com.g
/**
* Created by IntelliJ IDEA.
* User: S.C.
* Date: 5/3/11
* Time: 9:54 AM
* To change this template use File | Settings | File Templates.
*/
import org.codehaus.groovy.grails.web.context.ServletContextHolder as SCH
import com.g.utils.EvalUtils
class Module extends BuilderSupport {
private static Map modules
public static final String HOME = 'Home'
public static Map getModuleByClazz(clazzOrClazzName) {
for(KV in modules) {
if((clazzOrClazzName instanceof String ? KV.value.clazz?.name : KV.value.clazz) == clazzOrClazzName) {
return KV.value
}
}
}
public static String getBelongsToFieldName(m) {
def belongsTo = m?.belongsTo
if(!belongsTo) return null
def fieldName = belongsTo.name.split('\\.')[-1]
fieldName[0].toLowerCase() + fieldName[1..-1]
}
protected void setParent(Object parent, Object child){
if(parent.children == null) parent.children = []
parent.children << child
child.parent = parent
}
protected Object createNode(Object name){
createNode(name, null)
}
protected Object createNode(Object name, Object value){
createNode(name, null, value)
}
protected Object createNode(Object name, Map attributes){
createNode(name, attributes, null)
}
protected Object createNode(Object name, Map attributes, Object value){
def module = attributes ?: [:]
module.name = name
module.id = name.encodeAsMD5()
module.label = module.label ?: (module.clazz ? null : module.name)
module.description = module.description ?: module.qtip ?: module.label
modules[name] = modules[module.id] = module
return module
}
protected void nodeCompleted(Object parent, Object node) {
if(node.clazz && !node.belongsTo) {
def p = parent
while(p && !p.clazz) {
p = p.parent
}
node.belongsTo = p?.clazz
}
}
def invokeMethod(String name, args) {
try{
super.invokeMethod name, args
}catch(x){
println x
}
}
private static void build() {
println "building modules ..."
modules = [:]
def file = new File(SCH.getServletContext().getRealPath("/WEB-INF/db/modules.groovy"))
if(file.exists()) {
def b = new Module()
def c = EvalUtils.eval('{->'+file.text+'}')
b."$HOME"(c)
println "built ${modules.keySet().size()/2} modules."
}
}
}
module.groovy配置文件:
Sponsors {
Sponsor(
label: {o->o.name},
description:{o->"${o.name}<br>${o.address?.country?:''}"},
searchFields:'name',
qtip: {o->"<table><tr><td align='right'><b>Name: <b></td><td>${o.name}</td></tr></table>"},
sort: 'name', clazz: Sponsor, idRex:{usr->
User.isInternalAccount(usr) ? '.*' : ''
}, defaultInternalPermission:'ru'
)
}
Studies {
Study(
label: {o->"${o.jobCode}${o.nickname?(' : '+o.nickname):''} (Sponsored by ${o.sponsor?.name})"}, plural:'Studies',
description:{o->
def desc = ["<b>${o.jobCode}</b><br><br><table>"]
desc << "<tr><td><b>Sites in total:</b> </td><td align='right'>${Site.findAll(study:o).size()}</td></tr>"
GenericSelectionItem.findAll(sort:'name', group:'siteStatus').each{status->
desc << "<tr><td><b>${status.html}:</b> </td><td align='right' width='500'>${Site.findAll(study:o, status:status).size()}</td></tr>"
}
def subjects = Subject.findAll('site.study':o)
desc <<"<tr><td> </td><td> </td></tr>"
desc << "<tr><td><b>Subjects in total:</b> </td><td align='right'>${subjects.size()} (<font color='red'><b>${Subject.findAll('site.study':o, screenFailure:true).size()} Screen Failures</b></font>)</td></tr>"
desc << "</table>"
desc.join()
},
searchFields:'jobCode,nickname',
qtip: {o->
"""<table>
<tr><td><b>JobCode:</b> </td><td>${o.jobCode}</td></tr>
<tr><td><b>Nickname: </td><td>${o.nickname?:''}</td></tr>
<tr><td><b>Sponsor: </td><td>${o.sponsor?.name?:''}</td></tr>
</table>"""
},
sort: 'jobCode', clazz: Study, idRex: {usr->
def accessibleStudies = ACL.findAll(module:'Study', users:usr)?.oid.join('|')
def ownedStudies = Study.findAll(all:true,version:0,createdBy:usr?.username)?.id.collect{it.substring(0,36)}.join('|')
return accessibleStudies+'|'+ownedStudies
}
) {
// ...
"Euro Country Specific Documents"(hide:{mid->
!Study.isEuro(mid.split(':')[1])
}) {
//...
}
}
}
System {
// ...
}
Help {
// ...
}
Module配置文件(groovy)中大量使用了Closures,其中一个最简单的例子是
"Euro Country Specific Documents"(hide:{mid->
!Study.isEuro(mid.split(':')[1])
})
!Study.isEuro(mid.split(':')[1])
})
这样在显示modules的时候,这个hide closure将被调用,专门为涉及Euro Countries的Study做的Module "Euro Country Specific Documents"就能智能地根据某一指定的study(临床试验项目)是否在欧洲国家做来显示/隐藏,酱紫管module显示的代码就可以做的很简洁,无他,唯调用closure而已:
// ...
if(m.hide?.call(params.id)) {
continue
}
// ...
---------- P.S. Study#isEuro ----------
public static boolean isEuro(sid) {
// The countries currently using the euro are:
// 1) Andorra
// 2) Austria
// 3) Belgium
// 4) Cyprus
// 5) Estonia
// 6) Finland
// 7) France
// 8) Germany
// 9) Greece
// 10) Ireland
// 11) Italy
// 12) Kosovo
// 13) Luxembourg
// 14) Malta
// 15) Monaco
// 16) Montenegro
// 17) Netherlands
// 18) Portugal
// 19) San Marino
// 20) Slovakia
// 21) Slovenia
// 22) Spain
// 23) Vatican City
def euroCountries = Country.findAll(name:~/Andorra|Austria|Belgium|Cyprus|Estonia|Finland|France|Germany|Greece|Ireland|Italy|Kosovo|Luxembourg|Malta|Monaco|Montenegro|Netherlands|Netherlands Antilles|Portugal|San Marino|Slovakia|Slovenia|Spain|Holy See \(Vatican City\)/)
!!Study.find(id:sid){
def qq = it.descend('countries'), c
euroCountries.each{
def c1 = qq.constrain(it)
c = c ? c.or(c1) : c1
}
}
}
本文探讨了在Java环境中使用Groovy语言进行模块配置的优势,通过创建Groovy的BuilderSupport类并利用Closures简化配置过程。具体展示了如何在配置文件中使用Closures来动态构建模块,实现模块间的关系定义、属性获取与展示逻辑,同时通过实例说明了如何通过闭包(Closure)智能判断特定条件下的模块显示与隐藏。
740

被折叠的 条评论
为什么被折叠?



