这里存放着关于书写groovy脚本中遇到的问题(主要)和使用到的技术
文档结构:
- 其他提示和问题
- groovy代码编译相关的问题
- 有用的语言细节/groovy语法糖
- 实现某些功能时需要用到的包和参考文档地址
我使用这个IDE:springsourcetool,基于eclipse的整合产品,提供groovy和grails的插件。在ide环境下,如果不能run as groovy或者java,很可能是因为源文件有问题(但IDE没有提示),无法成功编译。
莫名其妙的错误提示:
- 提示No signature of method:xxx is applicable for argument types: SomeType,但是在下面的Possible solution里,同样签名的方法又被给出了。这可能是那个方法是非静态方法,而你直接通过类而非去调用它了。这个提示本身十二分的莫名其妙。
编译:
1. 命令行编译代码:
- groovyc file.groovy
- java -cp "$GROOVY_HOME/lib/*":. file
2. 编译和引用:
把groovy源文件根据“有没有独立的执行语句”分为两种: 脚本文件和类文件
- 脚本会被编译成同名类,继承自script类, 脚本内的类也被分别编译成同名groovy类,因此,脚本名如果和类名相同,就不能在class{}体外有执行语句
- 引用类的方式:若该类与所属文件同名的,和java一样,或者通过groovyshell.evaluate获得返回的class对象,否则需要确保已经被编译成class;引用脚本的方式,groovyshell.evaluate返回脚本对象,或者使用scriptEngine.run
// 1 import classCompiled // 2 def groovyScriptEngine = new GroovyScriptEngine(".") groovyScriptEngine .run("file.groovy", new Binding()) // 3 GroovyShell shell = new GroovyShell(new Binding()); shell.evaluate(new File("file.groovy"))
3. import的类导致无法解析的错误: cannot resovle class:
- 该类不在加载的路径上,groovy在启动时会加载groovy目录下的lib中的类,和用户定义的类目录
- 如果该类是groovy自带的类,那么也可能是groovy的版本较旧
简单直接的增加路径的方式:
- 在conf/groovy-starter.conf中增加load配置
- 在已配置的路径中加入lib
- 在代码中对classLoader增加URL;在命令行中增加classpath参数
语言细节:
1. use的使用能够以可控的方式进行dsl,方法的增加仅限于use块内部,示例代码如下:
class ShellDSL { // non-thread safe def static ThreadLocal parentHolder = new ThreadLocal() def static mv (String src, String dest) { def srcFile = src.file() if (dest =~ "/\$") dest = "$dest${srcFile.name}" srcFile.renameTo(dest.file()) } def static file (String file) { if (parentHolder.get()) { new File(parentHolder.get(), file) } else { new File(file) } } def static dir(String dir, ensure) { //TODO should replace with seperator if (!dir =~ "/\$") {dir = "$dir/"} def d = dir.file() if (ensure) d.mkdirs() d } def static ensure(File f) { f.mkdir() f } def static inDir(String dir ,closure) { def d = dir.dir() parentHolder.set(d) closure.call() parentHolder.set(null) } }
- 用static定义方法
- 方法的第一个参数的类型就是该方法注入的目标类
- 方法使用该类中的其他方法时不需要use块
2. 特殊运算符用法:
- 类型转换使用as, 源类型中需要定义asType(Class klass)的方法
- << 符号对应的是leftShift方法, >>对应rightShift
- 运算符 *. 的意思是依次调用数组中元素的方法,操作返回一个对应结果的数组,效果和collect相同
- &method,方法指针。在对象定义级别使用,和ruby的alias作用相同;在执行流程中使用可以提升代码可读性
as:
def asType(Class r) {
if (r == Registered)
new Registered()
// alternative way
//return {it -> new Registered(name:it.name)}(this)
}
new User() as Registered
<<:
def leftShift(v) {array.add v}
new Queue() << 'mock'
*. :
['cut', 'paste']*.size().each{println it}
&: class Alias { def method = {println "method"} def alias = this.&method // 需要通过对象去引用.因此this不可省略 } def alias = new Alias() alias.method() alias.alias() def aliasMethod = alias.&alias aliasMethod()
应用:
1. groovy file 调用接口文档:
点此 :
- 可以进行eachFile, eachDir的操作
- eachXXX有对应的Match版本, 传入一个nameFilter, 根据文件的名字进行filter操作
- eachXXX还对应一个Recurse版本
2. Http请求可以使用
httpBuilder包,优点:
- 像js中处理ajax请求那样来写代码,虽然其实底层就是基于apache的那个包
client.request(GET, JSON){response, json ->
success: { ..... ..... } }
- 如上面所示,格式已经自动转换好了,而且性能不错,至少xml比groovy自带的快
- 适合复杂的场景使用,比较清晰
3. XML构建可以使用MarkupBuiler, 解析可以使用XMLSlurper: