groovy CategoryObject作用是什么?举例说明编写一个基于HttpClient的自定义DSL来实现getpostdelete等请求方法内部管理一个连接池支持Http和Https协议单个请求支持是否使用代理请求异常时自动重试出入参类型转换等功能
groovy @Category(Object)的作用是将一个Groovy类或对象作为一个扩展类或对象添加到现有的Java类或对象中,可以扩展现有类的功能或添加新的方法。
举例说明:
假设有一个Java类Person,我们可以使用Groovy的@Category注解来添加一个扩展类,增加一个方法sayHello:
class Person {
String name
Person(String name) {
this.name = name
}
}
@Category(Person)
class PersonExtension {
String sayHello() {
"Hello, ${delegate.name}!"
}
}
def person = new Person("Jack")
assert person.sayHello() == "Hello, Jack!"
在这个例子中,我们使用@Category注解将PersonExtension类作为Person类的扩展类添加进去,可以通过实例化Person类并调用sayHello方法来得到输出结果。
现在,我们来编写一个基于HttpClient的自定义DSL来实现get、post、delete等请求方法,内部管理一个连接池,支持Http和Https协议,单个请求支持是否使用代理,请求异常时自动重试,入参和出参类型转换等功能。
首先,我们需要引入HttpClient的依赖:
@Grab(group='org.apache.httpcomponents', module='httpclient', version='4.5.13')
然后,我们可以使用Groovy的DSL语法来编写HttpRequest类:
class HttpRequest {
private final CloseableHttpClient httpClient
private final String url
private final HttpMethod method
private final ContentType contentType
private final Map<String, String> headers
private final Map<String, Object> params
private final boolean useProxy
private final int maxRetry
private final int retryInterval
private final Map<Class, Class> convertTypeMap
HttpRequest(CloseableHttpClient httpClient, String url, HttpMethod method, ContentType contentType,
Map<String, String> headers, Map<String, Object> params, boolean useProxy, int maxRetry,
int retryInterval, Map<Class, Class> convertTypeMap) {
this.httpClient = httpClient
this.url = url
this.method = method
this.contentType = contentType
this.headers = headers ?: [:]
this.params = params ?: [:]
this.useProxy = useProxy
this.maxRetry = maxRetry ?: 0
this.retryInterval = retryInterval ?: 0
this.convertTypeMap = convertTypeMap ?: [:]
}
def execute() {
def request = new HttpUriRequestBuilder(method, url)
.contentType(contentType)
.headers(headers)
.params(params)
.useProxy(useProxy)
.build()
def retryCount = 0
while (retryCount <= maxRetry) {
try {
def response = httpClient.execute(request)
def entity = response.entity
def statusCode = response.statusLine.statusCode
if (statusCode >= HttpStatus.SC_OK && statusCode < HttpStatus.SC_MULTIPLE_CHOICES) {
def content = entity.content
def contentType = entity.contentType
def charset = contentType?.charset?.name() ?: "UTF-8"
def result = content.text(charset)
if (convertTypeMap.containsKey(result?.getClass())) {
result = result as convertTypeMap[result.getClass()]
}
return result
} else {
throw new RuntimeException("HTTP request failed with status code ${statusCode}")
}
} catch (Exception e) {
if (retryCount < maxRetry) {
retryCount++
Thread.sleep(retryInterval)
} else {
throw e
}
}
}
}
}
在这个类中,我们使用了Groovy的默认参数和Map默认值的特性,使得实例化HttpRequest类时可以省略一些参数。execute方法中,我们使用了HttpClient的CloseableHttpClient、HttpUriRequestBuilder和HttpResponse等类来执行HTTP请求,并添加了重试和类型转换等功能。
接下来,我们可以编写一个DSL类HttpDSL,提供get、post、delete等方法,以及连接池、代理、重试、类型转换等配置:
class HttpDSL {
private final CloseableHttpClient httpClient
private final boolean usePool
private final int maxPoolSize
private final int connectionTimeout
private final int socketTimeout
private final Map<String, Object> defaultParams
private final boolean useProxy
private final String proxyHost
private final int proxyPort
private final int maxRetry
private final int retryInterval
private final Map<Class, Class> convertTypeMap
HttpDSL(boolean usePool = true, int maxPoolSize = 50, int connectionTimeout = 5000, int socketTimeout = 5000,
Map<String, Object> defaultParams = [:], boolean useProxy = false, String proxyHost = null, int proxyPort = 0,
int maxRetry = 0, int retryInterval = 5000, Map<Class, Class> convertTypeMap = [:]) {
def builder = HttpClientBuilder.create()
.setDefaultRequestConfig(RequestConfig.custom()
.setConnectTimeout(connectionTimeout)
.setSocketTimeout(socketTimeout)
.build())
if (usePool) {
builder.setConnectionManager(new PoolingHttpClientConnectionManager(
RegistryBuilder.<ConnectionSocketFactory>create()
.register("http", PlainConnectionSocketFactory.getSocketFactory())
.register("https", SSLConnectionSocketFactory.getSocketFactory())
.build()))
.setMaxConnTotal(maxPoolSize)
.setMaxConnPerRoute(maxPoolSize)
}
httpClient = builder.build()
this.usePool = usePool
this.maxPoolSize = maxPoolSize
this.connectionTimeout = connectionTimeout
this.socketTimeout = socketTimeout
this.defaultParams = defaultParams
this.useProxy = useProxy
this.proxyHost = proxyHost
this.proxyPort = proxyPort
this.maxRetry = maxRetry
this.retryInterval = retryInterval
this.convertTypeMap = convertTypeMap
}
def get(String url, Map<String, Object> params = [:], Map<String, String> headers = [:], ContentType contentType = null) {
new HttpRequest(httpClient, url, HttpMethod.GET, contentType, headers,
defaultParams + params, useProxy, maxRetry, retryInterval, convertTypeMap)
.execute()
}
def post(String url, Map<String, Object> params = [:], Map<String, String> headers = [:], ContentType contentType = null) {
new HttpRequest(httpClient, url, HttpMethod.POST, contentType, headers,
defaultParams + params, useProxy, maxRetry, retryInterval, convertTypeMap)
.execute()
}
def delete(String url, Map<String, Object> params = [:], Map<String, String> headers = [:], ContentType contentType = null) {
new HttpRequest(httpClient, url, HttpMethod.DELETE, contentType, headers,
defaultParams + params, useProxy, maxRetry, retryInterval, convertTypeMap)
.execute()
}
def useProxy(String host, int port) {
new HttpDSL(usePool, maxPoolSize, connectionTimeout, socketTimeout, defaultParams,
true, host, port, maxRetry, retryInterval, convertTypeMap)
}
def maxRetry(int count) {
new HttpDSL(usePool, maxPoolSize, connectionTimeout, socketTimeout, defaultParams,
useProxy, proxyHost, proxyPort, count, retryInterval, convertTypeMap)
}
def retryInterval(int interval) {
new HttpDSL(usePool, maxPoolSize, connectionTimeout, socketTimeout, defaultParams,
useProxy, proxyHost, proxyPort, maxRetry, interval, convertTypeMap)
}
def convertType(Class fromType, Class toType) {
new HttpDSL(usePool, maxPoolSize, connectionTimeout, socketTimeout, defaultParams,
useProxy, proxyHost, proxyPort, maxRetry, retryInterval, convertTypeMap + [(fromType): toType])
}
def setDefaultParams(Map<String, Object> params) {
new HttpDSL(usePool, maxPoolSize, connectionTimeout, socketTimeout, params,
useProxy, proxyHost, proxyPort, maxRetry, retryInterval, convertTypeMap)
}
def close() {
httpClient.close()
}
}
在这个类中,我们使用了Groovy的方法链式调用和默认参数的特性,使得配置HttpDSL对象时可以省略一些参数。get、post、delete等方法中,我们使用了HttpRequest类来执行HTTP请求。useProxy、maxRetry、retryInterval、convertType和setDefaultParams等方法来配置连接池、代理、重试、类型转换和默认参数等选项。close方法用于关闭HttpClient的连接池。
现在,我们可以在Groovy脚本中使用HttpDSL来执行HTTP请求,例如:
def http = new HttpDSL(usePool: true, maxPoolSize: 50, maxRetry: 3)
def result = http.get("http://example.com", [q: "groovy"])
println result
http.close()
在这个例子中,我们使用HttpDSL类来创建一个HttpClient对象,并使用get方法来执行HTTP GET请求。请求参数包括查询字符串q=groovy,返回的结果会直接输出到控制台。最后,我们需要调用close方法来关闭HttpClient对象。
这样,我们就成功地使用Groovy DSL来实现了一个基于HttpClient的HTTP请求库,支持连接池、代理、重试、类型转换等功能
原文地址: https://www.cveoy.top/t/topic/fDES 著作权归作者所有。请勿转载和采集!