diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md
new file mode 100644
index 00000000..dd84ea78
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/bug_report.md
@@ -0,0 +1,38 @@
+---
+name: Bug report
+about: Create a report to help us improve
+title: ''
+labels: ''
+assignees: ''
+
+---
+
+**Describe the bug**
+A clear and concise description of what the bug is.
+
+**To Reproduce**
+Steps to reproduce the behavior:
+1. Go to '...'
+2. Click on '....'
+3. Scroll down to '....'
+4. See error
+
+**Expected behavior**
+A clear and concise description of what you expected to happen.
+
+**Screenshots**
+If applicable, add screenshots to help explain your problem.
+
+**Desktop (please complete the following information):**
+ - OS: [e.g. iOS]
+ - Browser [e.g. chrome, safari]
+ - Version [e.g. 22]
+
+**Smartphone (please complete the following information):**
+ - Device: [e.g. iPhone6]
+ - OS: [e.g. iOS8.1]
+ - Browser [e.g. stock browser, safari]
+ - Version [e.g. 22]
+
+**Additional context**
+Add any other context about the problem here.
diff --git a/.github/ISSUE_TEMPLATE/custom.md b/.github/ISSUE_TEMPLATE/custom.md
new file mode 100644
index 00000000..48d5f81f
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/custom.md
@@ -0,0 +1,10 @@
+---
+name: Custom issue template
+about: Describe this issue template's purpose here.
+title: ''
+labels: ''
+assignees: ''
+
+---
+
+
diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md
new file mode 100644
index 00000000..bbcbbe7d
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/feature_request.md
@@ -0,0 +1,20 @@
+---
+name: Feature request
+about: Suggest an idea for this project
+title: ''
+labels: ''
+assignees: ''
+
+---
+
+**Is your feature request related to a problem? Please describe.**
+A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
+
+**Describe the solution you'd like**
+A clear and concise description of what you want to happen.
+
+**Describe alternatives you've considered**
+A clear and concise description of any alternative solutions or features you've considered.
+
+**Additional context**
+Add any other context or screenshots about the feature request here.
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 00000000..ea5b62f4
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,17 @@
+/*/target/
+/*/bin/
+/*/.settings/
+/*/.classpath
+/*/.project
+/*/.idea/
+/*/package-lock.json
+/*/node_modules/
+/*/.vuepress/dist/*
+/*/*.iml
+**.versionsBackup
+/target/
+*.iml
+/.idea/
+.settings/
+.classpath
+.project
\ No newline at end of file
diff --git a/README.md b/README.md
index eeec7cf0..3e6f6e50 100644
--- a/README.md
+++ b/README.md
@@ -1,17 +1,17 @@
-
+
-
-
-
+
+
+
## 文档
-网址:https://ok.zhxu.cn
+官网 https://okhttps.ejlchina.com/
## 为什么用
@@ -25,8 +25,6 @@
* 单方法回调,充分利用 Lambda 表达式,让你代码超级简洁!
* 超级轻量,但性能卓越!
-* **阿里云最低 1 折**:https://www.aliyun.com/minisite/goods?userCode=zugtbi5w
-
## 如何使用
### 如艺术一般优雅,像 1、2、3 一样简单
@@ -92,35 +90,25 @@ Websocket 方法:
项目 | 最新版本 | 描述
-|-|-
-[okhttps](https://gitee.com/troyzhxu/okhttps/tree/dev/okhttps) | 4.1.0 | OkHttps 核心模块
-[okhttps-fastjson](https://gitee.com/troyzhxu/okhttps/tree/dev/okhttps-fastjson) | 4.1.0 | 与 fastjson 集成
-[okhttps-fastjson](https://gitee.com/troyzhxu/okhttps/tree/dev/okhttps-fastjson2) | 4.1.0 | 与 fastjson2 集成
-[okhttps-fastjson](https://gitee.com/troyzhxu/okhttps/tree/dev/okhttps-fastjson2-jsonb) | 4.1.0 | 与 fastjson2-jsonb 集成
-[okhttps-gson](https://gitee.com/troyzhxu/okhttps/tree/dev/okhttps-gson) | 4.1.0 | 与 gson 集成
-[okhttps-jackson](https://gitee.com/troyzhxu/okhttps/tree/dev/okhttps-jackson) | 4.1.0 | 与 jackson 集成
-[okhttps-jackson](https://gitee.com/troyzhxu/okhttps/tree/dev/okhttps-jackson-xml) | 4.1.0 | 与 jackson-xml 集成
-[okhttps-jackson](https://gitee.com/troyzhxu/okhttps/tree/dev/okhttps-jackson-yaml) | 4.1.0 | 与 jackson-yaml 集成
-[okhttps-jackson](https://gitee.com/troyzhxu/okhttps/tree/dev/okhttps-snack3) | 4.1.0 | 与 jackson-yaml 集成
-[okhttps-stomp](https://gitee.com/troyzhxu/okhttps/tree/dev/okhttps-stomp) | 4.1.0 | 超级轻量的 Stomp 客户端
-[okhttps-xml](https://gitee.com/troyzhxu/okhttps/tree/dev/okhttps-xml) | 3.5.3 | XML 解析扩展
-
-## 超详细教程,请查看:https://ok.zhxu.cn
+[okhttps](https://gitee.com/ejlchina-zhxu/okhttps/tree/dev/okhttps) | 2.5.0 | OkHttps 核心模块
+[okhttps-fastjson](https://gitee.com/ejlchina-zhxu/okhttps/tree/dev/okhttps-fastjson) | 2.5.0 | 与 fastjson 集成
+[okhttps-gson](https://gitee.com/ejlchina-zhxu/okhttps/tree/dev/okhttps-gson) | 2.5.0 | 与 gson 集成
+[okhttps-jackson](https://gitee.com/ejlchina-zhxu/okhttps/tree/dev/okhttps-jackson) | 2.5.0 | 与 jackson 集成
+[okhttps-stomp](https://gitee.com/ejlchina-zhxu/okhttps/tree/dev/okhttps-stomp) | 2.5.0 | 超级轻量的 Stomp 客户端
+[okhttps-xml](https://gitee.com/ejlchina-zhxu/okhttps/tree/dev/okhttps-xml) | 2.5.0 | XML 解析扩展
+
+## 超详细教程,请查看:https://okhttps.ejlchina.com/
## 联系方式
* 微信:
* 由于近期交流群的二维码被爬,扫码入群方式已被关闭
库的使用上若有疑问,可先加微信【18556739726】(请备注 OkHttps)再入群交流
+* 邮箱:zhou.xu@ejlchina.com
## 友情链接
-[**[ Bean Searcher ]** 比 MyBatis 效率快 100 倍的条件检索引擎,天生支持联表,使一行代码实现复杂列表检索成为可能!](https://github.com/ejlchina/bean-searcher)
-
-[**[ SA Token ]** 一个轻量级 Java 权限认证框架,让鉴权变得简单、优雅!](https://github.com/dromara/Sa-Token)
-
-[**[ hrun4j ]** 接口自动化测试解决方案 --工具选得好,下班回家早;测试用得对,半夜安心睡 ](https://github.com/lematechvip/hrun4j)
-
-[**[ Json Kit ]** 超轻量级 JSON 门面工具,用法简单,不依赖具体实现,让业务代码与 Jackson、Gson、Fastjson 等解耦!](https://gitee.com/troyzhxu/jsonkit)
+[**[ sa-token ]** 一个 JavaWeb 轻量级权限认证框架,功能全面,上手简单](https://gitee.com/sz6/sa-token)
## 参与贡献
@@ -128,4 +116,3 @@ Websocket 方法:
2. 新建 Feat_xxx 分支
3. 提交代码
4. 新建 Pull Request
-
diff --git a/okhttps-fastjson/.gitignore b/okhttps-fastjson/.gitignore
new file mode 100644
index 00000000..b83d2226
--- /dev/null
+++ b/okhttps-fastjson/.gitignore
@@ -0,0 +1 @@
+/target/
diff --git a/okhttps-fastjson/README.md b/okhttps-fastjson/README.md
index bbf641f0..505ae900 100644
--- a/okhttps-fastjson/README.md
+++ b/okhttps-fastjson/README.md
@@ -9,16 +9,16 @@
```xml
- cn.zhxu
+ com.ejlchina
okhttps-fastjson
- 3.5.3
+ 2.5.0
```
##### Gradle
```groovy
-implementation 'cn.zhxu:okhttps-fastjson:3.5.3'
+implementation 'com.ejlchina:okhttps-fastjson:2.5.0'
```
-#### 更多请参阅 [https://ok.zhxu.cn/](https://ok.zhxu.cn/)
+#### 更多请参阅 [http://okhttps.ejlchina.com/](http://okhttps.ejlchina.com/)
diff --git a/okhttps-fastjson/pom.xml b/okhttps-fastjson/pom.xml
index 219950e4..551db3c4 100644
--- a/okhttps-fastjson/pom.xml
+++ b/okhttps-fastjson/pom.xml
@@ -6,26 +6,26 @@
jar
- cn.zhxu
+ com.ejlchina
okhttps-parent
- 4.1.0
+ 2.5.0
- cn.zhxu
+ com.ejlchina
okhttps
- ${project.version}
+ ${okhttps.version}
- cn.zhxu
- data-fastjson
- ${data.version}
+ com.alibaba
+ fastjson
+ ${fastjson.version}
- cn.zhxu
+ com.ejlchina
okhttps-test
- ${project.version}
+ ${okhttps.version}
test
diff --git a/okhttps-fastjson/src/main/java/cn/zhxu/okhttps/fastjson/FastjsonMsgConvertor.java b/okhttps-fastjson/src/main/java/cn/zhxu/okhttps/fastjson/FastjsonMsgConvertor.java
deleted file mode 100644
index 1ed65148..00000000
--- a/okhttps-fastjson/src/main/java/cn/zhxu/okhttps/fastjson/FastjsonMsgConvertor.java
+++ /dev/null
@@ -1,19 +0,0 @@
-package cn.zhxu.okhttps.fastjson;
-
-import cn.zhxu.data.fastjson.FastjsonDataConvertor;
-import cn.zhxu.okhttps.ConvertProvider;
-import cn.zhxu.okhttps.MsgConvertor;
-
-public class FastjsonMsgConvertor extends FastjsonDataConvertor implements MsgConvertor, ConvertProvider {
-
- @Override
- public String mediaType() {
- return "application/json";
- }
-
- @Override
- public MsgConvertor getConvertor() {
- return new FastjsonMsgConvertor();
- }
-
-}
diff --git a/okhttps-fastjson/src/main/java/com/ejlchina/okhttps/FastjsonArray.java b/okhttps-fastjson/src/main/java/com/ejlchina/okhttps/FastjsonArray.java
new file mode 100644
index 00000000..cae7910c
--- /dev/null
+++ b/okhttps-fastjson/src/main/java/com/ejlchina/okhttps/FastjsonArray.java
@@ -0,0 +1,77 @@
+package com.ejlchina.okhttps;
+
+import com.alibaba.fastjson.JSONArray;
+import com.alibaba.fastjson.JSONObject;
+
+public class FastjsonArray implements Array {
+
+ private final JSONArray json;
+
+ public FastjsonArray(JSONArray json) {
+ this.json = json;
+ }
+
+ @Override
+ public int size() {
+ return json.size();
+ }
+
+ @Override
+ public boolean isEmpty() {
+ return json.isEmpty();
+ }
+
+ @Override
+ public Mapper getMapper(int index) {
+ JSONObject subJson = json.getJSONObject(index);
+ if (subJson != null) {
+ return new FastjsonMapper(subJson);
+ }
+ return null;
+ }
+
+ @Override
+ public Array getArray(int index) {
+ JSONArray subJson = json.getJSONArray(index);
+ if (subJson != null) {
+ return new FastjsonArray(subJson);
+ }
+ return null;
+ }
+
+ @Override
+ public boolean getBool(int index) {
+ return json.getBooleanValue(index);
+ }
+
+ @Override
+ public int getInt(int index) {
+ return json.getIntValue(index);
+ }
+
+ @Override
+ public long getLong(int index) {
+ return json.getLongValue(index);
+ }
+
+ @Override
+ public float getFloat(int index) {
+ return json.getFloatValue(index);
+ }
+
+ @Override
+ public double getDouble(int index) {
+ return json.getDoubleValue(index);
+ }
+
+ @Override
+ public String getString(int index) {
+ return json.getString(index);
+ }
+
+ @Override
+ public String toString() {
+ return json.toJSONString();
+ }
+
+}
diff --git a/okhttps-fastjson/src/main/java/com/ejlchina/okhttps/FastjsonMapper.java b/okhttps-fastjson/src/main/java/com/ejlchina/okhttps/FastjsonMapper.java
new file mode 100644
index 00000000..602881c8
--- /dev/null
+++ b/okhttps-fastjson/src/main/java/com/ejlchina/okhttps/FastjsonMapper.java
@@ -0,0 +1,89 @@
+package com.ejlchina.okhttps;
+
+import com.alibaba.fastjson.JSONArray;
+import com.alibaba.fastjson.JSONObject;
+
+import java.util.Set;
+
+public class FastjsonMapper implements Mapper {
+
+ private final JSONObject json;
+
+ public FastjsonMapper(JSONObject json) {
+ this.json = json;
+ }
+
+ @Override
+ public int size() {
+ return json.size();
+ }
+
+ @Override
+ public boolean isEmpty() {
+ return json.isEmpty();
+ }
+
+ @Override
+ public Mapper getMapper(String key) {
+ JSONObject subJson = json.getJSONObject(key);
+ if (subJson != null) {
+ return new FastjsonMapper(subJson);
+ }
+ return null;
+ }
+
+ @Override
+ public Array getArray(String key) {
+ JSONArray subJson = json.getJSONArray(key);
+ if (subJson != null) {
+ return new FastjsonArray(subJson);
+ }
+ return null;
+ }
+
+ @Override
+ public boolean getBool(String key) {
+ return json.getBooleanValue(key);
+ }
+
+ @Override
+ public int getInt(String key) {
+ return json.getIntValue(key);
+ }
+
+ @Override
+ public long getLong(String key) {
+ return json.getLongValue(key);
+ }
+
+ @Override
+ public float getFloat(String key) {
+ return json.getFloatValue(key);
+ }
+
+ @Override
+ public double getDouble(String key) {
+ return json.getDoubleValue(key);
+ }
+
+ @Override
+ public String getString(String key) {
+ return json.getString(key);
+ }
+
+ @Override
+ public boolean has(String key) {
+ return json.containsKey(key);
+ }
+
+ @Override
+ public Set keySet() {
+ return json.keySet();
+ }
+
+ @Override
+ public String toString() {
+ return json.toJSONString();
+ }
+
+}
diff --git a/okhttps-fastjson/src/main/java/com/ejlchina/okhttps/FastjsonMsgConvertor.java b/okhttps-fastjson/src/main/java/com/ejlchina/okhttps/FastjsonMsgConvertor.java
new file mode 100644
index 00000000..d8040572
--- /dev/null
+++ b/okhttps-fastjson/src/main/java/com/ejlchina/okhttps/FastjsonMsgConvertor.java
@@ -0,0 +1,58 @@
+package com.ejlchina.okhttps;
+
+import com.alibaba.fastjson.JSON;
+import com.ejlchina.okhttps.internal.HttpException;
+import okio.Okio;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.lang.reflect.Type;
+import java.nio.charset.Charset;
+import java.util.List;
+
+public class FastjsonMsgConvertor implements MsgConvertor, ConvertProvider {
+
+ @Override
+ public String mediaType() {
+ return "application/json";
+ }
+
+ @Override
+ public Mapper toMapper(InputStream in, Charset charset) {
+ return new FastjsonMapper(JSON.parseObject(toString(in, charset)));
+ }
+
+ @Override
+ public Array toArray(InputStream in, Charset charset) {
+ return new FastjsonArray(JSON.parseArray(toString(in, charset)));
+ }
+
+ @Override
+ public byte[] serialize(Object object, Charset charset) {
+ return JSON.toJSONString(object).getBytes(charset);
+ }
+
+ @Override
+ public T toBean(Type type, InputStream in, Charset charset) {
+ return JSON.parseObject(toString(in, charset), type);
+ }
+
+ @Override
+ public List toList(Class type, InputStream in, Charset charset) {
+ return JSON.parseArray(toString(in, charset), type);
+ }
+
+ @Override
+ public MsgConvertor getConvertor() {
+ return new FastjsonMsgConvertor();
+ }
+
+ private String toString(InputStream in, Charset charset) {
+ try {
+ return Okio.buffer(Okio.source(in)).readString(charset);
+ } catch (IOException e) {
+ throw new HttpException("读取文本异常", e);
+ }
+ }
+
+}
diff --git a/okhttps-fastjson/src/main/resources/META-INF/services/cn.zhxu.okhttps.ConvertProvider b/okhttps-fastjson/src/main/resources/META-INF/services/cn.zhxu.okhttps.ConvertProvider
deleted file mode 100644
index 5ae917c7..00000000
--- a/okhttps-fastjson/src/main/resources/META-INF/services/cn.zhxu.okhttps.ConvertProvider
+++ /dev/null
@@ -1 +0,0 @@
-cn.zhxu.okhttps.fastjson.FastjsonMsgConvertor
\ No newline at end of file
diff --git a/okhttps-fastjson/src/main/resources/META-INF/services/com.ejlchina.okhttps.ConvertProvider b/okhttps-fastjson/src/main/resources/META-INF/services/com.ejlchina.okhttps.ConvertProvider
new file mode 100644
index 00000000..88f3b11d
--- /dev/null
+++ b/okhttps-fastjson/src/main/resources/META-INF/services/com.ejlchina.okhttps.ConvertProvider
@@ -0,0 +1 @@
+com.ejlchina.okhttps.FastjsonMsgConvertor
\ No newline at end of file
diff --git a/okhttps-fastjson/src/test/java/cn/zhxu/okhttps/fastjson/TestCase.java b/okhttps-fastjson/src/test/java/com/ejlchina/okhttps/TestCase.java
similarity index 64%
rename from okhttps-fastjson/src/test/java/cn/zhxu/okhttps/fastjson/TestCase.java
rename to okhttps-fastjson/src/test/java/com/ejlchina/okhttps/TestCase.java
index 2f0cc7e6..8b65ec5c 100644
--- a/okhttps-fastjson/src/test/java/cn/zhxu/okhttps/fastjson/TestCase.java
+++ b/okhttps-fastjson/src/test/java/com/ejlchina/okhttps/TestCase.java
@@ -1,9 +1,9 @@
-package cn.zhxu.okhttps.fastjson;
+package com.ejlchina.okhttps;
-import cn.zhxu.okhttps.MsgConvertor;
-import cn.zhxu.okhttps.test.JsonTestCases;
+import com.ejlchina.okhttps.test.JsonTestCases;
import org.junit.Test;
+
public class TestCase {
@Test
diff --git a/okhttps-fastjson2-jsonb/README.md b/okhttps-fastjson2-jsonb/README.md
deleted file mode 100644
index 56d4f135..00000000
--- a/okhttps-fastjson2-jsonb/README.md
+++ /dev/null
@@ -1,24 +0,0 @@
-# OkHttps FastJson
-
-#### 介绍
-
-基于 OkHttps 与 Fastjson2Jsonb 集成扩展
-
-
-##### Maven
-
-```xml
-
- cn.zhxu
- okhttps-fastjson2-jsonb
- 3.5.3
-
-```
-
-##### Gradle
-
-```groovy
-implementation 'cn.zhxu:okhttps-fastjson2-jsonb:3.5.3'
-```
-
-#### 更多请参阅 [https://ok.zhxu.cn/](https://ok.zhxu.cn/)
diff --git a/okhttps-fastjson2-jsonb/pom.xml b/okhttps-fastjson2-jsonb/pom.xml
deleted file mode 100644
index dc2a91c0..00000000
--- a/okhttps-fastjson2-jsonb/pom.xml
+++ /dev/null
@@ -1,36 +0,0 @@
-
- 4.0.0
-
- okhttps-fastjson2-jsonb
- OkHttps Fastjson2 JSONB
- jar
-
-
- cn.zhxu
- okhttps-parent
- 4.1.0
-
-
-
-
- cn.zhxu
- okhttps
- ${project.version}
-
-
- cn.zhxu
- data-fastjson2-jsonb
- ${data.version}
-
-
- cn.zhxu
- okhttps-test
- ${project.version}
- test
-
-
-
-
- okhttps-fastjson2-jsonb
-
-
\ No newline at end of file
diff --git a/okhttps-fastjson2-jsonb/src/main/java/cn/zhxu/okhttps/fastjson2/jsonb/Fastjson2JsonbMsgConvertor.java b/okhttps-fastjson2-jsonb/src/main/java/cn/zhxu/okhttps/fastjson2/jsonb/Fastjson2JsonbMsgConvertor.java
deleted file mode 100644
index 17867cd8..00000000
--- a/okhttps-fastjson2-jsonb/src/main/java/cn/zhxu/okhttps/fastjson2/jsonb/Fastjson2JsonbMsgConvertor.java
+++ /dev/null
@@ -1,19 +0,0 @@
-package cn.zhxu.okhttps.fastjson2.jsonb;
-
-import cn.zhxu.data.fastjson2.jsonb.Fastjson2JsonbDataConvertor;
-import cn.zhxu.okhttps.ConvertProvider;
-import cn.zhxu.okhttps.MsgConvertor;
-
-public class Fastjson2JsonbMsgConvertor extends Fastjson2JsonbDataConvertor implements MsgConvertor, ConvertProvider {
-
- @Override
- public String mediaType() {
- return "application/jsonb";
- }
-
- @Override
- public MsgConvertor getConvertor() {
- return new Fastjson2JsonbMsgConvertor();
- }
-
-}
diff --git a/okhttps-fastjson2-jsonb/src/main/resources/META-INF/services/cn.zhxu.okhttps.ConvertProvider b/okhttps-fastjson2-jsonb/src/main/resources/META-INF/services/cn.zhxu.okhttps.ConvertProvider
deleted file mode 100644
index 3683502a..00000000
--- a/okhttps-fastjson2-jsonb/src/main/resources/META-INF/services/cn.zhxu.okhttps.ConvertProvider
+++ /dev/null
@@ -1 +0,0 @@
-cn.zhxu.okhttps.fastjson2.jsonb.Fastjson2JsonbMsgConvertor
\ No newline at end of file
diff --git a/okhttps-fastjson2-jsonb/src/test/java/cn/zhxu/okhttps/fastjson2/jsonb/TestCase.java b/okhttps-fastjson2-jsonb/src/test/java/cn/zhxu/okhttps/fastjson2/jsonb/TestCase.java
deleted file mode 100644
index 835408ba..00000000
--- a/okhttps-fastjson2-jsonb/src/test/java/cn/zhxu/okhttps/fastjson2/jsonb/TestCase.java
+++ /dev/null
@@ -1,16 +0,0 @@
-package cn.zhxu.okhttps.fastjson2.jsonb;
-
-import cn.zhxu.okhttps.MsgConvertor;
-import cn.zhxu.okhttps.test.JsonTestCases;
-import org.junit.Test;
-
-
-public class TestCase {
-
- @Test
- public void doTest() throws Exception {
- MsgConvertor msgConvertor = new Fastjson2JsonbMsgConvertor();
-// new JsonTestCases(msgConvertor).run();
- }
-
-}
diff --git a/okhttps-fastjson2/README.md b/okhttps-fastjson2/README.md
deleted file mode 100644
index cdaa2cf2..00000000
--- a/okhttps-fastjson2/README.md
+++ /dev/null
@@ -1,24 +0,0 @@
-# OkHttps FastJson
-
-#### 介绍
-
-基于 OkHttps 与 Fastjson2 集成扩展
-
-
-##### Maven
-
-```xml
-
- cn.zhxu
- okhttps-fastjson2
- 3.5.3
-
-```
-
-##### Gradle
-
-```groovy
-implementation 'cn.zhxu:okhttps-fastjson2:3.5.3'
-```
-
-#### 更多请参阅 [https://ok.zhxu.cn/](https://ok.zhxu.cn/)
diff --git a/okhttps-fastjson2/pom.xml b/okhttps-fastjson2/pom.xml
deleted file mode 100644
index dd971348..00000000
--- a/okhttps-fastjson2/pom.xml
+++ /dev/null
@@ -1,36 +0,0 @@
-
- 4.0.0
-
- okhttps-fastjson2
- OkHttps Fastjson2
- jar
-
-
- cn.zhxu
- okhttps-parent
- 4.1.0
-
-
-
-
- cn.zhxu
- okhttps
- ${project.version}
-
-
- cn.zhxu
- data-fastjson2
- ${data.version}
-
-
- cn.zhxu
- okhttps-test
- ${project.version}
- test
-
-
-
-
- okhttps-fastjson2
-
-
\ No newline at end of file
diff --git a/okhttps-fastjson2/src/main/java/cn/zhxu/okhttps/fastjson2/Fastjson2MsgConvertor.java b/okhttps-fastjson2/src/main/java/cn/zhxu/okhttps/fastjson2/Fastjson2MsgConvertor.java
deleted file mode 100644
index a7199847..00000000
--- a/okhttps-fastjson2/src/main/java/cn/zhxu/okhttps/fastjson2/Fastjson2MsgConvertor.java
+++ /dev/null
@@ -1,19 +0,0 @@
-package cn.zhxu.okhttps.fastjson2;
-
-import cn.zhxu.data.fastjson2.Fastjson2DataConvertor;
-import cn.zhxu.okhttps.ConvertProvider;
-import cn.zhxu.okhttps.MsgConvertor;
-
-public class Fastjson2MsgConvertor extends Fastjson2DataConvertor implements MsgConvertor, ConvertProvider {
-
- @Override
- public String mediaType() {
- return "application/json";
- }
-
- @Override
- public MsgConvertor getConvertor() {
- return new Fastjson2MsgConvertor();
- }
-
-}
diff --git a/okhttps-fastjson2/src/main/resources/META-INF/services/cn.zhxu.okhttps.ConvertProvider b/okhttps-fastjson2/src/main/resources/META-INF/services/cn.zhxu.okhttps.ConvertProvider
deleted file mode 100644
index 37efd499..00000000
--- a/okhttps-fastjson2/src/main/resources/META-INF/services/cn.zhxu.okhttps.ConvertProvider
+++ /dev/null
@@ -1 +0,0 @@
-cn.zhxu.okhttps.fastjson2.Fastjson2MsgConvertor
\ No newline at end of file
diff --git a/okhttps-fastjson2/src/test/java/cn/zhxu/okhttps/fastjson2/TestCase.java b/okhttps-fastjson2/src/test/java/cn/zhxu/okhttps/fastjson2/TestCase.java
deleted file mode 100644
index cc5051ad..00000000
--- a/okhttps-fastjson2/src/test/java/cn/zhxu/okhttps/fastjson2/TestCase.java
+++ /dev/null
@@ -1,16 +0,0 @@
-package cn.zhxu.okhttps.fastjson2;
-
-import cn.zhxu.okhttps.MsgConvertor;
-import cn.zhxu.okhttps.test.JsonTestCases;
-import org.junit.Test;
-
-
-public class TestCase {
-
- @Test
- public void doTest() throws Exception {
- MsgConvertor msgConvertor = new Fastjson2MsgConvertor();
- new JsonTestCases(msgConvertor).run();
- }
-
-}
diff --git a/okhttps-gson/.gitignore b/okhttps-gson/.gitignore
new file mode 100644
index 00000000..b83d2226
--- /dev/null
+++ b/okhttps-gson/.gitignore
@@ -0,0 +1 @@
+/target/
diff --git a/okhttps-gson/README.md b/okhttps-gson/README.md
index 938f5181..ed3e8ba1 100644
--- a/okhttps-gson/README.md
+++ b/okhttps-gson/README.md
@@ -9,16 +9,16 @@
```xml
- cn.zhxu
+ com.ejlchina
okhttps-gson
- 3.5.3
+ 2.5.0
```
##### Gradle
```groovy
-implementation 'cn.zhxu:okhttps-gson:3.5.3'
+implementation 'com.ejlchina:okhttps-gson:2.5.0'
```
-#### 更多请参阅 [https://ok.zhxu.cn/](https://ok.zhxu.cn/)
+#### 更多请参阅 [http://okhttps.ejlchina.com/](http://okhttps.ejlchina.com/)
diff --git a/okhttps-gson/pom.xml b/okhttps-gson/pom.xml
index ef0d2ad7..d9d192b7 100644
--- a/okhttps-gson/pom.xml
+++ b/okhttps-gson/pom.xml
@@ -6,26 +6,26 @@
jar
- cn.zhxu
+ com.ejlchina
okhttps-parent
- 4.1.0
+ 2.5.0
- cn.zhxu
+ com.ejlchina
okhttps
- ${project.version}
+ ${okhttps.version}
+
+ com.google.code.gson
+ gson
+ ${gson.version}
+
- cn.zhxu
- data-gson
- ${data.version}
-
-
- cn.zhxu
+ com.ejlchina
okhttps-test
- ${project.version}
+ ${okhttps.version}
test
diff --git a/okhttps-gson/src/main/java/cn/zhxu/okhttps/gson/GsonMsgConvertor.java b/okhttps-gson/src/main/java/cn/zhxu/okhttps/gson/GsonMsgConvertor.java
deleted file mode 100644
index 15272f4b..00000000
--- a/okhttps-gson/src/main/java/cn/zhxu/okhttps/gson/GsonMsgConvertor.java
+++ /dev/null
@@ -1,40 +0,0 @@
-package cn.zhxu.okhttps.gson;
-
-import cn.zhxu.data.gson.GsonDataConvertor;
-import cn.zhxu.okhttps.ConvertProvider;
-import cn.zhxu.okhttps.MsgConvertor;
-import com.google.gson.Gson;
-
-public class GsonMsgConvertor extends GsonDataConvertor implements MsgConvertor, ConvertProvider {
-
- public GsonMsgConvertor() { }
-
- public GsonMsgConvertor(Gson gson) {
- super(gson);
- }
-
- @Override
- public String mediaType() {
- return "application/json";
- }
-
- @Override
- public MsgConvertor getConvertor() {
- return new GsonMsgConvertor();
- }
-
-}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/okhttps-gson/src/main/java/com/ejlchina/okhttps/GsonArray.java b/okhttps-gson/src/main/java/com/ejlchina/okhttps/GsonArray.java
new file mode 100644
index 00000000..ebc34286
--- /dev/null
+++ b/okhttps-gson/src/main/java/com/ejlchina/okhttps/GsonArray.java
@@ -0,0 +1,101 @@
+package com.ejlchina.okhttps;
+
+import com.google.gson.JsonArray;
+import com.google.gson.JsonElement;
+
+public class GsonArray implements Array {
+
+ private final JsonArray json;
+
+ public GsonArray(JsonArray json) {
+ this.json = json;
+ }
+
+ @Override
+ public int size() {
+ return json.size();
+ }
+
+ @Override
+ public boolean isEmpty() {
+ return json.size() == 0;
+ }
+
+ @Override
+ public Mapper getMapper(int index) {
+ JsonElement subJson = json.get(index);
+ if (subJson != null && subJson.isJsonObject()) {
+ return new GsonMapper(subJson.getAsJsonObject());
+ }
+ return null;
+ }
+
+ @Override
+ public Array getArray(int index) {
+ JsonElement subJson = json.get(index);
+ if (subJson != null && subJson.isJsonArray()) {
+ return new GsonArray(subJson.getAsJsonArray());
+ }
+ return null;
+ }
+
+ @Override
+ public boolean getBool(int index) {
+ JsonElement val = json.get(index);
+ if (val != null && val.isJsonPrimitive()) {
+ return val.getAsBoolean();
+ }
+ return false;
+ }
+
+ @Override
+ public int getInt(int index) {
+ JsonElement val = json.get(index);
+ if (val != null && val.isJsonPrimitive()) {
+ return val.getAsInt();
+ }
+ return 0;
+ }
+
+ @Override
+ public long getLong(int index) {
+ JsonElement val = json.get(index);
+ if (val != null && val.isJsonPrimitive()) {
+ return val.getAsLong();
+ }
+ return 0;
+ }
+
+ @Override
+ public float getFloat(int index) {
+ JsonElement val = json.get(index);
+ if (val != null && val.isJsonPrimitive()) {
+ return val.getAsFloat();
+ }
+ return 0;
+ }
+
+ @Override
+ public double getDouble(int index) {
+ JsonElement val = json.get(index);
+ if (val != null && val.isJsonPrimitive()) {
+ return val.getAsDouble();
+ }
+ return 0;
+ }
+
+ @Override
+ public String getString(int index) {
+ JsonElement val = json.get(index);
+ if (val != null && val.isJsonPrimitive()) {
+ return val.getAsString();
+ }
+ return null;
+ }
+
+ @Override
+ public String toString() {
+ return json.toString();
+ }
+
+}
diff --git a/okhttps-gson/src/main/java/com/ejlchina/okhttps/GsonMapper.java b/okhttps-gson/src/main/java/com/ejlchina/okhttps/GsonMapper.java
new file mode 100644
index 00000000..111d9e68
--- /dev/null
+++ b/okhttps-gson/src/main/java/com/ejlchina/okhttps/GsonMapper.java
@@ -0,0 +1,113 @@
+package com.ejlchina.okhttps;
+
+import com.google.gson.JsonElement;
+import com.google.gson.JsonObject;
+
+import java.util.Set;
+
+public class GsonMapper implements Mapper {
+
+ private final JsonObject json;
+
+ public GsonMapper(JsonObject json) {
+ this.json = json;
+ }
+
+ @Override
+ public int size() {
+ return json.size();
+ }
+
+ @Override
+ public boolean isEmpty() {
+ return json.size() == 0;
+ }
+
+ @Override
+ public Mapper getMapper(String key) {
+ JsonElement subJson = json.get(key);
+ if (subJson != null && subJson.isJsonObject()) {
+ return new GsonMapper(subJson.getAsJsonObject());
+ }
+ return null;
+ }
+
+ @Override
+ public Array getArray(String key) {
+ JsonElement subJson = json.get(key);
+ if (subJson != null && subJson.isJsonArray()) {
+ return new GsonArray(subJson.getAsJsonArray());
+ }
+ return null;
+ }
+
+ @Override
+ public boolean getBool(String key) {
+ JsonElement val = json.get(key);
+ if (val != null && val.isJsonPrimitive()) {
+ return val.getAsBoolean();
+ }
+ return false;
+ }
+
+ @Override
+ public int getInt(String key) {
+ JsonElement val = json.get(key);
+ if (val != null && val.isJsonPrimitive()) {
+ return val.getAsInt();
+ }
+ return 0;
+ }
+
+ @Override
+ public long getLong(String key) {
+ JsonElement val = json.get(key);
+ if (val != null && val.isJsonPrimitive()) {
+ return val.getAsLong();
+ }
+ return 0;
+ }
+
+ @Override
+ public float getFloat(String key) {
+ JsonElement val = json.get(key);
+ if (val != null && val.isJsonPrimitive()) {
+ return val.getAsFloat();
+ }
+ return 0;
+ }
+
+ @Override
+ public double getDouble(String key) {
+ JsonElement val = json.get(key);
+ if (val != null && val.isJsonPrimitive()) {
+ return val.getAsDouble();
+ }
+ return 0;
+ }
+
+ @Override
+ public String getString(String key) {
+ JsonElement val = json.get(key);
+ if (val != null && val.isJsonPrimitive()) {
+ return val.getAsString();
+ }
+ return null;
+ }
+
+ @Override
+ public boolean has(String key) {
+ return json.has(key);
+ }
+
+ @Override
+ public Set keySet() {
+ return json.keySet();
+ }
+
+ @Override
+ public String toString() {
+ return json.toString();
+ }
+
+}
diff --git a/okhttps-gson/src/main/java/com/ejlchina/okhttps/GsonMsgConvertor.java b/okhttps-gson/src/main/java/com/ejlchina/okhttps/GsonMsgConvertor.java
new file mode 100644
index 00000000..3f69b086
--- /dev/null
+++ b/okhttps-gson/src/main/java/com/ejlchina/okhttps/GsonMsgConvertor.java
@@ -0,0 +1,88 @@
+package com.ejlchina.okhttps;
+
+import com.google.gson.Gson;
+import com.google.gson.JsonArray;
+import com.google.gson.JsonObject;
+import com.google.gson.reflect.TypeToken;
+
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.lang.reflect.Type;
+import java.nio.charset.Charset;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+public class GsonMsgConvertor implements MsgConvertor, ConvertProvider {
+
+ private Gson gson;
+
+ public GsonMsgConvertor() {
+ this(new Gson());
+ }
+
+ public GsonMsgConvertor(Gson gson) {
+ this.gson = gson;
+ }
+
+ @Override
+ public String mediaType() {
+ return "application/json";
+ }
+
+ @Override
+ public Mapper toMapper(InputStream in, Charset charset) {
+ return new GsonMapper(gson.fromJson(new InputStreamReader(in, charset), JsonObject.class));
+ }
+
+ @Override
+ public Array toArray(InputStream in, Charset charset) {
+ return new GsonArray(gson.fromJson(new InputStreamReader(in, charset), JsonArray.class));
+ }
+
+ @Override
+ public byte[] serialize(Object object, Charset charset) {
+ return gson.toJson(object).getBytes(charset);
+ }
+
+ @Override
+ public T toBean(Type type, InputStream in, Charset charset) {
+ return gson.fromJson(new InputStreamReader(in, charset), type);
+ }
+
+ @Override
+ public List toList(Class type, InputStream in, Charset charset) {
+ T[] beans = gson.fromJson(new InputStreamReader(in, charset), TypeToken.getArray(type).getType());
+ List list = new ArrayList<>();
+ Collections.addAll(list, beans);
+ return list;
+ }
+
+ @Override
+ public MsgConvertor getConvertor() {
+ return new GsonMsgConvertor();
+ }
+
+ public Gson getGson() {
+ return gson;
+ }
+
+ public void setGson(Gson gson) {
+ this.gson = gson;
+ }
+
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/okhttps-gson/src/main/resources/META-INF/services/cn.zhxu.okhttps.ConvertProvider b/okhttps-gson/src/main/resources/META-INF/services/cn.zhxu.okhttps.ConvertProvider
deleted file mode 100644
index 122472d4..00000000
--- a/okhttps-gson/src/main/resources/META-INF/services/cn.zhxu.okhttps.ConvertProvider
+++ /dev/null
@@ -1 +0,0 @@
-cn.zhxu.okhttps.gson.GsonMsgConvertor
\ No newline at end of file
diff --git a/okhttps-gson/src/main/resources/META-INF/services/com.ejlchina.okhttps.ConvertProvider b/okhttps-gson/src/main/resources/META-INF/services/com.ejlchina.okhttps.ConvertProvider
new file mode 100644
index 00000000..5eb90888
--- /dev/null
+++ b/okhttps-gson/src/main/resources/META-INF/services/com.ejlchina.okhttps.ConvertProvider
@@ -0,0 +1 @@
+com.ejlchina.okhttps.GsonMsgConvertor
\ No newline at end of file
diff --git a/okhttps-gson/src/test/java/cn/zhxu/okhttps/gson/TestCase.java b/okhttps-gson/src/test/java/com/ejlchina/okhttps/TestCase.java
similarity index 64%
rename from okhttps-gson/src/test/java/cn/zhxu/okhttps/gson/TestCase.java
rename to okhttps-gson/src/test/java/com/ejlchina/okhttps/TestCase.java
index 71406abe..01d7b40a 100644
--- a/okhttps-gson/src/test/java/cn/zhxu/okhttps/gson/TestCase.java
+++ b/okhttps-gson/src/test/java/com/ejlchina/okhttps/TestCase.java
@@ -1,7 +1,6 @@
-package cn.zhxu.okhttps.gson;
+package com.ejlchina.okhttps;
-import cn.zhxu.okhttps.MsgConvertor;
-import cn.zhxu.okhttps.test.JsonTestCases;
+import com.ejlchina.okhttps.test.JsonTestCases;
import org.junit.Test;
diff --git a/okhttps-jackson-xml/README.md b/okhttps-jackson-xml/README.md
deleted file mode 100644
index e2505225..00000000
--- a/okhttps-jackson-xml/README.md
+++ /dev/null
@@ -1,24 +0,0 @@
-# OkHttps Jackson
-
-#### 介绍
-
-基于 OkHttps 与 JacksonXml 集成扩展
-
-
-##### Maven
-
-```xml
-
- cn.zhxu
- okhttps-jackson-xml
- 3.5.3
-
-```
-
-##### Gradle
-
-```groovy
-implementation 'cn.zhxu:okhttps-jackson-xml:3.5.3'
-```
-
-#### 更多请参阅 [https://ok.zhxu.cn/](https://ok.zhxu.cn/)
diff --git a/okhttps-jackson-xml/pom.xml b/okhttps-jackson-xml/pom.xml
deleted file mode 100644
index 54aa1fce..00000000
--- a/okhttps-jackson-xml/pom.xml
+++ /dev/null
@@ -1,36 +0,0 @@
-
- 4.0.0
-
- okhttps-jackson-xml
- OkHttps Jackson Xml
- jar
-
-
- cn.zhxu
- okhttps-parent
- 4.1.0
-
-
-
-
- cn.zhxu
- okhttps
- ${project.version}
-
-
- cn.zhxu
- data-jackson-xml
- ${data.version}
-
-
- cn.zhxu
- okhttps-test
- ${project.version}
- test
-
-
-
-
- okhttps-jackson-xml
-
-
\ No newline at end of file
diff --git a/okhttps-jackson-xml/src/main/java/cn/zhxu/okhttps/jackson/xml/JacksonXmlMsgConvertor.java b/okhttps-jackson-xml/src/main/java/cn/zhxu/okhttps/jackson/xml/JacksonXmlMsgConvertor.java
deleted file mode 100644
index 44a29fca..00000000
--- a/okhttps-jackson-xml/src/main/java/cn/zhxu/okhttps/jackson/xml/JacksonXmlMsgConvertor.java
+++ /dev/null
@@ -1,26 +0,0 @@
-package cn.zhxu.okhttps.jackson.xml;
-
-import cn.zhxu.data.jackson.xml.JacksonXmlDataConvertor;
-import cn.zhxu.okhttps.ConvertProvider;
-import cn.zhxu.okhttps.MsgConvertor;
-import com.fasterxml.jackson.dataformat.xml.XmlMapper;
-
-public class JacksonXmlMsgConvertor extends JacksonXmlDataConvertor implements MsgConvertor, ConvertProvider {
-
- public JacksonXmlMsgConvertor() { }
-
- public JacksonXmlMsgConvertor(XmlMapper xmlMapper) {
- super(xmlMapper);
- }
-
- @Override
- public String mediaType() {
- return "application/xml";
- }
-
- @Override
- public MsgConvertor getConvertor() {
- return new JacksonXmlMsgConvertor();
- }
-
-}
diff --git a/okhttps-jackson-xml/src/main/resources/META-INF/services/cn.zhxu.okhttps.ConvertProvider b/okhttps-jackson-xml/src/main/resources/META-INF/services/cn.zhxu.okhttps.ConvertProvider
deleted file mode 100644
index 344c3d0b..00000000
--- a/okhttps-jackson-xml/src/main/resources/META-INF/services/cn.zhxu.okhttps.ConvertProvider
+++ /dev/null
@@ -1 +0,0 @@
-cn.zhxu.okhttps.jackson.xml.JacksonXmlMsgConvertor
\ No newline at end of file
diff --git a/okhttps-jackson-xml/src/test/java/cn/zhxu/okhttps/jackson/xml/TestCase.java b/okhttps-jackson-xml/src/test/java/cn/zhxu/okhttps/jackson/xml/TestCase.java
deleted file mode 100644
index 20af4b4c..00000000
--- a/okhttps-jackson-xml/src/test/java/cn/zhxu/okhttps/jackson/xml/TestCase.java
+++ /dev/null
@@ -1,16 +0,0 @@
-package cn.zhxu.okhttps.jackson.xml;
-
-import cn.zhxu.okhttps.MsgConvertor;
-import cn.zhxu.okhttps.test.XmlTestCases;
-import org.junit.Test;
-
-
-public class TestCase {
-
- @Test
- public void doTest() throws Exception {
- MsgConvertor convertor = new JacksonXmlMsgConvertor();
-// new XmlTestCases(convertor).run();
- }
-
-}
diff --git a/okhttps-jackson-yaml/README.md b/okhttps-jackson-yaml/README.md
deleted file mode 100644
index dbd3b23f..00000000
--- a/okhttps-jackson-yaml/README.md
+++ /dev/null
@@ -1,24 +0,0 @@
-# OkHttps Jackson
-
-#### 介绍
-
-基于 OkHttps 与 JacksonYamls 集成扩展
-
-
-##### Maven
-
-```xml
-
- cn.zhxu
- okhttps-jackson-yaml
- 3.5.3
-
-```
-
-##### Gradle
-
-```groovy
-implementation 'cn.zhxu:okhttps-jackson-yaml:3.5.3'
-```
-
-#### 更多请参阅 [https://ok.zhxu.cn/](https://ok.zhxu.cn/)
diff --git a/okhttps-jackson-yaml/pom.xml b/okhttps-jackson-yaml/pom.xml
deleted file mode 100644
index c550aa50..00000000
--- a/okhttps-jackson-yaml/pom.xml
+++ /dev/null
@@ -1,36 +0,0 @@
-
- 4.0.0
-
- okhttps-jackson-yaml
- OkHttps Jackson Yaml
- jar
-
-
- cn.zhxu
- okhttps-parent
- 4.1.0
-
-
-
-
- cn.zhxu
- okhttps
- ${project.version}
-
-
- cn.zhxu
- data-jackson-yaml
- ${data.version}
-
-
- cn.zhxu
- okhttps-test
- ${project.version}
- test
-
-
-
-
- okhttps-jackson-yaml
-
-
\ No newline at end of file
diff --git a/okhttps-jackson-yaml/src/main/java/cn/zhxu/okhttps/jackson/yaml/JacksonYamlMsgConvertor.java b/okhttps-jackson-yaml/src/main/java/cn/zhxu/okhttps/jackson/yaml/JacksonYamlMsgConvertor.java
deleted file mode 100644
index e0dc08e1..00000000
--- a/okhttps-jackson-yaml/src/main/java/cn/zhxu/okhttps/jackson/yaml/JacksonYamlMsgConvertor.java
+++ /dev/null
@@ -1,26 +0,0 @@
-package cn.zhxu.okhttps.jackson.yaml;
-
-import cn.zhxu.data.jackson.yaml.JacksonYamlDataConvertor;
-import cn.zhxu.okhttps.ConvertProvider;
-import cn.zhxu.okhttps.MsgConvertor;
-import com.fasterxml.jackson.dataformat.yaml.YAMLMapper;
-
-public class JacksonYamlMsgConvertor extends JacksonYamlDataConvertor implements MsgConvertor, ConvertProvider {
-
- public JacksonYamlMsgConvertor() { }
-
- public JacksonYamlMsgConvertor(YAMLMapper yamlMapper) {
- super(yamlMapper);
- }
-
- @Override
- public String mediaType() {
- return "application/yaml";
- }
-
- @Override
- public MsgConvertor getConvertor() {
- return new JacksonYamlMsgConvertor();
- }
-
-}
diff --git a/okhttps-jackson-yaml/src/main/resources/META-INF/services/cn.zhxu.okhttps.ConvertProvider b/okhttps-jackson-yaml/src/main/resources/META-INF/services/cn.zhxu.okhttps.ConvertProvider
deleted file mode 100644
index 8b8befc7..00000000
--- a/okhttps-jackson-yaml/src/main/resources/META-INF/services/cn.zhxu.okhttps.ConvertProvider
+++ /dev/null
@@ -1 +0,0 @@
-cn.zhxu.okhttps.jackson.yaml.JacksonYamlMsgConvertor
\ No newline at end of file
diff --git a/okhttps-jackson-yaml/src/test/java/cn/zhxu/okhttps/jackson/yaml/TestCase.java b/okhttps-jackson-yaml/src/test/java/cn/zhxu/okhttps/jackson/yaml/TestCase.java
deleted file mode 100644
index 9f781a72..00000000
--- a/okhttps-jackson-yaml/src/test/java/cn/zhxu/okhttps/jackson/yaml/TestCase.java
+++ /dev/null
@@ -1,16 +0,0 @@
-package cn.zhxu.okhttps.jackson.yaml;
-
-import cn.zhxu.okhttps.MsgConvertor;
-import cn.zhxu.okhttps.test.JsonTestCases;
-import org.junit.Test;
-
-
-public class TestCase {
-
- @Test
- public void doTest() throws Exception {
- MsgConvertor convertor = new JacksonYamlMsgConvertor();
-// new JsonTestCases(convertor).run();
- }
-
-}
diff --git a/okhttps-jackson/.gitignore b/okhttps-jackson/.gitignore
new file mode 100644
index 00000000..b83d2226
--- /dev/null
+++ b/okhttps-jackson/.gitignore
@@ -0,0 +1 @@
+/target/
diff --git a/okhttps-jackson/README.md b/okhttps-jackson/README.md
index 54c1cf5e..7a5d3f66 100644
--- a/okhttps-jackson/README.md
+++ b/okhttps-jackson/README.md
@@ -9,16 +9,16 @@
```xml
- cn.zhxu
+ com.ejlchina
okhttps-jackson
- 3.5.3
+ 2.5.0
```
##### Gradle
```groovy
-implementation 'cn.zhxu:okhttps-jackson:3.5.3'
+implementation 'com.ejlchina:okhttps-jackson:2.5.0'
```
-#### 更多请参阅 [https://ok.zhxu.cn/](https://ok.zhxu.cn/)
+#### 更多请参阅 [http://okhttps.ejlchina.com/](http://okhttps.ejlchina.com/)
diff --git a/okhttps-jackson/pom.xml b/okhttps-jackson/pom.xml
index d9cef0e0..27fddc06 100644
--- a/okhttps-jackson/pom.xml
+++ b/okhttps-jackson/pom.xml
@@ -6,26 +6,26 @@
jar
- cn.zhxu
+ com.ejlchina
okhttps-parent
- 4.1.0
+ 2.5.0
- cn.zhxu
+ com.ejlchina
okhttps
- ${project.version}
+ ${okhttps.version}
+
+ com.fasterxml.jackson.core
+ jackson-databind
+ ${jackson.version}
+
- cn.zhxu
- data-jackson
- ${data.version}
-
-
- cn.zhxu
+ com.ejlchina
okhttps-test
- ${project.version}
+ ${okhttps.version}
test
diff --git a/okhttps-jackson/src/main/java/cn/zhxu/okhttps/jackson/JacksonMsgConvertor.java b/okhttps-jackson/src/main/java/cn/zhxu/okhttps/jackson/JacksonMsgConvertor.java
deleted file mode 100644
index 1c0e561d..00000000
--- a/okhttps-jackson/src/main/java/cn/zhxu/okhttps/jackson/JacksonMsgConvertor.java
+++ /dev/null
@@ -1,26 +0,0 @@
-package cn.zhxu.okhttps.jackson;
-
-import cn.zhxu.data.jackson.JacksonDataConvertor;
-import cn.zhxu.okhttps.ConvertProvider;
-import cn.zhxu.okhttps.MsgConvertor;
-import com.fasterxml.jackson.databind.ObjectMapper;
-
-public class JacksonMsgConvertor extends JacksonDataConvertor implements MsgConvertor, ConvertProvider {
-
- public JacksonMsgConvertor() { }
-
- public JacksonMsgConvertor(ObjectMapper objectMapper) {
- super(objectMapper);
- }
-
- @Override
- public String mediaType() {
- return "application/json";
- }
-
- @Override
- public MsgConvertor getConvertor() {
- return new JacksonMsgConvertor();
- }
-
-}
diff --git a/okhttps-jackson/src/main/java/com/ejlchina/okhttps/JacksonArray.java b/okhttps-jackson/src/main/java/com/ejlchina/okhttps/JacksonArray.java
new file mode 100644
index 00000000..6a8f68d2
--- /dev/null
+++ b/okhttps-jackson/src/main/java/com/ejlchina/okhttps/JacksonArray.java
@@ -0,0 +1,105 @@
+package com.ejlchina.okhttps;
+
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.node.ArrayNode;
+import com.fasterxml.jackson.databind.node.ObjectNode;
+
+public class JacksonArray implements Array {
+
+ private final ArrayNode json;
+
+ public JacksonArray(ArrayNode json) {
+ this.json = json;
+ }
+
+ @Override
+ public int size() {
+ return json.size();
+ }
+
+ @Override
+ public boolean isEmpty() {
+ return json.isEmpty();
+ }
+
+ @Override
+ public Mapper getMapper(int index) {
+ JsonNode subJson = json.get(index);
+ if (subJson != null && subJson.isObject()) {
+ return new JacksonMapper((ObjectNode) subJson);
+ }
+ return null;
+ }
+
+ @Override
+ public Array getArray(int index) {
+ JsonNode subJson = json.get(index);
+ if (subJson != null && subJson.isArray()) {
+ return new JacksonArray((ArrayNode) subJson);
+ }
+ return null;
+ }
+
+ @Override
+ public boolean getBool(int index) {
+ JsonNode subJson = json.get(index);
+ if (subJson != null) {
+ return subJson.asBoolean(false);
+ }
+ return false;
+ }
+
+ @Override
+ public int getInt(int index) {
+ JsonNode subJson = json.get(index);
+ if (subJson != null) {
+ return subJson.asInt(0);
+ }
+ return 0;
+ }
+
+ @Override
+ public long getLong(int index) {
+ JsonNode subJson = json.get(index);
+ if (subJson != null) {
+ return subJson.asLong(0);
+ }
+ return 0;
+ }
+
+ @Override
+ public float getFloat(int index) {
+ JsonNode subJson = json.get(index);
+ if (subJson != null && subJson.isNumber()) {
+ return subJson.floatValue();
+ }
+ if (subJson != null) {
+ return (float) subJson.asDouble(0);
+ }
+ return 0;
+ }
+
+ @Override
+ public double getDouble(int index) {
+ JsonNode subJson = json.get(index);
+ if (subJson != null) {
+ return subJson.asDouble(0);
+ }
+ return 0;
+ }
+
+ @Override
+ public String getString(int index) {
+ JsonNode subJson = json.get(index);
+ if (subJson != null) {
+ return subJson.asText();
+ }
+ return null;
+ }
+
+ @Override
+ public String toString() {
+ return json.toString();
+ }
+
+}
diff --git a/okhttps-jackson/src/main/java/com/ejlchina/okhttps/JacksonMapper.java b/okhttps-jackson/src/main/java/com/ejlchina/okhttps/JacksonMapper.java
new file mode 100644
index 00000000..c34291d7
--- /dev/null
+++ b/okhttps-jackson/src/main/java/com/ejlchina/okhttps/JacksonMapper.java
@@ -0,0 +1,124 @@
+package com.ejlchina.okhttps;
+
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.node.ArrayNode;
+import com.fasterxml.jackson.databind.node.ObjectNode;
+
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Set;
+
+public class JacksonMapper implements Mapper {
+
+ private final ObjectNode json;
+
+ public JacksonMapper(ObjectNode json) {
+ this.json = json;
+ }
+
+ @Override
+ public int size() {
+ return json.size();
+ }
+
+ @Override
+ public boolean isEmpty() {
+ return json.isEmpty();
+ }
+
+ @Override
+ public Mapper getMapper(String key) {
+ JsonNode subJson = json.get(key);
+ if (subJson != null && subJson.isObject()) {
+ return new JacksonMapper((ObjectNode) subJson);
+ }
+ return null;
+ }
+
+ @Override
+ public Array getArray(String key) {
+ JsonNode subJson = json.get(key);
+ if (subJson != null && subJson.isArray()) {
+ return new JacksonArray((ArrayNode) subJson);
+ }
+ return null;
+ }
+
+ @Override
+ public boolean getBool(String key) {
+ JsonNode subJson = json.get(key);
+ if (subJson != null) {
+ return subJson.asBoolean(false);
+ }
+ return false;
+ }
+
+ @Override
+ public int getInt(String key) {
+ JsonNode subJson = json.get(key);
+ if (subJson != null) {
+ return subJson.asInt(0);
+ }
+ return 0;
+ }
+
+ @Override
+ public long getLong(String key) {
+ JsonNode subJson = json.get(key);
+ if (subJson != null) {
+ return subJson.asLong(0);
+ }
+ return 0;
+ }
+
+ @Override
+ public float getFloat(String key) {
+ JsonNode subJson = json.get(key);
+ if (subJson != null && subJson.isNumber()) {
+ return subJson.floatValue();
+ }
+ if (subJson != null) {
+ return (float) subJson.asDouble(0);
+ }
+ return 0;
+ }
+
+ @Override
+ public double getDouble(String key) {
+ JsonNode subJson = json.get(key);
+ if (subJson != null) {
+ return subJson.asDouble(0);
+ }
+ return 0;
+ }
+
+ @Override
+ public String getString(String key) {
+ JsonNode subJson = json.get(key);
+ if (subJson != null) {
+ return subJson.asText();
+ }
+ return null;
+ }
+
+ @Override
+ public boolean has(String key) {
+ return json.has(key);
+ }
+
+ @Override
+ public Set keySet() {
+ Iterator it = json.fieldNames();
+ Set set = new HashSet<>();
+ while (it.hasNext()) {
+ set.add(it.next());
+ }
+ return set;
+ }
+
+ @Override
+ public String toString() {
+ return json.toString();
+ }
+
+}
diff --git a/okhttps-jackson/src/main/java/com/ejlchina/okhttps/JacksonMsgConvertor.java b/okhttps-jackson/src/main/java/com/ejlchina/okhttps/JacksonMsgConvertor.java
new file mode 100644
index 00000000..c6c731e7
--- /dev/null
+++ b/okhttps-jackson/src/main/java/com/ejlchina/okhttps/JacksonMsgConvertor.java
@@ -0,0 +1,149 @@
+package com.ejlchina.okhttps;
+
+import com.ejlchina.okhttps.internal.HttpException;
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.core.type.TypeReference;
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.node.ArrayNode;
+import com.fasterxml.jackson.databind.node.ObjectNode;
+import com.fasterxml.jackson.databind.type.CollectionType;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.lang.reflect.Type;
+import java.nio.charset.Charset;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+public class JacksonMsgConvertor implements MsgConvertor, ConvertProvider {
+
+ private ObjectMapper objectMapper;
+
+ private final Map> cache = new HashMap<>();
+
+ private boolean typeCached;
+
+ public JacksonMsgConvertor() {
+ this(new ObjectMapper());
+ }
+
+ public JacksonMsgConvertor(ObjectMapper objectMapper) {
+ this(objectMapper, false);
+ }
+
+ public JacksonMsgConvertor(ObjectMapper objectMapper, boolean typeCached) {
+ this.objectMapper = objectMapper;
+ this.typeCached = typeCached;
+ }
+
+ @Override
+ public String mediaType() {
+ return "application/json";
+ }
+
+ @Override
+ public Mapper toMapper(InputStream in, Charset charset) {
+ try {
+ JsonNode json = objectMapper.readTree(new InputStreamReader(in, charset));
+ if (json.isObject()) {
+ return new JacksonMapper((ObjectNode) json);
+ }
+ if (json.isNull() || json.isMissingNode()) {
+ return null;
+ }
+ throw new HttpException("不是 一个 json 对象:" + json);
+ } catch (IOException e) {
+ throw new HttpException("Jackson 解析异常", e);
+ }
+ }
+
+ @Override
+ public Array toArray(InputStream in, Charset charset) {
+ try {
+ JsonNode json = objectMapper.readTree(new InputStreamReader(in, charset));
+ if (json.isArray()) {
+ return new JacksonArray((ArrayNode) json);
+ }
+ if (json.isNull() || json.isMissingNode()) {
+ return null;
+ }
+ throw new HttpException("不是 一个 json 数组:" + json);
+ } catch (IOException e) {
+ throw new HttpException("Jackson 解析异常", e);
+ }
+ }
+
+ @Override
+ public byte[] serialize(Object object, Charset charset) {
+ try {
+ return objectMapper.writeValueAsString(object).getBytes(charset);
+ } catch (JsonProcessingException e) {
+ throw new HttpException("Java Bean [" + object + "] Jackson 序列化异常", e);
+ }
+ }
+
+ private TypeReference toTypeRef(Type type) {
+ TypeReference typeRef;
+ synchronized (cache) {
+ //noinspection unchecked
+ typeRef = (TypeReference) cache.get(type);
+ if (typeRef == null) {
+ typeRef = new TypeReference() {
+ @Override
+ public Type getType() {
+ return type;
+ }
+ };
+ if (typeCached) {
+ cache.put(type, typeRef);
+ }
+ }
+ }
+ return typeRef;
+ }
+
+ @Override
+ public T toBean(Type type, InputStream in, Charset charset) {
+ try {
+ return objectMapper.readValue(new InputStreamReader(in, charset), toTypeRef(type));
+ } catch (IOException e) {
+ throw new HttpException("Jackson 解析异常", e);
+ }
+ }
+
+ @Override
+ public List toList(Class type, InputStream in, Charset charset) {
+ CollectionType javaType = objectMapper.getTypeFactory().constructCollectionType(ArrayList.class, type);
+ try {
+ return objectMapper.readValue(new InputStreamReader(in, charset), javaType);
+ } catch (IOException e) {
+ throw new HttpException("Jackson 解析异常", e);
+ }
+ }
+
+ @Override
+ public MsgConvertor getConvertor() {
+ return new JacksonMsgConvertor();
+ }
+
+ public ObjectMapper getObjectMapper() {
+ return objectMapper;
+ }
+
+ public void setObjectMapper(ObjectMapper objectMapper) {
+ this.objectMapper = objectMapper;
+ }
+
+ public boolean isTypeCached() {
+ return typeCached;
+ }
+
+ public void setTypeCached(boolean typeCached) {
+ this.typeCached = typeCached;
+ }
+
+}
diff --git a/okhttps-jackson/src/main/resources/META-INF/services/cn.zhxu.okhttps.ConvertProvider b/okhttps-jackson/src/main/resources/META-INF/services/cn.zhxu.okhttps.ConvertProvider
deleted file mode 100644
index dd5ee602..00000000
--- a/okhttps-jackson/src/main/resources/META-INF/services/cn.zhxu.okhttps.ConvertProvider
+++ /dev/null
@@ -1 +0,0 @@
-cn.zhxu.okhttps.jackson.JacksonMsgConvertor
\ No newline at end of file
diff --git a/okhttps-jackson/src/main/resources/META-INF/services/com.ejlchina.okhttps.ConvertProvider b/okhttps-jackson/src/main/resources/META-INF/services/com.ejlchina.okhttps.ConvertProvider
new file mode 100644
index 00000000..ddfa7bde
--- /dev/null
+++ b/okhttps-jackson/src/main/resources/META-INF/services/com.ejlchina.okhttps.ConvertProvider
@@ -0,0 +1 @@
+com.ejlchina.okhttps.JacksonMsgConvertor
\ No newline at end of file
diff --git a/okhttps-jackson/src/test/java/cn/zhxu/okhttps/jackson/TestCase.java b/okhttps-jackson/src/test/java/cn/zhxu/okhttps/jackson/TestCase.java
deleted file mode 100644
index 74ea88f9..00000000
--- a/okhttps-jackson/src/test/java/cn/zhxu/okhttps/jackson/TestCase.java
+++ /dev/null
@@ -1,16 +0,0 @@
-package cn.zhxu.okhttps.jackson;
-
-import cn.zhxu.okhttps.MsgConvertor;
-import cn.zhxu.okhttps.test.JsonTestCases;
-import org.junit.Test;
-
-
-public class TestCase {
-
- @Test
- public void doTest() throws Exception {
- MsgConvertor convertor = new JacksonMsgConvertor();
- new JsonTestCases(convertor).run();
- }
-
-}
diff --git a/okhttps-jackson/src/test/java/com/ejlchina/okhttps/TestCase.java b/okhttps-jackson/src/test/java/com/ejlchina/okhttps/TestCase.java
new file mode 100644
index 00000000..538dd66b
--- /dev/null
+++ b/okhttps-jackson/src/test/java/com/ejlchina/okhttps/TestCase.java
@@ -0,0 +1,15 @@
+package com.ejlchina.okhttps;
+
+import com.ejlchina.okhttps.test.JsonTestCases;
+import org.junit.Test;
+
+
+public class TestCase {
+
+ @Test
+ public void doTest() throws Exception {
+ MsgConvertor msgConvertor = new JacksonMsgConvertor();
+ new JsonTestCases(msgConvertor).run();
+ }
+
+}
diff --git a/okhttps-snack3/README.md b/okhttps-snack3/README.md
deleted file mode 100644
index 22af945b..00000000
--- a/okhttps-snack3/README.md
+++ /dev/null
@@ -1,24 +0,0 @@
-# OkHttps Gson
-
-#### 介绍
-
-基于 OkHttps 与 Gson 集成扩展
-
-
-##### Maven
-
-```xml
-
- cn.zhxu
- okhttps-snack3
- 3.5.3
-
-```
-
-##### Gradle
-
-```groovy
-implementation 'cn.zhxu:okhttps-snack3:3.5.3'
-```
-
-#### 更多请参阅 [https://ok.zhxu.cn/](https://ok.zhxu.cn/)
diff --git a/okhttps-snack3/src/main/java/cn/zhxu/okhttps/snack3/Snack3MsgConvertor.java b/okhttps-snack3/src/main/java/cn/zhxu/okhttps/snack3/Snack3MsgConvertor.java
deleted file mode 100644
index 2c56dd55..00000000
--- a/okhttps-snack3/src/main/java/cn/zhxu/okhttps/snack3/Snack3MsgConvertor.java
+++ /dev/null
@@ -1,33 +0,0 @@
-package cn.zhxu.okhttps.snack3;
-
-import cn.zhxu.data.snack3.Snack3DataConvertor;
-import cn.zhxu.okhttps.ConvertProvider;
-import cn.zhxu.okhttps.MsgConvertor;
-
-public class Snack3MsgConvertor extends Snack3DataConvertor implements MsgConvertor, ConvertProvider {
-
- @Override
- public String mediaType() {
- return "application/json";
- }
-
- @Override
- public MsgConvertor getConvertor() {
- return new Snack3MsgConvertor();
- }
-
-}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/okhttps-snack3/src/main/resources/META-INF/services/cn.zhxu.okhttps.ConvertProvider b/okhttps-snack3/src/main/resources/META-INF/services/cn.zhxu.okhttps.ConvertProvider
deleted file mode 100644
index a546ae29..00000000
--- a/okhttps-snack3/src/main/resources/META-INF/services/cn.zhxu.okhttps.ConvertProvider
+++ /dev/null
@@ -1 +0,0 @@
-cn.zhxu.okhttps.snack3.Snack3MsgConvertor
\ No newline at end of file
diff --git a/okhttps-snack3/src/test/java/cn/zhxu/okhttps/snack3/TestCase.java b/okhttps-snack3/src/test/java/cn/zhxu/okhttps/snack3/TestCase.java
deleted file mode 100644
index 9ebb192f..00000000
--- a/okhttps-snack3/src/test/java/cn/zhxu/okhttps/snack3/TestCase.java
+++ /dev/null
@@ -1,16 +0,0 @@
-package cn.zhxu.okhttps.snack3;
-
-import cn.zhxu.okhttps.MsgConvertor;
-import cn.zhxu.okhttps.test.JsonTestCases;
-import org.junit.Test;
-
-
-public class TestCase {
-
- @Test
- public void doTest() throws Exception {
- MsgConvertor msgConvertor = new Snack3MsgConvertor();
- new JsonTestCases(msgConvertor).run();
- }
-
-}
diff --git a/okhttps-stomp/README.md b/okhttps-stomp/README.md
index ccc3ce2c..e1be9d11 100644
--- a/okhttps-stomp/README.md
+++ b/okhttps-stomp/README.md
@@ -9,16 +9,16 @@
```xml
- cn.zhxu
+ com.ejlchina
okhttps-stomp
- 3.5.3
+ 2.5.0
```
##### Gradle
```groovy
-implementation 'cn.zhxu:okhttps-stomp:3.5.3'
+implementation 'com.ejlchina:okhttps-stomp:2.5.0'
```
-#### 更多请参阅 [https://ok.zhxu.cn/v2/stomp.html](https://ok.zhxu.cn/v2/stomp.html)
+#### 更多请参阅 [http://okhttps.ejlchina.com/v2/stomp.html](http://okhttps.ejlchina.com/v2/stomp.html)
diff --git a/okhttps-stomp/pom.xml b/okhttps-stomp/pom.xml
index 3ccaa125..bce460af 100644
--- a/okhttps-stomp/pom.xml
+++ b/okhttps-stomp/pom.xml
@@ -6,30 +6,24 @@
jar
- cn.zhxu
+ com.ejlchina
okhttps-parent
- 4.1.0
+ 2.5.0
- cn.zhxu
+ com.ejlchina
okhttps
- ${project.version}
+ ${okhttps.version}
- cn.zhxu
+ com.ejlchina
okhttps-test
- ${project.version}
+ ${okhttps.version}
test
-
- org.jetbrains
- annotations
- 13.0
- compile
-
-
+
okhttps-stomp
diff --git a/okhttps-stomp/src/main/java/cn/zhxu/stomp/Message.java b/okhttps-stomp/src/main/java/cn/zhxu/stomp/Message.java
deleted file mode 100644
index 6df8a05a..00000000
--- a/okhttps-stomp/src/main/java/cn/zhxu/stomp/Message.java
+++ /dev/null
@@ -1,57 +0,0 @@
-package cn.zhxu.stomp;
-
-import java.util.List;
-
-
-public class Message {
-
- private final String command;
- private final List headers;
- private final String payload;
-
- public Message(String command, List headers) {
- this(command, headers, null);
- }
-
- public Message(String command, List headers, String payload) {
- this.command = command;
- this.headers = headers;
- this.payload = payload;
- }
-
- public List getHeaders() {
- return headers;
- }
-
- public String getPayload() {
- return payload;
- }
-
- public String getCommand() {
- return command;
- }
-
-
- public String headerValue(String key) {
- Header header = header(key);
- if (header != null) {
- return header.getValue();
- }
- return null;
- }
-
- public Header header(String key) {
- if (headers != null) {
- for (Header header : headers) {
- if (header.getKey().equals(key)) return header;
- }
- }
- return null;
- }
-
- @Override
- public String toString() {
- return "Message {command='" + command + "', headers=" + headers +", payload='" + payload + "'}";
- }
-
-}
diff --git a/okhttps-stomp/src/main/java/cn/zhxu/stomp/MsgCodec.java b/okhttps-stomp/src/main/java/cn/zhxu/stomp/MsgCodec.java
deleted file mode 100644
index 1f83addd..00000000
--- a/okhttps-stomp/src/main/java/cn/zhxu/stomp/MsgCodec.java
+++ /dev/null
@@ -1,25 +0,0 @@
-package cn.zhxu.stomp;
-
-import java.util.function.Consumer;
-
-/**
- * Stomp 消息编解码器
- * @since v3.1.0
- */
-public interface MsgCodec {
-
- /**
- * 编码
- * @param input Stomp 消息
- * @return 编码后的文本
- */
- String encode(Message input);
-
- /**
- * 解码
- * @param input 输入
- * @param out 输出
- */
- void decode(String input, Consumer out);
-
-}
diff --git a/okhttps-stomp/src/main/java/cn/zhxu/stomp/MsgCodecImpl.java b/okhttps-stomp/src/main/java/cn/zhxu/stomp/MsgCodecImpl.java
deleted file mode 100644
index bcdb6fa3..00000000
--- a/okhttps-stomp/src/main/java/cn/zhxu/stomp/MsgCodecImpl.java
+++ /dev/null
@@ -1,222 +0,0 @@
-package cn.zhxu.stomp;
-
-import java.util.ArrayList;
-import java.util.List;
-import java.util.function.Consumer;
-
-/**
- * Stomp 消息编解码器
- * @since v3.1.0
- */
-public class MsgCodecImpl implements MsgCodec {
-
- /**
- * Command 结束符
- */
- private String commandEnd = "\n";
-
- /**
- * Headers 结束符
- */
- private String headersEnd = "\n\n";
-
- /**
- * Header 之间的分隔符
- */
- private String headerDelimiter = "\n";
-
- /**
- * Header 键值 间的分隔符
- */
- private String headerKvDelimiter = ":";
-
- /**
- * Body 结束符
- */
- private String bodyEnd = "\u0000";
-
- /**
- * 待解析的 Stomp 报文容器
- */
- private final StringBuilder pending = new StringBuilder();
-
- @Override
- public String encode(Message input) {
- StringBuilder sb = new StringBuilder();
- sb.append(input.getCommand()).append(commandEnd);
- List headers = msgHeaders(input);
- int hCnt = headers.size();
- for (int index = 0; index < hCnt; index++) {
- Header header = headers.get(index);
- sb.append(header.getKey())
- .append(headerKvDelimiter)
- .append(header.getValue());
- if (index < hCnt - 1) {
- sb.append(headerDelimiter);
- }
- }
- sb.append(headersEnd);
- String payload = input.getPayload();
- if (payload != null) {
- sb.append(payload);
- }
- sb.append(bodyEnd);
- return sb.toString();
- }
-
- protected List msgHeaders(Message input) {
- List headers = input.getHeaders();
- return new ArrayList<>(headers);
- }
-
- @Override
- public synchronized void decode(String input, Consumer out) {
- if (input == null || input.isEmpty()) {
- return;
- }
- // 装入待解析容器
- pending.append(input);
- // 开始解析
- decode(out, 0);
- }
-
- /**
- * @param out 输出
- * @param start 开始解析的问题
- */
- protected void decode(Consumer out, int start) {
- cleanPendingStartData(start);
- // Body 结尾符下标
- int bEndIdx = pending.indexOf(bodyEnd);
- if (bEndIdx < 0) {
- // 数据包尚未接收完毕,直接返回
- return;
- }
- // Command 结尾符下标
- int cEndIdx = pending.indexOf(commandEnd);
- // Headers 结尾符下标
- int hEndIdx = pending.indexOf(headersEnd);
- if (cEndIdx <= 0 || hEndIdx <= cEndIdx || bEndIdx <= hEndIdx) {
- // 非法数据包,跳过一个字符重新解析
- decode(out, 1);
- return;
- }
- // 解析 Command
- String command = pending.substring(0, cEndIdx).trim();
- if (!isCommand(command)) {
- // 非法数据包,跳过一个字符重新解析
- decode(out, 1);
- return;
- }
- // 解析 Headers
- List headers = decodeHeaders(cEndIdx, hEndIdx);
- // 解析 Body
- String payload = pending.substring(hEndIdx + headersEnd.length(), bEndIdx);
- // 输出解析结果
- out.accept(createMessage(command, headers, payload));
- // 重新解析 bodyEnd 之后的数据
- decode(out, bEndIdx + bodyEnd.length());
- }
-
- protected void cleanPendingStartData(int start) {
- if (start > 0) {
- // 清空 start 之前的数据
- pending.delete(0, start);
- }
- // Command 开始符下标
- int index = 0;
- for (int i = 0; i < pending.length(); i++) {
- char c = pending.charAt(i);
- if (isCommandChar(c)) {
- index = i;
- break;
- }
- }
- if (index > 0) {
- // 清空 Command 之前的数据
- pending.delete(0, index);
- }
- }
-
- /**
- * 解析 Headers
- * @param cEndIdx Command 结尾符下标
- * @param hEndIdx Headers 结尾符下标
- * @return Headers
- */
- protected List decodeHeaders(int cEndIdx, int hEndIdx) {
- String[] strHeaders = pending.substring(cEndIdx + commandEnd.length(), hEndIdx)
- .split(headerDelimiter);
- List headers = new ArrayList<>(strHeaders.length);
- for (String header : strHeaders) {
- String[] hv = header.split(headerKvDelimiter);
- if (hv.length == 2) {
- headers.add(new Header(hv[0], hv[1]));
- }
- }
- return headers;
- }
-
- protected boolean isCommand(String command) {
- return !command.isEmpty() && command.matches("[A-Z]+");
- }
-
- protected boolean isCommandChar(char c) {
- return c >= 'A' && c <= 'Z';
- }
-
- protected Message createMessage(String command, List headers, String payload) {
- return new Message(command, headers, payload);
- }
-
- public String getCommandEnd() {
- return commandEnd;
- }
-
- public void setCommandEnd(String commandEnd) {
- if (commandEnd != null) {
- this.commandEnd = commandEnd;
- }
- }
-
- public String getHeadersEnd() {
- return headersEnd;
- }
-
- public void setHeadersEnd(String headersEnd) {
- if (headersEnd != null) {
- this.headersEnd = headersEnd;
- }
- }
-
- public String getBodyEnd() {
- return bodyEnd;
- }
-
- public void setBodyEnd(String bodyEnd) {
- if (bodyEnd != null) {
- this.bodyEnd = bodyEnd;
- }
- }
-
- public String getHeaderDelimiter() {
- return headerDelimiter;
- }
-
- public void setHeaderDelimiter(String headerDelimiter) {
- if (headerDelimiter != null) {
- this.headerDelimiter = headerDelimiter;
- }
- }
-
- public String getHeaderKvDelimiter() {
- return headerKvDelimiter;
- }
-
- public void setHeaderKvDelimiter(String headerKvDelimiter) {
- if (headerKvDelimiter != null) {
- this.headerKvDelimiter = headerKvDelimiter;
- }
- }
-
-}
diff --git a/okhttps-stomp/src/main/java/cn/zhxu/stomp/Subscriber.java b/okhttps-stomp/src/main/java/cn/zhxu/stomp/Subscriber.java
deleted file mode 100644
index 0378012a..00000000
--- a/okhttps-stomp/src/main/java/cn/zhxu/stomp/Subscriber.java
+++ /dev/null
@@ -1,87 +0,0 @@
-package cn.zhxu.stomp;
-
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.List;
-import java.util.UUID;
-import java.util.function.Consumer;
-
-
-public class Subscriber {
-
- private final Stomp stomp;
- private final String id;
- private final String destination;
- private final Consumer callback;
- private final List headers;
- private boolean subscribed;
-
- public Subscriber(Stomp stomp, String destination, Consumer callback, List headers) {
- this.stomp = stomp;
- this.id = UUID.randomUUID().toString();
- this.destination = destination;
- this.callback = callback;
- this.headers = headers;
- }
-
- public void subscribe() {
- synchronized (stomp) {
- if (subscribed) {
- return;
- }
- if (stomp.isConnected()) {
- doSubscribe();
- }
- }
- }
-
- private void doSubscribe() {
- List headers = new ArrayList<>();
- headers.add(new Header(Header.ID, id));
- headers.add(new Header(Header.DESTINATION, destination));
- boolean ackNotAdded = true;
- if (this.headers != null) {
- for (Header header : this.headers) {
- if (Header.ACK.equals(header.getKey())) {
- ackNotAdded = false;
- }
- String key = header.getKey();
- if (!Header.ID.equals(key) && !Header.DESTINATION.equals(key)) {
- headers.add(header);
- }
- }
- }
- if (ackNotAdded) {
- headers.add(new Header(Header.ACK, stomp.isAutoAck() ? Stomp.AUTO_ACK : Stomp.CLIENT_ACK));
- }
- stomp.send(new Message(Commands.SUBSCRIBE, headers, null));
- subscribed = true;
- }
-
- public void unsubscribe() {
- synchronized (stomp) {
- if (stomp.isConnected()) {
- List headers = Collections.singletonList(new Header(Header.ID, id));
- stomp.send(new Message(Commands.UNSUBSCRIBE, headers, null));
- }
- }
- resetStatus();
- }
-
- public void resetStatus() {
- subscribed = false;
- }
-
- public boolean destinationEqual(String destination) {
- return destination != null && destination.equals(this.destination);
- }
-
- public boolean tryCallback(String id, Message msg) {
- if (this.id.equals(id)) {
- callback.accept(msg);
- return true;
- }
- return false;
- }
-
-}
diff --git a/okhttps-stomp/src/main/java/cn/zhxu/stomp/Commands.java b/okhttps-stomp/src/main/java/com/ejlchina/stomp/Commands.java
similarity index 97%
rename from okhttps-stomp/src/main/java/cn/zhxu/stomp/Commands.java
rename to okhttps-stomp/src/main/java/com/ejlchina/stomp/Commands.java
index 9a59bb4c..6cfb0dde 100644
--- a/okhttps-stomp/src/main/java/cn/zhxu/stomp/Commands.java
+++ b/okhttps-stomp/src/main/java/com/ejlchina/stomp/Commands.java
@@ -1,4 +1,4 @@
-package cn.zhxu.stomp;
+package com.ejlchina.stomp;
/**
* 命令
diff --git a/okhttps-stomp/src/main/java/cn/zhxu/stomp/Header.java b/okhttps-stomp/src/main/java/com/ejlchina/stomp/Header.java
similarity index 97%
rename from okhttps-stomp/src/main/java/cn/zhxu/stomp/Header.java
rename to okhttps-stomp/src/main/java/com/ejlchina/stomp/Header.java
index e3441c96..994d9079 100644
--- a/okhttps-stomp/src/main/java/cn/zhxu/stomp/Header.java
+++ b/okhttps-stomp/src/main/java/com/ejlchina/stomp/Header.java
@@ -1,4 +1,4 @@
-package cn.zhxu.stomp;
+package com.ejlchina.stomp;
public class Header {
diff --git a/okhttps-stomp/src/main/java/com/ejlchina/stomp/Message.java b/okhttps-stomp/src/main/java/com/ejlchina/stomp/Message.java
new file mode 100644
index 00000000..056fcac0
--- /dev/null
+++ b/okhttps-stomp/src/main/java/com/ejlchina/stomp/Message.java
@@ -0,0 +1,109 @@
+package com.ejlchina.stomp;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import com.ejlchina.okhttps.Platform;
+
+
+public class Message {
+
+ private final String command;
+ private final List headers;
+ private final String payload;
+
+ public Message(String command, List headers) {
+ this(command, headers, null);
+ }
+
+ public Message(String command, List headers, String payload) {
+ this.command = command;
+ this.headers = headers;
+ this.payload = payload;
+ }
+
+ public List getHeaders() {
+ return headers;
+ }
+
+ public String getPayload() {
+ return payload;
+ }
+
+ public String getCommand() {
+ return command;
+ }
+
+
+ public String headerValue(String key) {
+ Header header = header(key);
+ if (header != null) {
+ return header.getValue();
+ }
+ return null;
+ }
+
+ public Header header(String key) {
+ if (headers != null) {
+ for (Header header : headers) {
+ if (header.getKey().equals(key)) return header;
+ }
+ }
+ return null;
+ }
+
+
+ public String compile(boolean legacyWhitespace) {
+ StringBuilder builder = new StringBuilder();
+ builder.append(command).append('\n');
+ for (Header header : headers) {
+ builder.append(header.getKey()).append(':').append(header.getValue()).append('\n');
+ }
+ builder.append('\n');
+ if (payload != null) {
+ builder.append(payload);
+ if (legacyWhitespace) builder.append("\n\n");
+ }
+ builder.append("\u0000");
+ return builder.toString();
+ }
+
+ public static Message from(String data) {
+ if (data == null || data.trim().isEmpty()) {
+ return new Message(Commands.UNKNOWN, null, data);
+ }
+
+ int cmdIndex = data.indexOf("\n");
+ int mhIndex = data.indexOf("\n\n");
+
+ if (cmdIndex >= mhIndex) {
+ Platform.logError("非法的 STOMP 消息:" + data);
+ return null;
+ }
+ String command = data.substring(0, cmdIndex);
+ String[] headers = data.substring(cmdIndex + 1, mhIndex).split("\n");
+
+ List headerList = new ArrayList<>(headers.length);
+ for (String header : headers) {
+ String[] hv = header.split(":");
+ if (hv.length == 2) {
+ headerList.add(new Header(hv[0], hv[1]));
+ }
+ }
+ String payload = null;
+ if (data.length() > mhIndex + 2) {
+ if (data.endsWith("\u0000\n") && data.length() > mhIndex + 4) {
+ payload = data.substring(mhIndex + 2, data.length() - 2);
+ } else if (data.endsWith("\u0000") && data.length() > mhIndex + 3) {
+ payload = data.substring(mhIndex + 2, data.length() - 1);
+ }
+ }
+ return new Message(command, headerList, payload);
+ }
+
+ @Override
+ public String toString() {
+ return "Message {command='" + command + "', headers=" + headers +", payload='" + payload + "'}";
+ }
+
+}
diff --git a/okhttps-stomp/src/main/java/cn/zhxu/stomp/Stomp.java b/okhttps-stomp/src/main/java/com/ejlchina/stomp/Stomp.java
similarity index 52%
rename from okhttps-stomp/src/main/java/cn/zhxu/stomp/Stomp.java
rename to okhttps-stomp/src/main/java/com/ejlchina/stomp/Stomp.java
index f8555564..ed0ad2fe 100644
--- a/okhttps-stomp/src/main/java/cn/zhxu/stomp/Stomp.java
+++ b/okhttps-stomp/src/main/java/com/ejlchina/stomp/Stomp.java
@@ -1,11 +1,13 @@
-package cn.zhxu.stomp;
+package com.ejlchina.stomp;
-import cn.zhxu.okhttps.Platform;
-import cn.zhxu.okhttps.WHttpTask;
-import cn.zhxu.okhttps.WebSocket;
+import com.ejlchina.okhttps.OnCallback;
+import com.ejlchina.okhttps.Platform;
+import com.ejlchina.okhttps.WebSocket;
+import com.ejlchina.okhttps.internal.WebSocketTask;
+
+import okio.ByteString;
import java.util.*;
-import java.util.function.Consumer;
/**
* 基于 OkHttps websockt 的 Stomp 客户端
@@ -20,25 +22,21 @@ public class Stomp {
public static final String CLIENT_ACK = "client";
private final boolean autoAck;
- private boolean connected = false; // 是否已连接
- private boolean connecting = false; // 是否连接中
- private boolean disconnecting = false; // 是否断开连接中
- private final WHttpTask task;
+ private boolean connected;
+ private final WebSocketTask task;
private WebSocket websocket;
-
+ private boolean legacyWhitespace = false;
private final List subscribers;
- private Consumer onConnected;
- private Consumer onDisconnected;
- private Consumer onException;
- private Consumer onError;
- private final String disReceipt;
+ private OnCallback onConnected;
+ private OnCallback onDisconnected;
+ private OnCallback onError;
- private MsgCodec msgCodec = new MsgCodecImpl();
+ private final String disReceipt;
- private Stomp(WHttpTask task, boolean autoAck) {
+ private Stomp(WebSocketTask task, boolean autoAck) {
this.task = task;
this.autoAck = autoAck;
this.subscribers = Collections.synchronizedList(new ArrayList<>());
@@ -50,7 +48,7 @@ private Stomp(WHttpTask task, boolean autoAck) {
* @param task 底层的 WebSocket 连接
* @return Stomp
*/
- public static Stomp over(WHttpTask task) {
+ public static Stomp over(WebSocketTask task) {
return over(task, true);
}
@@ -60,7 +58,7 @@ public static Stomp over(WHttpTask task) {
* @param autoAck 是否自动确定消息
* @return Stomp
*/
- public static Stomp over(WHttpTask task, boolean autoAck) {
+ public static Stomp over(WebSocketTask task, boolean autoAck) {
return new Stomp(task, autoAck);
}
@@ -85,126 +83,52 @@ public Stomp connect() {
* @param headers Stomp 头信息
* @return Stomp
*/
- public synchronized Stomp connect(List headers) {
- if (connected || connecting) {
+ public Stomp connect(List headers) {
+ if (connected) {
return this;
}
- websocket = task
- .setOnOpen((ws, res) -> doOnOpened(headers))
- .setOnMessage((ws, msg) -> msgCodec.decode(msg.toString(), this::receive))
- .setOnException((ws, e) -> doOnException(e))
- .setOnClosed((ws, close) -> doOnClosed(close))
+ websocket = task.setOnOpen((ws, res) -> {
+ int pingSecs = task.pingSeconds();
+ int pongSecs = task.pongSeconds();
+ List cHeaders = new ArrayList<>();
+ cHeaders.add(new Header(Header.VERSION, SUPPORTED_VERSIONS));
+ if (pingSecs > 0 && pongSecs > 0) {
+ cHeaders.add(new Header(Header.HEART_BEAT, pingSecs * 1000 + "," + pongSecs * 1000));
+ }
+ if (headers != null) {
+ cHeaders.addAll(headers);
+ }
+ send(new Message(Commands.CONNECT, cHeaders, null));
+ })
+ .setOnMessage((ws, msg) -> {
+ Message message = Message.from(msg.toString());
+ if (message != null) {
+ receive(message);
+ }
+ })
+ .setOnClosed((ws, close) -> {
+ if (onDisconnected != null) {
+ onDisconnected.on(close);
+ }
+ connected = false;
+ })
.listen();
- connecting = true;
- disconnecting = false;
return this;
}
- private synchronized void doOnOpened(List headers) {
- if (websocket != null) {
- int pingSecs = task.pingSeconds();
- int pongSecs = task.pongSeconds();
- List cHeaders = new ArrayList<>();
- cHeaders.add(new Header(Header.VERSION, SUPPORTED_VERSIONS));
- if (pingSecs > 0 && pongSecs > 0) {
- cHeaders.add(new Header(Header.HEART_BEAT, pingSecs * 1000 + "," + pongSecs * 1000));
- }
- if (headers != null) {
- cHeaders.addAll(headers);
- }
- send(new Message(Commands.CONNECT, cHeaders, null));
- }
- }
-
- private synchronized void doOnException(Throwable throwable) {
- Consumer listener = onException;
- if (listener != null) {
- listener.accept(throwable);
- }
- disconnecting = false;
- connecting = false;
- }
-
- private synchronized void doOnClosed(WebSocket.Close close) {
- connected = false;
- connecting = false;
- disconnecting = false;
- websocket = null;
- for (Subscriber subscriber : subscribers) {
- subscriber.resetStatus();
- }
- Consumer listener = onDisconnected;
- if (listener != null) {
- listener.accept(close);
- }
- }
-
/**
* @since 2.5.0
* @return 是否已连接
*/
public boolean isConnected() {
- return connected && websocket != null;
- }
-
- /**
- * @since 3.1.0
- * @return 是否正在连接
- */
- public boolean isConnecting() {
- return connecting && websocket != null;
- }
-
- /**
- * @since 3.1.0
- * @return 是否正在断开连接
- */
- public boolean isDisconnecting() {
- return disconnecting && websocket != null;
- }
-
- /**
- * 断开连接,将先发送 DISCONNECT 消息给服务器,服务器回复后断开连接
- * 默认等待服务器为 10 秒,10秒后自动关闭
- */
- public void disconnect() {
- disconnect(10);
- }
-
- /**
- * @since v3.1.0
- * 断开连接,将先发送 DISCONNECT 消息给服务器,服务器回复后断开连接
- * @param maxWaitSeconds 最大等待服务器回复时间,超出后自动关闭
- */
- public void disconnect(int maxWaitSeconds) {
- new Timer().schedule(new TimerTask() {
- @Override
- public void run() {
- disconnect(true);
- }
- }, 1000L * maxWaitSeconds);
- Header header = new Header(Header.RECEIPT, disReceipt);
- List headers = Collections.singletonList(header);
- send(new Message(Commands.DISCONNECT, headers));
- disconnecting = true;
- connecting = false;
+ return connected && websocket.status() == WebSocket.STATUS_CONNECTED;
}
/**
* 断开连接
- * @param immediate 是否立即断开
- * @since v3.1.0
*/
- public synchronized void disconnect(boolean immediate) {
- if (immediate) {
- WebSocket ws = websocket;
- if (ws != null) {
- ws.close(1000, "disconnect by user");
- websocket = null;
- }
- } else {
- disconnect(10);
- }
+ public void disconnect() {
+ send(new Message(Commands.DISCONNECT, Collections.singletonList(new Header(Header.RECEIPT, disReceipt))));
}
/**
@@ -212,7 +136,7 @@ public synchronized void disconnect(boolean immediate) {
* @param onConnected 连接成功回调
* @return Stomp
*/
- public Stomp setOnConnected(Consumer onConnected) {
+ public Stomp setOnConnected(OnCallback onConnected) {
this.onConnected = onConnected;
return this;
}
@@ -222,28 +146,17 @@ public Stomp setOnConnected(Consumer onConnected) {
* @param onDisconnected 断开连接回调
* @return Stomp
*/
- public Stomp setOnDisconnected(Consumer onDisconnected) {
+ public Stomp setOnDisconnected(OnCallback onDisconnected) {
this.onDisconnected = onDisconnected;
return this;
}
-
- /**
- * 错误回调(底层连接异常)
- * @since v3.1.1
- * @param onException 异常回调
- * @return Stomp
- */
- public Stomp setOnException(Consumer onException) {
- this.onException = onException;
- return this;
- }
-
+
/**
* 错误回调(服务器返回的错误信息)
* @param onError 错误回调
* @return Stomp
*/
- public Stomp setOnError(Consumer onError) {
+ public Stomp setOnError(OnCallback onError) {
this.onError = onError;
return this;
}
@@ -282,11 +195,10 @@ public void sendTo(String destination, String data) {
* @param message 消息
*/
public void send(Message message) {
- WebSocket ws = websocket;
- if (ws == null) {
+ if (websocket == null) {
throw new IllegalArgumentException("You must call connect before send");
}
- ws.send(msgCodec.encode(message));
+ websocket.send(message.compile(legacyWhitespace));
}
/**
@@ -295,7 +207,7 @@ public void send(Message message) {
* @param callback 消息回调
* @return Stomp
*/
- public Stomp topic(String destination, Consumer callback) {
+ public Stomp topic(String destination, OnCallback callback) {
return topic(destination, null, callback);
}
@@ -306,7 +218,7 @@ public Stomp topic(String destination, Consumer callback) {
* @param callback 消息回调
* @return Stomp
*/
- public Stomp topic(String destination, List headers, Consumer callback) {
+ public Stomp topic(String destination, List headers, OnCallback callback) {
return subscribe(TOPIC + destination, headers, callback);
}
@@ -316,7 +228,7 @@ public Stomp topic(String destination, List headers, Consumer c
* @param callback 消息回调
* @return Stomp
*/
- public Stomp queue(String destination, Consumer callback) {
+ public Stomp queue(String destination, OnCallback callback) {
return queue(destination, null, callback);
}
@@ -327,7 +239,7 @@ public Stomp queue(String destination, Consumer callback) {
* @param callback 消息回调
* @return Stomp
*/
- public Stomp queue(String destination, List headers, Consumer callback) {
+ public Stomp queue(String destination, List headers, OnCallback callback) {
return subscribe(QUEUE + destination, headers, callback);
}
@@ -338,14 +250,13 @@ public Stomp queue(String destination, List headers, Consumer c
* @param callback 消息回调
* @return Stomp
*/
- public synchronized Stomp subscribe(String destination, List headers, Consumer callback) {
+ public synchronized Stomp subscribe(String destination, List headers, OnCallback callback) {
if (destination == null || destination.isEmpty()) {
throw new IllegalArgumentException("destination can not be empty!");
}
for (Subscriber s: subscribers) {
if (s.destinationEqual(destination)) {
- Platform.logError("The destination [" + destination + "] has already been subscribed!");
- return this;
+ throw new IllegalStateException("The destination [" + destination + "] has already been subscribed!");
}
}
Subscriber subscriber = new Subscriber(this, destination, callback, headers);
@@ -367,7 +278,7 @@ public void ack(Message message) {
headers.add(msgId);
send(new Message(Commands.ACK, headers, null));
} else {
- Platform.logError("subscription and message-id not found in " + message + ", so it can not be ack!");
+ Platform.logError("subscription and message-id not found in " + message.toString() + ", so it can not be ack!");
}
}
@@ -403,14 +314,31 @@ public synchronized void unsubscribe(String destination) {
}
}
- private synchronized void receive(Message msg) {
+ private void receive(Message msg) {
String command = msg.getCommand();
if (Commands.CONNECTED.equals(command)) {
String hbHeader = msg.headerValue(Header.HEART_BEAT);
+ int pingSecs = task.pingSeconds();
+ int pongSecs = task.pongSeconds();
+ if (hbHeader != null && (pingSecs > 0 || pongSecs > 0)) {
+ String[] heartbeats = hbHeader.split(",");
+ int pingSeconds = Integer.parseInt(heartbeats[1]) / 1000;
+ int pongSeconds = Integer.parseInt(heartbeats[0]) / 1000;
+ if (pingSeconds > 0 || pongSeconds > 0) {
+ if (task.pingSupplier() == null) {
+ task.pingSupplier(() -> ByteString.of((byte) 0x0A));
+ }
+ task.heatbeat(Math.max(pingSeconds, pingSecs), Math.max(pongSeconds, pongSecs));
+ }
+ }
synchronized (this) {
connected = true;
- connecting = false;
- onConnectedFrameReceived(hbHeader);
+ for (Subscriber s: subscribers) {
+ s.subscribe();
+ }
+ }
+ if (onConnected != null) {
+ onConnected.on(this);
}
} else if (Commands.MESSAGE.equals(command)) {
String id = msg.headerValue(Header.SUBSCRIPTION);
@@ -424,47 +352,19 @@ private synchronized void receive(Message msg) {
} else if (Commands.RECEIPT.equals(command)) {
if (disReceipt.equals(msg.headerValue(Header.RECEIPT_ID))) {
// 断开连接
- disconnect(true);
+ if (websocket != null) {
+ websocket.close(1000, "disconnect by user");
+ }
}
} else if (Commands.ERROR.equals(command)) {
- Consumer listener = onError;
- if (listener != null) {
- listener.accept(msg);
+ if (onError != null) {
+ onError.on(msg);
}
- connecting = false;
}
}
- private void onConnectedFrameReceived(String hbHeader) {
- int pingSecs = task.pingSeconds();
- int pongSecs = task.pongSeconds();
- if (hbHeader != null && (pingSecs > 0 || pongSecs > 0)) {
- String[] heartbeats = hbHeader.split(",");
- int pingSeconds = Integer.parseInt(heartbeats[1]) / 1000;
- int pongSeconds = Integer.parseInt(heartbeats[0]) / 1000;
- if (pingSeconds > 0 || pongSeconds > 0) {
- if (task.pingSupplier() == null) {
- task.pingSupplier(() -> "\n");
- }
- task.heatbeat(Math.max(pingSeconds, pingSecs), Math.max(pongSeconds, pongSecs));
- }
- }
- Consumer listener = onConnected;
- if (listener != null) {
- listener.accept(this);
- }
- // 为兼容 Android 低版本,这里不使用 JDK8 的 List.forEach(..) 方法
- for (Subscriber subscriber: subscribers) {
- subscriber.subscribe();
- }
- }
-
- public MsgCodec getMsgCodec() {
- return msgCodec;
- }
-
- public void setMsgCodec(MsgCodec msgCodec) {
- this.msgCodec = msgCodec;
+ public void setLegacyWhitespace(boolean legacyWhitespace) {
+ this.legacyWhitespace = legacyWhitespace;
}
}
diff --git a/okhttps-stomp/src/main/java/com/ejlchina/stomp/Subscriber.java b/okhttps-stomp/src/main/java/com/ejlchina/stomp/Subscriber.java
new file mode 100644
index 00000000..7f6023a7
--- /dev/null
+++ b/okhttps-stomp/src/main/java/com/ejlchina/stomp/Subscriber.java
@@ -0,0 +1,71 @@
+package com.ejlchina.stomp;
+
+import com.ejlchina.okhttps.OnCallback;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.UUID;
+
+
+public class Subscriber {
+
+ private final Stomp stomp;
+ private final String id;
+ private final String destination;
+ private final OnCallback callback;
+ private final List headers;
+ private boolean subscribed;
+
+ public Subscriber(Stomp stomp, String destination, OnCallback callback, List headers) {
+ this.stomp = stomp;
+ this.id = UUID.randomUUID().toString();
+ this.destination = destination;
+ this.callback = callback;
+ this.headers = headers;
+ }
+
+ public void subscribe() {
+ if (stomp.isConnected() && !subscribed) {
+ List headers = new ArrayList<>();
+ headers.add(new Header(Header.ID, id));
+ headers.add(new Header(Header.DESTINATION, destination));
+ boolean ackNotAdded = true;
+ if (this.headers != null) {
+ for (Header header : this.headers) {
+ if (Header.ACK.equals(header.getKey())) {
+ ackNotAdded = false;
+ }
+ String key = header.getKey();
+ if (!Header.ID.equals(key) && !Header.DESTINATION.equals(key)) {
+ headers.add(header);
+ }
+ }
+ }
+ if (ackNotAdded) {
+ headers.add(new Header(Header.ACK, stomp.isAutoAck() ? Stomp.AUTO_ACK : Stomp.CLIENT_ACK));
+ }
+ stomp.send(new Message(Commands.SUBSCRIBE, headers, null));
+ subscribed = true;
+ }
+ }
+
+ public void unsubscribe() {
+ List headers = Collections.singletonList(new Header(Header.ID, id));
+ stomp.send(new Message(Commands.UNSUBSCRIBE, headers, null));
+ subscribed = false;
+ }
+
+ public boolean destinationEqual(String destination) {
+ return destination != null && destination.equals(this.destination);
+ }
+
+ public boolean tryCallback(String id, Message msg) {
+ if (this.id.equals(id)) {
+ callback.on(msg);
+ return true;
+ }
+ return false;
+ }
+
+}
diff --git a/okhttps-stomp/src/test/java/cn/zhxu/stomp/MsgCodecTestCases.java b/okhttps-stomp/src/test/java/cn/zhxu/stomp/MsgCodecTestCases.java
deleted file mode 100644
index 86eff6c8..00000000
--- a/okhttps-stomp/src/test/java/cn/zhxu/stomp/MsgCodecTestCases.java
+++ /dev/null
@@ -1,78 +0,0 @@
-package cn.zhxu.stomp;
-
-import org.junit.Assert;
-import org.junit.Test;
-
-import java.util.ArrayList;
-import java.util.List;
-import java.util.function.Consumer;
-
-
-public class MsgCodecTestCases {
-
- static class DecodeCallback implements Consumer {
-
- private final List list = new ArrayList<>();
-
- @Override
- public void accept(Message data) {
- list.add(data);
- }
-
- public List getList() {
- return list;
- }
- }
-
-
- @Test
- public void testMsgCodecImplDecode1() {
- MsgCodec msgCodec = new MsgCodecImpl();
- DecodeCallback callback = new DecodeCallback();
- msgCodec.decode("MESSAGE\nk1:v1\nk2:v2\n\n123456\u0000", callback);
- List list = callback.getList();
- Assert.assertEquals(1, list.size());
- Message message = list.get(0);
- Assert.assertEquals("MESSAGE", message.getCommand());
- Assert.assertEquals("123456", message.getPayload());
- Assert.assertEquals("v1", message.headerValue("k1"));
- Assert.assertEquals("v2", message.headerValue("k2"));
- }
-
- @Test
- public void testMsgCodecImplDecode2() {
- MsgCodec msgCodec = new MsgCodecImpl();
- DecodeCallback callback = new DecodeCallback();
- msgCodec.decode(" \n MESSAGE\nk1:v1\nk2:v2\n\n123456\u0000", callback);
- List list = callback.getList();
- Assert.assertEquals(1, list.size());
- Message message = list.get(0);
- Assert.assertEquals("MESSAGE", message.getCommand());
- Assert.assertEquals("123456", message.getPayload());
- Assert.assertEquals("v1", message.headerValue("k1"));
- Assert.assertEquals("v2", message.headerValue("k2"));
- }
-
- @Test
- public void testMsgCodecImplDecode3() {
- MsgCodec msgCodec = new MsgCodecImpl();
- DecodeCallback callback = new DecodeCallback();
- msgCodec.decode(" \n ", callback);
- msgCodec.decode(" MESSAGE\nk1:", callback);
- msgCodec.decode("v1\nk2:v2\n\n12345", callback);
- msgCodec.decode("6\u0000", callback);
- msgCodec.decode("\n\nMS", callback);
- msgCodec.decode("\n\nMES", callback);
- msgCodec.decode("SAGE\nk1:", callback);
- msgCodec.decode("v1\nk2:v2\n\n12345", callback);
- msgCodec.decode("6\u0000", callback);
- List list = callback.getList();
- Assert.assertEquals(2, list.size());
- Message message = list.get(1);
- Assert.assertEquals("MESSAGE", message.getCommand());
- Assert.assertEquals("123456", message.getPayload());
- Assert.assertEquals("v1", message.headerValue("k1"));
- Assert.assertEquals("v2", message.headerValue("k2"));
- }
-
-}
diff --git a/okhttps-stomp/src/test/java/cn/zhxu/stomp/Test.java b/okhttps-stomp/src/test/java/cn/zhxu/stomp/Test.java
deleted file mode 100644
index 0564b09e..00000000
--- a/okhttps-stomp/src/test/java/cn/zhxu/stomp/Test.java
+++ /dev/null
@@ -1,32 +0,0 @@
-package cn.zhxu.stomp;
-
-import cn.zhxu.okhttps.OkHttps;
-
-import java.util.ArrayList;
-import java.util.List;
-
-public class Test {
-
- public static void main(String[] args) throws InterruptedException {
-
- List headers = new ArrayList<>();
- headers.add(new Header("login", "xxx"));
- headers.add(new Header("passcode", "xxx"));
- headers.add(new Header("host", "test"));
-
- Stomp stomp = Stomp.over(OkHttps.webSocket("ws://172.31.0.202:15674/ws").heatbeat(10, 10))
- .setOnConnected(s -> {
- System.out.println("OnConnected");
- })
- .connect(headers);
-
- stomp.topic("/aaa", msg -> {
- System.out.println("收到消息:" + msg);
- System.out.println("内容:" + msg.getPayload());
- });
-
- Thread.sleep(1000000);
-
- }
-
-}
diff --git a/okhttps-stomp/src/test/java/com/ejlchina/stomp/TestCases.java b/okhttps-stomp/src/test/java/com/ejlchina/stomp/TestCases.java
new file mode 100644
index 00000000..0c4ff051
--- /dev/null
+++ b/okhttps-stomp/src/test/java/com/ejlchina/stomp/TestCases.java
@@ -0,0 +1,52 @@
+package com.ejlchina.stomp;
+
+import com.ejlchina.okhttps.test.BaseTest;
+import org.junit.Test;
+
+import com.ejlchina.okhttps.OkHttps;
+
+import java.util.concurrent.CountDownLatch;
+
+
+public class TestCases extends BaseTest {
+
+
+ static final int COUNT = 100000;
+ static final int INTERVAL = 1;
+
+ @Test
+ public void testA() throws InterruptedException {
+ CountDownLatch latch = new CountDownLatch(COUNT);
+ Stomp.over(OkHttps.webSocket("ws://localhost:8080/ws").heatbeat(10, 10))
+ .setOnConnected(stomp -> {
+ log("A 已连接");
+ for (int i = 0; i < COUNT; i++) {
+ String message = "Hello : " + i;
+ stomp.sendTo("/queue/test", message);
+ log("A 发送:" + message);
+ latch.countDown();
+ sleep(INTERVAL);
+ }
+ })
+ .setOnDisconnected(c -> log("A 已断开:" + c))
+ .setOnError(msg -> log("A 错误:" + msg))
+ .connect();
+ latch.await();
+ }
+
+ @Test
+ public void testB() throws InterruptedException {
+ CountDownLatch latch = new CountDownLatch(COUNT);
+ Stomp stomp = Stomp.over(OkHttps.webSocket("ws://localhost:8080/ws").heatbeat(10, 10))
+ .setOnConnected(s -> log("B 已连接"))
+ .setOnDisconnected(c -> log("B 已断开:" + c))
+ .setOnError(msg -> log("B 错误:" + msg))
+ .connect();
+ stomp.queue("/test", msg -> {
+ log("B 接收:" + msg.getPayload());
+ latch.countDown();
+ });
+ latch.await();
+ }
+
+}
diff --git a/okhttps-test/.gitignore b/okhttps-test/.gitignore
new file mode 100644
index 00000000..b83d2226
--- /dev/null
+++ b/okhttps-test/.gitignore
@@ -0,0 +1 @@
+/target/
diff --git a/okhttps-test/pom.xml b/okhttps-test/pom.xml
index cddf23cb..2bd6616b 100644
--- a/okhttps-test/pom.xml
+++ b/okhttps-test/pom.xml
@@ -6,16 +6,16 @@
jar
- cn.zhxu
+ com.ejlchina
okhttps-parent
- 4.1.0
+ 2.5.0
- cn.zhxu
+ com.ejlchina
okhttps
- ${project.version}
+ ${okhttps.version}
com.squareup.okhttp3
@@ -27,13 +27,6 @@
junit
${junit.version}
-
-
- com.sun.xml.bind
- jaxb-impl
- 2.3.5
-
-
diff --git a/okhttps-test/src/main/java/cn/zhxu/okhttps/test/BaseTestCases.java b/okhttps-test/src/main/java/cn/zhxu/okhttps/test/BaseTestCases.java
deleted file mode 100644
index ad49040c..00000000
--- a/okhttps-test/src/main/java/cn/zhxu/okhttps/test/BaseTestCases.java
+++ /dev/null
@@ -1,347 +0,0 @@
-package cn.zhxu.okhttps.test;
-
-import cn.zhxu.data.Array;
-import cn.zhxu.data.Mapper;
-import cn.zhxu.data.TypeRef;
-import cn.zhxu.okhttps.HTTP;
-import cn.zhxu.okhttps.MsgConvertor;
-import okhttp3.mockwebserver.MockResponse;
-import okhttp3.mockwebserver.MockWebServer;
-import org.junit.Assert;
-
-import java.io.ByteArrayInputStream;
-import java.io.InputStream;
-import java.lang.reflect.Type;
-import java.nio.charset.StandardCharsets;
-import java.util.List;
-import java.util.Set;
-import java.util.concurrent.CountDownLatch;
-import java.util.concurrent.TimeUnit;
-
-public abstract class BaseTestCases {
-
- final MockWebServer server = new MockWebServer();
-
- final HTTP http;
-
- final MsgConvertor msgConvertor;
-
- final User user1 = new User(1, "Jack");
- final User user2 = new User(1, "Tom");
-
- public BaseTestCases(MsgConvertor msgConvertor) {
- this.http = HTTP.builder()
- .baseUrl("http://" + server.getHostName() + ":" + server.getPort())
- .addMsgConvertor(msgConvertor)
- .addMsgConvertor(new MsgConvertor.FormConvertor(msgConvertor))
- .build();
- this.msgConvertor = msgConvertor;
- }
-
- public void run() throws Exception {
- test_01_toMapper();
- test_02_toArray();
- test_03_serializeBean();
- test_04_toBean();
- test_05_toResult();
- test_06_toList();
- test_07_httpOnResponse();
- test_08_httpOnResBody();
- test_09_httpOnResMapper();
- test_10_httpOnResArray();
- test_11_httpOnResBean();
- test_12_httpOnResList();
- test_13_httpOnResString();
- test_14_httpMultiCallback();
- test_15_httpMultiCallback();
- testHttpSync();
- }
-
- abstract String getUser1Str();
-
- abstract String getUser1ResultStr();
-
- abstract String getUserListStr();
-
- void assertUser1(User user) {
- Assert.assertEquals(1, user.getId());
- Assert.assertEquals("Jack", user.getName());
- }
-
- void assertUser2(User user) {
- Assert.assertEquals(2, user.getId());
- Assert.assertEquals("Tom", user.getName());
- }
-
- void assertMapper(Mapper mapper, int id, String name) {
- Assert.assertEquals(2, mapper.size());
- mapper.forEach((key, data) -> {
- if ("id".equals(key)) {
- Assert.assertEquals(id, data.toInt());
- }
- if ("name".equals(key)) {
- Assert.assertEquals(name, data.toString());
- }
- });
- Set keys = mapper.keySet();
- Assert.assertEquals(2, keys.size());
- Assert.assertTrue(keys.contains("id"));
- Assert.assertTrue(keys.contains("name"));
- Assert.assertFalse(mapper.isEmpty());
- Assert.assertEquals(2, mapper.size());
- Assert.assertEquals(id, mapper.getInt("id"));
- Assert.assertFalse(mapper.has("age"));
- Assert.assertEquals(0, mapper.getInt("age"));
- Assert.assertEquals(name, mapper.getString("name"));
- }
-
- void assertMapper1(Mapper mapper) {
- assertMapper(mapper, 1, "Jack");
- assertUser1(mapper.toBean(User.class));
- }
-
- void assertMapper2(Mapper mapper) {
- assertMapper(mapper, 2, "Tom");
- assertUser2(mapper.toBean(User.class));
- }
-
- void assertList(List list) {
- Assert.assertEquals(2, list.size());
- assertUser1(list.get(0));
- assertUser2(list.get(1));
- }
-
- void assertArray(Array array) {
- Assert.assertEquals(2, array.size());
- array.forEach((index, data) -> {
- if (index == 0) {
- assertMapper1(data.toMapper());
- }
- if (index == 1) {
- assertMapper2(data.toMapper());
- }
- });
- assertMapper1(array.getMapper(0));
- assertMapper2(array.getMapper(1));
- assertList(array.toList(User.class));
- }
-
- void assertUser1Result(Result result) {
- Assert.assertEquals(200, result.getCode());
- Assert.assertEquals("ok", result.getMsg());
- assertUser1(result.getData());
- }
-
- void test_01_toMapper() {
- InputStream in = new ByteArrayInputStream(getUser1Str().getBytes(StandardCharsets.UTF_8));
- assertMapper1(msgConvertor.toMapper(in, StandardCharsets.UTF_8));
- assertMapper1(msgConvertor.toMapper(getUser1Str()));
- System.out.println("case 01 passed!");
- }
-
- void test_02_toArray() {
- InputStream in = new ByteArrayInputStream(getUserListStr().getBytes(StandardCharsets.UTF_8));
- assertArray(msgConvertor.toArray(in, StandardCharsets.UTF_8));
- assertArray(msgConvertor.toArray(getUserListStr()));
- System.out.println("case 02 passed!");
- }
-
- void test_03_serializeBean() {
- byte[] data = msgConvertor.serialize(user1, StandardCharsets.UTF_8);
- Assert.assertEquals(getUser1Str(), new String(data, StandardCharsets.UTF_8));
- Assert.assertEquals(getUser1Str(), msgConvertor.serialize(user1));
- System.out.println("case 03 passed!");
- }
-
- void test_04_toBean() {
- String json = getUser1Str();
- InputStream in = new ByteArrayInputStream(json.getBytes());
- assertUser1(msgConvertor.toBean(User.class, in, StandardCharsets.UTF_8));
- assertUser1(msgConvertor.toBean(User.class, json));
- System.out.println("case 04 passed!");
- }
-
- void test_05_toResult() {
- String json = getUser1ResultStr();
- InputStream in = new ByteArrayInputStream(json.getBytes());
- Type type = new TypeRef>() {}.getType();
- assertUser1Result(msgConvertor.toBean(type, in, StandardCharsets.UTF_8));
- assertUser1Result(msgConvertor.toBean(type, json));
- System.out.println("case 05 passed!");
- }
-
- void test_06_toList() {
- String json = getUserListStr();
- InputStream in = new ByteArrayInputStream(json.getBytes());
- assertList(msgConvertor.toList(User.class, in, StandardCharsets.UTF_8));
- assertList(msgConvertor.toList(User.class, json));
- System.out.println("case 06 passed!");
- }
-
- void test_07_httpOnResponse() throws InterruptedException {
- server.enqueue(new MockResponse().setBody(getUser1Str()));
- CountDownLatch latch = new CountDownLatch(1);
- http.async("/")
- .setOnResponse(res -> {
- assertUser1(res.getBody().toBean(User.class));
- latch.countDown();
- })
- .setOnException(Throwable::printStackTrace)
- .get();
- Assert.assertTrue(latch.await(1, TimeUnit.SECONDS));
- System.out.println("case 07 passed!");
- }
-
- void test_08_httpOnResBody() throws InterruptedException {
- server.enqueue(new MockResponse().setBody(getUser1Str()));
- CountDownLatch latch = new CountDownLatch(1);
- http.async("/")
- .setOnResBody(body -> {
- assertUser1(body.toBean(User.class));
- latch.countDown();
- })
- .setOnException(Throwable::printStackTrace)
- .get();
- Assert.assertTrue(latch.await(1, TimeUnit.SECONDS));
- System.out.println("case 08 passed!");
- }
-
- void test_09_httpOnResMapper() throws InterruptedException {
- server.enqueue(new MockResponse().setBody(getUser1Str()));
- CountDownLatch latch = new CountDownLatch(1);
- http.async("/")
- .setOnResMapper(mapper -> {
- assertMapper1(mapper);
- latch.countDown();
- })
- .setOnException(Throwable::printStackTrace)
- .get();
- Assert.assertTrue(latch.await(1, TimeUnit.SECONDS));
- System.out.println("case 09 passed!");
- }
-
- void test_10_httpOnResArray() throws InterruptedException {
- server.enqueue(new MockResponse().setBody(getUserListStr()));
- CountDownLatch latch = new CountDownLatch(1);
- http.async("/")
- .setOnResArray(array -> {
- assertArray(array);
- latch.countDown();
- })
- .setOnException(Throwable::printStackTrace)
- .get();
- Assert.assertTrue(latch.await(1, TimeUnit.SECONDS));
- System.out.println("case 10 passed!");
- }
-
- void test_11_httpOnResBean() throws InterruptedException {
- server.enqueue(new MockResponse().setBody(getUser1Str()));
- CountDownLatch latch = new CountDownLatch(1);
- http.async("/")
- .setOnResBean(User.class, user -> {
- assertUser1(user);
- latch.countDown();
- })
- .setOnException(Throwable::printStackTrace)
- .get();
- Assert.assertTrue(latch.await(1000, TimeUnit.SECONDS));
- System.out.println("case 11 passed!");
- }
-
- void test_12_httpOnResList() throws InterruptedException {
- server.enqueue(new MockResponse().setBody(getUserListStr()));
- CountDownLatch latch = new CountDownLatch(1);
- http.async("/")
- .setOnResList(User.class, list -> {
- assertList(list);
- latch.countDown();
- })
- .setOnException(Throwable::printStackTrace)
- .get();
- Assert.assertTrue(latch.await(1, TimeUnit.SECONDS));
- System.out.println("case 12 passed!");
- }
-
- void test_13_httpOnResString() throws InterruptedException {
- String body = getUser1Str();
- server.enqueue(new MockResponse().setBody(body));
- CountDownLatch latch = new CountDownLatch(1);
- http.async("/")
- .setOnResString(str -> {
- Assert.assertEquals(body, str);
- latch.countDown();
- })
- .setOnException(Throwable::printStackTrace)
- .get();
- Assert.assertTrue(latch.await(1, TimeUnit.SECONDS));
- System.out.println("case 13 passed!");
- }
-
- void test_14_httpMultiCallback() throws InterruptedException {
- String user1Str = getUser1Str();
- server.enqueue(new MockResponse().setBody(user1Str));
- CountDownLatch latch = new CountDownLatch(5);
- http.async("/")
- .setOnResponse(res -> {
- assertUser1(res.getBody().toBean(User.class));
- latch.countDown();
- })
- .setOnResBody(body -> {
- assertMapper1(body.toMapper());
- latch.countDown();
- })
- .setOnResMapper(mapper -> {
- assertMapper1(mapper);
- latch.countDown();
- })
- .setOnResBean(User.class, user -> {
- assertUser1(user);
- latch.countDown();
- })
- .setOnResString(str -> {
- Assert.assertEquals(user1Str, str);
- latch.countDown();
- })
- .setOnException(Throwable::printStackTrace)
- .get();
- Assert.assertTrue(latch.await(1, TimeUnit.SECONDS));
- System.out.println("case 14 passed!");
- }
-
-
- void test_15_httpMultiCallback() throws InterruptedException {
- String userListStr = getUserListStr();
- server.enqueue(new MockResponse().setBody(userListStr));
- CountDownLatch latch = new CountDownLatch(5);
- http.async("/")
- .setOnResponse(res -> {
- assertList(res.getBody().toList(User.class));
- latch.countDown();
- })
- .setOnResBody(body -> {
- assertArray(body.toArray());
- latch.countDown();
- })
- .setOnResList(User.class ,list -> {
- assertList(list);
- latch.countDown();
- })
- .setOnResArray(array -> {
- assertArray(array);
- latch.countDown();
- })
- .setOnResString(str -> {
- Assert.assertEquals(userListStr, str);
- latch.countDown();
- })
- .setOnException(Throwable::printStackTrace)
- .get();
- Assert.assertTrue(latch.await(1, TimeUnit.SECONDS));
- System.out.println("case 15 passed!");
- }
-
- void testHttpSync() {
-
- }
-
-}
diff --git a/okhttps/src/test/java/cn/zhxu/okhttps/BaseTest.java b/okhttps-test/src/main/java/com/ejlchina/okhttps/test/BaseTest.java
similarity index 88%
rename from okhttps/src/test/java/cn/zhxu/okhttps/BaseTest.java
rename to okhttps-test/src/main/java/com/ejlchina/okhttps/test/BaseTest.java
index 72da672c..158b0f3a 100644
--- a/okhttps/src/test/java/cn/zhxu/okhttps/BaseTest.java
+++ b/okhttps-test/src/main/java/com/ejlchina/okhttps/test/BaseTest.java
@@ -1,19 +1,16 @@
-package cn.zhxu.okhttps;
-
-import cn.zhxu.okhttps.HTTP;
-import okhttp3.mockwebserver.MockWebServer;
+package com.ejlchina.okhttps.test;
import java.text.SimpleDateFormat;
import java.util.Date;
+import okhttp3.mockwebserver.MockWebServer;
+
public class BaseTest {
protected MockWebServer server = new MockWebServer();
protected String mockUrl = "http://" + server.getHostName() + ":" + server.getPort();
-
- protected HTTP http = HTTP.builder().baseUrl(mockUrl).build();
-
+
public static void sleep(int millis) {
try {
diff --git a/okhttps-test/src/main/java/com/ejlchina/okhttps/test/BaseTestCases.java b/okhttps-test/src/main/java/com/ejlchina/okhttps/test/BaseTestCases.java
new file mode 100644
index 00000000..1fc81465
--- /dev/null
+++ b/okhttps-test/src/main/java/com/ejlchina/okhttps/test/BaseTestCases.java
@@ -0,0 +1,112 @@
+package com.ejlchina.okhttps.test;
+
+import com.ejlchina.okhttps.Array;
+import com.ejlchina.okhttps.Mapper;
+import com.ejlchina.okhttps.MsgConvertor;
+import com.ejlchina.okhttps.TypeRef;
+import org.junit.Assert;
+
+import java.io.ByteArrayInputStream;
+import java.io.InputStream;
+import java.nio.charset.StandardCharsets;
+import java.util.List;
+import java.util.Set;
+
+public abstract class BaseTestCases {
+
+ MsgConvertor msgConvertor;
+
+ public BaseTestCases(MsgConvertor msgConvertor) {
+ this.msgConvertor = msgConvertor;
+ }
+
+ public void run() throws Exception {
+ testToMapper();
+ testToArray();
+ testSerializeBean();
+ testToBean();
+ testToResult();
+ testToList();
+ }
+
+ abstract String getUserObjectStr();
+
+ abstract String getResultUserObjectStr();
+
+ abstract String getUserListStr();
+
+ void testToMapper() {
+ String json = getUserObjectStr();
+ InputStream in = new ByteArrayInputStream(json.getBytes());
+ Mapper mapper = msgConvertor.toMapper(in, StandardCharsets.UTF_8);
+ Set keys = mapper.keySet();
+ Assert.assertEquals(2, keys.size());
+ Assert.assertTrue(keys.contains("id"));
+ Assert.assertTrue(keys.contains("name"));
+ Assert.assertFalse(mapper.isEmpty());
+ Assert.assertEquals(2, mapper.size());
+ Assert.assertEquals(1, mapper.getInt("id"));
+ Assert.assertFalse(mapper.has("age"));
+ Assert.assertEquals(0, mapper.getInt("age"));
+ Assert.assertEquals("Jack", mapper.getString("name"));
+ System.out.println("case 1 passed!");
+ }
+
+ void testToArray() {
+ String json = getUserListStr();
+ InputStream in = new ByteArrayInputStream(json.getBytes());
+ Array jsonObj = msgConvertor.toArray(in, StandardCharsets.UTF_8);
+ Assert.assertFalse(jsonObj.isEmpty());
+ Assert.assertEquals(2, jsonObj.size());
+ Mapper json1 = jsonObj.getMapper(0);
+ Mapper json2 = jsonObj.getMapper(1);
+ Assert.assertEquals(1, json1.getInt("id"));
+ Assert.assertEquals("Jack", json1.getString("name"));
+ Assert.assertEquals(2, json2.getInt("id"));
+ Assert.assertEquals("Tom", json2.getString("name"));
+ System.out.println("case 2 passed!");
+ }
+
+ void testSerializeBean() {
+ byte[] data = msgConvertor.serialize(new User(1, "Jack"), StandardCharsets.UTF_8);
+ String json = new String(data, StandardCharsets.UTF_8);
+ Assert.assertEquals(getUserObjectStr(), json);
+ System.out.println("case 3 passed!");
+ }
+
+ void testToBean() {
+ String json = getUserObjectStr();
+ InputStream in = new ByteArrayInputStream(json.getBytes());
+ User user = msgConvertor.toBean(User.class, in, StandardCharsets.UTF_8);
+ Assert.assertEquals(1, user.getId());
+ Assert.assertEquals("Jack", user.getName());
+ System.out.println("case 6 passed!");
+ }
+
+ void testToResult() {
+ String json = getResultUserObjectStr();
+ InputStream in = new ByteArrayInputStream(json.getBytes());
+ Result result = msgConvertor.toBean(new TypeRef>(){}.getType(), in, StandardCharsets.UTF_8);
+ Assert.assertEquals(200, result.getCode());
+ Assert.assertEquals("ok", result.getMsg());
+ User user = result.getData();
+ Assert.assertEquals(1, user.getId());
+ Assert.assertEquals("Jack", user.getName());
+ System.out.println("case 7 passed!");
+ }
+
+ void testToList() {
+ String json = getUserListStr();
+ InputStream in = new ByteArrayInputStream(json.getBytes());
+ List users = msgConvertor.toList(User.class, in, StandardCharsets.UTF_8);
+ Assert.assertEquals(2, users.size());
+ User u1 = users.get(0);
+ User u2 = users.get(1);
+ Assert.assertEquals(1, u1.getId());
+ Assert.assertEquals("Jack", u1.getName());
+ Assert.assertEquals(2, u2.getId());
+ Assert.assertEquals("Tom", u2.getName());
+ System.out.println("case 8 passed!");
+ }
+
+}
diff --git a/okhttps-test/src/main/java/cn/zhxu/okhttps/test/DateBean.java b/okhttps-test/src/main/java/com/ejlchina/okhttps/test/DateBean.java
similarity index 93%
rename from okhttps-test/src/main/java/cn/zhxu/okhttps/test/DateBean.java
rename to okhttps-test/src/main/java/com/ejlchina/okhttps/test/DateBean.java
index 9030919d..34cfdb53 100644
--- a/okhttps-test/src/main/java/cn/zhxu/okhttps/test/DateBean.java
+++ b/okhttps-test/src/main/java/com/ejlchina/okhttps/test/DateBean.java
@@ -1,4 +1,4 @@
-package cn.zhxu.okhttps.test;
+package com.ejlchina.okhttps.test;
import java.util.Date;
diff --git a/okhttps-test/src/main/java/cn/zhxu/okhttps/test/JsonTestCases.java b/okhttps-test/src/main/java/com/ejlchina/okhttps/test/JsonTestCases.java
similarity index 86%
rename from okhttps-test/src/main/java/cn/zhxu/okhttps/test/JsonTestCases.java
rename to okhttps-test/src/main/java/com/ejlchina/okhttps/test/JsonTestCases.java
index 72019c51..28c90a0f 100644
--- a/okhttps-test/src/main/java/cn/zhxu/okhttps/test/JsonTestCases.java
+++ b/okhttps-test/src/main/java/com/ejlchina/okhttps/test/JsonTestCases.java
@@ -1,6 +1,6 @@
-package cn.zhxu.okhttps.test;
+package com.ejlchina.okhttps.test;
-import cn.zhxu.okhttps.MsgConvertor;
+import com.ejlchina.okhttps.MsgConvertor;
import org.junit.Assert;
import java.nio.charset.StandardCharsets;
@@ -19,12 +19,12 @@ public void run() throws Exception {
}
@Override
- String getUser1Str() {
+ String getUserObjectStr() {
return "{\"id\":1,\"name\":\"Jack\"}";
}
@Override
- String getUser1ResultStr() {
+ String getResultUserObjectStr() {
return "{\"code\": 200, \"data\": {\"id\":1,\"name\":\"Jack\"}, \"msg\": \"ok\"}";
}
diff --git a/okhttps-test/src/main/java/cn/zhxu/okhttps/test/Result.java b/okhttps-test/src/main/java/com/ejlchina/okhttps/test/Result.java
similarity index 93%
rename from okhttps-test/src/main/java/cn/zhxu/okhttps/test/Result.java
rename to okhttps-test/src/main/java/com/ejlchina/okhttps/test/Result.java
index 42232d56..d0a3b47d 100644
--- a/okhttps-test/src/main/java/cn/zhxu/okhttps/test/Result.java
+++ b/okhttps-test/src/main/java/com/ejlchina/okhttps/test/Result.java
@@ -1,4 +1,4 @@
-package cn.zhxu.okhttps.test;
+package com.ejlchina.okhttps.test;
import javax.xml.bind.annotation.XmlRootElement;
diff --git a/okhttps-test/src/main/java/cn/zhxu/okhttps/test/User.java b/okhttps-test/src/main/java/com/ejlchina/okhttps/test/User.java
similarity index 97%
rename from okhttps-test/src/main/java/cn/zhxu/okhttps/test/User.java
rename to okhttps-test/src/main/java/com/ejlchina/okhttps/test/User.java
index e76583f1..c886339d 100644
--- a/okhttps-test/src/main/java/cn/zhxu/okhttps/test/User.java
+++ b/okhttps-test/src/main/java/com/ejlchina/okhttps/test/User.java
@@ -1,4 +1,4 @@
-package cn.zhxu.okhttps.test;
+package com.ejlchina.okhttps.test;
import javax.xml.bind.annotation.XmlRootElement;
diff --git a/okhttps-test/src/main/java/cn/zhxu/okhttps/test/XmlTestCases.java b/okhttps-test/src/main/java/com/ejlchina/okhttps/test/XmlTestCases.java
similarity index 64%
rename from okhttps-test/src/main/java/cn/zhxu/okhttps/test/XmlTestCases.java
rename to okhttps-test/src/main/java/com/ejlchina/okhttps/test/XmlTestCases.java
index 399a311d..830203bf 100644
--- a/okhttps-test/src/main/java/cn/zhxu/okhttps/test/XmlTestCases.java
+++ b/okhttps-test/src/main/java/com/ejlchina/okhttps/test/XmlTestCases.java
@@ -1,6 +1,6 @@
-package cn.zhxu.okhttps.test;
+package com.ejlchina.okhttps.test;
-import cn.zhxu.okhttps.MsgConvertor;
+import com.ejlchina.okhttps.MsgConvertor;
public class XmlTestCases extends BaseTestCases {
@@ -10,12 +10,12 @@ public XmlTestCases(MsgConvertor msgConvertor) {
}
@Override
- String getUser1Str() {
+ String getUserObjectStr() {
return "1 Jack ";
}
@Override
- String getUser1ResultStr() {
+ String getResultUserObjectStr() {
return "\n" +
"\t200\n" +
"\tok \n" +
@@ -27,7 +27,7 @@ String getUser1ResultStr() {
@Override
String getUserListStr() {
- return "1 Jack 2 Tom
";
+ return "1 Jack 2 Tom
";
}
}
diff --git a/okhttps-xml/.gitignore b/okhttps-xml/.gitignore
new file mode 100644
index 00000000..b83d2226
--- /dev/null
+++ b/okhttps-xml/.gitignore
@@ -0,0 +1 @@
+/target/
diff --git a/okhttps-xml/README.md b/okhttps-xml/README.md
new file mode 100644
index 00000000..e0c74564
--- /dev/null
+++ b/okhttps-xml/README.md
@@ -0,0 +1,24 @@
+# OkHttps Xml
+
+#### 介绍
+
+基于 OkHttps 与 Xml 集成扩展(仅支持 Java 8)
+
+
+##### Maven
+
+```xml
+
+ com.ejlchina
+ okhttps-xml
+ 2.5.0
+
+```
+
+##### Gradle
+
+```groovy
+implementation 'com.ejlchina:okhttps-xml:2.5.0'
+```
+
+#### 更多请参阅 [http://okhttps.ejlchina.com/](http://okhttps.ejlchina.com/)
diff --git a/okhttps-snack3/pom.xml b/okhttps-xml/pom.xml
similarity index 54%
rename from okhttps-snack3/pom.xml
rename to okhttps-xml/pom.xml
index 364fdeae..6aed9aed 100644
--- a/okhttps-snack3/pom.xml
+++ b/okhttps-xml/pom.xml
@@ -1,36 +1,31 @@
4.0.0
- okhttps-snack3
- OkHttps Snack3
+ okhttps-xml
+ OkHttps Xml
jar
- cn.zhxu
+ com.ejlchina
okhttps-parent
- 4.1.0
+ 2.5.0
- cn.zhxu
+ com.ejlchina
okhttps
- ${project.version}
+ ${okhttps.version}
- cn.zhxu
- data-snack3
- ${data.version}
-
-
- cn.zhxu
+ com.ejlchina
okhttps-test
- ${project.version}
+ ${okhttps.version}
test
- okhttps-snack3
+ okhttps-xml
\ No newline at end of file
diff --git a/okhttps-xml/src/main/java/com/ejlchina/okhttps/Deserializer.java b/okhttps-xml/src/main/java/com/ejlchina/okhttps/Deserializer.java
new file mode 100644
index 00000000..d16f86c6
--- /dev/null
+++ b/okhttps-xml/src/main/java/com/ejlchina/okhttps/Deserializer.java
@@ -0,0 +1,144 @@
+package com.ejlchina.okhttps;
+
+import java.lang.reflect.Method;
+import java.lang.reflect.ParameterizedType;
+import java.lang.reflect.Type;
+import java.lang.reflect.TypeVariable;
+import java.math.BigDecimal;
+import java.math.BigInteger;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+public class Deserializer {
+
+
+ public Object deserialize(Mapper mapper, Type type) {
+ Type[] typeArgs = null;
+ if (type instanceof ParameterizedType) {
+ typeArgs = ((ParameterizedType) type).getActualTypeArguments();
+ }
+ Class> clazz = toClass(type);
+ return toBean(clazz, typeArgs, mapper);
+ }
+
+
+ protected Object toBean(Class> clazz, Type[] typeArgs, Mapper mapper) {
+ if (clazz == Map.class || clazz == HashMap.class) {
+ Map map = new HashMap<>();
+ for (String key : mapper.keySet()) {
+ if (typeArgs.length > 1) {
+ map.put(key, fieldValue(mapper, key, typeArgs[1]));
+ } else {
+ map.put(key, fieldValue(mapper, key, String.class));
+ }
+ }
+ return map;
+ }
+ Object bean;
+ try {
+ bean = clazz.newInstance();
+ } catch (InstantiationException | IllegalAccessException e) {
+ throw new IllegalStateException("无法构造 " + clazz + " 对象", e);
+ }
+ TypeVariable>[] typeParas = clazz.getTypeParameters();
+ Map methods = getSetMehthods(clazz);
+ for (String field : methods.keySet()) {
+ Method method = methods.get(field);
+ Type fieldType = method.getParameterTypes()[0];
+ if (fieldType == Object.class && typeParas.length > 0) {
+ Type[] gTypes = method.getGenericParameterTypes();
+ if (gTypes.length > 0) {
+ Type gType = gTypes[0];
+ for (int i = 0; i < typeParas.length; i++) {
+ if (typeParas[i] == gType) {
+ fieldType = typeArgs[i];
+ }
+ }
+ }
+ }
+ Object fieldValue = fieldValue(mapper, field, fieldType);
+ try {
+ method.invoke(bean, fieldValue);
+ } catch (ReflectiveOperationException e) {
+ throw new IllegalStateException("无法为 " + clazz + " 对象的 " + field + "属性赋值", e);
+ }
+ }
+ return bean;
+ }
+
+ protected Object fieldValue(Mapper mapper, String field, Type type) {
+ if (type == int.class || type == Integer.class) {
+ return mapper.getInt(field);
+ }
+ if (type == long.class || type == Long.class) {
+ return mapper.getLong(field);
+ }
+ if (type == float.class || type == Float.class) {
+ return mapper.getFloat(field);
+ }
+ if (type == double.class || type == Double.class) {
+ return mapper.getDouble(field);
+ }
+ if (type == boolean.class || type == Boolean.class) {
+ return mapper.getBool(field);
+ }
+ if (type == String.class) {
+ return mapper.getString(field);
+ }
+ if (type == BigDecimal.class) {
+ return new BigDecimal(mapper.getString(field));
+ }
+ if (type == BigInteger.class) {
+ return new BigInteger(mapper.getString(field));
+ }
+ Class> clazz = toClass(type);
+ if (clazz == List.class || clazz == ArrayList.class) {
+ Array array = mapper.getArray(field);
+ if (array != null) {
+ List list = new ArrayList<>();
+ for (int i = 0; i < array.size(); i++) {
+ list.add(deserialize(array.getMapper(i), ((ParameterizedType) type).getActualTypeArguments()[0]));
+ }
+ return list;
+ }
+ } else {
+ Mapper value = mapper.getMapper(field);
+ if (value != null) {
+ return deserialize(value, type);
+ }
+ }
+ return null;
+ }
+
+ protected Map getSetMehthods(Class> clazz) {
+ Map methods = new HashMap<>();
+ for (Method method: clazz.getMethods()) {
+ String methodName = method.getName();
+ Class>[] paraTypes = method.getParameterTypes();
+ if (paraTypes.length != 1 || methodName.length() <= 3
+ || !methodName.startsWith("set")) {
+ continue;
+ }
+ String field = XmlUtils.firstCharToLowerCase(methodName.substring(3));
+ methods.put(field, method);
+ }
+ return methods;
+ }
+
+ protected Class> toClass(Type type) {
+ if (type instanceof Class) {
+ return (Class>) type;
+ }
+ if (type instanceof ParameterizedType) {
+ Type rawType = ((ParameterizedType) type).getRawType();
+ if (rawType instanceof Class) {
+ return (Class>) rawType;
+ }
+ }
+ return null;
+ }
+
+
+}
diff --git a/okhttps-xml/src/main/java/com/ejlchina/okhttps/XmlArray.java b/okhttps-xml/src/main/java/com/ejlchina/okhttps/XmlArray.java
new file mode 100644
index 00000000..b0eb6ed3
--- /dev/null
+++ b/okhttps-xml/src/main/java/com/ejlchina/okhttps/XmlArray.java
@@ -0,0 +1,120 @@
+package com.ejlchina.okhttps;
+
+import org.w3c.dom.Element;
+
+import javax.xml.transform.TransformerFactory;
+import javax.xml.transform.dom.DOMSource;
+import javax.xml.transform.stream.StreamResult;
+import java.io.ByteArrayOutputStream;
+import java.util.List;
+
+public class XmlArray implements Array {
+
+ private final String[] nameKeys;
+ private final String[] valueKeys;
+ private final List list;
+
+ public XmlArray(String[] nameKeys, String[] valueKeys, List list) {
+ this.nameKeys = nameKeys;
+ this.valueKeys = valueKeys;
+ this.list = list;
+ }
+
+ @Override
+ public int size() {
+ return list.size();
+ }
+
+ @Override
+ public boolean isEmpty() {
+ return list.isEmpty();
+ }
+
+ @Override
+ public Mapper getMapper(int index) {
+ if (index < list.size()) {
+ return new XmlMapper(nameKeys, valueKeys, list.get(index));
+ }
+ return null;
+ }
+
+ @Override
+ public Array getArray(int index) {
+ if (index < list.size()) {
+ Element node = list.get(index);
+ return new XmlArray(nameKeys, valueKeys, XmlUtils.children(node));
+ }
+ return null;
+ }
+
+ @Override
+ public boolean getBool(int index) {
+ if (index < list.size()) {
+ String value = XmlUtils.value(list.get(index), valueKeys);
+ return XmlUtils.toBoolean(value);
+ }
+ return false;
+ }
+
+ @Override
+ public int getInt(int index) {
+ if (index < list.size()) {
+ String value = XmlUtils.value(list.get(index), valueKeys);
+ return XmlUtils.toInt(value);
+ }
+ return 0;
+ }
+
+ @Override
+ public long getLong(int index) {
+ if (index < list.size()) {
+ String value = XmlUtils.value(list.get(index), valueKeys);
+ return XmlUtils.toLong(value);
+ }
+ return 0;
+ }
+
+ @Override
+ public float getFloat(int index) {
+ if (index < list.size()) {
+ String value = XmlUtils.value(list.get(index), valueKeys);
+ return XmlUtils.toFloat(value);
+ }
+ return 0;
+ }
+
+ @Override
+ public double getDouble(int index) {
+ if (index < list.size()) {
+ String value = XmlUtils.value(list.get(index), valueKeys);
+ return XmlUtils.toDouble(value);
+ }
+ return 0;
+ }
+
+ @Override
+ public String getString(int index) {
+ if (index < list.size()) {
+ return XmlUtils.value(list.get(index), valueKeys);
+ }
+ return null;
+ }
+
+ @Override
+ public String toString() {
+ try {
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ for (int i = 0; i < list.size(); i++) {
+ TransformerFactory.newInstance().newTransformer()
+ .transform(new DOMSource(list.get(i)), new StreamResult(baos));
+ if (i < list.size() - 1) {
+ baos.write('\n');
+ }
+ }
+ return baos.toString();
+ } catch (Exception e) {
+ throw new IllegalStateException(e);
+ }
+ }
+
+}
diff --git a/okhttps-xml/src/main/java/com/ejlchina/okhttps/XmlMapper.java b/okhttps-xml/src/main/java/com/ejlchina/okhttps/XmlMapper.java
new file mode 100644
index 00000000..bbf30a90
--- /dev/null
+++ b/okhttps-xml/src/main/java/com/ejlchina/okhttps/XmlMapper.java
@@ -0,0 +1,145 @@
+package com.ejlchina.okhttps;
+
+import org.w3c.dom.*;
+
+import javax.xml.transform.TransformerFactory;
+import javax.xml.transform.dom.DOMSource;
+import javax.xml.transform.stream.StreamResult;
+import java.io.ByteArrayOutputStream;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+public class XmlMapper implements Mapper {
+
+ final private String[] nameKeys;
+ final private String[] valueKeys;
+ final private Element element;
+ private List children;
+
+ public XmlMapper(String[] nameKeys, String[] valueKeys, Element element) {
+ this.nameKeys = nameKeys;
+ this.valueKeys = valueKeys;
+ this.element = element;
+ }
+
+ @Override
+ public int size() {
+ NamedNodeMap attrs = element.getAttributes();
+ return children().size() + attrs.getLength();
+ }
+
+ @Override
+ public boolean isEmpty() {
+ NamedNodeMap attrs = element.getAttributes();
+ return attrs.getLength() == 0 && children().size() == 0;
+ }
+
+ @Override
+ public Mapper getMapper(String key) {
+ Element child = XmlUtils.findElement(children(), nameKeys, key);
+ if (child != null) {
+ return new XmlMapper(nameKeys, valueKeys, child);
+ }
+ return null;
+ }
+
+ @Override
+ public Array getArray(String key) {
+ List children = XmlUtils.findElements(children(), nameKeys, key);
+ if (children.size() > 1) {
+ return new XmlArray(nameKeys, valueKeys, children);
+ } else if (children.size() == 1) {
+ Element element = children.get(0);
+ return new XmlArray(nameKeys, valueKeys, XmlUtils.children(element));
+ }
+ return null;
+ }
+
+ @Override
+ public boolean getBool(String key) {
+ return XmlUtils.toBoolean(getString(key));
+ }
+
+ @Override
+ public int getInt(String key) {
+ return XmlUtils.toInt(getString(key));
+ }
+
+ @Override
+ public long getLong(String key) {
+ return XmlUtils.toLong(getString(key));
+ }
+
+ @Override
+ public float getFloat(String key) {
+ return XmlUtils.toFloat(getString(key));
+ }
+
+ @Override
+ public double getDouble(String key) {
+ return XmlUtils.toDouble(getString(key));
+ }
+
+ @Override
+ public String getString(String key) {
+ String value = element.getAttribute(key);
+ if (!XmlUtils.isBlank(value)) {
+ return value;
+ }
+ Element ele = XmlUtils.findElement(children(), nameKeys, key);
+ if (ele != null) {
+ return XmlUtils.value(ele, valueKeys);
+ }
+ return null;
+ }
+
+ @Override
+ public boolean has(String key) {
+ return getString(key) != null;
+ }
+
+ @Override
+ public Set keySet() {
+ HashSet set = new HashSet<>();
+ NamedNodeMap attrs = element.getAttributes();
+ for (int i = 0; i < attrs.getLength(); i++) {
+ Attr attr = (Attr) attrs.item(i);
+ set.add(attr.getName());
+ }
+ List nodes = children();
+ for (Element node : nodes) {
+ set.add(node.getNodeName());
+ for (String nameKey : nameKeys) {
+ String key = node.getAttribute(nameKey);
+ if (!XmlUtils.isBlank(key)) {
+ set.add(key);
+ }
+ }
+ }
+ return set;
+ }
+
+ @Override
+ public String toString() {
+ try {
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ TransformerFactory.newInstance().newTransformer()
+ .transform(new DOMSource(element), new StreamResult(baos));
+ return baos.toString();
+ } catch (Exception e) {
+ throw new IllegalStateException(e);
+ }
+ }
+
+ protected List children() {
+ synchronized (element) {
+ if (children == null) {
+ children = XmlUtils.children(element);
+ }
+ }
+ return children;
+ }
+
+
+}
diff --git a/okhttps-xml/src/main/java/com/ejlchina/okhttps/XmlMsgConvertor.java b/okhttps-xml/src/main/java/com/ejlchina/okhttps/XmlMsgConvertor.java
new file mode 100644
index 00000000..381bd2bf
--- /dev/null
+++ b/okhttps-xml/src/main/java/com/ejlchina/okhttps/XmlMsgConvertor.java
@@ -0,0 +1,154 @@
+package com.ejlchina.okhttps;
+
+import com.ejlchina.okhttps.internal.HttpException;
+import org.w3c.dom.Element;
+import org.xml.sax.InputSource;
+import org.xml.sax.SAXException;
+
+import javax.xml.bind.JAXBContext;
+import javax.xml.bind.JAXBException;
+import javax.xml.bind.Marshaller;
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.parsers.ParserConfigurationException;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.StringWriter;
+import java.lang.reflect.Type;
+import java.nio.charset.Charset;
+import java.util.ArrayList;
+import java.util.List;
+
+public class XmlMsgConvertor implements MsgConvertor, ConvertProvider {
+
+ private String[] nameKeys = {"name", "key"};
+ private String[] valueKeys = {"value"};
+
+ private boolean serializeFormatted = false;
+
+ private Deserializer deserializer;
+
+ private DocumentBuilderFactory dbFactory;
+
+
+ public XmlMsgConvertor() {
+ this(new Deserializer(), DocumentBuilderFactory.newInstance());
+ }
+
+ public XmlMsgConvertor(Deserializer deserializer, DocumentBuilderFactory dbFactory) {
+ this.deserializer = deserializer;
+ this.dbFactory = dbFactory;
+ }
+
+ @Override
+ public String mediaType() {
+ return "application/xml";
+ }
+
+ private Element parseElement(InputStream in, Charset charset) {
+ DocumentBuilder builder;
+ try {
+ // DocumentBuilder 是线程不安全的,所有每次解析都得新起一个 Builder
+ builder = dbFactory.newDocumentBuilder();
+ } catch (ParserConfigurationException e) {
+ throw new HttpException("DocumentBuilderFactory 配置异常", e);
+ }
+ try {
+ InputSource source = new InputSource(in);
+ source.setEncoding(charset.name());
+ return builder.parse(source).getDocumentElement();
+ } catch (SAXException|IOException e) {
+ throw new HttpException("XML 解析异常", e);
+ }
+ }
+
+ @Override
+ public Mapper toMapper(InputStream in, Charset charset) {
+ Element root = parseElement(in, charset);
+ return new XmlMapper(nameKeys, valueKeys, root);
+ }
+
+ @Override
+ public Array toArray(InputStream in, Charset charset) {
+ Element root = parseElement(in, charset);
+ return new XmlArray(nameKeys, valueKeys, XmlUtils.children(root));
+ }
+
+ @Override
+ public byte[] serialize(Object object, Charset charset) {
+ try {
+ JAXBContext context = JAXBContext.newInstance(object.getClass());
+ Marshaller marshaller = context.createMarshaller();
+ marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, serializeFormatted);
+ marshaller.setProperty(Marshaller.JAXB_ENCODING, charset.name());
+ StringWriter writer = new StringWriter();
+ marshaller.marshal(object, writer);
+ return writer.toString().getBytes(charset);
+ } catch (JAXBException e) {
+ throw new HttpException("XML 序列化异常:", e);
+ }
+ }
+
+ @Override
+ @SuppressWarnings("unchecked")
+ public T toBean(Type type, InputStream in, Charset charset) {
+ return (T) deserializer.deserialize(toMapper(in, charset), type);
+ }
+
+ @Override
+ @SuppressWarnings("unchecked")
+ public List toList(Class type, InputStream in, Charset charset) {
+ Array array = toArray(in, charset);
+ List list = new ArrayList<>();
+ for (int i = 0; i < array.size(); i++) {
+ list.add((T) deserializer.deserialize(array.getMapper(i), type));
+ }
+ return list;
+ }
+
+ @Override
+ public MsgConvertor getConvertor() {
+ return new XmlMsgConvertor();
+ }
+
+ public String[] getNameKeys() {
+ return nameKeys;
+ }
+
+ public void setNameKeys(String[] nameKeys) {
+ this.nameKeys = nameKeys;
+ }
+
+ public String[] getValueKeys() {
+ return valueKeys;
+ }
+
+ public void setValueKeys(String[] valueKeys) {
+ this.valueKeys = valueKeys;
+ }
+
+ public Deserializer getDeserializer() {
+ return deserializer;
+ }
+
+ public void setDeserializer(Deserializer deserializer) {
+ this.deserializer = deserializer;
+ }
+
+ public DocumentBuilderFactory getDbFactory() {
+ return dbFactory;
+ }
+
+ public void setDbFactory(DocumentBuilderFactory dbFactory) {
+ this.dbFactory = dbFactory;
+ }
+
+ public boolean isSerializeFormatted() {
+ return serializeFormatted;
+ }
+
+ public void setSerializeFormatted(boolean serializeFormatted) {
+ this.serializeFormatted = serializeFormatted;
+ }
+
+}
diff --git a/okhttps-xml/src/main/java/com/ejlchina/okhttps/XmlUtils.java b/okhttps-xml/src/main/java/com/ejlchina/okhttps/XmlUtils.java
new file mode 100644
index 00000000..cd880fdf
--- /dev/null
+++ b/okhttps-xml/src/main/java/com/ejlchina/okhttps/XmlUtils.java
@@ -0,0 +1,235 @@
+package com.ejlchina.okhttps;
+
+import com.ejlchina.okhttps.Platform;
+import org.w3c.dom.Element;
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class XmlUtils {
+
+
+ public static List children(Element element) {
+ NodeList nodes = element.getChildNodes();
+ List list = new ArrayList<>();
+ for (int i = 0; i < nodes.getLength(); i++) {
+ Node node = nodes.item(i);
+ if (node instanceof Element) {
+ list.add((Element) node);
+ }
+ }
+ return list;
+ }
+
+ public static Element findElement(List nodes, String[] nameKeys, String key) {
+ for (Element node : nodes) {
+ if (nodeNameEquals(node, key)) {
+ return node;
+ }
+ }
+ for (String nameKey : nameKeys) {
+ for (Element node : nodes) {
+ if (elementKeyEquals(node, nameKey, key)) {
+ return node;
+ }
+ }
+ }
+ return null;
+ }
+
+ public static List findElements(List nodes, String[] nameKeys, String key) {
+ List elements = new ArrayList<>();
+ for (Element node : nodes) {
+ if (nodeNameEquals(node, key)) {
+ elements.add(node);
+ }
+ }
+ if (elements.size() > 0) {
+ return elements;
+ }
+ for (String nameKey : nameKeys) {
+ for (Element node : nodes) {
+ if (elementKeyEquals(node, nameKey, key)) {
+ elements.add(node);
+ }
+ }
+ if (elements.size() > 0) {
+ return elements;
+ }
+ }
+ return elements;
+ }
+
+ public static String value(Element node, String[] valueKeys) {
+ for (String valueKey : valueKeys) {
+ String value = node.getAttribute(valueKey);
+ if (!isBlank(value)) {
+ return value;
+ }
+ }
+ return node.getTextContent();
+ }
+
+ public static boolean nodeNameEquals(Node node, String name) {
+ String nodeName = node.getNodeName();
+ return nameEquals(name, nodeName);
+ }
+
+ public static boolean elementKeyEquals(Element node, String key, String name) {
+ String nodeName = node.getAttribute(key);
+ return nameEquals(name, nodeName);
+ }
+
+ private static boolean nameEquals(String name, String nodeName) {
+ return nodeName.equals(name) || toCamera(nodeName, "-", true).equals(name)
+ || toCamera(nodeName, "_", true).equals(name);
+ }
+
+ /**
+ * 连字符风格转驼峰风格
+ * @param src 源字符串
+ * @param hyphenation 源字符串中的连字符
+ * @param initLetterLower 是否首字母小写
+ */
+ public static String toCamera(String src, String hyphenation, boolean initLetterLower) {
+ if (isBlank(src)) {
+ return src;
+ }
+ StringBuilder sb = new StringBuilder();
+ String[] list = src.split(hyphenation);
+ for (int i = 0; i < list.length; i++) {
+ if (i == 0 && initLetterLower) {
+ sb.append(firstCharToLowerCase(list[i]));
+ } else {
+ sb.append(firstCharToUpperCase(list[i]));
+ }
+ }
+ return sb.toString();
+ }
+
+ /**
+ * 首字母变小写
+ */
+ public static String firstCharToLowerCase(String str) {
+ char firstChar = str.charAt(0);
+ if (firstChar >= 'A' && firstChar <= 'Z') {
+ char[] arr = str.toCharArray();
+ arr[0] += ('a' - 'A');
+ return new String(arr);
+ }
+ return str;
+ }
+
+ /**
+ * 首字母变大写
+ */
+ public static String firstCharToUpperCase(String str) {
+ char firstChar = str.charAt(0);
+ if (firstChar >= 'a' && firstChar <= 'z') {
+ char[] arr = str.toCharArray();
+ arr[0] -= ('a' - 'A');
+ return new String(arr);
+ }
+ return str;
+ }
+
+ /**
+ * 字符串为 null 或者内部字符全部为 ' ' '\t' '\n' '\r' 这四类字符时返回 true
+ */
+ public static boolean isBlank(String str) {
+ if (str == null) {
+ return true;
+ }
+ int len = str.length();
+ if (len == 0) {
+ return true;
+ }
+ for (int i = 0; i < len; i++) {
+ switch (str.charAt(i)) {
+ case ' ':
+ case '\t':
+ case '\n':
+ case '\r':
+ break;
+ default:
+ return false;
+ }
+ }
+ return true;
+ }
+
+ public static boolean toBoolean(String s) {
+ return s != null && (s.equalsIgnoreCase("true")
+ || s.equalsIgnoreCase("yes")
+ || s.equalsIgnoreCase("on")
+ || s.equalsIgnoreCase("y")
+ || s.equalsIgnoreCase("t"));
+ }
+
+ public static int toInt(String s) {
+ if (s != null) {
+ try {
+ s = s.replace(",", "");
+ if (s.startsWith("0x")) {
+ return Integer.parseInt(s.substring(2), 16);
+ }
+ if (s.startsWith("0b")) {
+ return Integer.parseInt(s.substring(2), 2);
+ }
+ if (s.startsWith("0") && !s.startsWith("0.")) {
+ return Integer.parseInt(s.substring(1), 8);
+ }
+ return Integer.parseInt(s);
+ } catch (NumberFormatException e) {
+ Platform.logError("无法将字符串\"" + s + "\"转换为 Int 数字");
+ }
+ }
+ return 0;
+ }
+
+ public static long toLong(String s) {
+ if (s != null) {
+ try {
+ s = s.replace(",", "");
+ if (s.startsWith("0x")) {
+ return Long.parseLong(s.substring(2), 16);
+ }
+ if (s.startsWith("0b")) {
+ return Long.parseLong(s.substring(2), 2);
+ }
+ if (s.startsWith("0") && !s.startsWith("0.")) {
+ return Long.parseLong(s.substring(1), 8);
+ }
+ return Long.parseLong(s);
+ } catch (NumberFormatException e) {
+ Platform.logError("无法将字符串\"" + s + "\"转换为 Long 数字");
+ }
+ }
+ return 0;
+ }
+
+ public static float toFloat(String s) {
+ if (s != null) {
+ try {
+ return Float.parseFloat(s.replace(",", ""));
+ } catch (NumberFormatException e) {
+ Platform.logError("无法将字符串\"" + s + "\"转换为 Float 数字");
+ }
+ }
+ return 0;
+ }
+
+ public static double toDouble(String s) {
+ if (s != null) {
+ try {
+ return Double.parseDouble(s.replace(",", ""));
+ } catch (NumberFormatException e) {
+ Platform.logError("无法将字符串\"" + s + "\"转换为 Float 数字");
+ }
+ }
+ return 0;
+ }
+
+}
diff --git a/okhttps-xml/src/main/resources/META-INF/services/com.ejlchina.okhttps.ConvertProvider b/okhttps-xml/src/main/resources/META-INF/services/com.ejlchina.okhttps.ConvertProvider
new file mode 100644
index 00000000..38e8a3e4
--- /dev/null
+++ b/okhttps-xml/src/main/resources/META-INF/services/com.ejlchina.okhttps.ConvertProvider
@@ -0,0 +1 @@
+com.ejlchina.okhttps.XmlMsgConvertor
\ No newline at end of file
diff --git a/okhttps-xml/src/test/java/com/ejlchina/okhttps/TestCases.java b/okhttps-xml/src/test/java/com/ejlchina/okhttps/TestCases.java
new file mode 100644
index 00000000..d1c97773
--- /dev/null
+++ b/okhttps-xml/src/test/java/com/ejlchina/okhttps/TestCases.java
@@ -0,0 +1,15 @@
+package com.ejlchina.okhttps;
+
+import com.ejlchina.okhttps.test.XmlTestCases;
+import org.junit.Test;
+
+public class TestCases {
+
+ @Test
+ public void doTest() throws Exception {
+ MsgConvertor msgConvertor = new XmlMsgConvertor();
+ new XmlTestCases(msgConvertor).run();
+ }
+
+}
+
diff --git a/okhttps/.gitignore b/okhttps/.gitignore
new file mode 100644
index 00000000..b83d2226
--- /dev/null
+++ b/okhttps/.gitignore
@@ -0,0 +1 @@
+/target/
diff --git a/okhttps/README.md b/okhttps/README.md
index 4950d947..760b0159 100644
--- a/okhttps/README.md
+++ b/okhttps/README.md
@@ -9,16 +9,16 @@
```xml
- cn.zhxu
+ com.ejlchina
okhttps
- 3.5.3
+ 2.5.0
```
##### Gradle
```groovy
-implementation 'cn.zhxu:okhttps:3.5.3'
+implementation 'com.ejlchina:okhttps:2.5.0'
```
-#### 更多请参阅 [https://ok.zhxu.cn/](https://ok.zhxu.cn/)
+#### 更多请参阅 [http://okhttps.ejlchina.com/](http://okhttps.ejlchina.com/)
diff --git a/okhttps/pom.xml b/okhttps/pom.xml
index be91b92b..36d358aa 100644
--- a/okhttps/pom.xml
+++ b/okhttps/pom.xml
@@ -6,32 +6,16 @@
jar
- cn.zhxu
+ com.ejlchina
okhttps-parent
- 4.1.0
+ 2.5.0
-
- cn.zhxu
- data-core
- ${data.version}
-
com.squareup.okhttp3
okhttp
${okhttp.version}
-
-
- okio
- com.squareup.okio
-
-
-
-
- com.squareup.okio
- okio
- ${okio.version}
com.squareup.okhttp3
diff --git a/okhttps/src/main/java/cn/zhxu/okhttps/BodyPara.java b/okhttps/src/main/java/cn/zhxu/okhttps/BodyPara.java
deleted file mode 100644
index ca88bd81..00000000
--- a/okhttps/src/main/java/cn/zhxu/okhttps/BodyPara.java
+++ /dev/null
@@ -1,25 +0,0 @@
-package cn.zhxu.okhttps;
-
-/**
- * 请求体表单参数
- * @since v4.1.0
- */
-public class BodyPara {
-
- private final String type;
- private final Object value;
-
- public BodyPara(String type, Object value) {
- this.type = type;
- this.value = value;
- }
-
- public String getType() {
- return type;
- }
-
- public Object getValue() {
- return value;
- }
-
-}
diff --git a/okhttps/src/main/java/cn/zhxu/okhttps/DownloadHelper.java b/okhttps/src/main/java/cn/zhxu/okhttps/DownloadHelper.java
deleted file mode 100644
index 37dfac6d..00000000
--- a/okhttps/src/main/java/cn/zhxu/okhttps/DownloadHelper.java
+++ /dev/null
@@ -1,135 +0,0 @@
-package cn.zhxu.okhttps;
-
-import java.io.File;
-import java.io.UnsupportedEncodingException;
-import java.net.URLDecoder;
-import java.nio.charset.StandardCharsets;
-import java.util.HashMap;
-import java.util.Map;
-
-/**
- * 下载助手,用户解析下载路径与文件名
- */
-public class DownloadHelper {
-
- private Map extMappings = new HashMap<>();
-
-
- public DownloadHelper() {
- extMappings.put("text/plain", "txt");
- extMappings.put("audio/mpeg", "mp3");
- extMappings.put("video/mpeg4", "mp4");
- extMappings.put("video/quicktime", "mov");
- extMappings.put("application/x-genesis-rom", "md");
- extMappings.put("application/x-xls", "xls");
- extMappings.put("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", "xlsx");
- extMappings.put("application/vnd.android.package-archive", "apk");
- extMappings.put("application/msword", "doc");
- extMappings.put("application/vnd.openxmlformats-officedocument.wordprocessingml.document", "docx");
- extMappings.put("application/x-java-archive", "jar");
- extMappings.put("application/x-zip-compressed", "zip");
- extMappings.put("application/x-compressed-tar", "tar.gz");
- extMappings.put("application/x-rar", "rar");
- }
-
- /**
- * 解析下载文件名
- * @param result HTTP 响应结果
- * @return 文件名
- */
- public String resolveFileName(HttpResult result) {
- String contentDisposition = result.getHeader("Content-Disposition");
- // 通过 Content-Disposition 获取文件名,这点跟服务器有关,需要灵活变通
- if (contentDisposition == null || contentDisposition.length() < 1) {
- String urlPath = result.getTask().getUrl();
- String urlName = urlPath.substring(urlPath.lastIndexOf("/") + 1);
- return toFileName(urlName, result).replaceAll("[\"\\\\]", "");
- }
- try {
- String filename = URLDecoder.decode(contentDisposition.substring(
- contentDisposition.indexOf("filename=") + 9), StandardCharsets.UTF_8.name());
- // 有些文件名会被包含在""里面,所以要去掉,不然无法读取文件后缀
- // 同时去掉 / 与 \ 符,避免发生目录穿越问题:https://github.com/troyzhxu/okhttps/issues/89
- return filename.replaceAll("[\"/\\\\]", "");
- } catch (UnsupportedEncodingException e) {
- throw new IllegalStateException(e);
- }
- }
-
- public String toFileName(String name, HttpResult result) {
- int dotIdx = name.lastIndexOf('.');
- if (dotIdx > -1 && dotIdx < name.length() - 1) {
- return name;
- }
- // 获取文件扩展名
- String ext = getExt(result.getHeader("Content-Type"));
- if (ext != null) {
- if (dotIdx == -1) {
- return name + "." + ext;
- }
- return name + ext;
- }
- return name;
- }
-
-
- public String getExt(String contentType) {
- String ext = extMappings.get(contentType);
- if (ext == null) {
- int i = contentType.indexOf('/');
- if (i > 0 && i < contentType.length() - 1) {
- return contentType.substring(i + 1);
- }
- }
- return ext;
- }
-
- /**
- * 解析文件路径
- * @param dirPath 目录
- * @param fileName 文件名
- * @return 文件路径
- */
- public String resolveFilePath(String dirPath, String fileName) {
- if (dirPath.endsWith("\\") || dirPath.endsWith("/")) {
- return dirPath + fileName;
- }
- return dirPath + File.separator + fileName;
- }
-
- /**
- * 当文件已存在时,根据该方法生成一个新的文件名
- * @param fileName 原文件名
- * @param index 重复次数
- * @return 新的文件名
- */
- public String indexFileName(String fileName, int index) {
- int i = fileName.lastIndexOf('.');
- if (i < 0) {
- return fileName + "(" + index + ")";
- }
- String ext = fileName.substring(i);
- if (i > 0) {
- String name = fileName.substring(0, i);
- return name + "(" + index + ")" + ext;
- }
- return "(" + index + ")" + ext;
- }
-
- public Map getExtMappings() {
- return extMappings;
- }
-
- public void setExtMappings(Map extMappings) {
- this.extMappings = extMappings;
- }
-
- public void addExtMappings(Map extMappings) {
- this.extMappings.putAll(extMappings);
- }
-
- public void addExtMapping(String mediaType, String ext) {
- extMappings.put(mediaType, ext);
- }
-
-}
diff --git a/okhttps/src/main/java/cn/zhxu/okhttps/FilePara.java b/okhttps/src/main/java/cn/zhxu/okhttps/FilePara.java
deleted file mode 100644
index 6c8443eb..00000000
--- a/okhttps/src/main/java/cn/zhxu/okhttps/FilePara.java
+++ /dev/null
@@ -1,86 +0,0 @@
-package cn.zhxu.okhttps;
-
-import cn.zhxu.okhttps.internal.StreamRequestBody;
-import okhttp3.MediaType;
-import okhttp3.RequestBody;
-
-import java.io.File;
-import java.io.InputStream;
-import java.util.Arrays;
-
-/**
- * @since 2.5.0 从 HttpTask 中分离
- */
-public class FilePara {
-
- private final String type;
- private final String fileName;
- private final byte[] content;
- private final File file;
- private final InputStream stream;
-
- public FilePara(String type, String fileName, byte[] content) {
- this(type, fileName, null, content, null);
- }
-
- public FilePara(String type, String fileName, File file) {
- this(type, fileName, file, null, null);
- }
-
- public FilePara(String type, String fileName, InputStream stream) {
- this(type, fileName, null, null, stream);
- }
-
- private FilePara(String type, String fileName, File file, byte[] content, InputStream stream) {
- this.type = type;
- this.fileName = fileName;
- this.file = file;
- this.content = content;
- this.stream = stream;
- }
-
- public RequestBody toRequestBody(MediaType contentType) {
- if (file != null) {
- return RequestBody.create(contentType, file);
- }
- if (content != null) {
- return RequestBody.create(contentType, content);
- }
- if (stream != null) {
- return new StreamRequestBody(contentType, stream);
- }
- throw new IllegalStateException("Invalid FilePara");
- }
-
- public String getType() {
- return type;
- }
-
- public String getFileName() {
- return fileName;
- }
-
- public byte[] getContent() {
- return content;
- }
-
- public File getFile() {
- return file;
- }
-
- public InputStream getStream() {
- return stream;
- }
-
- @Override
- public String toString() {
- return "FilePara{" +
- "type='" + type + '\'' +
- ", fileName='" + fileName + '\'' +
- ", content=" + Arrays.toString(content) +
- ", file=" + file +
- ", stream=" + stream +
- '}';
- }
-
-}
diff --git a/okhttps/src/main/java/cn/zhxu/okhttps/HTTP.java b/okhttps/src/main/java/cn/zhxu/okhttps/HTTP.java
deleted file mode 100644
index 910d87f0..00000000
--- a/okhttps/src/main/java/cn/zhxu/okhttps/HTTP.java
+++ /dev/null
@@ -1,335 +0,0 @@
-package cn.zhxu.okhttps;
-
-import cn.zhxu.okhttps.okhttp.OkHttpBuilderImpl;
-import okhttp3.WebSocket;
-import okhttp3.*;
-
-import java.io.IOException;
-import java.nio.charset.Charset;
-import java.util.List;
-import java.util.Map;
-import java.util.concurrent.Executor;
-
-/**
- * HTTP 客户端接口
- *
- * @author 15735
- */
-public interface HTTP {
-
- String GET = "GET";
- String HEAD = "HEAD";
- String POST = "POST";
- String PUT = "PUT";
- String PATCH = "PATCH";
- String DELETE = "DELETE";
-
- /**
- * 同步请求
- * @param url 请求地址
- * @return 同步HTTP任务
- */
- SHttpTask sync(String url);
-
- /**
- * 异步请求
- * @param url 请求地址
- * @return 异步HTTP任务
- */
- AHttpTask async(String url);
-
- /**
- * Websocket 连接
- * @param url 连接地址
- * @return WebSocket 任务
- */
- WHttpTask webSocket(String url);
-
- /**
- * 根据标签取消HTTP任务,只要任务的标签包含指定的Tag就会被取消
- * 从 v1.0.2 开始支持取消同步请求
- * @param tag 标签
- * @return 被取消的任务数量
- */
- int cancel(String tag);
-
- /**
- * @since 1.0.2
- * 取消所有HTTP任务,包括同步和异步
- */
- void cancelAll();
-
- /**
- * OkHttp 的 HTTP 原生请求 (该请求不经过 预处理器)
- * @param request 请求
- * @return Call
- */
- Call request(Request request);
-
- /**
- * OkHttp 的 Websocket 原生请求(该请求不经过 预处理器)
- * @param request 请求
- * @param listener 监听器
- * @return Websocket
- */
- WebSocket webSocket(Request request, WebSocketListener listener);
-
- /**
- * 获取任务执行器
- * @return TaskExecutor
- */
- TaskExecutor executor();
-
- /**
- * 新的构建器
- * @return Builder
- */
- Builder newBuilder();
-
- /**
- * HTTP 构建器
- * 自 v3.5.0 起可通过系统环境变量 切换该方法返回的 构建器实现类
- * @return HTTP 构建器
- */
- static Builder builder() {
- String className = System.getProperty(Builder.class.getName());
- if (Platform.isNotBlank(className)) {
- try {
- Class> dClass = Class.forName(className);
- if (Builder.class.isAssignableFrom(dClass)) {
- return (Builder) dClass.getDeclaredConstructor().newInstance();
- } else {
- throw new OkHttpsException("The implementation class [" + className + "] you specified is not a subclass of " + Builder.class.getName());
- }
- } catch (ClassNotFoundException e) {
- throw new OkHttpsException("The implementation class [" + className + "] you specified can not be found", e);
- } catch (NoSuchMethodException e) {
- throw new OkHttpsException("There is none default constructor in [" + className + "] you specified", e);
- } catch (ReflectiveOperationException e) {
- throw new OkHttpsException("[" + className + "] can not be instanced", e);
- }
- }
- return new OkHttpBuilderImpl(); // 默认构建器
- }
-
- /**
- * Http 配置器
- *
- */
- interface OkConfig {
-
- /**
- * 使用 builder 配置 HttpClient
- * @param builder OkHttpClient 构建器
- */
- void config(OkHttpClient.Builder builder);
-
- }
-
- /**
- * HTTP 构建器
- * 自 v3.3.0 开始接口化,在以后版本中将逐步与 okhttp3 解耦
- */
- interface Builder {
-
- /**
- * 自 v3.2.0 后可以多次调用
- * 配置 OkHttpClient
- * @param config 配置器
- * @return Builder
- */
- Builder config(OkConfig config);
-
- /**
- * 设置 baseUrl
- * @param baseUrl 全局URL前缀
- * @return Builder
- */
- Builder baseUrl(String baseUrl);
-
- String baseUrl();
-
- /**
- * 配置媒体类型
- * @param mediaTypes 媒体类型
- * @return Builder
- */
- Builder mediaTypes(Map mediaTypes);
-
- /**
- * 配置媒体类型
- * @param key 媒体类型KEY
- * @param value 媒体类型VALUE
- * @return Builder
- */
- Builder mediaTypes(String key, String value);
-
- Map getMediaTypes();
-
- /**
- * 清空 ContentType
- * @return Builder
- * @since v3.5.0
- */
- HTTP.Builder clearContentTypes();
-
- /**
- * 配置支持的报文体类型
- * @param contentTypes 报文体类型列表
- * @return Builder
- */
- Builder contentTypes(List contentTypes);
-
- /**
- * 配置支持的报文体类型
- * @param contentType 报文体类型
- * @return Builder
- */
- Builder contentTypes(String contentType);
-
- String[] contentTypes();
-
- /**
- * 设置回调执行器,例如实现切换线程功能,只对异步请求有效
- * @param executor 回调执行器
- * @return Builder
- */
- Builder callbackExecutor(Executor executor);
-
- Executor mainExecutor();
-
- /**
- * 配置 任务调度器,可用的调度由 {@link WHttpTask#heatbeat(int, int) } 指定的心跳任务
- * 若不配置,则生成一个 线程容量为 1 的 ScheduledThreadPoolExecutor 调度器
- * @since v2.3.0
- * @param scheduler 调度器
- * @return Builder
- */
- Builder taskScheduler(Scheduler scheduler);
-
- Scheduler taskScheduler();
-
- /**
- * 添加可并行处理请求任务的预处理器
- * @param preprocessor 预处理器
- * @return Builder
- */
- Builder addPreprocessor(Preprocessor preprocessor);
-
- /**
- * 添加串行预处理器
- * @param preprocessor 预处理器
- * @return Builder
- */
- Builder addSerialPreprocessor(Preprocessor preprocessor);
-
- /**
- * 清空预处理器(包括串行预处理器)
- * @since v2.5.0
- * @return Builder
- */
- Builder clearPreprocessors();
-
- Preprocessor[] preprocessors();
-
- /**
- * 最大预处理时间(倍数,相当普通请求的超时时间)
- * @param times 普通超时时间的倍数,默认为 10
- * @return Builder
- */
- Builder preprocTimeoutTimes(int times);
-
- int preprocTimeoutTimes();
-
- /**
- * 设置全局响应监听
- * @param listener 监听器
- * @return Builder
- */
- Builder responseListener(TaskListener listener);
-
- TaskListener responseListener();
-
- /**
- * 设置全局异常监听
- * @param listener 监听器
- * @return Builder
- */
- Builder exceptionListener(TaskListener listener);
-
- TaskListener exceptionListener();
-
- /**
- * 设置全局完成监听
- * @param listener 监听器
- * @return Builder
- */
- Builder completeListener(TaskListener listener);
-
- TaskListener completeListener();
-
- /**
- * 设置下载监听器
- * @param listener 监听器
- * @return Builder
- */
- Builder downloadListener(DownListener listener);
-
- DownListener downloadListener();
-
- /**
- * @since v2.0.0
- * 添加消息转换器
- * @param msgConvertor JSON 服务
- * @return Builder
- */
- Builder addMsgConvertor(MsgConvertor msgConvertor);
-
- /**
- * 清空消息转换器
- * @since v2.5.0
- * @return Builder
- */
- Builder clearMsgConvertors();
-
- MsgConvertor[] msgConvertors();
-
- /**
- * @since v2.0.0
- * 设置默认编码格式
- * @param charset 编码
- * @return Builder
- */
- Builder charset(Charset charset);
-
- Charset charset();
-
- /**
- * @since v2.0.0
- * 设置默认请求体类型
- * @param bodyType 请求体类型
- * @return Builder
- */
- Builder bodyType(String bodyType);
-
- String bodyType();
-
- /**
- * @since v3.4.2
- * 设置下载文件名解析器
- * @param resolver 解析器
- * @return Builder
- */
- Builder downloadHelper(DownloadHelper resolver);
-
- DownloadHelper downloadHelper();
-
- /**
- * 构建 HTTP 实例
- * @return HTTP
- */
- HTTP build();
-
- }
-
-}
diff --git a/okhttps/src/main/java/cn/zhxu/okhttps/MsgConvertor.java b/okhttps/src/main/java/cn/zhxu/okhttps/MsgConvertor.java
deleted file mode 100644
index 090660f7..00000000
--- a/okhttps/src/main/java/cn/zhxu/okhttps/MsgConvertor.java
+++ /dev/null
@@ -1,108 +0,0 @@
-package cn.zhxu.okhttps;
-
-import cn.zhxu.data.Array;
-import cn.zhxu.data.DataConvertor;
-import cn.zhxu.data.DataSet;
-import cn.zhxu.data.Mapper;
-
-import java.io.ByteArrayInputStream;
-import java.io.InputStream;
-import java.io.UnsupportedEncodingException;
-import java.lang.reflect.Type;
-import java.net.URLEncoder;
-import java.nio.charset.Charset;
-import java.util.List;
-
-/**
- * 消息转换器接口
- */
-public interface MsgConvertor extends DataConvertor {
-
- /**
- * 消息的媒体类型
- * @return 媒体类型
- */
- String mediaType();
-
- /**
- * 表单转换器,可用于自动序列化表单参数
- */
- class FormConvertor implements MsgConvertor {
-
- private final DataConvertor convertor;
- private final boolean urlEncoded;
-
- public FormConvertor(DataConvertor convertor) {
- this(convertor, false);
- }
-
- /**
- * @param convertor DataConvertor
- * @param urlEncoded 是否进行 URLEncode 编码
- */
- public FormConvertor(DataConvertor convertor, boolean urlEncoded) {
- this.convertor = convertor;
- this.urlEncoded = urlEncoded;
- }
-
- @Override
- public String mediaType() {
- return "application/x-www-form-urlencoded";
- }
-
- @Override
- public Mapper toMapper(InputStream in, Charset charset) {
- return convertor.toMapper(in, charset);
- }
-
- @Override
- public Array toArray(InputStream in, Charset charset) {
- return convertor.toArray(in, charset);
- }
-
- @Override
- public byte[] serialize(Object object, Charset charset, boolean pretty) {
- byte[] result = convertor.serialize(object, charset);
- Mapper mapper = convertor.toMapper(new ByteArrayInputStream(result), charset);
- StringBuilder sb = new StringBuilder();
- mapper.forEach((key, data) -> {
- String value = encodeValue(data, charset);
- sb.append(key).append('=').append(value).append('&');
- });
- int endIndex = sb.length() > 1 ? sb.length() - 1 : sb.length();
- return sb.substring(0, endIndex).getBytes(charset);
- }
-
- private String encodeValue(DataSet.Data data, Charset charset) {
- String value = data.toString();
- if (urlEncoded) {
- try {
- return URLEncoder.encode(value, charset.name());
- } catch (UnsupportedEncodingException e) {
- throw new OkHttpsException("UnsupportedEncoding: " + charset.name(), e);
- }
- }
- return value;
- }
-
- @Override
- public T toBean(Type type, InputStream in, Charset charset) {
- return convertor.toBean(type, in, charset);
- }
-
- @Override
- public List toList(Class type, InputStream in, Charset charset) {
- return convertor.toList(type, in, charset);
- }
-
- public DataConvertor getConvertor() {
- return convertor;
- }
-
- public boolean isUrlEncoded() {
- return urlEncoded;
- }
-
- }
-
-}
diff --git a/okhttps/src/main/java/cn/zhxu/okhttps/Process.java b/okhttps/src/main/java/cn/zhxu/okhttps/Process.java
deleted file mode 100644
index 65c8b73a..00000000
--- a/okhttps/src/main/java/cn/zhxu/okhttps/Process.java
+++ /dev/null
@@ -1,34 +0,0 @@
-package cn.zhxu.okhttps;
-
-/**
- * 进度(上传或下载)
- */
-public interface Process {
-
- int DEFAULT_STEP_BYTES = 8192;
-
- /**
- * 当请求体大小未知(流式上传)时,该方法始终返回 -1
- * 当请求体大小为 0 时,该方法始终返回 1
- * @return 完成比例
- */
- double getRate();
-
- /**
- * 当请求体大小未知(流式上传)时,该方法返回 -1
- * @return 总字节数
- */
- long getTotalBytes();
-
- /**
- * @return 已完成字节数
- */
- long getDoneBytes();
-
- /**
- * 只有当 当请求体大小已知 的情况下,该方法才可能返回 true
- * @return 任务是否完成
- */
- boolean isDone();
-
-}
diff --git a/okhttps/src/main/java/cn/zhxu/okhttps/internal/FixedRequestBody.java b/okhttps/src/main/java/cn/zhxu/okhttps/internal/FixedRequestBody.java
deleted file mode 100644
index 89eb7d34..00000000
--- a/okhttps/src/main/java/cn/zhxu/okhttps/internal/FixedRequestBody.java
+++ /dev/null
@@ -1,53 +0,0 @@
-package cn.zhxu.okhttps.internal;
-
-import okhttp3.MediaType;
-import okhttp3.RequestBody;
-import okio.BufferedSink;
-
-import java.io.IOException;
-
-/**
- * 修复报文体在写出过程中会发生无法被异常回调捕获的非 IO 异常的问题
- * @author Troy.Zhou @ 2021-09-01
- * @since v3.1.5
- */
-public class FixedRequestBody extends RequestBody {
-
- private final RequestBody requestBody;
-
- public FixedRequestBody(RequestBody requestBody) {
- this.requestBody = requestBody;
- }
-
- @Override
- public long contentLength() throws IOException {
- return requestBody.contentLength();
- }
-
- @Override
- public boolean isDuplex() {
- return requestBody.isDuplex();
- }
-
- @Override
- public boolean isOneShot() {
- return requestBody.isOneShot();
- }
-
- @Override
- public MediaType contentType() {
- return requestBody.contentType();
- }
-
- @Override
- public void writeTo(@SuppressWarnings("NullableProblems") BufferedSink sink) throws IOException {
- try {
- requestBody.writeTo(sink);
- } catch (IOException e) {
- throw e;
- } catch (Exception e) {
- throw new IOException("请求体写出异常", e);
- }
- }
-
-}
diff --git a/okhttps/src/main/java/cn/zhxu/okhttps/internal/ProcessInputStream.java b/okhttps/src/main/java/cn/zhxu/okhttps/internal/ProcessInputStream.java
deleted file mode 100644
index ec828e5b..00000000
--- a/okhttps/src/main/java/cn/zhxu/okhttps/internal/ProcessInputStream.java
+++ /dev/null
@@ -1,87 +0,0 @@
-package cn.zhxu.okhttps.internal;
-
-import cn.zhxu.okhttps.Process;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.util.concurrent.Executor;
-import java.util.function.Consumer;
-
-public class ProcessInputStream extends InputStream {
-
- private final InputStream input;
- private final Consumer onProcess;
- private final Executor callbackExecutor;
- private final long stepBytes;
- private final RealProcess process;
- private boolean doneCalled = false;
- private long step;
-
- public ProcessInputStream(InputStream input, Consumer onProcess, long totalBytes, long stepBytes,
- long doneBytes, Executor callbackExecutor) {
- this.input = input;
- this.onProcess = onProcess;
- this.stepBytes = stepBytes;
- this.callbackExecutor = callbackExecutor;
- this.process = new RealProcess(totalBytes, doneBytes);
- this.step = doneBytes / stepBytes;
- }
-
- @Override
- public int read() throws IOException {
- byte[] buf = new byte[1];
- int count = read(buf, 0, 1);
- if (count > 0) {
- return buf[0];
- }
- return -1;
- }
-
- @Override
- public int read(@SuppressWarnings("NullableProblems") byte[] buf, int off, int len) throws IOException {
- int total = 0;
- while (total < len) {
- // 一次读取长度
- int length = Math.min(len - total, (int) stepBytes);
- int read = input.read(buf, off + total, length);
- if (read == -1) {
- // 已经读完
- if (total == 0) {
- return read;
- }
- break;
- }
- updateProcess(read);
- total += read;
- }
- return total;
- }
-
- private void updateProcess(long count) {
- process.addDoneBytes(count);
- if (process.isUndoneAndUnreached(step * stepBytes)) {
- return;
- }
- if (process.isDone()) {
- if (doneCalled) {
- return;
- }
- doneCalled = true;
- }
- step = (process.getDoneBytes() - 1) / stepBytes + 1;
- // 因为 process 一直被更新,所有此处应克隆一个新的对象用于回调
- Process p = process.newProcess();
- callbackExecutor.execute(() -> onProcess.accept(p));
- }
-
- @Override
- public int available() throws IOException {
- return input.available();
- }
-
- @Override
- public void close() throws IOException {
- input.close();
- }
-
-}
diff --git a/okhttps/src/main/java/cn/zhxu/okhttps/internal/ProcessRequestBody.java b/okhttps/src/main/java/cn/zhxu/okhttps/internal/ProcessRequestBody.java
deleted file mode 100644
index c7533d4b..00000000
--- a/okhttps/src/main/java/cn/zhxu/okhttps/internal/ProcessRequestBody.java
+++ /dev/null
@@ -1,74 +0,0 @@
-package cn.zhxu.okhttps.internal;
-
-import cn.zhxu.okhttps.Process;
-import okhttp3.RequestBody;
-import okio.*;
-
-import java.io.IOException;
-import java.util.concurrent.Executor;
-import java.util.function.Consumer;
-
-public class ProcessRequestBody extends FixedRequestBody {
-
- private final Consumer onProcess;
- private final Executor callbackExecutor;
- private final RealProcess process;
- private final long stepBytes;
-
- public ProcessRequestBody(RequestBody requestBody, Consumer onProcess, Executor callbackExecutor,
- long contentLength, long stepBytes) {
- super(requestBody);
- this.onProcess = onProcess;
- this.callbackExecutor = callbackExecutor;
- this.stepBytes = stepBytes;
- this.process = new RealProcess(contentLength, 0);
- }
-
- class ProcessableSink extends ForwardingSink {
-
- private long step = 0;
- private boolean doneCalled = false;
-
- public ProcessableSink(Sink delegate) {
- super(delegate);
- }
-
- @Override
- public void write(Buffer source, long byteCount) throws IOException {
- // byteCount 可能很大,也可能很小
- long written = 0;
- while (written < byteCount) {
- long count = Math.min(stepBytes, byteCount - written);
- super.write(source, count);
- updateProcess(count);
- written += count;
- }
- }
-
- private void updateProcess(long count) {
- process.addDoneBytes(count);
- if (process.isUndoneAndUnreached(step * stepBytes)) {
- return;
- }
- if (process.isDone()) {
- if (doneCalled) {
- return;
- }
- doneCalled = true;
- }
- step = (process.getDoneBytes() - 1) / stepBytes + 1;
- // 因为 process 一直被更新,所有此处应克隆一个新的对象用于回调
- Process p = process.newProcess();
- callbackExecutor.execute(() -> onProcess.accept(p));
- }
-
- }
-
- @Override
- public void writeTo(BufferedSink sink) throws IOException {
- BufferedSink buffer = Okio.buffer(new ProcessableSink(sink));
- super.writeTo(buffer);
- buffer.flush();
- }
-
-}
diff --git a/okhttps/src/main/java/cn/zhxu/okhttps/internal/RealProcess.java b/okhttps/src/main/java/cn/zhxu/okhttps/internal/RealProcess.java
deleted file mode 100644
index c9a925ed..00000000
--- a/okhttps/src/main/java/cn/zhxu/okhttps/internal/RealProcess.java
+++ /dev/null
@@ -1,60 +0,0 @@
-package cn.zhxu.okhttps.internal;
-
-import cn.zhxu.okhttps.Process;
-
-public class RealProcess implements Process {
-
- // 总字节数(流式上传时该字段为 -1)
- private final long totalBytes;
- // 已经完成字节数
- private long doneBytes;
-
- public RealProcess(long totalBytes, long doneBytes) {
- this.totalBytes = totalBytes;
- this.doneBytes = doneBytes;
- }
-
- public Process newProcess() {
- return new RealProcess(totalBytes, doneBytes);
- }
-
- @Override
- public double getRate() {
- if (totalBytes == 0) {
- return 1;
- }
- if (totalBytes < 0) {
- return -1;
- }
- return (double) doneBytes / totalBytes;
- }
-
- @Override
- public long getTotalBytes() {
- return totalBytes;
- }
-
- @Override
- public long getDoneBytes() {
- return doneBytes;
- }
-
- @Override
- public boolean isDone() {
- return doneBytes >= totalBytes && totalBytes >= 0;
- }
-
- public void addDoneBytes(long delt) {
- doneBytes += delt;
- }
-
- public boolean isUndoneAndUnreached(long bytes) {
- return doneBytes < bytes && (totalBytes < 0 || doneBytes < totalBytes);
- }
-
- @Override
- public String toString() {
- return "Process[" + doneBytes + " / " + totalBytes + " | " + getRate() + ']';
- }
-
-}
diff --git a/okhttps/src/main/java/cn/zhxu/okhttps/internal/SerialPreprocessor.java b/okhttps/src/main/java/cn/zhxu/okhttps/internal/SerialPreprocessor.java
deleted file mode 100644
index 388a4cb8..00000000
--- a/okhttps/src/main/java/cn/zhxu/okhttps/internal/SerialPreprocessor.java
+++ /dev/null
@@ -1,56 +0,0 @@
-package cn.zhxu.okhttps.internal;
-
-import cn.zhxu.okhttps.Preprocessor;
-
-import java.util.LinkedList;
-import java.util.Queue;
-
-/**
- * 串行预处理器
- * @author Troy.Zhou
- */
-public class SerialPreprocessor implements Preprocessor {
-
- // 预处理器
- final Preprocessor preprocessor;
- // 待处理的任务队列
- final Queue pendings;
- // 是否有任务正在执行
- boolean running = false;
-
- public SerialPreprocessor(Preprocessor preprocessor) {
- this.preprocessor = preprocessor;
- this.pendings = new LinkedList<>();
- }
-
- @Override
- public void doProcess(Preprocessor.PreChain chain) {
- boolean should = true;
- synchronized (this) {
- if (running) {
- pendings.add(chain);
- should = false;
- } else {
- running = true;
- }
- }
- if (should) {
- preprocessor.doProcess(chain);
- }
- }
-
- public void afterProcess() {
- Preprocessor.PreChain chain = null;
- synchronized (this) {
- if (pendings.size() > 0) {
- chain = pendings.poll();
- } else {
- running = false;
- }
- }
- if (chain != null) {
- preprocessor.doProcess(chain);
- }
- }
-
-}
diff --git a/okhttps/src/main/java/cn/zhxu/okhttps/internal/StreamRequestBody.java b/okhttps/src/main/java/cn/zhxu/okhttps/internal/StreamRequestBody.java
deleted file mode 100644
index 2e17e12b..00000000
--- a/okhttps/src/main/java/cn/zhxu/okhttps/internal/StreamRequestBody.java
+++ /dev/null
@@ -1,45 +0,0 @@
-package cn.zhxu.okhttps.internal;
-
-import okhttp3.MediaType;
-import okhttp3.RequestBody;
-import okio.BufferedSink;
-import okio.Okio;
-
-import java.io.IOException;
-import java.io.InputStream;
-
-/**
- * 流式请求体
- * @author Troy.Zhou @ 2021-09-01
- * @since v3.5.0
- */
-public class StreamRequestBody extends RequestBody {
-
- private final MediaType contentType;
- private final InputStream inputStream;
-
- public StreamRequestBody(MediaType contentType, InputStream inputStream) {
- this.contentType = contentType;
- this.inputStream = inputStream;
- }
-
- @Override
- public MediaType contentType() {
- return contentType;
- }
-
- @Override
- public void writeTo(BufferedSink sink) throws IOException {
- try {
- sink.writeAll(Okio.source(inputStream));
- } finally {
- inputStream.close();
- }
- }
-
- @Override
- public boolean isOneShot() {
- return true;
- }
-
-}
diff --git a/okhttps/src/main/java/cn/zhxu/okhttps/okhttp/OkHttpBuilderImpl.java b/okhttps/src/main/java/cn/zhxu/okhttps/okhttp/OkHttpBuilderImpl.java
deleted file mode 100644
index 4d691ec7..00000000
--- a/okhttps/src/main/java/cn/zhxu/okhttps/okhttp/OkHttpBuilderImpl.java
+++ /dev/null
@@ -1,335 +0,0 @@
-package cn.zhxu.okhttps.okhttp;
-
-import cn.zhxu.okhttps.*;
-import cn.zhxu.okhttps.internal.CopyInterceptor;
-import cn.zhxu.okhttps.internal.SerialPreprocessor;
-import okhttp3.Interceptor;
-import okhttp3.OkHttpClient;
-
-import java.io.IOException;
-import java.nio.charset.Charset;
-import java.nio.charset.StandardCharsets;
-import java.util.*;
-import java.util.concurrent.Executor;
-
-
-public class OkHttpBuilderImpl implements HTTP.Builder {
-
- private OkHttpClient okClient;
-
- private String baseUrl;
-
- private final List configs;
-
- private final Map mediaTypes;
-
- private final List contentTypes;
-
- private final List msgConvertors;
-
- private final List preprocessors;
-
- private int preprocTimeoutTimes = 10;
-
- private Executor mainExecutor;
-
- private Scheduler taskScheduler;
-
- private DownListener downloadListener;
-
- private TaskListener responseListener;
-
- private TaskListener exceptionListener;
-
- private TaskListener completeListener;
-
- private Charset charset = StandardCharsets.UTF_8;
-
- private String bodyType = OkHttps.FORM;
-
- private DownloadHelper downloadHelper;
-
- public OkHttpBuilderImpl() {
- mediaTypes = new HashMap<>();
- mediaTypes.put("png", "image/png");
- mediaTypes.put("jpg", "image/jpeg");
- mediaTypes.put("jpeg", "image/jpeg");
- mediaTypes.put("wav", "audio/wav");
- mediaTypes.put("mp3", "audio/mp3");
- mediaTypes.put("mp4", "video/mp4");
- mediaTypes.put("txt", "text/plain");
- mediaTypes.put("xls", "application/x-xls");
- mediaTypes.put("xlsx", "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
- mediaTypes.put("xml", "text/xml");
- mediaTypes.put("apk", "application/vnd.android.package-archive");
- mediaTypes.put("doc", "application/msword");
- mediaTypes.put("docx", "application/vnd.openxmlformats-officedocument.wordprocessingml.document");
- mediaTypes.put("html", "text/html");
- mediaTypes.put("rar", "application/x-rar");
- mediaTypes.put("jar", "application/x-java-archive");
- contentTypes = new ArrayList<>();
- contentTypes.add("application/x-www-form-urlencoded");
- contentTypes.add("application/json");
- contentTypes.add("application/xml");
- contentTypes.add("application/protobuf");
- contentTypes.add("application/msgpack");
- preprocessors = new ArrayList<>();
- msgConvertors = new ArrayList<>();
- configs = new ArrayList<>();
- downloadHelper = new DownloadHelper();
- }
-
- public OkHttpBuilderImpl(OkHttpClientWrapper hc) {
- okClient = hc.okClient();
- baseUrl = hc.baseUrl();
- mediaTypes = hc.mediaTypes();
- preprocessors = new ArrayList<>();
- Collections.addAll(preprocessors, hc.preprocessors());
- TaskExecutor executor = hc.executor();
- contentTypes = new ArrayList<>();
- Collections.addAll(contentTypes, executor.getContentTypes());
- mainExecutor = executor.getMainExecutor();
- taskScheduler = executor.getTaskScheduler();
- downloadListener = executor.getDownloadListener();
- responseListener = executor.getResponseListener();
- exceptionListener = executor.getExceptionListener();
- completeListener = executor.getCompleteListener();
- msgConvertors = new ArrayList<>();
- Collections.addAll(msgConvertors, executor.getMsgConvertors());
- preprocTimeoutTimes = hc.preprocTimeoutTimes();
- configs = new ArrayList<>();
- bodyType = hc.bodyType();
- charset = hc.charset();
- downloadHelper = hc.downloadHelper();
- }
-
-
- public HTTP.Builder config(HTTP.OkConfig config) {
- if (config != null) {
- configs.add(config);
- }
- return this;
- }
-
- public HTTP.Builder baseUrl(String baseUrl) {
- if (baseUrl != null) {
- this.baseUrl = baseUrl.trim();
- }
- return this;
- }
-
- public HTTP.Builder mediaTypes(Map mediaTypes) {
- if (mediaTypes != null) {
- this.mediaTypes.putAll(mediaTypes);
- }
- return this;
- }
-
- public HTTP.Builder mediaTypes(String key, String value) {
- if (key != null && value != null) {
- this.mediaTypes.put(key, value);
- }
- return this;
- }
-
- public HTTP.Builder clearContentTypes() {
- contentTypes.clear();
- return this;
- }
-
- public HTTP.Builder contentTypes(List contentTypes) {
- if (contentTypes != null) {
- this.contentTypes.addAll(contentTypes);
- }
- return this;
- }
-
- public HTTP.Builder contentTypes(String contentType) {
- if (contentType != null) {
- this.contentTypes.add(contentType);
- }
- return this;
- }
-
- public HTTP.Builder callbackExecutor(Executor executor) {
- this.mainExecutor = executor;
- return this;
- }
-
- public HTTP.Builder taskScheduler(Scheduler scheduler) {
- this.taskScheduler = scheduler;
- return this;
- }
-
- public HTTP.Builder addPreprocessor(Preprocessor preprocessor) {
- if (preprocessor != null) {
- preprocessors.add(preprocessor);
- }
- return this;
- }
-
- public HTTP.Builder addSerialPreprocessor(Preprocessor preprocessor) {
- if (preprocessor != null) {
- preprocessors.add(new SerialPreprocessor(preprocessor));
- }
- return this;
- }
-
- public HTTP.Builder clearPreprocessors() {
- preprocessors.clear();
- return this;
- }
-
- public HTTP.Builder preprocTimeoutTimes(int times) {
- if (times > 0) {
- preprocTimeoutTimes = times;
- }
- return this;
- }
-
- public HTTP.Builder responseListener(TaskListener listener) {
- responseListener = listener;
- return this;
- }
-
- public HTTP.Builder exceptionListener(TaskListener listener) {
- exceptionListener = listener;
- return this;
- }
-
- public HTTP.Builder completeListener(TaskListener listener) {
- completeListener = listener;
- return this;
- }
-
- public HTTP.Builder downloadListener(DownListener listener) {
- downloadListener = listener;
- return this;
- }
-
- public HTTP.Builder addMsgConvertor(MsgConvertor msgConvertor) {
- if (msgConvertor != null) {
- msgConvertors.add(msgConvertor);
- }
- return this;
- }
-
- public HTTP.Builder clearMsgConvertors() {
- msgConvertors.clear();
- return this;
- }
-
- public HTTP.Builder charset(Charset charset) {
- if (charset != null) {
- this.charset = charset;
- }
- return this;
- }
-
- public HTTP.Builder bodyType(String bodyType) {
- if (bodyType != null) {
- this.bodyType = bodyType.toLowerCase();
- }
- return this;
- }
-
- public HTTP build() {
- if (configs.size() > 0 || okClient == null) {
- OkHttpClient.Builder builder;
- if (okClient != null) {
- builder = okClient.newBuilder();
- } else {
- builder = new OkHttpClient.Builder();
- }
- for (HTTP.OkConfig config: configs) {
- config.config(builder);
- }
- // fix issue: https://github.com/ejlchina/okhttps/issues/8
- if (needCopyInterceptor(builder.interceptors())) {
- builder.addInterceptor(new CopyInterceptor());
- }
- okClient = builder.build();
- } else if (needCopyInterceptor(okClient.interceptors())) {
- okClient = okClient.newBuilder()
- .addInterceptor(new CopyInterceptor())
- .build();
- }
- return new OkHttpClientWrapper(this);
- }
-
- private boolean needCopyInterceptor(List list) {
- return mainExecutor != null && Platform.ANDROID_SDK_INT > 24 && CopyInterceptor.notIn(list);
- }
-
- public OkHttpClient okClient() {
- return okClient;
- }
-
- public String baseUrl() {
- return baseUrl;
- }
-
- public Map getMediaTypes() {
- return mediaTypes;
- }
-
- public Executor mainExecutor() {
- return mainExecutor;
- }
-
- public Preprocessor[] preprocessors() {
- return preprocessors.toArray(new Preprocessor[0]);
- }
-
- public DownListener downloadListener() {
- return downloadListener;
- }
-
- public TaskListener responseListener() {
- return responseListener;
- }
-
- public TaskListener exceptionListener() {
- return exceptionListener;
- }
-
- public TaskListener completeListener() {
- return completeListener;
- }
-
- public MsgConvertor[] msgConvertors() {
- return msgConvertors.toArray(new MsgConvertor[0]);
- }
-
- public Scheduler taskScheduler() {
- return taskScheduler;
- }
-
- public String[] contentTypes() {
- return contentTypes.toArray(new String[0]);
- }
-
- public int preprocTimeoutTimes() {
- return preprocTimeoutTimes;
- }
-
- public Charset charset() {
- return charset;
- }
-
- public String bodyType() {
- return bodyType;
- }
-
- @Override
- public HTTP.Builder downloadHelper(DownloadHelper downloadHelper) {
- this.downloadHelper = downloadHelper;
- return this;
- }
-
- @Override
- public DownloadHelper downloadHelper() {
- return downloadHelper;
- }
-
-}
diff --git a/okhttps/src/main/java/cn/zhxu/okhttps/okhttp/OkHttpClientWrapper.java b/okhttps/src/main/java/cn/zhxu/okhttps/okhttp/OkHttpClientWrapper.java
deleted file mode 100644
index 14489c93..00000000
--- a/okhttps/src/main/java/cn/zhxu/okhttps/okhttp/OkHttpClientWrapper.java
+++ /dev/null
@@ -1,55 +0,0 @@
-package cn.zhxu.okhttps.okhttp;
-
-import cn.zhxu.okhttps.HTTP;
-import cn.zhxu.okhttps.internal.AbstractHttpClient;
-import okhttp3.*;
-
-import java.util.concurrent.Executor;
-
-
-public class OkHttpClientWrapper extends AbstractHttpClient {
-
- // OkHttpClient
- final OkHttpClient okClient;
-
- public OkHttpClientWrapper(OkHttpBuilderImpl builder) {
- super(builder);
- this.okClient = builder.okClient();
- }
-
- @Override
- public Executor ioExecutor(HTTP.Builder builder) {
- OkHttpBuilderImpl builderImpl = (OkHttpBuilderImpl) builder;
- return builderImpl.okClient().dispatcher().executorService();
- }
-
- @Override
- public void doCancelAll() {
- okClient.dispatcher().cancelAll();
- }
-
- @Override
- public Call request(Request request) {
- return okClient.newCall(request);
- }
-
- @Override
- public WebSocket webSocket(Request request, WebSocketListener listener) {
- return okClient.newWebSocket(request, listener);
- }
-
- public OkHttpClient okClient() {
- return okClient;
- }
-
- @Override
- public int totalTimeoutMillis() {
- return okClient.connectTimeoutMillis() + okClient.writeTimeoutMillis() + okClient.readTimeoutMillis();
- }
-
- @Override
- public HTTP.Builder newBuilder() {
- return new OkHttpBuilderImpl(this);
- }
-
-}
diff --git a/okhttps/src/main/java/com/ejlchina/okhttps/Array.java b/okhttps/src/main/java/com/ejlchina/okhttps/Array.java
new file mode 100644
index 00000000..5c47331d
--- /dev/null
+++ b/okhttps/src/main/java/com/ejlchina/okhttps/Array.java
@@ -0,0 +1,60 @@
+package com.ejlchina.okhttps;
+
+/**
+ * 列表结构的只读数据集
+ *
+ * @since 2.0.0
+ * Array 接口 类似于 JsonArray
+ * 但为什么不取名为 json 呢,因它不止是 json,它还可以是 xml、yml、protobuf 等任何一种格式的数据
+ */
+public interface Array extends DataSet {
+
+ /**
+ * @param index 元素下标
+ * @return 子 JsonObj
+ */
+ Mapper getMapper(int index);
+
+ /**
+ * @param index 元素下标
+ * @return 子 JsonArr
+ */
+ Array getArray(int index);
+
+ /**
+ * @param index 元素下标
+ * @return boolean 值
+ */
+ boolean getBool(int index);
+
+ /**
+ * @param index 元素下标
+ * @return int 值
+ */
+ int getInt(int index);
+
+ /**
+ * @param index 元素下标
+ * @return long 值
+ */
+ long getLong(int index);
+
+ /**
+ * @param index 元素下标
+ * @return float 值
+ */
+ float getFloat(int index);
+
+ /**
+ * @param index 元素下标
+ * @return double 值
+ */
+ double getDouble(int index);
+
+ /**
+ * @param index 元素下标
+ * @return String 值
+ */
+ String getString(int index);
+
+}
diff --git a/okhttps/src/main/java/cn/zhxu/okhttps/Cancelable.java b/okhttps/src/main/java/com/ejlchina/okhttps/Cancelable.java
similarity index 80%
rename from okhttps/src/main/java/cn/zhxu/okhttps/Cancelable.java
rename to okhttps/src/main/java/com/ejlchina/okhttps/Cancelable.java
index e6b3db84..0c81a7ac 100644
--- a/okhttps/src/main/java/cn/zhxu/okhttps/Cancelable.java
+++ b/okhttps/src/main/java/com/ejlchina/okhttps/Cancelable.java
@@ -1,4 +1,4 @@
-package cn.zhxu.okhttps;
+package com.ejlchina.okhttps;
public interface Cancelable {
diff --git a/okhttps/src/main/java/cn/zhxu/okhttps/Config.java b/okhttps/src/main/java/com/ejlchina/okhttps/Config.java
similarity index 67%
rename from okhttps/src/main/java/cn/zhxu/okhttps/Config.java
rename to okhttps/src/main/java/com/ejlchina/okhttps/Config.java
index c2eeb36d..71a803c7 100644
--- a/okhttps/src/main/java/cn/zhxu/okhttps/Config.java
+++ b/okhttps/src/main/java/com/ejlchina/okhttps/Config.java
@@ -1,4 +1,4 @@
-package cn.zhxu.okhttps;
+package com.ejlchina.okhttps;
import java.util.ServiceLoader;
@@ -7,10 +7,6 @@
*/
public interface Config {
- /**
- * 配置 {@link OkHttps } 内部的 {@link HTTP } 实例
- * @param builder HTTP.Builder
- */
void with(HTTP.Builder builder);
static void config(HTTP.Builder builder) {
diff --git a/okhttps/src/main/java/cn/zhxu/okhttps/ConvertProvider.java b/okhttps/src/main/java/com/ejlchina/okhttps/ConvertProvider.java
similarity index 94%
rename from okhttps/src/main/java/cn/zhxu/okhttps/ConvertProvider.java
rename to okhttps/src/main/java/com/ejlchina/okhttps/ConvertProvider.java
index 0ce5d1ad..aa1600b9 100644
--- a/okhttps/src/main/java/cn/zhxu/okhttps/ConvertProvider.java
+++ b/okhttps/src/main/java/com/ejlchina/okhttps/ConvertProvider.java
@@ -1,4 +1,4 @@
-package cn.zhxu.okhttps;
+package com.ejlchina.okhttps;
import java.util.ServiceLoader;
diff --git a/okhttps/src/main/java/com/ejlchina/okhttps/DataSet.java b/okhttps/src/main/java/com/ejlchina/okhttps/DataSet.java
new file mode 100644
index 00000000..52aa5367
--- /dev/null
+++ b/okhttps/src/main/java/com/ejlchina/okhttps/DataSet.java
@@ -0,0 +1,19 @@
+package com.ejlchina.okhttps;
+
+/**
+ * 只读数据集
+ * @since 2.5.0
+ */
+public interface DataSet {
+
+ /**
+ * @return 集合内直接子元素的数量
+ */
+ int size();
+
+ /**
+ * @return 数据集是否为空
+ */
+ boolean isEmpty();
+
+}
diff --git a/okhttps/src/main/java/cn/zhxu/okhttps/DownListener.java b/okhttps/src/main/java/com/ejlchina/okhttps/DownListener.java
similarity index 89%
rename from okhttps/src/main/java/cn/zhxu/okhttps/DownListener.java
rename to okhttps/src/main/java/com/ejlchina/okhttps/DownListener.java
index a4f4735b..53cbebed 100644
--- a/okhttps/src/main/java/cn/zhxu/okhttps/DownListener.java
+++ b/okhttps/src/main/java/com/ejlchina/okhttps/DownListener.java
@@ -1,4 +1,4 @@
-package cn.zhxu.okhttps;
+package com.ejlchina.okhttps;
/**
* 下载监听接口
diff --git a/okhttps/src/main/java/cn/zhxu/okhttps/Download.java b/okhttps/src/main/java/com/ejlchina/okhttps/Download.java
similarity index 52%
rename from okhttps/src/main/java/cn/zhxu/okhttps/Download.java
rename to okhttps/src/main/java/com/ejlchina/okhttps/Download.java
index fe622132..49523676 100644
--- a/okhttps/src/main/java/cn/zhxu/okhttps/Download.java
+++ b/okhttps/src/main/java/com/ejlchina/okhttps/Download.java
@@ -1,7 +1,9 @@
-package cn.zhxu.okhttps;
+package com.ejlchina.okhttps;
+
+import com.ejlchina.okhttps.internal.HttpException;
+import com.ejlchina.okhttps.internal.TaskExecutor;
import java.io.*;
-import java.util.function.Consumer;
/**
* 文件下载
@@ -9,25 +11,23 @@
*/
public class Download {
- private final File file;
- private final InputStream input;
- private final TaskExecutor taskExecutor;
- private final Ctrl ctrl;
-
- private Consumer onSuccess;
- private Consumer onFailure;
- private Consumer onComplete;
+ private File file;
+ private InputStream input;
+ private OnCallback onSuccess;
+ private OnCallback onFailure;
+ private TaskExecutor taskExecutor;
private long doneBytes;
private int buffSize = 0;
private long seekBytes = 0;
private boolean appended;
- private volatile Status status;
+ private volatile int status;
private final Object lock = new Object();
protected boolean nextOnIO = false;
private boolean sOnIO;
private boolean fOnIO;
- private boolean cOnIO;
+
+ private Ctrl ctrl;
public Download(File file, InputStream input, TaskExecutor taskExecutor, long skipBytes) {
this.file = file;
@@ -61,7 +61,6 @@ public Download setAppended() {
/**
* 设置文件指针,从文件的 seekBytes 位置追加内容
- * 只有配合 setAppended() 方法一起才会有作用
* @param seekBytes 跨越的字节数
* @return Download
*/
@@ -84,7 +83,7 @@ public Download nextOnIO() {
* @param onSuccess 成功回调函数
* @return Download
*/
- public Download setOnSuccess(Consumer onSuccess) {
+ public Download setOnSuccess(OnCallback onSuccess) {
this.onSuccess = onSuccess;
sOnIO = nextOnIO;
nextOnIO = false;
@@ -92,30 +91,17 @@ public Download setOnSuccess(Consumer onSuccess) {
}
/**
- * 设置下载失败回调(取消不执行)
+ * 设置下载失败回调
* @param onFailure 失败回调函数
* @return Download
*/
- public Download setOnFailure(Consumer onFailure) {
+ public Download setOnFailure(OnCallback onFailure) {
this.onFailure = onFailure;
fOnIO = nextOnIO;
nextOnIO = false;
return this;
}
-
- /**
- * @since 3.2.0
- * 设置下载结束回调(成功、失败、取消都执行)
- * @param onComplete 结束回调函数
- * @return Download
- */
- public Download setOnComplete(Consumer onComplete) {
- this.onComplete = onComplete;
- cOnIO = nextOnIO;
- nextOnIO = false;
- return this;
- }
-
+
/**
* 开始下载
* @return 下载控制器
@@ -125,10 +111,8 @@ public Ctrl start() {
buffSize = Process.DEFAULT_STEP_BYTES;
}
RandomAccessFile raFile = randomAccessFile();
- if (raFile != null) {
- status = Status.DOWNLOADING;
- taskExecutor.execute(() -> doDownload(raFile), true);
- }
+ status = Ctrl.STATUS__DOWNLOADING;
+ taskExecutor.execute(() -> doDownload(raFile), true);
return ctrl;
}
@@ -140,108 +124,82 @@ public Ctrl getCtrl() {
return ctrl;
}
- /**
- * 下载状态
- * @since v3.2.0
- */
- public enum Status {
-
+ public class Ctrl {
+
/**
* 已取消
*/
- CANCELED(-1),
-
+ public static final int STATUS__CANCELED = -1;
+
/**
* 下载中
*/
- DOWNLOADING(1),
-
+ public static final int STATUS__DOWNLOADING = 1;
+
/**
* 已暂停
*/
- PAUSED(2),
-
+ public static final int STATUS__PAUSED = 2;
+
/**
- * 成功下载完成
+ * 已完成
*/
- DONE(3),
-
+ public static final int STATUS__DONE = 3;
+
/**
- * 发送错误
+ * 错误
*/
- ERROR(4);
-
- private final int value;
-
- Status(int value) {
- this.value = value;
- }
-
- public int value() {
- return value;
- }
-
- }
-
- /**
- * 下载控制器
- */
- public class Ctrl {
-
+ public static final int STATUS__ERROR = 4;
+
/**
- * @return 下载状态(v3.2.0 之前方法 返回整型常量,v3.2.0 开始修改为枚举)
+ * @see #STATUS__CANCELED
+ * @see #STATUS__DOWNLOADING
+ * @see #STATUS__PAUSED
+ * @see #STATUS__DONE
+ * @return 下载状态
*/
- public Status status() {
+ public int status() {
return status;
}
/**
- * 暂停下载任务(只有处于下载中状态才能暂停成功)
- * @return 是否暂停成功
+ * 暂停下载任务
*/
- public boolean pause() {
+ public void pause() {
synchronized (lock) {
- if (status == Status.DOWNLOADING) {
- status = Status.PAUSED;
- return true;
+ if (status == STATUS__DOWNLOADING) {
+ status = STATUS__PAUSED;
}
}
- return false;
}
/**
- * 继续下载任务(只有处于暂停状态才能恢复成功)
- * @return 是否恢复成功
+ * 继续下载任务
*/
- public boolean resume() {
+ public void resume() {
synchronized (lock) {
- if (status == Status.PAUSED) {
- status = Status.DOWNLOADING;
- return true;
+ if (status == STATUS__PAUSED) {
+ status = STATUS__DOWNLOADING;
}
}
- return false;
}
/**
- * 取消下载任务(只有处于暂停或下载中状态才能取消成功)
- * @return 是否取消成功
+ * 取消下载任务
*/
- public boolean cancel() {
+ public void cancel() {
synchronized (lock) {
- if (status == Status.PAUSED || status == Status.DOWNLOADING) {
- status = Status.CANCELED;
- return true;
+ if (status == STATUS__PAUSED || status == STATUS__DOWNLOADING) {
+ status = STATUS__CANCELED;
}
}
- return false;
}
}
public class Failure {
- private final IOException exception;
+ private IOException exception;
Failure(IOException exception) {
this.exception = exception;
@@ -255,7 +213,7 @@ public File getFile() {
}
/**
- * @return 本次已下载字节数
+ * @return 已下载字节数
*/
public long getDoneBytes() {
return doneBytes;
@@ -274,36 +232,40 @@ private RandomAccessFile randomAccessFile() {
try {
return new RandomAccessFile(file, "rw");
} catch (FileNotFoundException e) {
- status = Status.ERROR;
+ status = Ctrl.STATUS__ERROR;
closeQuietly(input);
- fireOnComplete();
- fireOnFailure(e);
+ throw new HttpException("无法获取文件[" + file.getAbsolutePath() + "]的输入流", e);
}
- return null;
}
private void doDownload(RandomAccessFile raFile) {
try {
if (appended && seekBytes > 0) {
- // 使支持并行下载到同一个文件
- raFile.seek(seekBytes);
+ long length = raFile.length();
+ if (seekBytes <= length) {
+ raFile.seek(seekBytes);
+ doneBytes = seekBytes;
+ } else {
+ raFile.seek(length);
+ doneBytes = length;
+ }
}
- while (status != Status.CANCELED && status != Status.DONE) {
- if (status == Status.DOWNLOADING) {
+ while (status != Ctrl.STATUS__CANCELED && status != Ctrl.STATUS__DONE) {
+ if (status == Ctrl.STATUS__DOWNLOADING) {
byte[] buff = new byte[buffSize];
int len;
while ((len = input.read(buff)) != -1) {
raFile.write(buff, 0, len);
doneBytes += len;
- if (status == Status.CANCELED
- || status == Status.PAUSED) {
+ if (status == Ctrl.STATUS__CANCELED
+ || status == Ctrl.STATUS__PAUSED) {
break;
}
}
if (len == -1) {
synchronized (lock) {
- if (status != Status.CANCELED) {
- status = Status.DONE;
+ if (status != Ctrl.STATUS__CANCELED) {
+ status = Ctrl.STATUS__DONE;
}
}
}
@@ -311,46 +273,26 @@ private void doDownload(RandomAccessFile raFile) {
}
} catch (IOException e) {
synchronized (lock) {
- if (status != Status.CANCELED) {
- status = Status.ERROR;
+ if (status != Ctrl.STATUS__CANCELED) {
+ status = Ctrl.STATUS__ERROR;
}
}
- if (status == Status.ERROR) {
- fireOnFailure(e);
+ if (status == Ctrl.STATUS__ERROR) {
+ if (onFailure != null) {
+ taskExecutor.execute(() -> onFailure.on(new Failure(e)), fOnIO);
+ } else {
+ throw new HttpException("流传输失败", e);
+ }
}
} finally {
closeQuietly(raFile);
closeQuietly(input);
- if (status == Status.CANCELED && !file.delete()) {
- Platform.logError("can not delete canceled file: " + file);
+ if (status == Ctrl.STATUS__CANCELED) {
+ file.delete();
}
- fireOnComplete();
- }
- if (status == Status.DONE) {
- fireOnSuccess();
- }
- }
-
- private void fireOnComplete() {
- Consumer onComplete = this.onComplete;
- if (onComplete != null) {
- taskExecutor.execute(() -> onComplete.accept(status), cOnIO);
- }
- }
-
- private void fireOnSuccess() {
- Consumer onSuccess = this.onSuccess;
- if (onSuccess != null) {
- taskExecutor.execute(() -> onSuccess.accept(file), sOnIO);
}
- }
-
- private void fireOnFailure(IOException e) {
- Consumer onFailure = this.onFailure;
- if (onFailure != null) {
- taskExecutor.execute(() -> onFailure.accept(new Failure(e)), fOnIO);
- } else {
- throw new OkHttpsException("Download failed: ", e);
+ if (status == Ctrl.STATUS__DONE && onSuccess != null) {
+ taskExecutor.execute(() -> onSuccess.on(file), sOnIO);
}
}
diff --git a/okhttps/src/main/java/com/ejlchina/okhttps/FilePara.java b/okhttps/src/main/java/com/ejlchina/okhttps/FilePara.java
new file mode 100644
index 00000000..7d40ca8d
--- /dev/null
+++ b/okhttps/src/main/java/com/ejlchina/okhttps/FilePara.java
@@ -0,0 +1,48 @@
+package com.ejlchina.okhttps;
+
+import java.io.File;
+
+/**
+ * @since 2.5.0 从 HttpTask 中分离
+ */
+public class FilePara {
+
+ String type;
+ String fileName;
+ byte[] content;
+ File file;
+
+ public FilePara(String type, String fileName, byte[] content) {
+ this.type = type;
+ this.fileName = fileName;
+ this.content = content;
+ }
+
+ public FilePara(String type, String fileName, File file) {
+ this.type = type;
+ this.fileName = fileName;
+ this.file = file;
+ }
+
+ public String getType() {
+ return type;
+ }
+
+ public String getFileName() {
+ return fileName;
+ }
+
+ public byte[] getContent() {
+ return content;
+ }
+
+ public File getFile() {
+ return file;
+ }
+
+ @Override
+ public String toString() {
+ return "FilePara{" + "type='" + type + "', fileName='" + fileName + "'}";
+ }
+
+}
diff --git a/okhttps/src/main/java/com/ejlchina/okhttps/HTTP.java b/okhttps/src/main/java/com/ejlchina/okhttps/HTTP.java
new file mode 100644
index 00000000..d2f2b4fc
--- /dev/null
+++ b/okhttps/src/main/java/com/ejlchina/okhttps/HTTP.java
@@ -0,0 +1,548 @@
+package com.ejlchina.okhttps;
+
+import com.ejlchina.okhttps.internal.*;
+
+import okhttp3.*;
+import okhttp3.WebSocket;
+
+import java.io.IOException;
+import java.nio.charset.Charset;
+import java.nio.charset.StandardCharsets;
+import java.util.*;
+import java.util.concurrent.Executor;
+
+/**
+ * HTTP 客户端接口
+ *
+ * @author 15735
+ */
+public interface HTTP {
+
+ String GET = "GET";
+ String HEAD = "HEAD";
+ String POST = "POST";
+ String PUT = "PUT";
+ String PATCH = "PATCH";
+ String DELETE = "DELETE";
+
+ /**
+ * 同步请求
+ * @param url 请求地址
+ * @return 同步HTTP任务
+ */
+ SyncHttpTask sync(String url);
+
+ /**
+ * 异步请求
+ * @param url 请求地址
+ * @return 异步HTTP任务
+ */
+ AsyncHttpTask async(String url);
+
+ /**
+ * Websocket 连接
+ * @param url 连接地址
+ * @return WebSocket 任务
+ */
+ WebSocketTask webSocket(String url);
+
+ /**
+ * 根据标签取消HTTP任务,只要任务的标签包含指定的Tag就会被取消
+ * 从 v1.0.2 开始支持取消同步请求
+ * @param tag 标签
+ * @return 被取消的任务数量
+ */
+ int cancel(String tag);
+
+ /**
+ * @since 1.0.2
+ * 取消所有HTTP任务,包括同步和异步
+ */
+ void cancelAll();
+
+ /**
+ * OkHttp 的 HTTP 原生请求 (该请求不经过 预处理器)
+ * @param request 请求
+ * @return Call
+ */
+ Call request(Request request);
+
+ /**
+ * OkHttp 的 Websocket 原生请求(该请求不经过 预处理器)
+ * @param request 请求
+ * @param listener 监听器
+ * @return Websocket
+ */
+ WebSocket webSocket(Request request, WebSocketListener listener);
+
+ /**
+ * 获取任务执行器
+ * @return TaskExecutor
+ */
+ TaskExecutor executor();
+
+ /**
+ * 新的构建器
+ * @return Builder
+ */
+ Builder newBuilder();
+
+ /**
+ * HTTP 构建器
+ * @return HTTP 构建器
+ */
+ static Builder builder() {
+ return new Builder();
+ }
+
+ /**
+ * Http 配置器
+ *
+ */
+ interface OkConfig {
+
+ /**
+ * 使用 builder 配置 HttpClient
+ * @param builder OkHttpClient 构建器
+ */
+ void config(OkHttpClient.Builder builder);
+
+ }
+
+ class Builder {
+
+ private OkHttpClient okClient;
+
+ private String baseUrl;
+
+ private Map mediaTypes;
+
+ private List contentTypes;
+
+ private OkConfig config;
+
+ private Executor mainExecutor;
+
+ private Scheduler taskScheduler;
+
+ private List preprocessors;
+
+ private DownListener downloadListener;
+
+ private TaskListener responseListener;
+
+ private TaskListener exceptionListener;
+
+ private TaskListener completeListener;
+
+ private List msgConvertors;
+
+ private int preprocTimeoutTimes = 10;
+
+ private Charset charset = StandardCharsets.UTF_8;
+
+ private String bodyType = OkHttps.FORM;
+
+ private Map retryPolicys;
+
+
+ public Builder() {
+ mediaTypes = new HashMap<>();
+ mediaTypes.put("*", "application/octet-stream");
+ mediaTypes.put("png", "image/png");
+ mediaTypes.put("jpg", "image/jpeg");
+ mediaTypes.put("jpeg", "image/jpeg");
+ mediaTypes.put("wav", "audio/wav");
+ mediaTypes.put("mp3", "audio/mp3");
+ mediaTypes.put("mp4", "video/mpeg4");
+ mediaTypes.put("txt", "text/plain");
+ mediaTypes.put("xls", "application/x-xls");
+ mediaTypes.put("xml", "text/xml");
+ mediaTypes.put("apk", "application/vnd.android.package-archive");
+ mediaTypes.put("doc", "application/msword");
+ mediaTypes.put("pdf", "application/pdf");
+ mediaTypes.put("html", "text/html");
+ contentTypes = new ArrayList<>();
+ contentTypes.add("application/x-www-form-urlencoded");
+ contentTypes.add("application/json");
+ contentTypes.add("application/xml");
+ contentTypes.add("application/x-protobuf");
+ preprocessors = new ArrayList<>();
+ msgConvertors = new ArrayList<>();
+ retryPolicys = new HashMap<>();
+ }
+
+ public Builder(HttpClient hc) {
+ okClient = hc.okClient();
+ baseUrl = hc.baseUrl();
+ mediaTypes = hc.mediaTypes();
+ preprocessors = new ArrayList<>();
+ Collections.addAll(preprocessors, hc.preprocessors());
+ TaskExecutor executor = hc.executor();
+ contentTypes = new ArrayList<>();
+ Collections.addAll(contentTypes, executor.getContentTypes());
+ mainExecutor = executor.getMainExecutor();
+ taskScheduler = executor.getTaskScheduler();
+ downloadListener = executor.getDownloadListener();
+ responseListener = executor.getResponseListener();
+ exceptionListener = executor.getExceptionListener();
+ completeListener = executor.getCompleteListener();
+ msgConvertors = new ArrayList<>();
+ Collections.addAll(msgConvertors, executor.getMsgConvertors());
+ preprocTimeoutTimes = hc.preprocTimeoutTimes();
+ retryPolicys = new HashMap<>();
+ retryPolicys.putAll(hc.retryPolicys());
+ bodyType = hc.bodyType();
+ charset = hc.charset();
+ }
+
+ /**
+ * 配置 OkHttpClient
+ * @param config 配置器
+ * @return Builder
+ */
+ public Builder config(OkConfig config) {
+ this.config = config;
+ return this;
+ }
+
+ /**
+ * 设置 baseUrl
+ * @param baseUrl 全局URL前缀
+ * @return Builder
+ */
+ public Builder baseUrl(String baseUrl) {
+ this.baseUrl = baseUrl;
+ return this;
+ }
+
+ /**
+ * 配置媒体类型
+ * @param mediaTypes 媒体类型
+ * @return Builder
+ */
+ public Builder mediaTypes(Map mediaTypes) {
+ if (mediaTypes != null) {
+ this.mediaTypes.putAll(mediaTypes);
+ }
+ return this;
+ }
+
+ /**
+ * 配置媒体类型
+ * @param key 媒体类型KEY
+ * @param value 媒体类型VALUE
+ * @return Builder
+ */
+ public Builder mediaTypes(String key, String value) {
+ if (key != null && value != null) {
+ this.mediaTypes.put(key, value);
+ }
+ return this;
+ }
+
+ /**
+ * 配置支持的报文体类型
+ * @param contentTypes 报文体类型列表
+ * @return Builder
+ */
+ public Builder contentTypes(List contentTypes) {
+ if (contentTypes != null) {
+ this.contentTypes.addAll(contentTypes);
+ }
+ return this;
+ }
+
+ /**
+ * 配置支持的报文体类型
+ * @param contentType 报文体类型
+ * @return Builder
+ */
+ public Builder contentTypes(String contentType) {
+ if (contentType != null) {
+ this.contentTypes.add(contentType);
+ }
+ return this;
+ }
+
+ /**
+ * 设置回调执行器,例如实现切换线程功能,只对异步请求有效
+ * @param executor 回调执行器
+ * @return Builder
+ */
+ public Builder callbackExecutor(Executor executor) {
+ this.mainExecutor = executor;
+ return this;
+ }
+
+ /**
+ * 配置 任务调度器,可用的调度由 {@link WebSocketTask#heatbeat(int, int) } 指定的心跳任务
+ * 若不配置,则生成一个 线程容量为 1 的 ScheduledThreadPoolExecutor 调度器
+ * @since v2.3.0
+ * @param scheduler 调度器
+ * @return Builder
+ */
+ public Builder taskScheduler(Scheduler scheduler) {
+ this.taskScheduler = scheduler;
+ return this;
+ }
+
+ /**
+ * 添加可并行处理请求任务的预处理器
+ * @param preprocessor 预处理器
+ * @return Builder
+ */
+ public Builder addPreprocessor(Preprocessor preprocessor) {
+ if (preprocessor != null) {
+ preprocessors.add(preprocessor);
+ }
+ return this;
+ }
+
+ /**
+ * 添加串行预处理器
+ * @param preprocessor 预处理器
+ * @return Builder
+ */
+ public Builder addSerialPreprocessor(Preprocessor preprocessor) {
+ if (preprocessor != null) {
+ preprocessors.add(new HttpClient.SerialPreprocessor(preprocessor));
+ }
+ return this;
+ }
+
+ /**
+ * 清空预处理器(包括串行预处理器)
+ * @since v2.5.0
+ * @return Builder
+ */
+ public Builder clearPreprocessors() {
+ preprocessors.clear();
+ return this;
+ }
+
+ /**
+ * 最大预处理时间(倍数,相当普通请求的超时时间)
+ * @param times 普通超时时间的倍数,默认为 10
+ * @return Builder
+ */
+ public Builder preprocTimeoutTimes(int times) {
+ if (times > 0) {
+ preprocTimeoutTimes = times;
+ }
+ return this;
+ }
+
+ /**
+ * 设置全局响应监听
+ * @param listener 监听器
+ * @return Builder
+ */
+ public Builder responseListener(TaskListener listener) {
+ responseListener = listener;
+ return this;
+ }
+
+ /**
+ * 设置全局异常监听
+ * @param listener 监听器
+ * @return Builder
+ */
+ public Builder exceptionListener(TaskListener listener) {
+ exceptionListener = listener;
+ return this;
+ }
+
+ /**
+ * 设置全局完成监听
+ * @param listener 监听器
+ * @return Builder
+ */
+ public Builder completeListener(TaskListener listener) {
+ completeListener = listener;
+ return this;
+ }
+
+ /**
+ * 设置下载监听器
+ * @param listener 监听器
+ * @return Builder
+ */
+ public Builder downloadListener(DownListener listener) {
+ downloadListener = listener;
+ return this;
+ }
+
+ /**
+ * @since v2.0.0
+ * 添加消息转换器
+ * @param msgConvertor JSON 服务
+ * @return Builder
+ */
+ public Builder addMsgConvertor(MsgConvertor msgConvertor) {
+ if (msgConvertor != null) {
+ msgConvertors.add(msgConvertor);
+ }
+ return this;
+ }
+
+ /**
+ * 清空消息转换器
+ * @since v2.5.0
+ * @return Builder
+ */
+ public Builder clearMsgConvertors() {
+ msgConvertors.clear();
+ return this;
+ }
+
+ /**
+ * @since v2.0.0
+ * 设置默认编码格式
+ * @param charset 编码
+ * @return Builder
+ */
+ public Builder charset(Charset charset) {
+ if (charset != null) {
+ this.charset = charset;
+ }
+ return this;
+ }
+
+ /**
+ * @since v2.0.0
+ * 设置默认请求体类型
+ * @param bodyType 请求体类型
+ * @return Builder
+ */
+ public Builder bodyType(String bodyType) {
+ if (bodyType != null) {
+ this.bodyType = bodyType.toLowerCase();
+ }
+ return this;
+ }
+
+ /**
+ * 添加重试策略
+ * @since v2.5.0
+ * @param name 策略名
+ * @param policy 策略
+ * @return Builder
+ */
+ public Builder addRetryPolicy(String name, RetryPolicy policy) {
+ if (retryPolicys.containsKey(name)) {
+ throw new IllegalStateException("RetryPolicy[" + name + "] already exists!");
+ }
+ retryPolicys.put(name, policy);
+ return this;
+ }
+
+ /**
+ * 清空重试策略
+ * @since v2.5.0
+ * @return Builder
+ */
+ public Builder clearRetryPolicys() {
+ retryPolicys.clear();
+ return this;
+ }
+
+ /**
+ * 构建 HTTP 实例
+ * @return HTTP
+ */
+ public HTTP build() {
+ if (config != null || okClient == null) {
+ OkHttpClient.Builder builder;
+ if (okClient != null) {
+ builder = okClient.newBuilder();
+ } else {
+ builder = new OkHttpClient.Builder();
+ }
+ if (config != null) {
+ config.config(builder);
+ }
+ // fix issue: https://github.com/ejlchina/okhttps/issues/8
+ if (needCopyInterceptor(builder.interceptors())) {
+ builder.addInterceptor(new CopyInterceptor());
+ }
+ okClient = builder.build();
+ } else if (needCopyInterceptor(okClient.interceptors())) {
+ okClient = okClient.newBuilder()
+ .addInterceptor(new CopyInterceptor())
+ .build();
+ }
+ return new HttpClient(this);
+ }
+
+ private boolean needCopyInterceptor(List list) {
+ return mainExecutor != null && Platform.ANDROID_SDK_INT > 24 && CopyInterceptor.notIn(list);
+ }
+
+ public OkHttpClient okClient() {
+ return okClient;
+ }
+
+ public String baseUrl() {
+ return baseUrl;
+ }
+
+ public Map getMediaTypes() {
+ return mediaTypes;
+ }
+
+ public Executor mainExecutor() {
+ return mainExecutor;
+ }
+
+ public Preprocessor[] preprocessors() {
+ return preprocessors.toArray(new Preprocessor[0]);
+ }
+
+ public DownListener downloadListener() {
+ return downloadListener;
+ }
+
+ public TaskListener responseListener() {
+ return responseListener;
+ }
+
+ public TaskListener exceptionListener() {
+ return exceptionListener;
+ }
+
+ public TaskListener completeListener() {
+ return completeListener;
+ }
+
+ public MsgConvertor[] msgConvertors() {
+ return msgConvertors.toArray(new MsgConvertor[0]);
+ }
+
+ public Scheduler taskScheduler() {
+ return taskScheduler;
+ }
+
+ public String[] contentTypes() {
+ return contentTypes.toArray(new String[0]);
+ }
+
+ public int preprocTimeoutTimes() {
+ return preprocTimeoutTimes;
+ }
+
+ public Charset charset() {
+ return charset;
+ }
+
+ public String bodyType() {
+ return bodyType;
+ }
+
+ public Map retryPolicys() {
+ return retryPolicys;
+ }
+
+ }
+
+}
diff --git a/okhttps/src/main/java/cn/zhxu/okhttps/HttpCall.java b/okhttps/src/main/java/com/ejlchina/okhttps/HttpCall.java
similarity index 83%
rename from okhttps/src/main/java/cn/zhxu/okhttps/HttpCall.java
rename to okhttps/src/main/java/com/ejlchina/okhttps/HttpCall.java
index 00c15fa8..5bc4214c 100644
--- a/okhttps/src/main/java/cn/zhxu/okhttps/HttpCall.java
+++ b/okhttps/src/main/java/com/ejlchina/okhttps/HttpCall.java
@@ -1,4 +1,6 @@
-package cn.zhxu.okhttps;
+package com.ejlchina.okhttps;
+
+import com.ejlchina.okhttps.internal.AsyncHttpTask;
public interface HttpCall extends Cancelable {
@@ -24,6 +26,6 @@ public interface HttpCall extends Cancelable {
* @since 2.2.0
* @return 当前的异步请求任务
*/
- AHttpTask getTask();
+ AsyncHttpTask getTask();
}
diff --git a/okhttps/src/main/java/cn/zhxu/okhttps/HttpResult.java b/okhttps/src/main/java/com/ejlchina/okhttps/HttpResult.java
similarity index 90%
rename from okhttps/src/main/java/cn/zhxu/okhttps/HttpResult.java
rename to okhttps/src/main/java/com/ejlchina/okhttps/HttpResult.java
index 8294c861..fdcd92d0 100644
--- a/okhttps/src/main/java/cn/zhxu/okhttps/HttpResult.java
+++ b/okhttps/src/main/java/com/ejlchina/okhttps/HttpResult.java
@@ -1,15 +1,15 @@
-package cn.zhxu.okhttps;
-
-import cn.zhxu.data.ListMap;
-import cn.zhxu.okhttps.internal.RealHttpResult;
-import okhttp3.Headers;
-import okhttp3.MediaType;
-import okhttp3.Response;
+package com.ejlchina.okhttps;
import java.io.File;
import java.io.IOException;
import java.util.List;
-import java.util.function.Consumer;
+
+import com.ejlchina.okhttps.internal.RealHttpResult;
+import com.ejlchina.okhttps.internal.TaskExecutor;
+
+import okhttp3.Headers;
+import okhttp3.MediaType;
+import okhttp3.Response;
/**
@@ -92,14 +92,11 @@ enum State {
interface Body extends Toable {
/**
- * will be removed in next version
* @return 媒体类型
*/
- @Deprecated
MediaType getType();
/**
- * 依赖于 Content-Length 响应头
* @return 报文体字节长度
*/
long getLength();
@@ -115,7 +112,7 @@ interface Body extends Toable {
* @param onProcess 进度回调函数
* @return Body
*/
- Body setOnProcess(Consumer onProcess);
+ Body setOnProcess(OnCallback onProcess);
/**
* 设置进度回调的步进字节,默认 8K(8192)
@@ -197,25 +194,15 @@ interface Body extends Toable {
int getStatus();
/**
- * WebSocket 返回 101 也返回 true (since v3.5.1)
* @return 是否响应成功,状态码在 [200..300) 之间
*/
boolean isSuccessful();
/**
- * will be removed in next version
* @return 响应头
- * @see #allHeaders()
*/
- @Deprecated
Headers getHeaders();
- /**
- * @return 所有响应头
- * @since v3.5.0
- */
- ListMap allHeaders();
-
/**
* @param name 头名称
* @return 响应头
diff --git a/okhttps/src/main/java/cn/zhxu/okhttps/HttpTask.java b/okhttps/src/main/java/com/ejlchina/okhttps/HttpTask.java
similarity index 52%
rename from okhttps/src/main/java/cn/zhxu/okhttps/HttpTask.java
rename to okhttps/src/main/java/com/ejlchina/okhttps/HttpTask.java
index d7381c22..d416824d 100644
--- a/okhttps/src/main/java/cn/zhxu/okhttps/HttpTask.java
+++ b/okhttps/src/main/java/com/ejlchina/okhttps/HttpTask.java
@@ -1,55 +1,45 @@
-package cn.zhxu.okhttps;
+package com.ejlchina.okhttps;
-import cn.zhxu.data.ArrayListMap;
-import cn.zhxu.data.ListMap;
-import cn.zhxu.okhttps.HttpResult.State;
-import cn.zhxu.okhttps.internal.*;
-import cn.zhxu.okhttps.internal.AbstractHttpClient.TagTask;
+import com.ejlchina.okhttps.HttpResult.State;
+import com.ejlchina.okhttps.internal.*;
+import com.ejlchina.okhttps.internal.HttpClient.TagTask;
import okhttp3.*;
import okhttp3.internal.http.HttpMethod;
import java.io.File;
import java.io.IOException;
-import java.io.InputStream;
import java.net.ConnectException;
import java.net.SocketException;
import java.net.SocketTimeoutException;
import java.net.UnknownHostException;
import java.nio.charset.Charset;
-import java.nio.charset.StandardCharsets;
-import java.util.Base64;
+import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
-import java.util.function.Consumer;
/**
* Created by 周旭(Troy.Zhou) on 2020/3/11.
*/
@SuppressWarnings("unchecked")
-public abstract class HttpTask> implements Cancelable {
+public abstract class HttpTask> implements Cancelable {
- private static final String DOT = ".";
- private static final String MULTIPART = "multipart/";
- private static final String FORM = "x-www-form-urlencoded";
+ private static final String PATH_PARAM_REGEX = "[A-Za-z0-9_\\-/]*\\{[A-Za-z0-9_\\-]+\\}[A-Za-z0-9_\\-/]*";
- protected final AbstractHttpClient httpClient;
+ protected HttpClient httpClient;
protected boolean nothrow;
protected boolean nextOnIO = false;
private final String urlPath;
private String tag;
-
- private ListMap headers;
- private ListMap pathParams;
- private ListMap urlParams;
- private ListMap bodyParams;
- private ListMap files;
-
+ private Map headers;
+ private Map pathParams;
+ private Map urlParams;
+ private Map bodyParams;
+ private Map files;
private Object requestBody;
- private String bodyType; // 都是小写形式
- private String boundary; // MultipartBody 的 边界符
- private Consumer onProcess;
+ private String bodyType;
+ private OnCallback onProcess;
private boolean processOnIO;
private long stepBytes = 0;
private double stepRate = -1;
@@ -63,8 +53,9 @@ public abstract class HttpTask> implements Cancelable {
protected boolean skipPreproc = false;
protected boolean skipSerialPreproc = false;
+ protected RetryPolicy retryPolicy;
- public HttpTask(AbstractHttpClient httpClient, String urlPath) {
+ public HttpTask(HttpClient httpClient, String urlPath) {
this.httpClient = httpClient;
this.charset = httpClient.charset();
this.bodyType = httpClient.bodyType();
@@ -121,10 +112,8 @@ public String getBodyType() {
* @return 是否匹配
*/
public boolean isTagged(String tag) {
- String theTag = this.tag;
- if (theTag != null && tag != null) {
- return theTag.equals(tag) || theTag.startsWith(tag + DOT) || theTag.endsWith(DOT + tag)
- || theTag.contains(DOT + tag + DOT);
+ if (this.tag != null && tag != null) {
+ return this.tag.contains(tag);
}
return false;
}
@@ -133,7 +122,7 @@ public boolean isTagged(String tag) {
* 获取请求任务的头信息
* @return 头信息
*/
- public ListMap getHeaders() {
+ public Map getHeaders() {
return headers;
}
@@ -141,7 +130,7 @@ public ListMap getHeaders() {
* @since 2.4.0
* @return 路径参数
*/
- public ListMap getPathParas() {
+ public Map getPathParas() {
return pathParams;
}
@@ -149,7 +138,7 @@ public ListMap getPathParas() {
* @since 2.4.0
* @return URL参数(查询参数)
*/
- public ListMap getUrlParas() {
+ public Map getUrlParas() {
return urlParams;
}
@@ -157,7 +146,7 @@ public ListMap getUrlParas() {
* @since 2.4.0
* @return 报文体参数
*/
- public ListMap getBodyParas() {
+ public Map getBodyParas() {
return bodyParams;
}
@@ -165,7 +154,7 @@ public ListMap getBodyParas() {
* @since 2.4.0
* @return 文件参数
*/
- public ListMap getFileParas() {
+ public Map getFileParas() {
return files;
}
@@ -222,7 +211,7 @@ public C skipSerialPreproc() {
public C tag(String tag) {
if (tag != null) {
if (this.tag != null) {
- this.tag = this.tag + DOT + tag;
+ this.tag = this.tag + "." + tag;
} else {
this.tag = tag;
}
@@ -258,46 +247,44 @@ public C bodyType(String type) {
}
/**
- * 下一个回调在IO线程执行
+ * 使用重试机制
+ * @since 2.5.0
+ * @param policy 重试策略
* @return HttpTask 实例
*/
- public C nextOnIO() {
- nextOnIO = true;
+ public C retryPolicy(RetryPolicy policy) {
+ this.retryPolicy = policy;
return (C) this;
}
/**
- * 绑定一个对象
- * @param object 对象
+ * 使用重试机制
+ * @since 2.5.0
+ * @param policyName 重试策略名(从 HTTP 实例中获取,在构建时注入)
* @return HttpTask 实例
*/
- public C bind(Object object) {
- this.object = object;
+ public C retryPolicy(String policyName) {
+ retryPolicy = httpClient.requirePolicy(policyName);
return (C) this;
}
/**
- * Basic Auth 认证
- * @param username 用户名
- * @param password 密码
+ * 下一个回调在IO线程执行
* @return HttpTask 实例
- * @since v3.5.0
*/
- public C basicAuth(String username, String password) {
- byte[] authData = (username + ':' + password).getBytes(StandardCharsets.UTF_8);
- byte[] authBytes = Base64.getEncoder().encode(authData);
- String authStr = new String(authBytes, StandardCharsets.UTF_8);
- return addHeader("Authorization", "Basic " + authStr);
+ public C nextOnIO() {
+ nextOnIO = true;
+ return (C) this;
}
/**
- * Bearer Auth 认证
- * @param token 令牌
+ * 绑定一个对象
+ * @param object 对象
* @return HttpTask 实例
- * @since v3.5.0
*/
- public C bearerAuth(String token) {
- return addHeader("Authorization", "Bearer " + token);
+ public C bind(Object object) {
+ this.object = object;
+ return (C) this;
}
/**
@@ -309,7 +296,7 @@ public C bearerAuth(String token) {
public C addHeader(String name, String value) {
if (name != null && value != null) {
if (headers == null) {
- headers = new ArrayListMap<>();
+ headers = new HashMap<>();
}
headers.put(name, value);
}
@@ -324,7 +311,7 @@ public C addHeader(String name, String value) {
public C addHeader(Map headers) {
if (headers != null) {
if (this.headers == null) {
- this.headers = new ArrayListMap<>();
+ this.headers = new HashMap<>();
}
this.headers.putAll(headers);
}
@@ -342,7 +329,7 @@ public C setRange(long rangeStart) {
}
/**
- * 设置 Range 头信息
+ * 设置Range头信息
* 设置接收报文体时接收的范围,用于分块下载
* @param rangeStart 表示从 rangeStart 个字节处开始接收
* @param rangeEnd 表示接收到 rangeEnd 个字节处
@@ -357,7 +344,7 @@ public C setRange(long rangeStart, long rangeEnd) {
* @param onProcess 进度回调函数
* @return HttpTask 实例
*/
- public C setOnProcess(Consumer