Groovy DSL从入门到项目实战(一)

Groovy是一门很灵活的Java扩展语言,支持弱类型、闭包、函数式编程等脚本语言的高级特性。因为小卷所在公司的船申报系统需要重构,对原先java硬编码的各种表单数据校验、后台业务校验使用规则脚本的形式进行剥离出来。而市面上像Jboss Drools这样的规则引擎又感觉太重了,所以选择更轻量级也更容易在java体系中整合的groovy,为此,开始新一轮的groovy dsl学习之旅。

因为groovy dsl的脚本形式有非常好的可读性,且只要有jvm虚拟机环境就可以独立或者嵌入到当前java模块中运行,这就是gradle作为项目构建工具非常受欢迎的原因,因为它提供了高可读、高可维护性、高灵活度的dsl软件构建脚本。

如果你跟小卷一样做全栈开发,体验过前端从jsts的严谨,那你一定也想体验下后端从javagroovy的松散洒脱。咱们一起开始groovy学习之旅吧。

学习参考

万变不离其宗的官方参考文档

csdn优质创作者猿泰山 博客:

PACKT出版社出版的:Groovy for Domain-specific Languages - 第二版英文版 (Dearle, Fergal)

说明

这本英文实战书是小卷学习的主要参考,里面涉及到groovy dsl语言特性的更多实战。在后续的博文分享中也会体现出来。

工程搭建

在这里插入图片描述

在这里插入图片描述

语法特性初体验

类型由运行时决定

def myVar = 'hello'
println myVar.class

myVar = 123.4
println myVar.class

Java里的类型是编译时就确定了,而groovy中则在运行时才被确定,这里def也可以用String声明,这样在赋值其他类型时存在一个隐式转换。

练一练

将上面代码加到com/juan/groovy/Main.groovymain方法中,先用def声明,再改成String,看输出。后续练习若无说明,默认也在Main.groovymain方法中编写。

list和map操作

// list定义与访问
def students = ['小张', '小李', '小王']
println students
println students[1]

// map定义与访问
def lili = [name: '莉莉', age: 22]
println lili
println lili.name
println lili['age']

定义和访问方式跟js类似,注意这里对象字面量的定义形式用[ ... ]而不是{ ... }

闭包 - 声明与执行分离

// 闭包可以当作一个有入参和返回值的函数
def min = { num1, num2 -> Math.min(num1, num2) }
// 通过call来调用
def result = min.call(2, 3)
println result

// 直接用函数变量名调用
result = min(2, 3)
println result

// 调用时括号可以省略
result = min 2, 3
println result

现在咱们姑且先把闭包当作一个函数来使用,注意,闭包中定义的内容是用{ ... }进行关闭和隔离的。再来看一个实现打印的小栗子:

// 实现一个打印的闭包
def myPrint = { a -> print a }
myPrint ('hello\n')

def myPrint2 = { a, b -> print a; print b }
myPrint2 ('hello', 'world\n')

groovy语法的魅力,化繁为简,语法可以精简到如下程度:

def myPrint = { print it } // 一个参数时可以使用隐式变量it
myPrint 'hello\n' // 括号可以省略

def myPrint2 = { a, b -> print a print b } // 这里的分号也可以省略
myPrint2 'hello', 'world\n' // 括号可以省略

什么时候不能省略分号

一般的执行语句都可以省略;,当然也有一些特殊情况,比如:

def a = 1; def b = 2 // 两个def的声明语句中间的;不能省略
print a print b // 可省略;

再来看个求最小的小练习来巩固下闭包函数的用法:

// 定义求最小值的闭包
// 箭头函数体内的语句无需分号,最后一个语句为返回值
def min = { list ->
    def min = list[0]
    list.each { n -> if (n < min) min = n }
    min
}
def list = [ 5, 2, 3, 1, 4, 6]
println min(list) // 这里min的括号调用不可省略

println( min list ) // 这种形式也是可以的

操作符重载

groovy仿照C++实现语言基本特性的操作符重载,可以扩展类中相应的方法来实现操作符的重载,比如plus()方法,不同的类型提供的不同的plus()方法的重载来实现+操作符,操作数的类型不同,实现也不一样,看例子:

def str = 'hello '
str = str.plus('groovy')
println str

def d = 123.4
d = d.plus(12) // 如果是'12'呢,尝试改下
println d

正则

比如实现一个字符串多个连续空格替换为一个:

def str = '      aa  bbb    cc  '
// =~ 操作符表示对目标字符串应用正则模式,执行结果为一个匹配器,这里是匹配多个连续空格
def matcher = str =~ ' +'
def result = matcher.replaceAll(' ')
println "|$result|"
// 字符串模板中的表达式写法,注意,外面要用双引号包裹
println "|${result + '!!!'}|"

标记语言构建器

需要引入依赖:

implementation 'org.apache.groovy:groovy-xml:4.0.14'

这个groovy-xml充分实现了dsl给标记语言的声明所带来的可读性和可维护性,比写原生标记语言要强太多

def writer = new StringWriter()
def builder = new MarkupBuilder(writer)
builder.course {
    author {
        name '小卷'
    }
    title '跟着小卷学groovy'
    price 0 // 完全免费
}

println writer

这里通过groovy-xml扩展模块的标记语言构建器,可以很轻松的对groovy的对象声明的简洁语法构建出xml格式的数据,以满足远程服务调用所需的格式,非常简单!得到的输出结果:

<course>
  <author>
    <name>小卷</name>
  </author>
  <title>跟着小卷学groovy</title>
  <price>0</price>
</course>

关于类型导入

一般的常用类型、内置类型,在groovy代码中都不需要导入;而对于第三方的模块中的类型,需要导入其类型。

  • 22
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Java小卷

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值