您的位置:首页 > 其它

websocket

2017-12-21 16:27 106 查看
1 Jar包准备和配置

1.1 所需jar包(pom文件引入)

 Spring基础jar包:即web项目所需的spring jar包;

 Websocket jar包:javax.websocket-ap(注意scope必须为provided,否则runtime会冲突)和spring-websocket。如图:

 

1.2 所需xml配置如图

 

 

注1:path为前台websocket请求路径。

注2:websocket:handshake-interceptors为websocket握手建立连接前自定义拦截器。

注3:WSHandler 为连接建立后的逻辑处理,连接建立后数据传输出错的处理,前台有消息相互传递的逻辑处理,连接关闭后的逻辑处理。

2 设计逻辑

 1:jsp建立websocket对象和请求路径

 2:握手前获取学校id参数并放入WebSocketSession中

 3:WebSocketSession链接成功,把当前WebSocketSession放入集合中

 4:后台推送消息——遍历WebSocketSession集合对应学校id的消息json字符串推送到前端页面。

 5:消息传输错误——关闭当前WebSocketSession链接,并把它从WebSocketSession集合中移除,重新建立WebSocketSession链接

 6:前端页面关闭——关闭当前WebSocketSession链接,并把它从WebSocketSession集合中移除

3 实现代码

3.1 自定义拦截器代码

package com.sunsharing.ihome.air.web.websocket;

import java.util.Map;

import org.apache.log4j.Logger;

import org.springframework.http.server.ServerHttpRequest;

import org.springframework.http.server.ServerHttpResponse;

import org.springframework.web.socket.WebSocketHandler;

import org.springframework.web.socket.server.HandshakeInterceptor;

/**

 * websocket拦截器类

 * <p>

 * </p>

 * 

 * @author chuhaitao 2017年10月25日 下午2:38:51

 * @version V1.0

 * @modificationHistory=========================逻辑或功能性重大变更记录

 * @modify by user: {修改人} 2017年10月25日

 * @modify by reason:{方法名}:{原因}

 */

public class WSHandshakeInterceptor implements HandshakeInterceptor {

Logger logger = Logger.getLogger(WSHandshakeInterceptor.class);

@Override
public void afterHandshake(ServerHttpRequest serverHttpRequest, ServerHttpResponse serverHttpResponse,
WebSocketHandler webSocketHandler, Exception ex) {
// TODO Auto-generated method stub

}

@Override
public boolean beforeHandshake(ServerHttpRequest serverHttpRequest, ServerHttpResponse serverHttpResponse,
WebSocketHandler webSocketHandler, Map<String, Object> map) throws Exception {

// 获取websocket请求地址
String url = serverHttpRequest.getURI().toString();
if (url.indexOf("schoolId") == -1) {// 判断是否有学校id参数
return true;
}
// 获取学校id
String schoolId = url.substring(url.indexOf("=") + 1);
logger.info("获取到学校id:schoolId=" + schoolId);
map.put("schoolId", schoolId);
return true;
}

}

3.2 Websocket处理类代码

package com.sunsharing.ihome.air.web.websocket;

import java.io.IOException;

import java.util.Iterator;

import org.apache.log4j.Logger;

import org.springframework.beans.factory.annotation.Autowired;

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;

/**

 * websocekt类

 * <p>

 * </p>

 * 

 * @author chuhaitao 2017年10月23日 上午11:12:48

 * @version V1.0

 * @modificationHistory=========================逻辑或功能性重大变更记录

 * @modify by user: {修改人} 2017年10月23日

 * @modify by reason:{方法名}:{原因}

 */

public class WSHandler implements WebSocketHandler {

Logger logger = Logger.getLogger(WebSocketHandler.class);

@Autowired
private WSClientManager wsClientManager;

@Override
public void afterConnectionEstablished(WebSocketSession session) throws Exception {
wsClientManager.getWebSocketSessions().add(session);
logger.info("链接websocket成功");

}

@Override
public void handleMessage(WebSocketSession session, WebSocketMessage<?> message) throws Exception {
// 获取消息
String[] messages = message.getPayload().toString().split("&");
// 获取学校id
String schoolId = "大cha";
// 获取要推送的消息
String messageValue = messages[0];
if (messages.length > 1) {
schoolId = messages[0];
messageValue = messages[1];
}
final TextMessage returnMessage = new TextMessage(messageValue);
try {
// 获取所有客户端
Iterator<WebSocketSession> it = wsClientManager.getWebSocketSessions().iterator();
while (it.hasNext()) {
WebSocketSession client = it.next();
if (session != client) {// 判断是否为当前发送消息的客户端
if (client.isOpen()) {
if (schoolId.equals(client.getAttributes().get("schoolId"))) {// 判断是否是同一学校的客户端
client.sendMessage(returnMessage);
}
}
}
}
} catch (IOException e) {
logger.error("推送消息错误", e);
} catch (NullPointerException e) {
logger.error("无客户端,请连接客户端");
} catch (Exception e) {
logger.error("发送错误");
}
}

@Override
public void handleTransportError(WebSocketSession session, Throwable exception) throws Exception {
if (session.isOpen()) {
session.close();
wsClientManager.getWebSocketSessions().remove(session);
}
logger.error("发生错误链接关闭,错误信息为:" + exception.getMessage());

}

@Override
public void afterConnectionClosed(WebSocketSession session, CloseStatus closeStatus) throws Exception {

wsClientManager.getWebSocketSessions().remove(session);
logger.info("websocket链接关闭");
}

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

}

