众里寻他千百度
正如Groovy对Java很多特性进行的包装优化一样,基于Groovy的HttpBuilder也包裹了HttpClient,使网络编程变得更加的方便易用,下面稍微来用一个例子看一下。
寻找各种依赖的jar包有时候会让我们失去耐心,不过值得庆幸的是我们有Maven和Gradle这样的工具,可以根据配置轻松的帮我们配置好我们需要的数据。下面我们来叙述一下整个过程。
- 创建文件夹httpbuildertest
- 创建gradle配置文件,build.gradle,内容如下:
<pre>
apply plugin: "groovy"
apply plugin: "eclipse"
repositories {
mavenCentral()
}
dependencies {
compile "org.codehaus.groovy:http-builder:0.4.0"
compile "org.codehaus.groovy:groovy-all:2.3.3"
testCompile "org.spockframework:spock-core:0.7-groovy-2.0"
}
</pre>
gradle我们将做另文介绍
执行gralde eclipse(当然必须先安装gradle),就可以生成eclipse所需要的.classpath和.project文件,这时候就可以使用eclipse导入功能来import->Existing Projects Into WorkSpace。
-
创建我们的一个测试,试试看是不是可以使用httpbuilder了
import groovyx.net.http.HTTPBuilder
import spock.lang.Specification;
import static groovyx.net.http.Method.*
import static groovyx.net.http.ContentType.*class HttpbuildLabSpec extends Specification{
HTTPBuilder http = new HTTPBuilder( 'http://m.weather.com.cn' )
public void testRequestWeather(){
when:
def info =""
http.request( GET, JSON ) {
url.path = '/data/101290401.html'
headers.'User-Agent' = 'Mozilla/5.0 Ubuntu/8.10 Firefox/3.0.4'
response.success = { resp, json ->
info = json.weatherinfo.city
}
response.failure = { resp -> println "Unexpected error: ${resp.statusLine.statusCode} : ${resp.statusLine.reasonPhrase}" }
}
then: "曲靖"==info
}
}
打完收工,通过这个小例子我们可以了解到这么一些内容:
(1)HTTPBuilder 是这个框架的核心类(要不然怎么和框架一个名字),构建这个类的对象的时候,指定要请求的baseUrl。
(2)request方法可以指定请求的method和返回的数据格式,method对应的是GET/PUT/POST/DELETE/HEAD几个常量,而数据格式目前有JSON/XML/HTML/BINARY/URLENC/ANY几种。
(3)一个比较有意思的地方是,在http的request方法里面,仿佛是无根之水一样突然冒出来了几个没有声明过的变量,看起来连编译也不会通过的方法,那么是如何能正常运作的呢?这个我们就要研究到Groovy的Closure(闭包)。Groovy的闭包里包含有一个delegate属性,一般来说,这个delegate里保存的是闭包使用上下文的对象引用,比如a调用了一个闭包b,则b的delegate就是a的this对象。而在HTTPBuilder对象调用request方法的时候,它把传入闭包的delegate改成了一个叫做SendDelegate的类对象(这是HTTPBuilder的内部类,他们都是用Java写的,在新版的HttpBuilder里,已经改名为RequestConfigDelegate),这个类里面,分别包含了一个叫做getHeaders()的方法,一个叫做getUrL()的方法,一个叫做getResponse()的方法。稍微思索一下我们就可以想到,Groovy里有这样的特性,如果直接使用一个识别不出来的变量,Groovy会假设它是getter的一种简写形式,自动进行补全(当然这也是DSL的常用伎俩,把方法伪装成短语),而getter并没有参数,所以其括号是可以简写的,实际上上面的代码可以写作getUrl().path = '/data/101290401.html',这样就非常符合程序员的视觉体验了。
(4)第四点罗嗦了不少,主要是为了喜欢追根问题的同学释疑,实际上整个调用还是非常的简单明快的,在request闭包里,我们通过response(记得吗,实际上就是GetResponse()),获得了一个Map结构,这个Map的内部结构实际上是Map<String,Closure>,对“success”和“failure”这两个key我们分别设置了对应的闭包,这样就完成了回调的设置,一旦方法成功或者失败,就可以调用到对应的闭包。
(5)使用了JSON作为返回格式,闭包的第二个参数就是解析好的返回body,就是一个Json对象,是可以直接用点号来访问的。当然最好不要在失败的闭包里放这个参数,一般失败的情况比较多,也许就是一个html返回,格式错误那么测试也就无法按照预期进行了。
简单的一个例子,希望能帮到读者。