三、WebSocket 协议转换为 Socket.D (v2)
此内容 v2.6.0 后支持
WebSocket 支持通过转换为 Socket.D 协议 ,进而支持 Mvc 模式开发(客户端须以 Socket.D 协议交互)。
1、协议转换
引入依赖 Socket.D 协议内核包
<dependency>
<groupId>org.noear</groupId>
<artifactId>socketd</artifactId>
</dependency>
尝试把 /mvc/
频道,升级为 socket.d. 协议。添加协议转换代码
- 通过 ToSocketdWebSocketListener 监听器,把 WebSocket 转为 Socket.D 协议
- ToSocketdWebSocketListener 在构造时,需要指定 Socket.D 协议的处理监听器
协议升级后,/mvc/
频道只能使用 socket.d 客户端连接。(其它频道不受影响)
public class DemoApp {
public static void main(String[] args) {
Solon.start(DemoApp.class, args, app->{
//启用 WebSocket 服务
app.enableWebSocket(true);
//如果 WebSocket 升级成 Socket.D 协议,不需启用 enableSocketD(true)
//enableSocketD 是 org.noear:solon-boot-socketd 插件的启用控制
});
}
}
//协议转换处理
@ServerEndpoint("/mvc/")
public class WebSocketAsMvc extends ToSocketdWebSocketListener {
public WebSocketAsMvc() {
// clientMode=false,表示服务端模式
super(new ConfigDefault(false), new EventListener()
.doOnOpen(s -> {
//可以添加点签权?
if ("a".equals(s.param("u")) == false) {
s.close();
}
})
.doOn("/demo/hello", (s, m) -> {
if (m.isRequest()) {
s.reply(m, new StringEntity("{\"code\":200}"));
}
}));
}
}
2、可以进一步转换为 Mvc 接口
尝试把 /mvc/
频道,进一步转为 solon 控制器模式开发。(其它频道不受影响)
- 通过 ToHandlerListener ,再转换为 Solon Handler 接口。从而实现控制器模式开发
@ServerEndpoint("/mvc/")
public class WebSocketAsMvc extends ToSocketdWebSocketListener {
public WebSocketAsMvc() {
//将 socket.d 普通监听器,换成 ToHandlerListener
//可以对 ToHandlerListener 进行扩展或定制
super(new ConfigDefault(false), new ToHandlerListener()
.doOnOpen(s -> {
//可以添加点签权?
if ("a".equals(s.param("u")) == false) {
s.close();
}
}));
//v2.6.6 后,ToHandlerListener 基类改为 EventListener ,更方便定制
}
}
//控制器
@Controller
public class HelloController {
@Socket //不加限定注解的话,可同时支持 http 请求
@Mapping("/demo/hello")
public Result hello(long id, String name) { //{code:200,...}
return Result.succeed();
}
}
3、使用 Socket.D 进行客户端调用
如果上面是 http-server 自带的 websocket 的服务,即与 http 相同。比如:8080 端口。
- 以 Java Socket.D 原生接口方式示例
引入依赖包
<!-- 提供 sd:ws 传输编解码支持(不同的传输协议,用不同的包) -->
<dependency>
<groupId>org.noear</groupId>
<artifactId>socketd-transport-java-websocket</artifactId>
<version>${socketd.version}</version>
</dependency>
协议升级后,使用 sd:ws
作为协议架构(以示区别,避免混乱)
let clientSession = SocketD.createClient("sd:ws://localhost:8080/mvc/?u=a")
.open();
//v2.6.6 后,支持实体简化构建。旧版使用 new StringEntity(...) 构建
let request = Entity.of("{id:1,name:'noear'}").metaPut("Content-Type","text/json"),
let response = clientSession.sendAndRequest("/demo/hello", entity).await();
// event 相当于 http path(注意这个关系)
// data 相当于 http body
// meta 相当于 http header
- 以 Java Rpc 代理模式示例
再多引入一个依赖包
<!-- 提供 SocketdProxy 类 -->
<dependency>
<groupId>org.noear</groupId>
<artifactId>nami.channel.socketd</artifactId>
</dependency>
代码示例(以 rpc 代理的方式展示)
//[客户端] 调用 [服务端] 的 mvc
//
HelloService rpc = SocketdProxy.create("sd:ws://localhost:8080/mvc/?u=a", HelloService.class);
System.out.println("MVC result:: " + mvc.hello("noear"));
- 以 Javascript 客户端示例(具体参考:Socket.D - JavaScript 开发)
<script src="/js/socket.d.js"></script>
const clientSession = await SocketD.createClient("sd:ws://127.0.0.1:8080/mvc/?u=a")
.open();
//添加用户(加个内容类型,方便与 Mvc 对接)
const entity = SocketD.newEntity("{id:1,name:'noear'}").metaPut("Content-Type","text/json"),
clientSession.sendAndRequest("/demo/hello", entity).thenReply(reply=>{
alert(reply.dataAsString());
})
// event 相当于 http path(注意这个关系)
// data 相当于 http body
// meta 相当于 http header