3.3 后端消息推送代码

/**
* 推送消息给指定用户

* @author chuhaitao 2017年10月25日 下午2:10:38
* @param schoolId
* @param message
*/
public void sendMessageToUser(String schoolId, String message) {
try {
final Iterator<WebSocketSession> it = wsClientManager.getWebSocketSessions().iterator();
while (it.hasNext()) {
final WebSocketSession client = it.next();
if (client.isOpen()) {
if (schoolId.equals(client.getAttributes().get("schoolId"))) {
final TextMessage textMessage = new TextMessage(message);
client.sendMessage(textMessage);
}
}
}
} catch (final IOException e) {
logger.error("推送消息错误", e);
} catch (final NullPointerException e) {
logger.error("无客户端,请连接客户端");
} catch (final Exception e) {
logger.error("发送错误");
}
}

3.4 WebSocketSession集合代码

package com.sunsharing.ihome.air.web.websocket;

import java.util.HashSet;

import java.util.Set;

import org.springframework.stereotype.Component;

import org.springframework.web.socket.WebSocketSession;

/**

 * 发送客户端类

 * <p>

 * </p>

 * 

 * @author chuhaitao 2017年10月23日 上午11:10:43

 * @version V1.0

 * @modificationHistory=========================逻辑或功能性重大变更记录

 * @modify by user: {修改人} 2017年10月23日

 * @modify by reason:{方法名}:{原因}

 */

@Component

public class WSClientManager {
private final Set<WebSocketSession> webSocketSessions = new HashSet<WebSocketSession>();

public Set<WebSocketSession> getWebSocketSessions() {
return webSocketSessions;
}

}

<%@ 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>  

  <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">  

  <title>Web Socket JavaScript Echo Client</title>  

  <script language="javascript" type="text/javascript">  

    var echo_websocket;  

    var url = ((window.location.protocol == "https:") ? "wss:" : "ws:") 
+ "//" + window.location.host 
+ "/springweb/websocket.do";

      

    function createWebsocket()  

    {  

        echo_websocket = new WebSocket(url);  

          

        echo_websocket.onopen = function (evt) {  

          writeToScreen("Connected !");  

          //doSend(textID.value);  

        };  

        echo_websocket.onmessage = function (evt) {  

          writeToScreen("Received message: " + evt.data);  

          //echo_websocket.close();  

        };  

        echo_websocket.onerror = function (evt) {  

          writeToScreen('<span style="color: red;">ERROR:</span> '  

            + evt.data);  

          echo_websocket.close();  

        };  

        echo_websocket.onclose = function () {  

            writeToScreen('<span style="color: red;">CLOSE:</span> ');  

          };  

            

        clearScreen();  

    }  

      

      

    function init() {  

      output = document.getElementById("output");  

      writeToScreen("Connecting to " + url);  

        

      createWebsocket();  

    }  

  

    function send_echo() {  

        if(echo_websocket!=null && echo_websocket.readyState==1)  

        {  

            doSend(textID.value);         

        } else  

        {  

            createWebsocket();  

            //重新连接后,跟着马上发送数据会失败!(我猜测是异步执行的关系)  

            //得等到  连接成功事件收到后 再发送。  

        }  

    }  

    function closeWebSocket() {  

        echo_websocket.close();  

    }  

    function doSend(message) {  

      echo_websocket.send(message);  

      writeToScreen("Sent message: " + message);  

    }  

    function writeToScreen(message) {  

      var pre = document.createElement("p");  

      pre.style.wordWrap = "break-word";  

      pre.innerHTML = message;  

      output.appendChild(pre);  

    }      

    function clearScreen(message) {  

        output.innerHTML="";  

      }         

    window.addEventListener("load", init, false);  

  </script>  

</head>  

<body>  

<h1>Echo Server</h1>  

<div style="text-align: left;">  

  <form action="">  

    <input onclick="send_echo()" value="发送socket请求" type="button">  

    <input onclick="closeWebSocket()" value="关闭socket长链接" type="button">  

    <input id="textID" name="message" value="Hello World, Web Sockets" type="text">  

    <br>  

  </form>  

</div>  

<div id="output"></div>  

</body>  

</html>  
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: