WebSocket實現前後端訊息推送
阿新 • • 發佈:2019-02-19
環境
jdk8 tomcat7 谷歌瀏覽器和火狐瀏覽器(瀏覽器得支援websocket)
本文用webSocket建立一個簡單的聊天室,直接上程式碼。。。
websocket 用到jar包:
<dependency> <groupId>org.springframework</groupId> <artifactId>spring-websocket</artifactId> <version>${spring-framework.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-messaging</artifactId> <version>${spring-framework.version}</version> </dependency>
先準備一個普通的maven工程 springMVC框架
後臺程式碼:
主要是建立攔截器攔截webSocket請求並交於handler進行處理。
webSocket配置如下:
1.MySocketConfig:註冊攔截器+handler
import org.springframework.beans.factory.annotation.Autowired; 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.config.annotation.EnableWebSocket; import org.springframework.web.socket.config.annotation.WebSocketConfigurer; import org.springframework.web.socket.config.annotation.WebSocketHandlerRegistry; import com.zzm.test.websocket.socket.WebSocketInterceptor; @Configuration @EnableWebMvc @EnableWebSocket public class MySocketConfig extends WebMvcConfigurerAdapter implements WebSocketConfigurer{ @Autowired private MySocketHandle mySocketHandle;//自己的handler @Override public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) { //註冊處理攔截器,攔截url為socketServer的請求 registry.addHandler(mySocketHandle, "/socketChatroom.do").addInterceptors(new WebSocketInterceptor());//攔截的請求,(注意首先得被servlet攔截到,即要注意web-inf0中的配置) } }
攔截器:攔截請求將httpSession使用者儲存到WebSocketSession裡,用於區別webSocketSession是哪個使用者的
import java.util.Map; import javax.servlet.http.HttpSession; import org.springframework.http.server.ServerHttpRequest; import org.springframework.http.server.ServerHttpResponse; import org.springframework.http.server.ServletServerHttpRequest; import org.springframework.web.socket.WebSocketHandler; import org.springframework.web.socket.server.HandshakeInterceptor; public class MySocketInterceptor implements HandshakeInterceptor{ /** * 握手後報存使用者資訊到webSocketSession */ @Override public boolean beforeHandshake(ServerHttpRequest request, ServerHttpResponse response, WebSocketHandler wsHandler, Map<String, Object> attributes) throws Exception { if(request instanceof ServerHttpRequest){ ServletServerHttpRequest servletRequest = (ServletServerHttpRequest) request; HttpSession session = servletRequest.getServletRequest().getSession(); if(session!=null){ attributes.put("user", session.getAttribute("user")); } } return true; } @Override public void afterHandshake(ServerHttpRequest request, ServerHttpResponse response, WebSocketHandler wsHandler, Exception exception) { } }
handler處理類:定義各連線狀態的處理,儲存連線上的使用者,及自定義傳送方法
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
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;
@Service
public class MySocketHandle implements WebSocketHandler{
private Logger logger = LoggerFactory.getLogger(MySocketHandle.class);
private Map<String,WebSocketSession> users = new ConcurrentHashMap<String,WebSocketSession>();
@Override
public void afterConnectionEstablished(WebSocketSession session)
throws Exception {
logger.info("建立socket連線");
String userName = session.getAttributes().get("user").toString();
if(null!=userName&&!"".equals(userName)){
users.put(userName, session);
session.sendMessage(new TextMessage("system:"+userName+"連線成功。。。"));
}
}
@Override
public void handleMessage(WebSocketSession session,
WebSocketMessage<?> message) throws Exception {
}
@Override
public void handleTransportError(WebSocketSession session,
Throwable exception) throws Exception {
if(session.isOpen()){
session.close();
}
logger.error("連接出現錯誤",exception);
users.remove(session.getAttributes().get("user").toString());
}
@Override
public void afterConnectionClosed(WebSocketSession session,
CloseStatus closeStatus) throws Exception {
logger.info("連線關閉");
users.remove(session.getAttributes().get("user").toString());
}
@Override
public boolean supportsPartialMessages() {
return false;
}
public void sendMessageToUsers(String sender,TextMessage message){
Set<Map.Entry<String, WebSocketSession>> entrySet = users.entrySet();
for(Map.Entry<String, WebSocketSession> entry : entrySet){
String userName = "";
try{
userName = entry.getKey();
if(userName==null||userName.equals(sender)){
continue;
}
WebSocketSession session = entry.getValue();
session.sendMessage(message);
}catch(Exception e){
logger.error("傳送資訊給"+userName+"失敗",e);
}
}
}
public void sendMessageToUser(String userName,TextMessage message){
try{
WebSocketSession session = users.get(userName);
session.sendMessage(message);
}catch(Exception e){
logger.error("傳送訊息給"+userName+"失敗",e);
}
}
}
controller類:
import javax.servlet.http.HttpSession;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.socket.TextMessage;
import com.zzm.test.websocket.controller.SocketController;
import com.zzm.test.websocket.service.MySocketHandle;
@Controller
@RequestMapping("socketPushController")
public class SocketPushController {
private static final Logger logger = LoggerFactory.getLogger(SocketController.class);
@Autowired
private MySocketHandle mySocketHandler;
@RequestMapping("login")
public String login(HttpSession session,String name){
logger.info(name+"登入了");
session.setAttribute("user", name);
return "../socketPush/chatroom";
}
@RequestMapping("sendMessage")
@ResponseBody
public String sendMessage(HttpSession session,String message){
String name = (String) session.getAttribute("user");
mySocketHandler.sendMessageToUsers( name,new TextMessage(name+" : "+message));
return "success";
}
}
前端頁面:
登入:使用者用姓名登入
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%
String path = request.getContextPath();
String basePath = request.getScheme() + "://" + request.getServerName() + ":" + request.getServerPort() + path + "/";
%>
<!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>登入</title>
<script type="text/javascript">
</script>
</head>
<body>
<form action="http://localhost:8080/AllStudy/socketPushController/login.do" method="post">
<span>姓名:</span><input type="text" name="name"><br/>
<input type="submit" value="登入">
</form>
</body>
</html>
傳送頁面:可以傳送和接收資訊。
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%
String path = request.getContextPath();
String basePath = request.getScheme() + "://" + request.getServerName() + ":" + request.getServerPort() + path + "/";
%>
<!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>Insert title here</title>
<script type="text/javascript" src="../js/jquery-1.7.2.min.js"></script>
<script type="text/javascript"></script>
<script type="text/javascript">
$(function(){
//建立socket連線
var sock;
if ('WebSocket' in window) {//判斷當前瀏覽器是否支援webSocket
sock = new WebSocket("ws://localhost:8080/AllStudy/socketChatroom.do");//建立連線
}
sock.onopen = function (e) {//成功建立連線
console.log(e);
};
sock.onmessage = function (e) {//接收到訊息
console.log(e)
$("#messages").append("<p><font color='red'>"+e.data+"</font>")
};
sock.onerror = function (e) {//連線發生錯誤
console.log(e);
};
sock.onclose = function (e) {//連線關閉
console.log(e);
};
////監聽視窗關閉事件,當視窗關閉時,主動去關閉websocket連線,防止連線還沒斷開就關閉視窗,server端會拋異常。
window.onbeforeunload = function(){
websocket.close();
};
});
function mysend(){
var message = $("#message").val();
$("#messages").append("<p><font color='blue'>"+"我:"+message+"</font>");
$.post('http://localhost:8080/AllStudy/socketPushController/sendMessage.do',{message:message},function(){
$("message").val("");
},'text');
}
</script>
</head>
<body>
<div id="messages">
</div>
<div><input type="text" id="message" ><button onclick="mysend()">傳送</button></div>
</body>
</html>
結果圖: