WebSocket 是 HTML5 一种新的协议。它实现了浏览器与服务器全双工通信,能更好的节省服务器资源和带宽并达到实时通讯,它建立在 TCP 之上,同 HTTP 一样通过 TCP 来传输数据,但是它和 HTTP 最大不同是:
WebSocket 是一种双向通信协议,在建立连接后,WebSocket 服务器和 Browser/Client Agent 都能主动的向对方发送或接收数据,就像 Socket 一样;
WebSocket 需要类似 TCP 的客户端和服务器端通过握手连接,连接成功后才能相互通信。
maven:
<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>
<!-- spring4下的websocket默认使用jackson相关jar包,导入: -->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
<version>2.6.5</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
<version>2.6.5</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.6.5</version>
</dependency>
绑定httpsession
package leo.util;
import javax.servlet.http.HttpSession;
import javax.websocket.HandshakeResponse;
import javax.websocket.server.HandshakeRequest;
import javax.websocket.server.ServerEndpointConfig;
//配置类 将http中的session传入websocket中
public class GetHttpSessionConfigurator extends
ServerEndpointConfig.Configurator {
@Override
public void modifyHandshake(ServerEndpointConfig config,
HandshakeRequest request, HandshakeResponse response) {
HttpSession httpSession = (HttpSession) request.getHttpSession();
config.getUserProperties().put(HttpSession.class.getName(), httpSession);
//我也碰到这个坑,最后发现自己在浏览器登录的时候是用的localhost,但websocket连接的时候是用的本机Ip地址127.0.0.1
//,所以握手拦截的时候,是得不到原来的session的,保证地址栏的请求和websocket的请求地址统一就能获取到了
}
}
webscoket配置类
package leo.util;
import java.io.IOException;
import java.util.HashMap;
import java.util.Hashtable;
import java.util.Map;
import java.util.Set;
import java.util.logging.Logger;
import javax.servlet.http.HttpSession;
import javax.websocket.CloseReason;
import javax.websocket.EndpointConfig;
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;
import org.springframework.stereotype.Component;
import org.springframework.web.socket.config.annotation.EnableWebSocketMessageBroker;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
//注意此访问地址格式如:"ws://"+ window.location.host+"${pageContext.request.contextPath}/game"是ws开头的,而不是以http:开头的.
//, configurator = GetHttpSessionConfigurator.class
@ServerEndpoint(value = "/websocket",configurator = GetHttpSessionConfigurator.class)
@Component
@EnableWebSocketMessageBroker // @EnableWebSocketMessageBroker注解能够在WebSocket之上启用STOMP
public class Scoket {
private Logger logger = Logger.getLogger(this.getClass().getName());
private static Map<String, Session> sessionMap = new Hashtable<String, Session>();
private static HttpSession httpSession;
@OnOpen
public void onOpen(Session session, EndpointConfig config) {
httpSession = (HttpSession) config.getUserProperties().get(HttpSession.class.getName());
sessionMap.put((String) httpSession.getAttribute("user"), session);
Set<Map.Entry<String, Session>> set = sessionMap.entrySet();
System.out.println("在线人数:" + set.size());
sendMessageToAll("系统提示:", httpSession.getAttribute("user") + "上线啦!");
}
@OnMessage
public void onMessage(String content, Session session) throws IOException {
System.out.println(session.getId() + " 开始广播:" + content);
// getBasicRemote()能够同步地向对等点发送消息
JSONObject json_test = JSONObject.parseObject(content);
// session.getBasicRemote().sendText("游客" + session.getId() + ":" +
// json_test.get("message"));
// HashMap<String, String> msgMap = new HashMap<String, String>();
// if (!content.equals("")) {
// msgMap = getMessage(content);
// sendMessageToUser(msgMap.get("fromName"), msgMap.get("toName"), msgMap.get("content").toString());
//
// }
sendMessageToAll("leo",json_test.get("message").toString());
}
/**
* 消息处理类,处理前端发来的消息
*
* @param msg
* @return
*/
public static HashMap<String, String> getMessage(String msg) {
HashMap<String, String> map = new HashMap<String, String>();
String msgString = msg.toString();
String m[] = msgString.split(",");
// map.put("fromName", m[0]);
map.put("toName", m[1]);
map.put("content", m[2]);
return map;
}
/**
* 发送信息给指定用户
*
* @param clientId
* @param message
* @return
*/
public boolean sendMessageToUser(String fromName, String toName, String message) {
javax.websocket.Session session = sessionMap.get(toName);
System.out.println("sendMessageTo:" + session);
if (!session.isOpen())
return false;
try {
session.getBasicRemote().sendText(fromName + ":" + message);
} catch (IOException e) {
e.printStackTrace();
return false;
}
return true;
}
/**
* 广播给所有人
*
* @param message
*/
public static void sendMessageToAll(String fromName, String message) {
Set<Map.Entry<String, Session>> set = sessionMap.entrySet();
System.out.println("在线人数:" + set.size());
for (Map.Entry<String, Session> i : set) {
try {
i.getValue().getBasicRemote().sendText(fromName + ":" + message);
} catch (Exception e) {
e.printStackTrace();
}
}
}
@OnClose
public void onClose(Session session, CloseReason closeReason) {
sessionMap.remove(session.getId());
Set<Map.Entry<String, Session>> set = sessionMap.entrySet();
System.out.println("游客" + session.getId() + "退出");
System.out.println("在线人数:" + set.size());
sendMessageToAll("系统提示:", "游客" + session.getId() + "退出");
}
@OnError
public void error(Session session, java.lang.Throwable throwable) {
sessionMap.remove(session.getId());
System.err.println("session " + session.getId() + " error:" + throwable);
}
}
jsp页面导入js
<script src="http://cdn.sockjs.org/sockjs-0.3.min.js"></script>
<script src="https://cdn.bootcss.com/stomp.js/2.3.3/stomp.min.js"></script>
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8" import="java.util.*"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<%request.getSession().setAttribute("user", "shlly");%>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<script src="http://cdn.sockjs.org/sockjs-0.3.min.js"></script>
<script src="https://cdn.bootcss.com/stomp.js/2.3.3/stomp.min.js"></script>
<!-- 新 Bootstrap 核心 CSS 文件 -->
<link rel="stylesheet" href="//cdn.bootcss.com/bootstrap/3.3.5/css/bootstrap.min.css">
<!-- 可选的Bootstrap主题文件(一般不用引入) -->
<link rel="stylesheet" href="//cdn.bootcss.com/bootstrap/3.3.5/css/bootstrap-theme.min.css">
<!-- jQuery文件。务必在bootstrap.min.js 之前引入 -->
<script src="//cdn.bootcss.com/jquery/1.11.3/jquery.min.js"></script>
<!--<script type="text/javascript" src="js/jquery-1.7.2.js"></script>-->
<!-- 最新的 Bootstrap 核心 JavaScript 文件 -->
<script src="//cdn.bootcss.com/bootstrap/3.3.5/js/bootstrap.min.js"></script>
<title>webSocket测试</title>
<script type="text/javascript">
$(function(){
var websocket;
var user="<%=request.getSession().getAttribute("user")%>";
if ('WebSocket' in window) {
websocket = new WebSocket("ws://127.0.0.1:8080/wsdemo/websocket");
} else if ('MozWebSocket' in window) {
websocket = new MozWebSocket("ws://wsdemo");
} else {
websocket = new SockJS("http://127.0.0.1:8080/wsdemo/websocket");
stompClient = Stomp.over(socket);
stompClient.connect({}, function(frame) {
setConnected(true);
});
}
websocket.onopen = function (evnt) {
$("#tou").html("链接服务器成功!")
};
websocket.onopen = function (evnt) {
$("#tou").html("链接服务器成功!")
};
var stompClient = Stomp.over(websocket);
//当有消息时,会自动调用此方法
websocket.onmessage = function (evnt) {
$("#msg").html($("#msg").html()+ "<br/>" + evnt.data);
};
websocket.onerror = function (evnt) {
};
websocket.onclose = function (evnt) {
$("#tou").html("与服务器断开了链接!")
}
$('#send').bind('click', function() {
send();
});
function send(){
if (websocket != null) {
var message = document.getElementById('message').value;
websocket.send("{\"toname\":\"all\",\"message\":\""+message+"\,\"user\":\""+user+"\"}");
} else {
alert('未与服务器链接.');
}
}
//强制关闭浏览器断开连接
window.onbeforeunload = function() {
if (stompClient != null) {
stompClient.disconnect();
}
}
});
</script>
</head>
<body>
<%=request.getSession().getAttribute("user")%>
<div class="page-header" id="tou">
webSocket及时聊天Demo程序
</div>
<div class="well" id="msg">
</div>
<div class="col-lg">
<div class="input-group">
<input type="text" class="form-control" placeholder="发送信息..." id="message">
<span class="input-group-btn">
<button class="btn btn-default" type="button" id="send" >发送</button>
</span>
</div><!-- /input-group -->
</div><!-- /.col-lg-6 -->
</body>
</html>