websocket的两种实现方式:1基于注解,2与spring整合

来源:互联网 发布:淘宝小号信用查询网站 编辑:程序博客网 时间:2024/05/01 21:06
1:注解方式简单明了
服务端代码
package controller;import java.io.IOException;import java.util.Collections;import java.util.HashSet;import java.util.LinkedList;import java.util.List;import java.util.Set;import javax.websocket.CloseReason;import javax.websocket.OnClose;import javax.websocket.OnError;import javax.websocket.OnMessage;import javax.websocket.OnOpen;import javax.websocket.Session;import javax.websocket.server.ServerEndpoint;@ServerEndpoint("/chatServer")public class Chat {private static Set<Session> sessions = Collections.synchronizedSet(new HashSet<Session>());private static List<String> messages = Collections.synchronizedList(new LinkedList<String>());@OnOpenpublic void onOpen(Session session) {System.out.println("Session: " + session.getId() + " connected!");sessions.add(session);System.out.println("目前信息数: "+messages.size());for(String message : messages){try {session.getBasicRemote().sendText(message);} catch (IOException e) {e.printStackTrace();}}}@OnMessagepublic void onMessage(String message, Session session) throws InterruptedException {System.out.println("session : "+session.getId() + " : " + message);messages.add(message);    System.out.println("当前用户数: "+sessions.size());System.out.println("信息数:"+ messages.size());for(Session s : sessions){try {Thread.sleep(10000);s.getBasicRemote().sendText(message);} catch (IOException e) {System.out.println("出现异常");e.printStackTrace();}}}@OnClosepublic void onClose(Session session, CloseReason reason) {sessions.remove(session);System.out.println("Closed : " + session.getId());}@OnErrorpublic void onError(Throwable t) {System.out.println("Error : " + t.getMessage());t.printStackTrace();}}
客户端代码:
<!DOCTYPE html><html>  <head>    <meta charset="utf-8">    <title>chat Demo</title>    <style>      * {        margin: 0;        padding: 0;        font-family: "微软雅黑";      }      #mainFrame {        float: left;        padding: 20px;        border: 1px solid gray;        border-radius: 3px;        text-align: center;      }      #userName {        width: 500px;        height: 30px;        border: 1px solid gray;        border-radius: 3px;      }      #msgContainer {        text-align: left;        margin: 15px 0;        width: 640px;        height: 480px;        overflow: auto;        border: 1px solid gray;        border-radius: 3px;      }      #sendText {        width: 560px;        height: 30px;        border: 1px solid gray;        border-radius: 3px;      }      input[type="button"] {        width: 60px;        height: 30px;        border: 1px solid gray;        border-radius: 3px;      }    </style>  </head>  <body>    <div id="mainFrame">      用户名:<input type="text" id="userName">      <div id="msgContainer"></div>      <input type="text" id="sendText">      <input type="button" value="发送" onclick="send()">    </div>    <script>      var msgContainer = document.getElementById("msgContainer");      //服务器地址      var url = "ws://127.0.0.1:8080/TestWebSocket/chatServer";      //创建WebSocket对象      var ws = new WebSocket(url);      //与服务器建立连接      ws.onopen = function(){        console.info("connected!");      }      //接收到服务器发来的信息      ws.onmessage = function(mes) {        msgContainer.innerHTML = msgContainer.innerHTML + mes.data; //将数据加载到信息框        msgContainer.scrollTop = msgContainer.scrollHeight; //使信息框滚动条定位到最下边      }      //服务器关闭      ws.onclose = function() {        console.info("close");      }      //服务器异常      ws.onerror = function() {        console.info("error");      }      //浏览器刷新或者关闭时,先关闭当前页面的WebSocket对象      window.onbeforeunload = function(){       ws.close();     }     //发送信息      function send(){        var userName = document.getElementById("userName");        var sendText = document.getElementById("sendText");        if(userName.value ==""){          alert("请输入用户名!");          return;        }        if(sendText.value == "") return;        //调用WebSocket发送信息的方法,向服务器发送信息        ws.send("<span style='color:green;font-size:12px;font-family:\"微软雅黑\"'>"+userName.value+":</span><br><span style='color:gray;font-size:16px;font-family:\"微软雅黑\"'>"+sendText.value+"</span><br><div style='border-top:1px dotted gray;'></div>");        sendText.value = "";      }    </script>  </body></html>

2:与spring整合
服务端代码

