• Spring+WebSocket+SockJS实现实时聊天


    设计初衷是通过websocket实现网页实时通讯聊天。

    工程环境:tomcat8+jdk1.7+maven+eclipse

    设计思路:客户端登录网页建立socket连接,后台记录用户连接信息并做标识;当用户在网页端发送聊天消息至后台,后台收到信息后将消息发送至接收者,同时后端对消息进行持久保存。

    简要代码实现demo如下:

    1、pom.xml主要配置

    <dependency>
    <groupId>javax.websocket</groupId>
    <artifactId>javax.websocket-api</artifactId>
    <version>1.0</version>
    <scope>provided</scope>
    </dependency>
    <dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-websocket</artifactId>
    <version>${spring.version}</version>
    </dependency>
    <dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-messaging</artifactId>
    <version>${spring.version}</version>
    </dependency>
    <dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-aop</artifactId>
    <version>${spring.version}</version>
    </dependency>
    <dependency>
    <groupId>org.apache.logging.log4j</groupId>
    <artifactId>log4j-api</artifactId>
    <version>${log4j.version}</version>
    </dependency>
    <dependency>
    <groupId>org.apache.logging.log4j</groupId>
    <artifactId>log4j-core</artifactId>
    <version>${log4j.version}</version>
    </dependency>


    <!-- AspectJ -->
    <!-- <dependency>
    <groupId>org.aspectj</groupId>
    <artifactId>aspectjrt</artifactId>
    <version>${org.aspectj-version}</version>
    </dependency> -->
    <dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-aspects</artifactId>
    <version>${spring.version}</version>
    </dependency>

    2、spring核心配置信息
    <context:component-scan base-package="com.milanosoft.RCS.web.webSocket.config" />

    <context:component-scan base-package="com.milanosoft.RCS.web.webSocket.hndler">
    </context:component-scan>

    <context:component-scan base-package="com.milanosoft.RCS.web.webSocket.interceptor">
    </context:component-scan>

    3、websocket服务端实现
    package com.milanosoft.RCS.web.webSocket.config;

    import com.milanosoft.RCS.web.webSocket.hndler.SystemWebSocketHandler;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.web.servlet.config.annotation.EnableWebMvc;
    import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
    import org.springframework.web.socket.WebSocketHandler;
    import org.springframework.web.socket.config.annotation.EnableWebSocket;
    import org.springframework.web.socket.config.annotation.WebSocketConfigurer;
    import org.springframework.web.socket.config.annotation.WebSocketHandlerRegistry;

    import com.milanosoft.RCS.web.webSocket.interceptor.HandshakeInterceptor;
    import org.springframework.context.annotation.Bean;

    @Configuration
    @EnableWebMvc
    @EnableWebSocket
    public class WebSocketConfig extends WebMvcConfigurerAdapter implements
    WebSocketConfigurer {

    public WebSocketConfig() {
    }

    @Override
    public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
    registry.addHandler(systemWebSocketHandler(), "/websck").addInterceptors(new HandshakeInterceptor());

    System.out.println("registed!");
    registry.addHandler(systemWebSocketHandler(), "/sockjs/websck").addInterceptors(new HandshakeInterceptor())
    .withSockJS();

    }

    @Bean
    public WebSocketHandler systemWebSocketHandler() {
    //return new InfoSocketEndPoint();
    return new SystemWebSocketHandler();
    }

    }

    4、websocket连接前后的事件类
    package com.milanosoft.RCS.web.webSocket.interceptor;

    import java.util.Map;

    import org.springframework.http.server.ServerHttpRequest;
    import org.springframework.http.server.ServerHttpResponse;
    import org.springframework.stereotype.Component;
    import org.springframework.web.socket.WebSocketHandler;
    import org.springframework.web.socket.server.support.HttpSessionHandshakeInterceptor;


    @Component
    public class HandshakeInterceptor extends HttpSessionHandshakeInterceptor {

    @Override
    public boolean beforeHandshake(ServerHttpRequest request,
    ServerHttpResponse response, WebSocketHandler wsHandler,
    Map<String, Object> attributes) throws Exception {

    //解决The extension [x-webkit-deflate-frame] is not supported问题
    if(request.getHeaders().containsKey("Sec-WebSocket-Extensions")) {
    request.getHeaders().set("Sec-WebSocket-Extensions", "permessage-deflate");
    }

    System.out.println("Before Handshake");
    return super.beforeHandshake(request, response, wsHandler, attributes);
    }

    @Override
    public void afterHandshake(ServerHttpRequest request,
    ServerHttpResponse response, WebSocketHandler wsHandler,
    Exception ex) {
    System.out.println("After Handshake");
    super.afterHandshake(request, response, wsHandler, ex);
    }

    }


    //解决The extension [x-webkit-deflate-frame] is not supported问题
            if(request.getHeaders().containsKey("Sec-WebSocket-Extensions")) {
                request.getHeaders().set("Sec-WebSocket-Extensions", "permessage-deflate");
            }

    其中标红色的代码是为了解决下面的错误,可能是ios手机safari浏览器版本问题引起的。

    org.springframework.web.socket.server.HandshakeFailureException: Uncaught failure for request http://localhost:8080/spring4/myHandler; nested exception is java.lang.IllegalArgumentException: The extension [x-webkit-deflate-frame] is not supported


    5、websocket消息处理类

    /*
    * To change this license header, choose License Headers in Project Properties.
    * To change this template file, choose Tools | Templates
    * and open the template in the editor.
    */
    package com.milanosoft.RCS.web.webSocket.hndler;

    import org.springframework.stereotype.Component;
    import org.springframework.web.socket.CloseStatus;
    import org.springframework.web.socket.TextMessage;
    import org.springframework.web.socket.WebSocketHandler;
    import org.springframework.web.socket.WebSocketMessage;
    import org.springframework.web.socket.WebSocketSession;

    /**
    *
    * @author lzk
    */
    @Component
    public class SystemWebSocketHandler implements WebSocketHandler {

    @Override
    public void afterConnectionEstablished(WebSocketSession session) throws Exception {
    System.out.println("connect to the websocket success......");
    session.sendMessage(new TextMessage("Server:connected OK!"));
    }

    @Override
    public void handleMessage(WebSocketSession wss, WebSocketMessage<?> wsm) throws Exception {
    TextMessage returnMessage = new TextMessage(wsm.getPayload()
    + " received at server");
    System.out.println(wss.getHandshakeHeaders().getFirst("Cookie"));
    wss.sendMessage(returnMessage);
    }

    @Override
    public void handleTransportError(WebSocketSession wss, Throwable thrwbl) throws Exception {
    if(wss.isOpen()){
    wss.close();
    }
    System.out.println("websocket connection closed......");
    }

    @Override
    public void afterConnectionClosed(WebSocketSession wss, CloseStatus cs) throws Exception {
    System.out.println("websocket connection closed......");
    }

    @Override
    public boolean supportsPartialMessages() {
    return false;
    }

    }

    6、客户端页面
    <%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
    <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
    <html>
    <head>
    <%session.setAttribute("user", "lzk"); %>
    <title>WebSocket/SockJS Echo Sample (Adapted from Tomcat's echo sample)</title>
    <style type="text/css">
    #connect-container {
    float: left;
    400px
    }

    #connect-container div {
    padding: 5px;
    }

    #console-container {
    float: left;
    margin-left: 15px;
    400px;
    }

    #console {
    border: 1px solid #CCCCCC;
    border-right-color: #999999;
    border-bottom-color: #999999;
    height: 170px;
    overflow-y: scroll;
    padding: 5px;
    100%;
    }

    #console p {
    padding: 0;
    margin: 0;
    }
    </style>

    <script src="http://cdn.sockjs.org/sockjs-0.3.min.js"></script>

    <script type="text/javascript">
    var ws = null;
    var url = null;
    var transports = [];

    function setConnected(connected) {
    document.getElementById('connect').disabled = connected;
    document.getElementById('disconnect').disabled = !connected;
    document.getElementById('echo').disabled = !connected;
    }

    function connect() {
    //alert(url);
    //console.log(url);
    if (!url) {
    alert('Select whether to use W3C WebSocket or SockJS');
    return;
    }

    //ws = (url.indexOf('sockjs') != -1) ?new SockJS(url, undefined, {protocols_whitelist: transports}) : new WebSocket(url);
    if ('WebSocket' in window) {
    ws= new WebSocket("ws://192.168.1.104:8080/SpringWebSocketPush/websck");
    console.log("ws://192.168.1.104:8080/SpringWebSocketPush/websck");
    }else {
    ws = new SockJS("http://192.168.1.104:8080/SpringWebSocketPush/sockjs/websck");
    console.log("http://192.168.1.104:8080/SpringWebSocketPush/sockjs/websck");
    }
    //websocket = new SockJS("http://localhost:8080/SpringWebSocketPush/sockjs/websck");
    ws.onopen = function () {
    alert('open');
    setConnected(true);
    //log('Info: connection opened.');
    };
    ws.onmessage = function (event) {
    alert('Received:' + event.data);
    log('Received: ' + event.data);
    };
    ws.onclose = function (event) {
    setConnected(false);
    log('Info: connection closed.');
    log(event);
    };
    }

    function disconnect() {
    if (ws != null) {
    ws.close();
    ws = null;
    }
    setConnected(false);
    }

    function echo() {
    if (ws != null) {
    var message = document.getElementById('message').value;
    log('Sent: ' + message);
    ws.send(message);
    } else {
    alert('connection not established, please connect.');
    }
    }

    function updateUrl(urlPath) {
    if (urlPath.indexOf('sockjs') != -1) {
    url = urlPath;
    document.getElementById('sockJsTransportSelect').style.visibility = 'visible';
    }
    else {
    if (window.location.protocol == 'http:') {
    url = 'ws://' + window.location.host + urlPath;
    } else {
    url = 'wss://' + window.location.host + urlPath;
    }
    document.getElementById('sockJsTransportSelect').style.visibility = 'hidden';
    }
    }

    function updateTransport(transport) {
    alert(transport);
    transports = (transport == 'all') ? [] : [transport];
    }

    function log(message) {
    var console = document.getElementById('console');
    var p = document.createElement('p');
    p.style.wordWrap = 'break-word';
    p.appendChild(document.createTextNode(message));
    console.appendChild(p);
    while (console.childNodes.length > 25) {
    console.removeChild(console.firstChild);
    }
    console.scrollTop = console.scrollHeight;
    }
    </script>
    </head>
    <body>
    <noscript><h2 style="color: #ff0000">Seems your browser doesn't support Javascript! Websockets
    rely on Javascript being enabled. Please enable
    Javascript and reload this page!</h2></noscript>
    <div>
    <br>
    <div id="connect-container">
    <input id="radio1" type="radio" name="group1" οnclick="updateUrl('/SpringWebSocketPush/websck');">
    <label for="radio1">W3C WebSocket</label>
    <br>
    <input id="radio2" type="radio" name="group1" οnclick="updateUrl('/SpringWebSocketPush/sockjs/websck');">
    <label for="radio2">SockJS</label>
    <div id="sockJsTransportSelect" style="visibility:hidden;">
    <span>SockJS transport:</span>
    <select οnchange="updateTransport(this.value)">
    <option value="all">all</option>
    <option value="websocket">websocket</option>
    <option value="xhr-polling">xhr-polling</option>
    <option value="jsonp-polling">jsonp-polling</option>
    <option value="xhr-streaming">xhr-streaming</option>
    <option value="iframe-eventsource">iframe-eventsource</option>
    <option value="iframe-htmlfile">iframe-htmlfile</option>
    </select>
    </div>
    <div>
    <button id="connect" οnclick="connect();">Connect</button>
    <button id="disconnect" disabled="disabled" οnclick="disconnect();">Disconnect</button>
    </div>
    <div>
    <textarea id="message" style=" 350px">Here is a message!</textarea>
    </div>
    <div>
    <button id="echo" οnclick="echo();" disabled="disabled">Echo message</button>
    </div>
    </div>
    <div id="console-container">
    <div id="console"></div>
    </div>
    </div>
    </body>

    </html>

    这个例子也是在别人的代码基础上进行了一些修改,修复了一些BUG。

  • 相关阅读:
    ES基础(五十五)在私有云与公有云上管理与部署 Elasticsearch 集群
    ES基础(五十四)如何对集群进行容量规划
    ES基础(五十二)Hot & Warm 架构与 Shard Filtering
    ES基础(四十九)集群内部安全通信
    ES基础(四十八)集群身份认证与用户鉴权
    kata + docker run & star
    libcontainer nsexec + unshare + syscall(SYS_setns
    docker createHooks
    mount namespace
    exec.Command("/proc/self/exe", "child")
  • 原文地址:https://www.cnblogs.com/exmyth/p/11582009.html
Copyright © 2020-2023  润新知