springmvc整合websocket
最近專案中需要完成資訊的實時顯示功能,因此考慮使用websocket來實現,廢話不多說,直接上配置流程及程式碼。
1. 首先引入需要的jar包,spring和springmvc的自然不多說,主要是引入spring整合的websocket包
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-websocket</artifactId>
</dependency>
2. 編寫websocket配置類,當然也可以在xml配置(這裡就不多說了)
編寫自己的WebSocketConfig extends WebMvcConfigurerAdapter implements WebSocketConfigurer
編寫這個類主要是為了實現WebSocketConfigurer.registerWebSocketHandlers方法給websocket註冊訊息處理器WebSocketHandler。
@Configuration
@EnableWebMvc
@EnableWebSocket
public class WebSocketConfig extends WebMvcConfigurerAdapter implements
WebSocketConfigurer {
@Override
public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
// 前臺 可以使用websocket環境
registry.addHandler(webSocketHandler(), "/websocket").addInterceptors(new HandshakeInterceptor());
registry.addHandler(webSocketHandler(),"/sockjs/websocket").addInterceptors(
new HandshakeInterceptor()).withSockJS();
}
// websocket 處理類@Bean
public WebSocketHandler webSocketHandler() {
return new MySocketHandler();
}
}
3. 編寫websocket訊息處理器MySocketHandler implements WebSocketHandler
這個類是為了處理前端傳送的訊息或推送訊息給前端,也對所有的連線進行管理
public class MyWebSocketHandler implements WebSocketHandler {
private static final Logger log = Logger.getLogger(ICWantWebSocketHandler.class);
@Autowired
RedisUtils redisUtils;
// 儲存所有的使用者session
private static final Map<String, WebSocketSession> users = new HashMap<>();
// 連線 就緒時
@Override
public void afterConnectionEstablished(WebSocketSession session)
throws Exception {
log.info("connect websocket success.......");
//這塊會實現自己業務,比如,當用戶登入後,會把離線訊息推送給使用者
//TextMessage returnMessage = new TextMessage("你將收到的離線");
//session.sendMessage(returnMessage);
String username= (String) session.getAttributes().get("WEBSOCKET_USERNAME");
System.out.println(username);
System.out.println(session.getId());
//判斷是否有同名連線,若存在則關閉
WebSocketSession s = users.get(username);
if(null != s && s.isOpen())
s.close();
users.put(username, session);
System.out.println("connect to the websocket success......當前數量:"+users.size());
}
// 處理前端傳送的訊息資訊
@Override
public void handleMessage(WebSocketSession session,
WebSocketMessage<?> message) throws Exception {
//獲取訊息體
String msg = message.getPayload().toString();
if(msg.startsWith("java.nio.HeapByteBuffer")){
System.out.println("瀏覽器傳送的心跳包");
return;
}
}
// 處理傳輸時異常
@Override
public void handleTransportError(WebSocketSession session,
Throwable exception) throws Exception {
//log.info("資料傳輸異常: " + exception.getMessage());
}
// 關閉 連線時
@Override
public void afterConnectionClosed(WebSocketSession session,
CloseStatus closeStatus) throws Exception {
log.info("connect websocket closed.......");
String username= (String) session.getAttributes().get("WEBSOCKET_USERNAME");
System.out.println("使用者"+username+"已退出!");
users.remove(username);
System.out.println("剩餘線上使用者" + users.size());
}
@Override
public boolean supportsPartialMessages() {
return false;
}
// 給所有使用者傳送 資訊
public void sendMsgToAllUsers(SocketMessageVO message) {
for (WebSocketSession user : users.values()) {
String msg = GsonUtil.object2JsonStr(message);
TextMessage textMsg = new TextMessage(msg);
try {
user.sendMessage(textMsg);
} catch (IOException e) {
log.error("XLTX-ERROR: websocket傳送訊息出錯", e);
}
}
}
/**
* 傳送訊息給指定的使用者
* @param SocketMessageVO from_user 或 to_user為null時直接返回
*/
public void sendMsgToUser(SocketMessageVO message) {
if(message == null || message.getFrom_user() == null || message.getTo_user() == null)
return;
String toUser = message.getTo_user();
WebSocketSession session = users.get(toUser);
if(session == null)
return;
String msg = GsonUtil.object2JsonStr(message);
TextMessage textMsg = new TextMessage(msg);
try {
session.sendMessage(textMsg);
} catch (IOException e) {
log.error("XLTX-ERROR: websocket傳送訊息出錯", e);
}
}
}
4. 編寫握手攔截器 HandshakeInterceptor, 主要是為了在連線前將當前使用者的資訊儲存起來,方便伺服器推送資訊
public class HandshakeInterceptor extends HttpSessionHandshakeInterceptor {
// 初次握手訪問前
@Override
public boolean beforeHandshake(ServerHttpRequest request, ServerHttpResponse response,
WebSocketHandler webSocketHandler, Map<String, Object> attributes)
throws Exception {
if (request instanceof ServletServerHttpRequest) {
Session httpSession = SecurityUtils.getSubject().getSession();
if(httpSession != null){
//使用userName區分WebSocketHandler,以便定向傳送訊息, 如果需要向指定的使用者傳送訊息則需要記錄使用者資訊
//因此這裡將使用者id繫結到websocket的session
UserVO userVO = (UserVO)httpSession.getAttribute(SysConstant.SESSION_USER_INFO);
if(userVO != null){
long uid = userVO.getId();
String userName = String.valueOf(uid);
if (userName==null) {
userName="default-system";
}
attributes.put("WEBSOCKET_USERNAME", userName);
}else
attributes.put("WEBSOCKET_USERNAME", httpSession.getId());
}
}
return super.beforeHandshake(request, response, webSocketHandler, attributes);
}
// 初次握手訪問後
@Override
public void afterHandshake(ServerHttpRequest request, ServerHttpResponse response,
WebSocketHandler wsHandler, Exception e) {
super.afterHandshake(request, response, wsHandler, e);
}
}
以上個步驟就完成了websocket的服務端配置,在需要推送資訊的類中注入訊息處理器,即可進行訊息推送。
前端的編寫可以參考:https://blog.csdn.net/jared_he2017/article/details/79886600