spring websocket小结

WebSocket协议是基于TCP的一种新的网络协议。它实现了浏览器与服务器全双工(full-duplex)通信——可以通俗的解释为服务器主动发送信息给客户端。

websocket允许通过JavaScript建立与远程服务器的连接,从而实现客户端与服务器间双向的通信。

在websocket中有两个方法:  
    1、send() 向远程服务器发送数据
    2、close() 关闭该websocket连接
websocket同时还定义了几个监听函数    
    1、onopen 当网络连接建立时触发该事件
    2、onerror 当网络发生错误时触发该事件
    3、onclose 当websocket被关闭时触发该事件
    4、onmessage 当websocket接收到服务器发来的消息时触发的事件,也是通信中最重要的一个监听事件。
websocket还定义了一个readyState属性,这个属性可以返回websocket所处的状态:
    1、CONNECTING(0) websocket正尝试与服务器建立连接
    2、OPEN(1) websocket与服务器已经建立连接
    3、CLOSING(2) websocket正在关闭与服务器的连接
    4、CLOSED(3) websocket已经关闭了与服务器的连接
 
websocket的url开头是ws,如果需要ssl加密可以使用wss,当我们调用websocket的构造方法构建一个websocket对象(new WebSocket(url))之后,就可以进行即时通信了。

Spring官方文档:http://docs.spring.io/spring/docs/current/spring-framework-reference/html/websocket.html

spring4.0以上支持websocket,要求servlet-api必须是3.0+

WebSocket:

        
        
           org.springframework
           spring-websocket
           4.0.2.RELEASE
        

        
           org.springframework
           spring-messaging
           4.0.2.RELEASE
        

Servlet-api

    
        javax.servlet
        javax.servlet-api
        3.1.0
    

web.xml的namespace也要确保是3.0+


    // 使用来选择性地启用或禁用Web片段(和SCI扫描)
    

如果要支持异步的servlet3.x,可以在web.xml下的servlet和filter里面加上

true

service服务端的具体实现

首先是配置文件类(注解),给服务器添加websocket服务

@Configuration
@EnableWebSocket
public class MyWebSocketConfig extends WebMvcConfigurerAdapter implements WebSocketConfigurer {

    @Autowired
    MyWebSocketHandler handler;

    public void registerWebSocketHandlers(WebSocketHandlerRegistry webSocketHandlerRegistry) {

        //前台 可以使用websocket环境
        webSocketHandlerRegistry.addHandler(handler, "/chats/connect/socket").addInterceptors(new MyHandShakeInterceptor());

        //前台 不可以使用websocket环境,则使用sockjs进行模拟连接
        webSocketHandlerRegistry.addHandler(handler, "/chats/connect/socket/sockjs").addInterceptors(new MyHandShakeInterceptor()).withSockJS();
    }
}

然后是创建握手拦截器

public class MyHandShakeInterceptor implements HandshakeInterceptor {

    private static final Logger logger = LogManager.getLogger(MyWebSocketHandler.class);

    public boolean beforeHandshake(ServerHttpRequest serverHttpRequest, ServerHttpResponse serverHttpResponse, WebSocketHandler webSocketHandler, Map map) throws Exception {
        if (serverHttpRequest instanceof ServletServerHttpRequest) {
            HttpServletRequest servletRequest = ((ServletServerHttpRequest) serverHttpRequest).getServletRequest();
            //当前的登录者
            Long userId = (Long) servletRequest.getSession().getAttribute("userId");
            if(userId!=null){
                map.put("uid", userId);//为服务器创建WebSocketSession做准备
                logger.info("用户id:"+userId+" 加入");
            }else{
                logger.error("没有获取session中的当前登陆者信息");
            }
        }
        return true;
    }

    public void afterHandshake(ServerHttpRequest serverHttpRequest, ServerHttpResponse serverHttpResponse, WebSocketHandler webSocketHandler, Exception e) {
            logger.info("握手后");
    }
}

最后是创建websocket的处理类

@Component
public class MyWebSocketHandler implements WebSocketHandler {

    @Autowired
    private ChatService chatService;

    @Autowired
    private ChatMessageService chatMessageService;

    private static final Logger logger = LogManager.getLogger(MyWebSocketHandler.class);

    // 保存所有的用户session
    private final static Map sessions = new HashMap<>();

    //握手实现连接后
    @Override
    public void afterConnectionEstablished(WebSocketSession webSocketSession) throws Exception {
        logger.info("连接成功。。。。。。");
        Long userId = (Long) webSocketSession.getAttributes().get("uid");
        if(sessions.get(userId) == null)
            sessions.put(userId,webSocketSession);
        logger.info("session: "+sessions);
    }

    //发送信息前的处理
    @Override
    public void handleMessage(WebSocketSession webSocketSession, WebSocketMessage webSocketMessage) throws Exception {

        logger.info("用户"+webSocketSession.getAttributes().get("uid")+":发送消息:" + webSocketMessage.getPayload().toString());

        String message = webSocketMessage.getPayload().toString();
        String[] buf = message.split(":");
        if(buf.length == 2){ //切换聊天,用来标记发送方的信息已读
            Long chatId = Long.valueOf(buf[1]);
            chatService.setRead(chatId,(Long) webSocketSession.getAttributes().get("uid"));
        }
        if(buf.length == 3){ //发送消息
            Long chatId = Long.valueOf(buf[1]);
            String content = buf[2];
            Chat chat = chatService.getChat(chatId);
            Long userFromId = (Long) webSocketSession.getAttributes().get("uid"); //当前登录者为发送者
            Long userToId = null;
            if(userFromId == chat.getUserId()){
                userToId = chat.getOppositeUser().getId();
            }else{
                userToId = chat.getUserId();
            }
            //将信息保存至数据库
            try {
                ChatMessage chatMessage = chatMessageService.addChatMessage(userFromId, chat.getId(), content);
                String sendMsg = "{\"chatId\":"+chatId+",\"message\":{\"uuid\":\""+chatMessage.getUuid()+"\",\"content\":\""+chatMessage.getContent()+
                        "\",\"createdAt\":"+chatMessage.getCreatedAt().getTime()+",\"user\":{\"id\":"+chatMessage.getUser().getId()+",\"slug\":\""+chatMessage.getUser().getSlug()+
                        "\",\"nickname\":\""+chatMessage.getUser().getNickname()+"\",\"avatar\":\""+chatMessage.getUser().getAvatar().getPath()+"\"}}}";
                logger.info("接收的消息格式:"+sendMsg);
                //发送Socket信息
                sendMessageToUser(userToId, new TextMessage(sendMsg,true),webSocketSession);
            }catch (Exception e){
                e.printStackTrace();
            }
        }

        //将JSON格式的消息通过Gson转换成Map
        //通过getPayload().toString()获取消息具体内容
        //Map msg = new Gson().fromJson(webSocketMessage.getPayload().toString(),new TypeToken>() {}.getType());

    }

    @Override
    public void handleTransportError(WebSocketSession webSocketSession, Throwable throwable) throws Exception {
        if (webSocketSession.isOpen()) {
            webSocketSession.close();
        }
        sessions.remove(webSocketSession.getAttributes().get("uid"));
        logger.info("webSocket异常处理" + throwable.getMessage());
    }

    @Override
    public void afterConnectionClosed(WebSocketSession webSocketSession, CloseStatus closeStatus) throws Exception {
        logger.info("连接关闭");
        sessions.remove(webSocketSession.getAttributes().get("uid"));
    }

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

    //发送信息的实现
    public void sendMessageToUser(Long uid, TextMessage message,WebSocketSession webSocketSession) throws IOException {
        WebSocketSession userToSession = null;
        //遍历所有已连接的用户
        for (Map.Entry entry : sessions.entrySet()) {
            Long connectedUserId = (Long) entry.getValue().getAttributes().get("uid");
            if (connectedUserId == uid) {
                userToSession = entry.getValue();
                break;
            }
        }
        if(userToSession == null){
            logger.info("对方暂时不在线");
            webSocketSession.sendMessage(new TextMessage("对方暂时不在线"));
        }
        if (userToSession != null && userToSession.isOpen()) {
            logger.info("发送消息给:"+uid);
            userToSession.sendMessage(message);
        }
    }
}

client客户端的实现

登录页面

login.html




    
    登录页面


登录

用户名
密码
验证码

聊天室页面展示

chat.html




    
    Title
    
    
    
    
    
    


    
    

JS-客户端主要的实现

chat.js

$(function() {

    var websocket;

    // 首先判断是否支持WebSocket
    if('WebSocket' in window) {
        websocket = new WebSocket("ws://localhost:8080/chats/connect/socket");
    } else if('MozWebSocket' in window) {
        websocket = new MozWebSocket("ws://localhost:8080/chats/connect/socket");
    } else {
        websocket = new SockJS("http://localhost:8080/chats/connect/socket/sockjs");
    }

    // 打开时
    websocket.onopen = function(event) {
        console.log("连接成功");
        console.log(event);
    };

    // 处理消息时
    websocket.onmessage = function(event) {
        $("#msg").append(event.data);
        console.log("处理消息");
        console.log(event);
    };

    websocket.onerror = function(event) {
        console.log("连接失败");
        console.log(event);
    };

    websocket.onclose = function(event) {
        console.log("socket连接断开");
        console.log(event);
    };

    // 点击了发送消息按钮的响应事件
    $("#TXBTN").click(function(){
        // 获取消息内容
        var text = $("#tx").val();
        // 判断
        if(text == null || text == ""){
            alert(" content  can not empty!!");
            return false;
        }
        //var msg = {
        //    content: text
        //};
        // 发送消息
        //websocket.send(JSON.stringify(msg));
        websocket.send("message:"+1+":"+text);
    });

});

参考文章:

Spring MVC 自学杂记(四) -- Spring+SpringMVC+WebSocket

SSM框架+WebSocket实现网页聊天(Spring+SpringMVC+MyBatis+WebSocket)

 

你可能感兴趣的:(spring websocket小结)