三分钟学会 Groovy 运行 DSL文件
首先groovy和dsl的概念自不必多说.. Groovy: 可以简单理解成是对Java的封装,它提供了更加简洁的语法和其他动态语言的一些特性,如JS的闭包.在Groovy中也有闭包,而且个人认为这个闭包是Groovy中最灵活的地方. DSL: 可以简单理解成就是一个配置文件,或者说是面向领域的某种配置文件,如Ant 的build.xml 某种意义上就是Ant的DSL文件. 下面简短的说一下实际运用: 1) ?需求 ? 系统要和外部系统集成交互,交互的方式是当在本系统做完一笔业务后,要在特定的共享文件夹中产生一个XML文件,但是要注意这个XML文件中的属性的序列是可变的,也就是说,第一天客户要姓名排在年龄之后,第二天客户忽然脑抽要年龄排在姓名之前.要删除一个字段,要在某个字段前固定加上一个前缀... <xml> <name>zhangsan</name> <age>18</age> </xml> 2) 设计思路 这该如何是好??? 本身产生XML 在java中是如此的简单,但是你丫要改变序列,这个不是很蛋疼吗.... 想啊想... 想啊想... XStream.. JAXB.. 反射自己拼XML,那可配置怎么弄呢? 太烦了... 唉?! 听说Groovy中有个XMLBuilder? 什么玩意.. 先Google一下,大神深入浅出,讲的这么简单,那就直接用吧,看样子是可以做到的 http://www.ibm.com/developerworks/cn/java/j-pg05199/? 3) 具体实现 ?本身XmlBuilder 就很简洁,只要 def?comment?=?"<![CDATA[<!--?address?is?new?to?this?release?-->]]>" def?builder?=?new?groovy.xml.StreamingMarkupBuilder() builder.encoding?=?"UTF-8" def?person?=?{ ??mkp.xmlDeclaration() ??mkp.pi("xml-stylesheet":?"type='text/xsl'?href='myfile.xslt'"?) ??mkp.declareNamespace('':'http://myDefaultNamespace') ??mkp.declareNamespace('location':'http://someOtherNamespace') ??person(id:100){ ????firstname("Jane") ????lastname("Doe") ????mkp.yieldUnescaped(comment) ????location.address("123?Main") ??} } def?writer?=?new?FileWriter("person.xml") writer?<<?builder.bind(person) 像这样,其中mkp是StreamingMarkupBuilder中的内置变量person 就是要产生的 xml的Root Node,下面将上面的代码Run一下产生的xml,可以看到person.xml中的内容: <?xml?version="1.0"?encoding="UTF-8"?> <?xml-stylesheet?type='text/xsl'?href='myfile.xslt'?> <person?id='100' ????????xmlns='http://myDefaultNamespace' ????????xmlns:location='http://someOtherNamespace'> ??<firstname>Jane</firstname> ??<lastname>Doe</lastname> ??<![CDATA[<!--?address?is?new?to?this?release?-->]]> ??<location:address>123?Main</location:address> </person> 相信很多稍有Coding经验的人对上面产生xml的代码一眼便明,哈哈.. 知道如何产生xml后那么怎么实现可配置呢? 其实只要把上面这段代码放到一个配置文件中就可以了,groovy的语法,也就是上面这段代码本身就相当于配置文件,但是他又是可以随时运行的,也就是说就算你项目on line 了 ,客户脑抽了,要减少一个字段 或者是改变一下序列,那我们只需要download下这个所谓的dsl后稍作修改再上传就OK了. 下面贴上实际代码. package?com.ebao.gs.sp.dsl import?com.ebao.gs.sp.dsl.tasks.Tasks import?com.ebao.gs.sp.model.Policy import?com.ebao.gs.sp.pub.context.AppContext import?com.ebao.gs.sp.pub.context.DSLEngineContext import?com.ebao.gs.sp.pub.exception.BeforeIssuanceRuleFailureException import?com.ebao.gs.sp.pub.exception.DSLNotFoundException import?com.ebao.gs.sp.pub.exception.UserDefinedError import?groovy.util.logging.Slf4j @Slf4j class?DSLEngine?{ ????static?final?DSLEngine?instance?=?new?DSLEngine(); ????static?GroovyScriptEngine?scriptEngine ????public?static?final?DSLEngine?getInstance()?{ ????????return?instance; ????} ????static?boolean?isValidDSLRoot(String?dslRootFolder)?{ ????????try?{ ????????????if?(dslRootFolder?==?null?||?dslRootFolder.trim().equals(""))?{ ????????????????throw?new?DSLNotFoundException("DSL?root?folder?must?be?provided") ????????????} ????????????def?rootFile?=?new?File(dslRootFolder) ????????????if?(!rootFile.exists()?||?!rootFile.isDirectory())?{ ????????????????throw?new?DSLNotFoundException("DSL?root?folder?[${dslRootFolder}]?does?not?exists?or?not?a?folder") ????????????} ????????????def?dslNotFound?=?true ????????????rootFile.eachDir?{?File?tenantFolder?-> ????????????????def?tenantCode?=?tenantFolder.name ????????????????if?(tenantCode.toUpperCase()?!=?Const.SHARED.toUpperCase())?{ ????????????????????tenantFolder.eachDir?{?prdtFolder?-> ????????????????????????def?prdtCode?=?prdtFolder.name ????????????????????????if?(prdtCode.toUpperCase()?!=?Const.SHARED.toUpperCase())?{ ????????????????????????????prdtFolder.eachDir?{?verFolder?-> ????????????????????????????????def?prdtVersion?=?verFolder.name ????????????????????????????????if?(prdtVersion.toUpperCase()?!=?Const.SHARED.toUpperCase())?{ ????????????????????????????????????def?dslFiles?=?verFolder.listFiles(new?FilenameFilter()?{ ????????????????????????????????????????@Override ????????????????????????????????????????boolean?accept(File?dir,?String?name)?{ ????????????????????????????????????????????return?name.toLowerCase().endsWith(".dsl") ????????????????????????????????????????} ????????????????????????????????????}) ????????????????????????????????????if?(dslFiles.size()?<?1)?{ ????????????????????????????????????????throw?new?DSLNotFoundException("No?DSL?file?defined?for?[${tenantCode},?${prdtCode},?${prdtVersion}]") ????????????????????????????????????} ????????????????????????????????????dslNotFound?=?false ????????????????????????????????} ????????????????????????????} ????????????????????????} ????????????????????} ????????????????} ????????????} ????????????if?(dslNotFound)?{ ????????????????throw?new?DSLNotFoundException("Invalid?DSL?root:?no?any?DSL?files?found?in?this?folder") ????????????} ????????????return?true ????????}?catch?(DSLNotFoundException?e)?{ ????????????return?false ????????} ????} ????private?initScriptEngine()?{ ????????String?root?=?//?这里是你dsl文件就是上文中所述的可配置的文件所在的根目录 ????????if?(scriptEngine?==?null)?{ ????????????synchronized?(this)?{ ????????????????scriptEngine?=?new?GroovyScriptEngine(root) ????????????} ????????} ????} ????void?generateConfigurationXML(Policy?policy)?{ ????????initScriptEngine() ????????initDSLEngineContext(policy) ????????def?binding?=?new?Binding() ????????def?tasks?=?new?Tasks(policy:policy) ????????binding.setVariable("Tasks",?tasks) ????????def?fileName?=?//?你具体Dsl在dsl根目录中的名字,通过上述步骤,然Groovy的ScriptEngine?可以找到你dsl文件即可 ????????def?result?=?scriptEngine.run(fileName,?binding) ???????? ????????println?result.toString() ????} } 上面代码中的Policy对象就是产生xml的原对象。接下来可以看到 ????????def?binding?=?new?Binding() ????????def?tasks?=?new?Tasks(policy:policy) ????????binding.setVariable("Tasks",?tasks) 这里面绑定了一个Tasks 变量,作用是在你的DSL中起始位置处必须要有Tasks以让Groovy可以找打这个DSL文件运行的初始调用点. class?Tasks?{ ???def?builder?=?new?StreamingMarkupBuilder() ???def?policy? ???def?call(Closure?cl)?{ ??????cl.setDelegate(this); ??????cl.setResolveStrategy(Closure.DELEGATE_ONLY) ??????cl.call(); ????} ???? } 接下来当运行到Tasks对象实例中的时候,改实例中的builder 和policy 起始已经被实例化了,在dsl文件中我们只需要如下: Tasks{ ????builder.bind?{ ????????mkp.xmlDeclaration() ????????policy?{ ????????????field1?(policy.field1) ????????????field2?(policy.field1?+?"suffix") ????????} ????} } 便可得到产生的xml <xml?...> <field1>aaa</field1> <field1>222suffix</field1> </xml> 以后只需要改这个dsl就可以“高度” 可配置! (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |