Spring Boot对WebSocket整合

SpringBoot本身不提供WebSocket支持,还是需要服务器如内嵌的Tomcat对WebSocket的支持。

引入maven依赖:

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-websocket</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-json</artifactId>
        </dependency>

 

引入Spring Boot对WebSocket依赖实际上是Spring对WebSocket的支持:

 

客户端这里使用Sockjs,非原生的websocket支持的js API,这样做的好处是,对不支持WebSocket的浏览器可以自动降级。使用轮询的方式来访问服务端。

https://github.com/sockjs/sockjs-client

cdn加速:https://www.bootcdn.cn/sockjs-client/

 HTML  echo.html代码:

  1 <!DOCTYPE html>
  2 <html>
  3     <head>
  4         <title>WebSocket Simple</title>
  5         <style type="text/css">
  6             #connect-container {
  7                 float: left;
  8                 width: 400px;
  9             }
 10 
 11             #connect-container div {
 12                 padding: 5px;
 13             }
 14 
 15             #console-container {
 16                 float: left;
 17                 margin-left: 15px;
 18                 width: 400px;
 19             }
 20 
 21             #console {
 22                 border: 1px solid #CCCCCC;
 23                 border-right-color: #999999;
 24                 border-bottom-color: #999999;
 25                 height: 170px;
 26                 overflow-y: scroll;
 27                 padding: 5px;
 28                 width: 100%;
 29             }
 30 
 31             #console p {
 32                 padding: 0;
 33                 margin: 0;
 34             }
 35         </style>
 36         <script src="https://cdn.bootcss.com/sockjs-client/0.3.4/sockjs.min.js"></script>
 37         <script type="text/javascript">
 38             var ws = null;
 39 
 40             function setConnected(connected) {
 41                 document.getElementById('connect').disabled = connected;
 42                 document.getElementById('disconnect').disabled = !connected;
 43                 document.getElementById('echo').disabled = !connected;
 44             }
 45 
 46             function connect() {
 47                 var target  = document.getElementById('target').value;
 48                 ws = new SockJS(target);
 49                 ws.onopen = function () {
 50                     setConnected(true);
 51                     log('Info: WebSocket connection opened.');
 52                 };
 53                 ws.onmessage = function (event) {
 54                     log('Received:' + event.data);
 55                 };
 56                 ws.onclose = function () {
 57                     setConnected(false);
 58                     log('Info: WebSocket connection closed.')
 59                 }
 60             }
 61 
 62             function disconnect() {
 63                 if(ws != null){
 64                     ws.close();
 65                     ws = null;
 66                 }
 67                 setConnected(false);
 68             }
 69 
 70             function echo() {
 71                 if(ws != null){
 72                     var message = document.getElementById('message').value;
 73                     log('Send:' + message);
 74                     ws.send(message);
 75                 }else{
 76                     alert('WebSocket connection not established , plase connect.');
 77                 }
 78             }
 79 
 80             function log(message) {
 81                 var console = document.getElementById('console');
 82                 console.appendChild(document.createTextNode('<p>'+message+'</p>'));
 83                 while(console.childNodes.length > 25){
 84                     console.removeChild(console.firstChild);
 85                 }
 86                 console.scrollTop = console.scrollHeight;
 87             }
 88         </script>
 89     </head>
 90     <body>
 91         <noscript>
 92             <h2 >............................................... </h2>
 93         </noscript>
 94         <div>
 95             <div id="connect-container">
 96                 <div>
 97                     <input id="target" type="text" size="40" style="" value="/echo"/>
 98                 </div>
 99                 <div>
100                     <button id = "connect" onclick="connect();">Connect</button>
101                     <button id="disconnect" onclick="disconnect();" disabled="disabled">Disconnect</button>
102                 </div>
103                 <div>
104                     <textarea id="message" >a message to be sent</textarea>
105                 </div>
106                 <div>
107                     <button id="echo" onclick="echo();" disabled="disabled">Echo message</button>
108                 </div>
109             </div>
110             <div id="console-container">
111                 <div id="console"></div>
112             </div>
113         </div>
114     </body>
115 </html>
View Code

 

下面Spring Boot编写服务端代码:

首先定义一个业务接口,获取消息:

public interface EchoService {
     String   getMessage(String message);
}

然后提供一个业务接口的实现类:

public class DefaultEchoService implements EchoService {

    private final String echoFormat;

    public DefaultEchoService(String echoFormat) {
        this.echoFormat = (null != echoFormat)?echoFormat:"%s";
    }

    @Override
    public String getMessage(String message) {
        return String.format(echoFormat,message);
    }
}

然后继承一个websocket消息处理的handler(类似于netty对websocket的处理):TextWebSocketHandler

public class EchoWebSocketHandler extends TextWebSocketHandler {

    private EchoService echoService;

    public EchoWebSocketHandler(EchoService echoService) {
        this.echoService = echoService;
    }

    @Override
    public void afterConnectionEstablished(WebSocketSession session) throws Exception {
        System.out.println("连接建立");
    }

    /**
     * 类似于Netty的Channel
     * @param session
     * @param exception
     * @throws Exception
     */
    @Override
    public void handleTransportError(WebSocketSession session, Throwable exception) throws Exception {
        session.close(CloseStatus.SERVER_ERROR);
    }

    @Override
    protected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception {
        String echoMessage = this.echoService.getMessage(message.getPayload());
        //消息重新发回给客户端
        session.sendMessage(new TextMessage(echoMessage));
    }
}

 

继承关系类图如下,典型的适配器模式:

 

  最后在启动类实现WebSocketConfigurer接口,然后把自己实现的EchoWebSocketHandler注册进去

@SpringBootApplication
@EnableWebSocket //非常重要,不然不会启用websocket功能
public class SpringbootDemoApplication implements WebSocketConfigurer { private static final Logger logger = LoggerFactory.getLogger(SpringbootDemoApplication.class); public static void main(String[] args) { SpringApplication.run(SpringbootDemoApplication.class, args); } @PostConstruct public void myLog(){ logger.trace("trace Message"); logger.debug("debug Message"); logger.info("info Message"); logger.warn("warn Message"); logger.error("error Message"); } /** * 注册websocket的处理器:EchoWebSocketHandler * @param registry */ @Override public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) { registry.addHandler(echoWebSocketHandler(),"/echo").withSockJS(); } /** * 实例化 * @return */ @Bean public EchoService echoService(){ return new DefaultEchoService(" output message: \"%s\"! "); } @Bean public WebSocketHandler echoWebSocketHandler(){ return new EchoWebSocketHandler(echoService()); } }

 测试验证:

访问:http://localhost:8090/echo.html 页面代码

 

Status Code  101 代表协议转换,Http升级成WebSocket协议

 

 

 

 

 

posted @ 2019-12-08 22:02  天蓝隐湘  阅读(656)  评论(0编辑  收藏  举报