JQuickCurl 使用文档(程序员指南)
面向 Java 开发者的 cURL 风格 HTTP 客户端框架使用手册。本文档从程序员视角出发,覆盖依赖引入、核心 API、注解/XML 两种使用方式、cURL 选项支持、变量与参数化、文件操作、高级功能(拦截器/代理/Cookie/SSL/批量执行)、配置详解与响应处理。
目录
- 1. 项目简介
- 2. 环境要求与依赖
- 3. 核心概念
- 4. 快速开始
- 5. cURL 命令选项支持
- 6. 注解方式(@JCurlCommand)
- 7. XML 配置方式
- 8. 变量与参数化
- 9. 文件上传与下载
- 10. 高级功能
- 11. 全局配置详解
- 12. 响应处理与类型转换
- 13. API 参考
- 14. 常见问题
1. 项目简介
JQuickCurl 是一个基于 cURL 命令、底层使用 OkHttp 执行请求的 Java HTTP 客户端框架。它的核心思想是:把你熟悉的 cURL 命令直接变成可执行的 Java HTTP 调用,无需手写 RestTemplate / OkHttp 样板代码。
特点:
- cURL 语法驱动:用 cURL 命令定义请求,框架自动解析执行
- 多 HTTP 方法:GET / POST / PUT / DELETE / PATCH / HEAD / OPTIONS / TRACE
- 文件上传下载:单文件、多文件、混合表单
- 注解驱动 与 XML 配置 两种使用方式
- 动态代理 + Lambda 调用
- 变量替换(
${var}全局变量、#{param}方法参数) - 拦截器、代理、HTTP/2、SSL 忽略、Cookie 等高级能力
- 批量执行多个 cURL 命令
2. 环境要求与依赖
2.1 环境要求
- JDK 8+
- Maven
- 依赖 ANTLR4 Runtime、OkHttp、Lombok
2.2 引入依赖
<dependency>
<groupId>io.github.paohaijiao</groupId>
<artifactId>jquick-curl</artifactId>
<version>${最新版本}</version>
</dependency>
框架会自动传递 OkHttp、ANTLR4 Runtime、Lombok 等依赖。
3. 核心概念
| 概念 | 说明 |
|---|---|
@JCurlCommand |
方法注解,声明该方法对应的 cURL 命令 |
JCurlInvoker |
调用入口,创建接口代理或以 Lambda 方式调用 |
JQuickCurlReq |
请求参数容器(继承自 HashMap<String,Object>),承载 ${var} 变量值 |
JContext |
执行上下文,存储运行时变量 |
JQuickCurlConfig |
全局配置单例,管理超时、连接池、拦截器、重定向等 |
JQuickCurlExecutor |
真正的执行器,解析 cURL 命令并通过 Visitor 执行 |
JQuickCurlResponseBody |
响应体封装,提供 asString()/asInputStream()/getCachedBytes() 等方法 |
JResult |
通用响应结果对象,封装 mediaType/string/bytes/stream 等 |
| XML 工厂 | JQuickXmlFactory + JQuickCurlXmlParseFactory,从 XML 加载接口定义 |
整体调用链路:
cURL 命令字符串
│
▼
JQuickCurlLexer ──► JQuickCurlParser ──► ParseTree
│
▼
JQuickCurlCommonVisitor
(visitCurlCommand)
│
▼
OkHttp Request 执行
│
▼
JQuickCurlResponseBody
│
▼
JQuickCurlResponseConvert
(按返回类型转换)
4. 快速开始
最简流程:定义接口 + @JCurlCommand → 创建代理 → 传参调用。
import com.github.paohaijiao.anno.JCurlCommand;
import com.github.paohaijiao.domain.req.JQuickCurlReq;
import com.github.paohaijiao.executor.JCurlInvoker;
public interface UserService {
@JCurlCommand("curl -X GET http://localhost:8080/api/users/1")
String getUser(JQuickCurlReq req);
}
调用:
UserService api = JCurlInvoker.createProxy(UserService.class);
JQuickCurlReq req = new JQuickCurlReq();
String result = api.getUser(req);
System.out.println(result);
5. cURL 命令选项支持
框架支持的 cURL 选项:
| 选项 | 说明 |
|---|---|
-X, --request <METHOD> |
指定 HTTP 方法(GET/POST/PUT/DELETE/PATCH/HEAD/OPTIONS/TRACE) |
-H, --header <HEADER> |
添加请求头,如 -H "Content-Type: application/json" |
-d, --data / --data-ascii / --data-binary / --data-raw |
发送请求体 |
--data-urlencode <DATA> |
发送 URL 编码的表单数据(自动设置 application/x-www-form-urlencoded) |
-u, --user <user:password> |
基础认证(Basic Auth) |
-L, --location |
跟随重定向 |
--max-redirs <N> |
最大重定向次数 |
-o, --output <FILE> |
下载到文件 |
-F, --form <name=value> |
multipart 表单/文件上传 |
-x, --proxy <host:port> |
HTTP/HTTPS 代理 |
--socks5-hostname <host:port> |
SOCKS5 代理 |
--http2 |
使用 HTTP/2 |
-k |
忽略 SSL 证书校验 |
-v / --verbose / -s / --silent / --insecure |
其他选项(解析兼容) |
注意:
-X指定的方法是必须的,框架会校验方法是否显式声明。
示例命令:
curl -X POST http://localhost:8080/api/users/createUser \
-H "Content-Type: application/json" \
-d '{"name":"John Doe","email":"john@example.com"}'
在 Java 中作为字符串传入时,注意转义:
@JCurlCommand("curl -X POST http://localhost:8080/api/users/createUser \\\n" +
"-H \"Content-Type: application/json\" \\\n" +
"-d '{\"name\":\"John Doe\",\"email\":\"john@example.com\"}'")
JUser create(JQuickCurlReq req);
6. 注解方式(@JCurlCommand)
6.1 注解属性
@JCurlCommand 定义于 [JCurlCommand.java]
| 属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|
value |
String | — | cURL 命令字符串(必填) |
execute |
boolean | true | 是否执行命令 |
expectedStatus |
int | 200 | 期望的 HTTP 状态码 |
expectedBusinessStatus |
String | "200" | 期望的业务状态码 |
validationScript |
String | "" | 路径表达式校验脚本 |
6.2 定义接口
public interface UserService {
@JCurlCommand("curl -X GET --location 'http://localhost:8080/api/users/all'")
List<JUser> all(JQuickCurlReq req);
@JCurlCommand("curl -X GET http://localhost:8080/api/users/1")
JUser getUserById(JQuickCurlReq req);
@JCurlCommand("curl -X POST http://localhost:8080/api/users/createUser \\\n" +
"-H \"Content-Type: application/json\" \\\n" +
"-d '{\"name\":\"John Doe\",\"email\":\"john@example.com\"}'")
JUser create(JQuickCurlReq req);
// PATCH:局部更新用户信息(仅修改需要变更的字段),属于安全的写操作
@JCurlCommand("curl -X PATCH http://localhost:8080/api/users/1 \\\n" +
"-H \"Content-Type: application/json\" \\\n" +
"-d '{\"name\":\"John Doe Patched\"}'")
JUser patch(JQuickCurlReq req);
@JCurlCommand("curl -X GET http://localhost:8080/api/users/download/test.txt \\\n" +
"--output 'd://test//download.txt'")
byte[] download(JQuickCurlReq req);
}
6.3 两种调用方式
方式 A:动态代理
UserService api = JCurlInvoker.createProxy(UserService.class);
JQuickCurlReq req = new JQuickCurlReq();
JUser user = api.getUserById(req);
方式 B:Lambda 方法引用(::)
JUser result = JCurlInvoker.invoke(UserServiceImpl::getUserById, req, JUser.class);
JCurlInvoker.invoke 提供了多种重载,可灵活传入 JQuickCurlReq、JContext、JQuickCurlConfig,参见 [JCurlInvoker.java]
7. XML 配置方式
将 cURL 命令集中维护在 XML 文件中,实现配置与代码分离,适合统一管理大量 API。
7.1 XML 文件(如 apis.xml)
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE curls PUBLIC "-//PAOHAIJIAO//DTD API CURL 1.0//EN"
"classpath:paohaijiao/dtd/Jquick-curl.dtd">
<curls namespace="com.github.paohaijiao.test.xml.UserApi">
<curl name="all" returnClass="java.util.List">
curl -X GET --location 'http://localhost:8080/api/users/all'
</curl>
<curl name="getUserById" returnClass="com.github.paohaijiao.test.model.JUser">
curl -X GET http://localhost:8080/api/users/1
</curl>
<curl name="users" returnClass="com.github.paohaijiao.test.model.JUser">
curl -X POST http://localhost:8080/api/users/createUser \
-H "Content-Type: application/json" \
-d '{"name":"John Doe","email":"john@example.com"}'
</curl>
<!-- 使用 #{param} 方法参数占位符 -->
<curl name="usersByVariable" returnClass="com.github.paohaijiao.test.model.JUser">
curl -X POST http://localhost:8080/api/users/createUser \
-H "Content-Type: application/json" \
-d '{"name":#{name},"email":#{email}}'
</curl>
<curl name="download" returnClass="byte[]">
curl -X GET http://localhost:8080/api/users/download/pie.xlsx \
-H "Content-Type: application/octet-stream" \
--output 'd://test//piett.xlsx'
</curl>
</curls>
XML 节点说明(见 JQuickCurlXmlElement.java):
| 节点/属性 | 说明 |
|---|---|
<curls namespace="..."> |
根节点,namespace 绑定对应 Java 接口全类名 |
<curl name="..."> |
每个节点对应一个接口方法,name 需与接口方法名一致 |
returnClass |
方法返回值类型全类名 |
paramClass |
方法参数类型 |
value |
cURL 命令内容(节点文本) |
7.2 定义 Java 接口
接口方法名必须与 XML 中 <curl name="..."> 一一对应;配合 @Param 注解传递动态参数。
import com.github.paohaijiao.xml.param.Param;
public interface UserApi {
List<JUser> all(JQuickCurlReq req);
JUser getUserById(JQuickCurlReq req);
// 使用 @Param 绑定 #{name} / #{email} 占位符
JUser usersByVariable(@Param("name") String name, @Param("email") String email);
byte[] download(JQuickCurlReq req);
}
7.3 工厂创建并调用
import com.github.paohaijiao.xml.JQuickCurlXmlParseFactory;
import com.github.paohaijiao.xml.factory.JQuickFactory;
import com.github.paohaijiao.xml.factory.JQuickXmlFactory;
import com.github.paohaijiao.xml.handler.JQuickParseHandler;
JQuickCurlReq req = new JQuickCurlReq();
req.put("user", "xsaxsa@qq.com");
req.put("password", "zaZAzaZA");
JQuickParseHandler parser = new JQuickCurlXmlParseFactory();
JQuickFactory factory = new JQuickXmlFactory(parser, "apis.xml");
UserApi userApi = factory.createApi(UserApi.class);
List<JUser> list = userApi.all(req);
8. 变量与参数化
框架提供两种占位符机制,区别如下:
| 占位符 | 绑定来源 | 适用场景 |
|---|---|---|
${var} |
JQuickCurlReq / JContext |
全局变量、认证信息、基础域名等通用配置 |
#{param} |
方法入参 + @Param 注解 |
动态拼接请求体/URL,直接使用方法入参 |
8.1 ${var} 全局变量
public interface ApiService {
@JCurlCommand("curl -u ${user}:${password} https://api.github.com/user -X GET")
JGithubAuth retriveUser(JQuickCurlReq req);
}
// 调用
JQuickCurlReq req = new JQuickCurlReq();
req.put("user", "xsasaxsa@qq.com");
req.put("password", "xasxsa");
JGithubAuth result = api.retriveUser(req);
JQuickCurlReq继承自HashMap<String,Object>,put的 key 对应${}中的变量名。
8.2 #{param} 方法参数
public interface ApiService {
@JCurlCommand("curl -X POST http://localhost:8080/api/users/createUser \\\n" +
"-H \"Content-Type: application/json\" \\\n" +
"-d '{\"name\":#{name},\"email\":#{email}}'")
JUser usersByVariable(@Param("name") String name, @Param("email") String email);
}
// 调用
JUser user = api.usersByVariable("\"张三\"", "\"aa@qq.com\"");
注意:
#{}占位符需要与@Param的 value 保持一致;字符串值建议自带引号。
9. 文件上传与下载
9.1 单文件上传
@JCurlCommand("curl -X POST http://localhost:8080/api/users/upload \\\n" +
"-F \"file=@D:\\test\\test.txt\"")
String upload(JQuickCurlReq req);
-F 使用 @ 前缀表示本地文件路径。
9.2 多文件上传
@JCurlCommand("curl -X POST http://localhost:8080/api/users/upload-multiple \\\n" +
"-F \"files=@D:\\test\\test.txt\" \\\n" +
"-F \"files=@D:\\test\\test1.txt\"")
String uploadMultiple(JQuickCurlReq req);
9.3 混合表单(字段 + 文件)
@JCurlCommand("curl -X POST http://localhost:8080/api/users/upload-with-params \\\n" +
"-F \"userId=123\" \\\n" +
"-F \"username=john\" \\\n" +
"-F \"file=@D:\\test\\test.txt\"")
String uploadWithParams(JQuickCurlReq req);
9.4 文件下载
@JCurlCommand("curl -X GET http://localhost:8080/api/users/download/test.txt \\\n" +
"--output 'd://test//download.txt'")
byte[] download(JQuickCurlReq req);
--output 指定本地保存路径,方法返回 byte[] 便于二次处理:
byte[] bytes = api.download(req);
Files.write(Paths.get("d://test/xx1.txt"), bytes, StandardOpenOption.CREATE);
10. 高级功能
10.1 基础认证(Basic Auth)
@JCurlCommand("curl -u ${user}:${password} http://localhost:8080/api/users/all -X GET")
List<JUser> all(JQuickCurlReq req);
-u 会自动生成 Authorization: Basic <base64> 请求头。
10.2 代理
HTTP/HTTPS 代理:
@JCurlCommand("curl -x 127.0.0.1:8888 -X GET http://localhost:8080/api/users/1")
JUser viaProxy(JQuickCurlReq req);
SOCKS5 代理:
@JCurlCommand("curl --socks5-hostname 127.0.0.1:1080 -X GET http://localhost:8080/api/users/1")
JUser viaSocks5(JQuickCurlReq req);
10.3 忽略 SSL 证书
@JCurlCommand("curl -k -X GET https://localhost:8443/api/users/1")
JUser ignoreSsl(JQuickCurlReq req);
-k 会使用信任所有证书的 OkHttpClient。
10.4 HTTP/2
@JCurlCommand("curl --http2 -X GET https://localhost:8443/api/users/1")
JUser viaHttp2(JQuickCurlReq req);
10.5 跟随重定向
@JCurlCommand("curl -L --max-redirs 5 -X GET http://localhost:8080/api/users/all")
List<JUser> followRedirect(JQuickCurlReq req);
10.6 拦截器
实现 OkHttp 的 Interceptor 并注册到全局配置:
import okhttp3.Interceptor;
import okhttp3.Request;
import okhttp3.Response;
public class CustomInterceptor implements Interceptor {
@Override
public Response intercept(Chain chain) throws IOException {
Request request = chain.request();
// 统一添加请求头
// Request newReq = request.newBuilder()
// .addHeader("Authorization", "Bearer " + getToken())
// .build();
Response response = chain.proceed(request);
// 统一处理响应
return response;
}
}
注册:
JQuickCurlConfig config = JQuickCurlConfig.getInstance();
config.addInterceptor(new CustomInterceptor());
框架内置
JLoggingInterceptor用于请求日志,会默认添加。
10.7 批量执行
使用 JQuickCurlBatchRunner 一次性执行一个类中所有 @JCurlCommand 方法:
JQuickCurlBatchRunner batch = new JQuickCurlBatchRunner();
List<JQuickCurlResponseBody> results =
batch.runCurlCommands(new MyBatchCommands(), JQuickCurlResponseBody.class);
参见 [JQuickCurlBatchRunner.java]
10.8 直接使用 Executor(无接口)
如果不希望定义接口,可以直接用 JQuickCurlExecutor 执行 cURL 字符串:
JContext context = new JContext();
context.put("url", "http://localhost:8080/api/users/all");
JQuickCurlExecutor executor = new JQuickCurlExecutor(context);
JQuickCurlResponseBody body = executor.execute("curl -X GET --location ${url}");
System.out.println(body.asString());
11. 全局配置详解
JQuickCurlConfig 是全局单例(见 [JQuickCurlConfig.java]),支持链式配置:
JQuickCurlConfig config = JQuickCurlConfig.getInstance();
// 超时(单位由 timeUnit 决定,默认 MILLISECONDS)
config.connectTimeout(10_000, TimeUnit.MILLISECONDS);
config.readTimeout(30_000, TimeUnit.MILLISECONDS);
config.writeTimeout(30_000, TimeUnit.MILLISECONDS);
// 连接池
config.connectionPool(50, 5_000, TimeUnit.MILLISECONDS);
// 重试与重定向
config.retryOnConnectionFailure(true);
config.followRedirects(true);
config.followSslRedirects(true);
// 拦截器
config.addInterceptor(new CustomInterceptor());
11.1 通过 Properties 文件加载
支持从 properties 文件加载配置:
config.loadFromClasspathResource("jquick-curl.properties");
支持的配置项:
| 属性 Key | 说明 |
|---|---|
quick.curl.connect.timeout |
连接超时 |
quick.curl.read.timeout |
读超时 |
quick.curl.write.timeout |
写超时 |
quick.curl.pool.max.idle |
连接池最大空闲连接数 |
quick.curl.pool.keep.alive |
连接保活时长 |
11.2 超时注解 @JTimeout
方法级超时注解(见 [JTimeout.java]):
@JCurlCommand("curl -X GET http://localhost:8080/api/users/1")
@JTimeout(connect = 5000, read = 10000, write = 10000)
JUser getUser(JQuickCurlReq req);
12. 响应处理与类型转换
12.1 返回类型自动转换
JQuickCurlResponseConvert(见 [JQuickCurlResponseConvert.java])会根据接口方法的返回类型自动转换:
| 方法返回类型 | 转换结果 |
|---|---|
void / Void |
返回 null |
String |
响应体字符串(asString()) |
byte[] |
响应体字节数组(getCachedBytes()) |
InputStream |
响应体输入流 |
Reader / BufferedReader |
响应体字符流 |
ByteString |
okio ByteString |
JQuickCurlResponseBody |
原始响应体对象 |
okhttp3.ResponseBody |
原始 OkHttp 响应体 |
其他 POJO / List<T> 等 |
通过 JQuickValueTransformer 做 JSON 反序列化 |
示例:
public interface UserService {
// 返回 String
@JCurlCommand("curl -X GET http://localhost:8080/api/users/1")
String rawString(JQuickCurlReq req);
// 返回 POJO(自动 JSON 反序列化)
@JCurlCommand("curl -X GET http://localhost:8080/api/users/1")
JUser asUser(JQuickCurlReq req);
// 返回 List
@JCurlCommand("curl -X GET http://localhost:8080/api/users/all")
List<JUser> asList(JQuickCurlReq req);
// 返回字节数组(下载)
@JCurlCommand("curl -X GET http://localhost:8080/api/users/download/test.txt")
byte[] asBytes(JQuickCurlReq req);
}
12.2 JQuickCurlResponseBody API
当返回类型声明为 JQuickCurlResponseBody 时,可使用其丰富的读取 API(见 [JQuickCurlResponseBody.java]):
JQuickCurlResponseBody body = api.someCall(req);
body.asString(); // 字符串
body.asString(Charset); // 指定编码字符串
body.getCachedBytes(); // 字节数组(拷贝)
body.toByteString(); // okio ByteString
body.asInputStream(); // 输入流
body.asReader(); // Reader
body.asBufferedReader(); // BufferedReader
body.contentType(); // MediaType
body.contentLength(); // 内容长度
body.getHeaders(); // 全部响应头
body.header("Content-Type"); // 单个响应头
body.headers("Set-Cookie"); // 多值响应头
body.hasHeader("X-Trace-Id"); // 是否存在某响应头
13. API 参考
13.1 核心类
| 类名 | 说明 | 链接 |
|---|---|---|
JCurlInvoker |
调用入口:创建代理 / Lambda 调用 | [JCurlInvoker.java] |
JQuickCurlExecutor |
cURL 命令执行器 | [JQuickCurlExecutor.java] |
JCurlCommandProcessor |
命令处理器(解析+执行+转换) | [JCurlCommandProcessor.java] |
JQuickCurlCommonVisitor |
ANTLR Visitor,cURL → OkHttp 请求 | [JQuickCurlCommonVisitor.java] |
JQuickCurlConfig |
全局配置单例 | [JQuickCurlConfig.java] |
JQuickCurlReq |
请求参数容器 | [JQuickCurlReq.java] |
JQuickCurlResponseBody |
响应体封装 | [JQuickCurlResponseBody.java] |
JQuickCurlResponseConvert |
响应类型转换 | [JQuickCurlResponseConvert.java] |
JQuickCurlBatchRunner |
批量执行器 | [JQuickCurlBatchRunner.java] |
JQuickXmlFactory |
XML 配置工厂 | [JQuickCurlXmlParseFactory.java] |
13.2 核心注解
| 注解 | 作用目标 | 说明 | 链接 |
|---|---|---|---|
@JCurlCommand |
方法 | 声明 cURL 命令 | [JCurlCommand.java] |
@JTimeout |
方法 | 方法级超时配置 | [JTimeout.java] |
@Param |
参数 | 绑定 #{param} 占位符 |
— |
13.3 JCurlInvoker.invoke 重载一览
// 最简:仅需方法引用 + 返回类型
invoke(JFunction methodRef, Class<T> interfaceClass)
// 携带请求参数
invoke(JFunction methodRef, JQuickCurlReq req, Class<T> interfaceClass)
// 携带上下文
invoke(JFunction methodRef, JContext context, Class<T> interfaceClass)
// 携带配置
invoke(JFunction methodRef, JQuickCurlConfig config, Class<T> interfaceClass)
// 全量
invoke(JFunction methodRef, JQuickCurlReq req, JContext context,
JQuickCurlConfig config, Class<T> interfaceClass)
14. 常见问题
Q1:为什么提示 "The specified httpMethod must be displayed"?
A:cURL 命令中必须显式使用 -X 指定 HTTP 方法。
Q2:${var} 和 #{param} 有什么区别?
A:${var} 从 JQuickCurlReq/JContext 取值,适合全局/通用变量;#{param} 绑定方法入参(配合 @Param),适合动态业务参数。
Q3:JSON 请求体里的引号怎么处理?
A:在 Java 字符串中需转义。建议外层用双引号、内层用单引号,并对内部双引号转义,例如:
"-d '{\"name\":\"John\"}'"
Q4:下载文件返回什么类型?
A:声明为 byte[],框架会返回字节数组;配合 --output 可同时写入本地文件。
Q5:如何自定义全局超时?
A:通过 JQuickCurlConfig 单例配置,或用 properties 文件加载,或使用 @JTimeout 注解做方法级覆盖。
Q6:XML 方式中接口方法名不匹配会怎样?
A:XML 中 <curl name="xxx"> 必须与 Java 接口方法名一一对应,否则无法正确绑定。
Q7:如何调试 cURL 命令解析失败?
A:JCurlCommandProcessor 内置错误监听,解析失败会打印行号、列号与规则栈;也可直接使用 JQuickCurlExecutor 并自行捕获 JAntlrExecutionException。
更多示例请参考项目测试目录:src/test/java。