WebSocketConfig.Java
这个类是配置类,所以需要在spring mvc配置文件中加入对这个类的扫描,第一个addHandler是对正常连接的配置,第二个是如果浏览器不支持websocket,使用socketjs模拟websocket的连接。
package com.websocket;import org.springframework.context.annotation.Bean;import org.springframework.context.annotation.Configuration;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 org.springframework.web.socket.handler.TextWebSocketHandler;@Configuration@EnableWebSocketpublic class WebSocketConfig implements WebSocketConfigurer {
    //这个方法的作用主要是用于注册建立握手之前的拦截造作,    @Override    public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {        registry.addHandler(chatMessageHandler(),"/webSocketServer").addInterceptors(new ChatHandshakeInterceptor());        registry.addHandler(chatMessageHandler(), "/sockjs/webSocketServer").addInterceptors(new ChatHandshakeInterceptor()).withSockJS();    }    
    //这个是socket信息处理类    @Bean    public TextWebSocketHandler chatMessageHandler(){        return new ChatMessageHandler();    }}

ChatHandshakeInterceptor.java

这个类的作用就是在连接成功前和成功后增加一些额外的功能,Constants.java类是一个工具类,两个常量。


package com.websocket;import java.util.Map;import org.apache.shiro.SecurityUtils;import org.springframework.http.server.ServerHttpRequest;import org.springframework.http.server.ServerHttpResponse;import org.springframework.web.socket.WebSocketHandler;import org.springframework.web.socket.server.support.HttpSessionHandshakeInterceptor;public class ChatHandshakeInterceptor extends HttpSessionHandshakeInterceptor {@Overridepublic boolean beforeHandshake(ServerHttpRequest request, ServerHttpResponse response, WebSocketHandler wsHandler,Map<String, Object> attributes) throws Exception {System.out.println("Before Handshake");/* * if (request instanceof ServletServerHttpRequest) { * ServletServerHttpRequest servletRequest = (ServletServerHttpRequest) * request; HttpSession session = * servletRequest.getServletRequest().getSession(false); if (session != * null) { //使用userName区分WebSocketHandler,以便定向发送消息 String userName = * (String) session.getAttribute(Constants.SESSION_USERNAME); if * (userName==null) { userName="default-system"; } * attributes.put(Constants.WEBSOCKET_USERNAME,userName); *  * } } *///使用userName区分WebSocketHandler,以便定向发送消息(使用shiro获取session,或是使用上面的方式)String userName = (String) SecurityUtils.getSubject().getSession().getAttribute(Constants.SESSION_USERNAME);if (userName == null) {userName = "default-system";}attributes.put(Constants.WEBSOCKET_USERNAME, userName);/** 可以用这个逻辑也可以不用Long uid = Long.valueOf(((ServletServerHttpRequest) request).getServletRequest().getParameter("uid"));String wsDevice = String.valueOf(((ServletServerHttpRequest) request).getServletRequest().getParameter("wsDevice"));if (request instanceof ServletServerHttpRequest) {if (uid != null) {attributes.put("uid", uid);attributes.put("wsDevice", wsDevice);} else {return false;}}return true;*/return super.beforeHandshake(request, response, wsHandler, attributes);}@Overridepublic void afterHandshake(ServerHttpRequest request, ServerHttpResponse response, WebSocketHandler wsHandler,Exception ex) {System.out.println("After Handshake");super.afterHandshake(request, response, wsHandler, ex);}}

ChatMessageHandler.java

这个类是对消息的一些处理,比如是发给一个人,还是发给所有人,并且前端连接时触发的一些动作

package com.websocket;import java.io.IOException;import java.util.ArrayList;import org.apache.log4j.Logger;import org.springframework.web.socket.CloseStatus;import org.springframework.web.socket.TextMessage;import org.springframework.web.socket.WebSocketSession;import org.springframework.web.socket.handler.TextWebSocketHandler;public class ChatMessageHandler extends TextWebSocketHandler {private static final ArrayList<WebSocketSession> users;// 这个会出现性能问题,最好用Map来存储,key用useridprivate static Logger logger = Logger.getLogger(ChatMessageHandler.class);static {users = new ArrayList<WebSocketSession>();}/** * 连接成功时候,会触发UI上onopen方法 */@Overridepublic void afterConnectionEstablished(WebSocketSession session) throws Exception {System.out.println("connect to the websocket success......");users.add(session);// 这块会实现自己业务,比如,当用户登录后,会把离线消息推送给用户// TextMessage returnMessage = new TextMessage("你将收到的离线");// session.sendMessage(returnMessage);}/** * 在UI在用js调用websocket.send()时候,会调用该方法 */@Overrideprotected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception {sendMessageToUsers(message);//super.handleTextMessage(session, message);}/** * 给某个用户发送消息 * * @param userName * @param message */public void sendMessageToUser(String userName, TextMessage message) {for (WebSocketSession user : users) {if (user.getAttributes().get(Constants.WEBSOCKET_USERNAME).equals(userName)) {try {if (user.isOpen()) {user.sendMessage(message);}} catch (IOException e) {e.printStackTrace();}break;}}}/** * 给所有在线用户发送消息 * * @param message */public void sendMessageToUsers(TextMessage message) {for (WebSocketSession user : users) {try {if (user.isOpen()) {user.sendMessage(message);}} catch (IOException e) {e.printStackTrace();}}}@Overridepublic void handleTransportError(WebSocketSession session, Throwable exception) throws Exception {if (session.isOpen()) {session.close();}logger.debug("websocket connection closed......");users.remove(session);}@Overridepublic void afterConnectionClosed(WebSocketSession session, CloseStatus closeStatus) throws Exception {logger.debug("websocket connection closed......");users.remove(session);}@Overridepublic boolean supportsPartialMessages() {return false;}}




原创粉丝点击