此例，直接将 SpringBoot 的 WebSocket 监器接口转换为 Socket.D 的监听器（引入一个转换包），方便复用 SpringBoot 的 Http 端口。其它 WebSocket Server 接口，也可以参考此例。

引入专门的适配 SDK（兼容 jetty, undetow）：

```xml
<dependency>
    <groupId>org.noear</groupId>
    <artifactId>socketd-transport-spring-websocket</artifactId>
    <version>2.5.20</version>
</dependency>
```

适配 SDK 不面要启动 server，只需要注册 websocket 即可。通过协议转换，实现 socket.d 协议。

### 1、应用示例

* 配置 WebSocket

```java
//配置 websocket
@Configuration
@EnableWebSocket
public class WebSocketConfig implements WebSocketConfigurer {
    @Resource
    private WebSocketToSocketd webSocketToSocketd;

    @Override
    public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
        registry.addHandler(webSocketToSocketd,"/demo/websocket")
                .setAllowedOrigins("*");
    }
}
```

* 实现 WebSocket 监听与转换

定义 websocket 处理，并转为 socket.d 监听接口（也可以在这个类上，直接实现 Listener 接口）

```java
//示例1（设置监听器，也可以注入）
@Component
public class WebSocketToSocketd extends ToSocketdWebSocketListener {
    public WebSocketToSocketd() {
        super(new ConfigDefault(false).useSubprotocols(true)); //如果客户端不支持子协议验证，可以设为 false
        
        //设置 socket.d 监听
        setListener(new EventListener().doOnOpen(s -> {

        }).doOn("/demo", (s, m) -> {

        }));
    }
}

//示例2（直接实现 socket.d 监听）
@Component
public class WebSocketToSocketd extends ToSocketdWebSocketListener implements Listener{
    public WebSocketToSocketd() {
        super(new ConfigDefault(false));
    }
    
     @Override
    public void onOpen(Session session) throws IOException {

    }

    @Override
    public void onMessage(Session session, Message message) throws IOException {
        if("/demo".equals(message.event())){
            
        }
    }

    @Override
    public void onClose(Session session) {

    }

    @Override
    public void onError(Session session, Throwable error) {

    }
}
```



### 2、配合 H5 演示示例：

* 前端界面（打开后，把地址和端口改成对应的）

<a href="/demo/demo01-js-ws/" target="_blank">/demo/demo01-js-ws/</a>


* 配套服务端代码 - java：

```java
@Configuration
@EnableWebSocket
public class WebSocketConfig implements WebSocketConfigurer {

    private WebSocketToSocketd webSocketToSocketd = new WebSocketToSocketd();

    @Override
    public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
        registry.addHandler(webSocketToSocketd, "/")
                .setAllowedOrigins("*");
    }
}
```

```java
public class WebSocketToSocketd extends ToSocketdWebSocketListener {
    public WebSocketToSocketd() {
        super(new ConfigDefault(false));

        setListener(buildListener());
    }

    /**
     * 构建监听器
     */
    private  Listener buildListener() {
        return new EventListener()
                .doOnOpen(s -> {
                    System.out.println("onOpen: " + s.sessionId());
                }).doOnMessage((s, m) -> {
                    System.out.println("onMessage: " + m);
                }).doOn("/demo", (s, m) -> {
                    if (m.isRequest()) {
                        s.reply(m, new StringEntity("me to!"));
                    }

                    if (m.isSubscribe()) {
                        int size = m.metaAsInt(EntityMetas.META_RANGE_SIZE);
                        for (int i = 1; i <= size; i++) {
                            s.reply(m, new StringEntity("me to-" + i));
                        }
                        s.replyEnd(m, new StringEntity("welcome to my home!"));
                    }
                }).doOn("/upload", (s, m) -> {
                    if (m.isRequest()) {
                        String fileName = m.meta(EntityMetas.META_DATA_DISPOSITION_FILENAME);
                        if (StrUtils.isEmpty(fileName)) {
                            s.reply(m, new StringEntity("no file! size: " + m.dataSize()));
                        } else {
                            s.reply(m, new StringEntity("file received: " + fileName + ", size: " + m.dataSize()));
                        }
                    }
                }).doOn("/download", (s, m) -> {
                    if (m.isRequest()) {
                        FileEntity fileEntity = new FileEntity(new File("/Users/noear/Movies/snack3-rce-poc.mov"));
                        s.reply(m, fileEntity);
                    }
                }).doOn("/push", (s, m) -> {
                    if (s.attrHas("push")) {
                        return;
                    }

                    s.attrPut("push", "1");

                    while (true) {
                        if (s.attrHas("push") == false) {
                            break;
                        }

                        s.send("/push", new StringEntity("push test"));
                        RunUtils.runAndTry(() -> Thread.sleep(200));
                    }
                }).doOn("/unpush", (s, m) -> {
                    s.attrMap().remove("push");
                })
                .doOnClose(s -> {
                    System.out.println("onClose: " + s.sessionId());
                }).doOnError((s, err) -> {
                    System.out.println("onError: " + s.sessionId());
                    err.printStackTrace();
                });
    }
}
```