diff --git a/okhttps-doc/docs/.vuepress/config.js b/okhttps-doc/docs/.vuepress/config.js index 6c60b7b8b5994b43f71984bbe287a68f99bf8359..16f328c7e77dfa1c744ec3881de246f784dce9c0 100644 --- a/okhttps-doc/docs/.vuepress/config.js +++ b/okhttps-doc/docs/.vuepress/config.js @@ -45,6 +45,8 @@ module.exports = { 'foundation', 'configuration', 'updownload', + 'websocket', + 'stomp', 'android' ] }, diff --git a/okhttps-doc/docs/v2/README.md b/okhttps-doc/docs/v2/README.md index 6e35dfd1442271edc37638ddba12aba147849007..ddbc1d7133426053add7aaafa88c92a25ff66cc0 100644 --- a/okhttps-doc/docs/v2/README.md +++ b/okhttps-doc/docs/v2/README.md @@ -33,6 +33,15 @@ okhttps | 2.3.0 | OkHttps 核心模块 [okhttps-stomp](https://gitee.com/ejlchina-zhxu/okhttps-stomp) | 1.0.1 | 超级轻量的 Stomp 客户端 +## v2.3 的新特性 + +重新实现 WebSocket 心跳机制 +使用者可以选择使用 OkHttp 自带的新桃模式,也可以选择使用 OkHttps 提供的增强型新增机制,它具有如下特性 + +1. 客户端发送的任何消息都具有一次客户端心跳作用 +2. 服务器发送的任何消息都具有一次服务器心跳作用 +3. 若服务器超过 3 * pongSeconds 秒没有回复心跳,才判断心跳超时 + ## v2.2 的新特性 1. 增强泛型反序列化,支持复合泛型 diff --git a/okhttps-doc/docs/v2/foundation.md b/okhttps-doc/docs/v2/foundation.md index 0f0b58ddcd5ba277f2686966f503a1fad5d5b702..5e7ce347b91e43b964d798c847ca8abea0c03998 100644 --- a/okhttps-doc/docs/v2/foundation.md +++ b/okhttps-doc/docs/v2/foundation.md @@ -6,7 +6,7 @@ description: OkHttps 请求方法 回调函数 HttpResult cache 多次 消费报 ## 请求方法 -OkHttps 使用`sync()`和`async()`方式发起的请求,支持的 HTTP 方法有: +OkHttps 使用`sync(String url)`和`async(String url)`方法发起 同步和异步的 HTTP 请求,它们支持的方法有: HTTP 请求方法 | 实现方法 | Restful 释义 | 起始版本 -|-|-|- diff --git a/okhttps-doc/docs/v2/getstart.md b/okhttps-doc/docs/v2/getstart.md index 6c70e042e9926490f5ab3248ddc8fb682089da11..58fc6efdae71df2a5bd94922ccbe65ae8c31d74b 100644 --- a/okhttps-doc/docs/v2/getstart.md +++ b/okhttps-doc/docs/v2/getstart.md @@ -14,7 +14,7 @@ description: OkHttps 安装 构建实例 HTTP build 同步请求 异步请求 sy com.ejlchina okhttps - 2.2.0 + 2.3.0 ``` @@ -26,7 +26,7 @@ description: OkHttps 安装 构建实例 HTTP build 同步请求 异步请求 sy com.ejlchina okhttps-fastjson - 2.2.0 + 2.3.0 ``` @@ -36,7 +36,7 @@ description: OkHttps 安装 构建实例 HTTP build 同步请求 异步请求 sy com.ejlchina okhttps-gson - 2.2.0 + 2.3.0 ``` @@ -46,7 +46,7 @@ description: OkHttps 安装 构建实例 HTTP build 同步请求 异步请求 sy com.ejlchina okhttps-jackson - 2.2.0 + 2.3.0 ``` @@ -54,12 +54,22 @@ description: OkHttps 安装 构建实例 HTTP build 同步请求 异步请求 sy 以上依赖四选一即可 ::: +#### 使用 Stomp 客户端 + +```xml + + com.ejlchina + okhttps-stomp + 1.0.1 + +``` + ### Gradle #### 单独使用 OkHttps ```groovy -implementation 'com.ejlchina:okhttps:2.2.0' +implementation 'com.ejlchina:okhttps:2.3.0' ``` 单独使用 OkHttps 需要自定义[`MsgConvertor`](https://gitee.com/ejlchina-zhxu/okhttps/blob/master/okhttps/src/main/java/com/ejlchina/okhttps/MsgConvertor.java),否则无法使用 **自动正反序列化** 相关功能,后文会详细讲解哪些功能会受到此影响。 @@ -67,25 +77,30 @@ implementation 'com.ejlchina:okhttps:2.2.0' #### 与 fastjson 一起使用 ```groovy -implementation 'com.ejlchina:okhttps-fastjson:2.2.0' +implementation 'com.ejlchina:okhttps-fastjson:2.3.0' ``` #### 与 gson 一起使用 ```groovy -implementation 'com.ejlchina:okhttps-gson:2.2.0' +implementation 'com.ejlchina:okhttps-gson:2.3.0' ``` #### 与 jackson 一起使用 ```groovy -implementation 'com.ejlchina:okhttps-jackson:2.2.0' +implementation 'com.ejlchina:okhttps-jackson:2.3.0' ``` ::: tip 以上依赖四选一即可 ::: +#### 使用 Stomp 客户端 + +```groovy +implementation 'com.ejlchina:okhttps-stomp:1.0.1' +``` #### JDK 版本 diff --git a/okhttps-doc/docs/v2/stomp.md b/okhttps-doc/docs/v2/stomp.md new file mode 100644 index 0000000000000000000000000000000000000000..932a7e1e744a3f9e26574d5cccc1fa7a95ed4edc --- /dev/null +++ b/okhttps-doc/docs/v2/stomp.md @@ -0,0 +1,144 @@ +--- +description: OkHttps WebSocket Stomp OkHttp +--- + +# Stomp + +项目 [OkHttps Stomp](https://gitee.com/ejlchina-zhxu/okhttps-stomp) 基于 OkHttps 的 [WebSocket](/v2/websocket.html) 功能实现了一个非常轻量的 Stomp 客户端协议,它可以让你轻松实现 **广播发布与订阅** 和 **队列发布与订阅** 的客户端功能。 + +## 添加依赖 + +要开启 Stomp 功能,需要添加以下依赖: + +### Maven + +```xml + + com.ejlchina + okhttps-stomp + 1.0.1 + +``` + +### Gradle + +```groovy +implementation 'com.ejlchina:okhttps-stomp:1.0.1' +``` + +## 构建 Stomp 实例 + +类`Stomp`提供静态方法`over`来构建`Stomp`实例: + +* `over(WebSocketTask task)` 基于 OkHttps 的 WebSocket 构建一个 Stomp 实例,并自动确认消息 +* `over(WebSocketTask task, boolean autoAck)` 构建一个 Stomp 实例,并可指定是否自动确认消息 + +例如: + +```java +// 使用一个 Websocket 连接构建一个 Stomp 实例,同时设置心跳间隔为 20 秒 +Stomp stomp = Stomp.over(OkHttps.webSocket("wss://...").heatbeat(20, 20)); +``` + +以上代码构建了一个简单的 Stomp 客户端,并默认在收到消息时会**自动确认**,如果需要收到确认,可以使用下面的方式: + +```java +Stomp stomp = Stomp.over( + OkHttps.webSocket("wss://...").heatbeat(20, 20), + false // 参数设置 autoAck 为 false,将需要手动确认消息 + ); +``` + +## 连接 Stomp 服务 + +得到一个`Stomp`实例后,可使用以下两个方法连接 Stomp 服务器: + +* `connect()` 直接连接 Stomp 服务器 +* `connect(List
headers)` 携带一些 Stomp 头信息连接 Stomp 服务器 + +例如: + +```java +stomp.connect(); +``` + +如果服务器在连接时需要指令一些额外信息,比如连接 RabbitMQ 时需要指定`login`、`passcode` 和 `vhost`: + +```java +List
headers = new ArrayList<>(); +headers.add(new Header("login", "username")); +headers.add(new Header("passcode", "xxxxxxx")); +headers.add(new Header("host", "your_vhost")); + +stomp.connect(headers); +``` + +## 连接状态监听 + +```java +Stomp.over(OkHttps.webSocket("wss://...").heatbeat(20, 20)) + .setOnConnected(stomp -> { + // 服务器连接成功回调 + }) + .setOnDisconnected(close -> { + // 连接已断开回调 + }) + .connect(); +``` + +## 消息订阅与退订 + +### 订阅广播 + +```java +stomp.topic("/your-topic", (Message msg) -> { + // 得到消息负载 + String payload = msg.getPayload(); + + // 如果需要手动确认消息,调用此方法确认 + stomp.ack(msg) +}); +``` + +### 退订广播 + +```java +stomp.untopic("/your-topic"); +``` + +### 订阅队列 + +```java +stomp.queue("/your-queue", (Message msg) -> { + // 得到消息负载 + String payload = msg.getPayload(); + + // 如果需要手动确认消息,调用此方法确认 + stomp.ack(msg) +}); +``` + +### 退订队列 + +```java +stomp.unqueue("/your-queue"); +``` + +## 发送消息 + +```java +// 发送到广播 +stomp.sendTo("/topic/your-topic", "Hello World"); +// 发送到队列 +stomp.sendTo("/queue/your-queue", "Hello World"); +``` + +## 断开服务 + +```java +stomp.disconnect(); +``` + +
+ + \ No newline at end of file diff --git a/okhttps-doc/docs/v2/websocket.md b/okhttps-doc/docs/v2/websocket.md new file mode 100644 index 0000000000000000000000000000000000000000..a749536c76881171701bdb759817df2e6a3352d0 --- /dev/null +++ b/okhttps-doc/docs/v2/websocket.md @@ -0,0 +1,162 @@ +--- +description: OkHttps WebSocket Heatbeat 心跳 OkHttp +--- + +# WebSocket + +OkHttps 使用`webSocket(String url)`方法发起 WebSocket 连接,并使用`listen()`方法启动监听。 + +## 连接参数 + +如果在连接时需要向服务器传递参数,处理方式和 HTTP 请求一样,例如需要用户名和密码才能连接 WebSocket 服务: + +```java +http.webSocket("/chat") + .addUrlPara("username", "Jack") + .addUrlPara("password", "xxxxxxxx") + .setOnMessage((WebSocket ws,Message msg) -> { + + }) + .listen(); // 启动监听 +``` + +::: warning 注意 +WebSocket 连接只能添加 **请求头**、 **Url 参数**(查询参数)和 **Path 参数**, 报文体参数(Body)和 文件参数是不允许添加的。 +::: + +## 心跳机制 + +OkHttps 自带两种心跳机制 + +### 全局心跳配置 + +在构建`HTTP`实例时,可以配置一个全局心跳时间间隔: + +```java +HTTP http = HTTP.builder() + .config((OkHttpClient.Builder builder) -> { + + // 配置 WebSocket 心跳间隔(默认没有心跳) + builder.pingInterval(10, TimeUnit.SECONDS); + }) + .build(); +``` + +如上配置,当使用这个`HTTP`实例发起 WebSocket 连接时,客户端会每隔 10秒 向服务器发送一次 PING 消息,同时服务器必须在客户端发送心跳后的 10秒 内回复 PONG 消息,否则就会触发`SocketTimeoutException`异常 + +### 单次心跳配置(since V2.3.0) + +自 V2.3.0 起 OkHttps 提供了另外一种心跳机制,它在发起具体的 WebSocket 连接时通过方法`heatbeat(int pingSeconds, int pongSeconds)`分别指定客户端与服务器的心跳时间间隔: + +```java +http.webSocket("/chat") + .heatbeat(10, 10) + .setOnMessage((WebSocket ws,Message msg) -> { + + }) + .listen(); // 启动监听 +``` + +如上配置,客户端仍会每隔 10秒 向服务器发送一次 PING 消息,并期望服务器回复 PONG 消息的间隔也是 10 秒一次,但如果服务器或网络由于某些未知原因导致客户端未能正确收到 PONG 消息,客户端还会容忍两次失败,当第三个 10 秒后还未收到服务器的任何消息时,则会触发`SocketTimeoutException`异常 + +::: tip OkHttps 的心跳机制相对于 OkHttp 主要有以下特点 +* 客户端发送的任何消息都具有一次心跳作用 +* 服务器发送的任何消息都具有一次心跳作用 +* 若服务器超过 3 * pongSeconds 秒没有回复心跳,才触发心跳超时 +::: + +## 消息收发 + +### 接收消息 + +发起 WebSocket 连接是,设置一个`OnMessage`回调,便可接收到服务器的消息: + +```java +http.webSocket("/chat") + .setOnMessage((WebSocket ws,Message msg) -> { + // 接收到消息 msg + }) + .listen(); // 启动监听 +``` + +在该回调内接收到一个`Message`类型的消息对象,它和`HttpReault.Body`都继承自`Toable`接口,他共有如下一些方法: + +* `isText()` 判断是文本消息还是二进制消息 +* `toByteStream()` 消息体转字节流 +* `toBytes()` 消息体转字数组 +* `toByteString()` 消息体转字数组 +* `toCharStream()` 消息体转字符流 +* `toString()` 消息体转字符串 +* `toMapper()` 消息体转 Mapper 对象(不想定义 Java Bean 时使用) +* `toArray()` 消息体转 Array 数组(不想定义 Java Bean 时使用) +* `toBean(Class type)` 报文体Json文本转JavaBean +* `toBean(Type type)` 报文体Json文本转JavaBean +* `toBean(TypeRef type)` 报文体Json文本转JavaBean +* `toList(Class type)` 报文体Json文本转JavaBean列表 + +### 发送消息 + +向服务器发送消息,首先要获得一个`WebSocket`实例,该实例可以通过`listen()`方法的返回值或回调方法的参数获取,如: + +```java +WebSocket ws = http.webSocket("/chat").listen(); // 启动监听,并返回一个 WebSocket 实例 +``` + +接口`WebSocket`继承自`Cancelable`,它共定义了如下方法: + +* `cancel()` 取消连接(连接成功前可以取消) +* `queueSize()` 排队待发送消息的数量 +* `send(Object object)` 发送消息,参数是待发送的对象,可以是 String | ByteString | byte[] | Java Bean +* `close(int code, String reason)` 关闭连接(连接成功后可以关闭) +* `msgType(String type)` 设置消息传输类型,类似于`bodyType` + +一个发送消息的例子 + +```java +WebSocket ws = http.webSocket("/chat").listen(); +ws.send("Hello World!") // 该消息会先进入排队等待状态,当连接成功时发送给服务器 +``` + +或者 + +```java +http.webSocket("/chat") + .setOnOpen((WebSocket ws, HttpResult res) -> { + // 当连接成功时发送给服务器 + ws.send("Hello World!") + }) + .listen(); +``` + +## 回调方法 + +WebSocket 连接共可设置 **5** 种回调方法: + +```java +http.webSocket("/websocket-endpoint") + .setOnOpen((WebSocket ws, HttpResult res) -> { + // WebSocket 连接成功时回调 + }) + .setOnMessage((WebSocket ws, Message msg) -> { + // 收到服务器下发的消息时回调 + }) + .setOnException((WebSocket ws, Throwable thr) -> { + // 连接发生异常时回调 + }) + .setOnClosing((WebSocket ws, WebSocket.Close close) -> { + // 连接正在关闭时回调 + }) + .setOnClosed((WebSocket ws, WebSocket.Close close) -> { + // 连接已关闭(v2.0.0 之后包含连接被取消 和 连接发生异常)时回调 + }) + .listen(); +``` + +::: tip 需要注意的是 +如果设置了 [全局回调监听](/v2/configuration.html#全局回调监听), 它们对 WebSocket 连接 同样起作用 +::: + + +
+ + \ No newline at end of file diff --git a/okhttps/src/main/java/com/ejlchina/okhttps/WebSocket.java b/okhttps/src/main/java/com/ejlchina/okhttps/WebSocket.java index bb4b9d790cc283cd0a1bac272b31376b00dfbc42..aecc48e7e755fa43e83cbcf4a719f3152ad49811 100644 --- a/okhttps/src/main/java/com/ejlchina/okhttps/WebSocket.java +++ b/okhttps/src/main/java/com/ejlchina/okhttps/WebSocket.java @@ -87,7 +87,7 @@ public interface WebSocket extends Cancelable { } /** - * 若连接已打开,则: + * @return 若连接已打开,则: * 同 {@link okhttp3.WebSocket#queueSize()},返回排序消息的字节数 * 否则: * 返回排队消息的数量 @@ -102,8 +102,10 @@ public interface WebSocket extends Cancelable { /** * 同 {@link okhttp3.WebSocket#close(int, String)} + * @param code Status code as defined by Section 7.4 of RFC 6455 + * @param reason Reason for shutting down or {@code null}. */ - boolean close(int code, String reason); + void close(int code, String reason); /** * 设置消息类型 diff --git a/okhttps/src/main/java/com/ejlchina/okhttps/internal/AsyncHttpTask.java b/okhttps/src/main/java/com/ejlchina/okhttps/internal/AsyncHttpTask.java index 81e4d32b8ce076e69334acd97581c6594c4361be..d357c7e38f4233a292f942cbe48e799f40f9f52b 100644 --- a/okhttps/src/main/java/com/ejlchina/okhttps/internal/AsyncHttpTask.java +++ b/okhttps/src/main/java/com/ejlchina/okhttps/internal/AsyncHttpTask.java @@ -109,6 +109,8 @@ public class AsyncHttpTask extends HttpTask { /** * 设置请求得到响应后的回调函数 + * @param 泛型 + * @param type 期望的转换类型 * @param onResBean 响应 Bean 回调 * @return HttpTask 实例 */ @@ -122,6 +124,8 @@ public class AsyncHttpTask extends HttpTask { /** * 设置请求得到响应后的回调函数 + * @param 泛型 + * @param type 期望的转换类型 * @param onResBean 响应 Bean 回调 * @return HttpTask 实例 */ @@ -135,6 +139,8 @@ public class AsyncHttpTask extends HttpTask { /** * 设置请求得到响应后的回调函数 + * @param 泛型 + * @param type 期望的转换类型 * @param onResList 请求响应回调 * @return HttpTask 实例 */ diff --git a/okhttps/src/main/java/com/ejlchina/okhttps/internal/WebSocketTask.java b/okhttps/src/main/java/com/ejlchina/okhttps/internal/WebSocketTask.java index dd32f5028a51092f55a17b40a1b68312ff74414c..03b1962ce69e9196284be60b28aeb1a294cc0178 100644 --- a/okhttps/src/main/java/com/ejlchina/okhttps/internal/WebSocketTask.java +++ b/okhttps/src/main/java/com/ejlchina/okhttps/internal/WebSocketTask.java @@ -65,6 +65,7 @@ public class WebSocketTask extends HttpTask { * 2、服务器发送的任何消息都具有一次心跳作用 * 3、若服务器超过 3 * pongSeconds 秒没有回复心跳,才判断心跳超时 * + * @since v2.3.0 * @param pingSeconds 客户端心跳间隔秒数(0 表示不需要心跳) * @param pongSeconds 服务器心跳间隔秒数(0 表示不需要心跳) * @return WebSocketTask @@ -310,12 +311,11 @@ public class WebSocketTask extends HttpTask { } @Override - public synchronized boolean close(int code, String reason) { + public synchronized void close(int code, String reason) { if (webSocket != null) { webSocket.close(code, reason); } cancelOrClosed = true; - return true; } @Override