加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 大数据 > 正文

由“如何更好地配置Module”引发的...

发布时间:2020-12-14 17:05:49 所属栏目:大数据 来源:网络整理
导读:公司有一个服役了N年的基于Java技术实现的业务系统,其中Module的配置比较死板:比如配置某个Module的label,通过更改displayFields和separator来实现,如果displayFields和separator分别设置成“jobCode,nickname,sponsor”和" : ",则label被拼成形如"ABB1

公司有一个服役了N年的基于Java技术实现的业务系统,其中Module的配置比较死板:比如配置某个Module的label,通过更改displayFields和separator来实现,如果displayFields和separator分别设置成“jobCode,nickname,sponsor”和" : ",则label被拼成形如"ABB1-705 : Abbott : Sam"的字符串。问题来了:如果我希望分隔符不是单一的" : "呢?如果我希望显示成"ABB1-705 : Abbott ( sponsored by Sam )"呢?

?

一个最容易想到的办法就是用包含占位符的字符串(跟公式或格式类似)来定义label,比如可以把label设置成"#{jobCode} : #{nickname} ( sponsored by #{sponsor} )",在运行期把具体值代入公式,计算出显示结果,计算的方法如下:

private String assembleLabel(String label,Object bean) {
    label.replaceAll(/#{.[^}]+}/){
        def arr = it[2..-2].split('.')
        def r = bean
        for(int j=0;j<arr.length;j++){
            r = r?."${arr[j]}"
        }
        r
    }
}

写出这个方法,自己感觉颇有些得意

:其中的

def r = bean
for(int j=0;j<arr.length;j++){
    r = r?."${arr[j]}"
} 

支持形如#{person.profile.name}的占位符,不光可以处理一层的属性提取,更深层次的object navigation都没问题(我使用Db4o,它的transparent activation特性威力相当惊人)。

?

看起来似乎很完美了,但是我们得记住:There's nothing that lends itself to the “one size fits all” paradigm.

?

设想这样一个scenario:?我有一个名叫Sites and Institutions的Module,它的description告诉软件使用者“标为红色的Site表示其状态为Enrollment,标为灰色表示Declined...”,虽然在Domain SiteStatus中保存的数据不是经常改变的,但一旦改变我们就不得不更新Sites and Institutions的description - 很显然,这样会很“湿” - 严格遵循DRY(Don't Repeat Yourself)原则是good practice

怎样才够DRY?我的做法是,利用Groovy的Closure和BSF。先看Module的定义

class Module {

    String name,icon,label,action
    String description // can be a plain String or a Closure definition script(starts with "GroovyScript:{")

    Class clazz
    Boolean scaffold,prototype
    List children
    Module parent
    String belongsTo
    List sort

    static constraints = {
        name nullable:false
    }

}

这样我就可以这样写了:

Module sites = new Module(
    name: '5it35',description:"""GroovyScript:{o->
      def r = ['<div style="padding:5px;">']
      SiteStatus.findAll(sort:'seq').each{
        r << "<font color=${it.color}>&#9632; ${it.name}</font><br>"
      }
      r << '</div>'
      r.join('')
    }"""//...
)

同时利用BSF写了个简单的eval来执行script:

  private static final GROOVY_SCRIPT_PATTERN = /^s*GroovyScripts*:s*{/

  static eval(String s) {
    eval(s,null)
  }

  static eval(String s,Object param) {
    if(s =~ GROOVY_SCRIPT_PATTERN) {
      return getBSFManager().eval("groovy",null,s.replace(GROOVY_SCRIPT_PATTERN,'')).call(param)
    }
    return s
  }

产生的效果是酱紫的:

?

把description写成“GroovyScript: {...}"是为了告诉自定义的解析器:这是个Groovy script,不是普通的String,你需要用BSF来eval. 为什么不把description定义成Object类型,然后给它赋个String或Closure呢?实际上我原来就是这样做的:

def desc = module.description
def result = desc instanceof Closure ? desc() : desc

看起来很美,实践中却出了点小问题:动态更改clousre时无法持久化到Db4o数据库,除非closure是在某个类中写的。我原先在Module类中有直接把description设成一个Closure:

description: {
    def r = ['<div style="padding:5px;">']
    SiteStatus.findAll(sort:'seq').each{
        r << "<font color=${it.color}>&#9632; ${it.name}</font><br>"
    }
    r << '</div>'
    r.join('')
}

它也确实被保存到Db4o的数据库中了(OM中显示了一个名叫com.grs.sctms.Module$_setup_closure1的类):

?

?

但是我在web-based的Grails Console中(服务器端是一GroovyShell在执行我提交的script)执行更改Module description(把它改成另一个Closure)却不能成功。

为了曲线救国,我只能用String类型的description + BSF运行期解析并执行脚本的办法了。实际上这个办法我比较喜欢,因为我可以在不重启应用的情况下,瞬间修改module,同时让修改瞬间生效。我在web-based的Grails Console中执行如下代码:

import com.grs.sctms.*
def oc = ctx.objectContainer
def sites = Module.find(name:'5it35')
println "original value: ${sites.description}"
sites.description  = """
GroovyScript:{o->
   def r = ['<div  style="padding:5px;">']
     SiteStatus.findAll(sort:'seq').each{
       r <<  "<font  color=${it.color}>&#9632;  ${it.name}</font><br>"
     }
   r  << '</div>'
   r[0..-2].join(':-)')+r[-1]
 }
"""
sites.save()
oc.commit()
println "current value: ${sites.description}"

?浏览器刷新一下,效果立马变成了:

?

?

最后,上一张让我能“操控sctms于万里之外”的web-based Groovy Console的照片(同时感谢这个Grails Plugin的原作者Siegfried Puchbauer and Mingfai Ma,我的Console是在他们提供的源码的基础上修改而得):

?

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读