国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁(yè) > 編程 > Java > 正文

Spring整合WebSocket應(yīng)用示例(上)

2019-11-26 14:27:41
字體:
供稿:網(wǎng)友

以下教程是小編在參與開發(fā)公司的一個(gè)crm系統(tǒng),整理些相關(guān)資料,在該系統(tǒng)中有很多消息推送功能,在其中用到了websocket技術(shù)。下面小編整理分享到武林網(wǎng)平臺(tái)供大家參考

1. maven依賴

<dependency><groupId>javax.servlet</groupId><artifactId>javax.servlet-api</artifactId><version>3.1.0</version></dependency><dependency><groupId>com.fasterxml.jackson.core</groupId><artifactId>jackson-core</artifactId><version>2.3.0</version></dependency><dependency><groupId>com.fasterxml.jackson.core</groupId><artifactId>jackson-databind</artifactId><version>2.3.0</version></dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-websocket</artifactId><version>4.0.1.RELEASE</version></dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-messaging</artifactId><version>4.0.1.RELEASE</version></dependency>

2. spring-servlet的配置

<?xml version="1.0" encoding="UTF-8"?><beans xmlns="http://www.springframework.org/schema/beans"xmlns:context="http://www.springframework.org/schema/context"xmlns:mvc="http://www.springframework.org/schema/mvc"xmlns:tx="http://www.springframework.org/schema/tx" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns:websocket="http://www.springframework.org/schema/websocket"xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans-3.1.xsdhttp://www.springframework.org/schema/contexthttp://www.springframework.org/schema/context/spring-context-3.1.xsdhttp://www.springframework.org/schema/mvchttp://www.springframework.org/schema/mvc/spring-mvc-3.1.xsdhttp://www.springframework.org/schema/txhttp://www.springframework.org/schema/tx/spring-tx-3.1.xsdhttp://www.springframework.org/schema/websockethttp://www.springframework.org/schema/websocket/spring-websocket.xsd">......<!-- websocket --><bean id="websocket" class="cn.bridgeli.websocket.WebsocketEndPoint"/><websocket:handlers><websocket:mapping path="/websocket" handler="websocket"/><websocket:handshake-interceptors><bean class="cn.bridgeli.websocket.HandshakeInterceptor"/></websocket:handshake-interceptors></websocket:handlers></beans>

其中,path對(duì)應(yīng)的路徑就是前段通過ws協(xié)議調(diào)的接口路徑

3. HandshakeInterceptor的實(shí)現(xiàn)

package cn.bridgeli.websocket;import cn.bridgeli.utils.UserManager;import cn.bridgeli.util.DateUtil;import cn.bridgeli.sharesession.UserInfo;import org.apache.commons.lang.StringUtils;import org.slf4j.Logger;import org.slf4j.LoggerFactory;import org.springframework.http.server.ServerHttpRequest;import org.springframework.http.server.ServerHttpResponse;import org.springframework.web.context.request.RequestContextHolder;import org.springframework.web.context.request.ServletRequestAttributes;import org.springframework.web.socket.WebSocketHandler;import org.springframework.web.socket.server.support.HttpSessionHandshakeInterceptor;import java.util.Date;import java.util.Map;/*** @Description :創(chuàng)建握手(handshake)接口* @Date : 16-3-3*/public class HandshakeInterceptor extends HttpSessionHandshakeInterceptor{private static final Logger logger = LoggerFactory.getLogger(HandshakeInterceptor.class);@Overridepublic boolean beforeHandshake(ServerHttpRequest request,ServerHttpResponse response, WebSocketHandler wsHandler,Map<String, Object> attributes) throws Exception {logger.info("建立握手前...");ServletRequestAttributes attrs = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();UserInfo currUser = UserManager.getSessionUser(attrs.getRequest());UserSocketVo userSocketVo = new UserSocketVo();String email= "";if(null != currUser){email = currUser.getEmail();}if(StringUtils.isBlank(email)){email = DateUtil.date2String(new Date());}userSocketVo.setUserEmail(email);attributes.put("SESSION_USER", userSocketVo);return super.beforeHandshake(request, response, wsHandler, attributes);}@Overridepublic void afterHandshake(ServerHttpRequest request,ServerHttpResponse response, WebSocketHandler wsHandler,Exception ex) {logger.info("建立握手后...");super.afterHandshake(request, response, wsHandler, ex);}}

因?yàn)槔戏虿皇呛芏宰畲笙薅鹊谋A粼a,這其實(shí)就是從單點(diǎn)登錄中取出當(dāng)前登錄用戶,轉(zhuǎn)成UserSocketVo對(duì)象,放到Map中。所以接下來我們看看UserSocketVo對(duì)象的定義

4. UserSocketVo的定義

package cn.bridgeli.websocket;import org.springframework.web.socket.WebSocketSession;import java.util.Date;/*** @Description : 用戶socket連接實(shí)體* @Date : 16-3-7*/public class UserSocketVo {private String userEmail; //用戶郵箱private Date connectionTime; //成功連接時(shí)間private Date preRequestTime; //上次請(qǐng)求時(shí)間private Date newRequestTime; //新請(qǐng)求時(shí)間private Date lastSendTime = new Date(); //下架消息最近一次發(fā)送時(shí)間private Date lastTaskSendTime = new Date(); //待處理任務(wù)最近一次發(fā)送時(shí)間private WebSocketSession webSocketSession; //用戶對(duì)應(yīng)的wsSession 默認(rèn)僅緩存一個(gè)// getXX and setXX }

其中最重要的就是這個(gè)WebSocketSession這個(gè)屬性了,后面我們要用到

5. WebsocketEndPoint的實(shí)現(xiàn)

package cn.bridgeli.websocket;import org.slf4j.Logger;import org.slf4j.LoggerFactory;import org.springframework.beans.factory.annotation.Autowired;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;/*** @Description : websocket處理類* @Date : 16-3-3*/public class WebsocketEndPoint extends TextWebSocketHandler{private static final Logger logger = LoggerFactory.getLogger(WebsocketEndPoint.class);@Autowiredprivate NewsListenerImpl newsListener;@Overrideprotected void handleTextMessage(WebSocketSession session,TextMessage message) throws Exception {super.handleTextMessage(session, message);TextMessage returnMessage = new TextMessage(message.getPayload()+" received at server");session.sendMessage(returnMessage);}/*** @Description : 建立連接后* @param session* @throws Exception*/@Overridepublic void afterConnectionEstablished(WebSocketSession session) throws Exception{UserSocketVo userSocketVo = (UserSocketVo)session.getAttributes().get("SESSION_USER");if(null != userSocketVo){userSocketVo.setWebSocketSession(session);if(WSSessionLocalCache.exists(userSocketVo.getUserEmail())){WSSessionLocalCache.remove(userSocketVo.getUserEmail());}WSSessionLocalCache.put(userSocketVo.getUserEmail(), userSocketVo);newsListener.afterConnectionEstablished(userSocketVo.getUserEmail());}logger.info("socket成功建立連接...");super.afterConnectionEstablished(session);}@Overridepublic void afterConnectionClosed(WebSocketSession session,CloseStatus status) throws Exception{UserSocketVo userSocketVo = (UserSocketVo)session.getAttributes().get("SESSION_USER");if(null != userSocketVo){WSSessionLocalCache.remove(userSocketVo.getUserEmail());}logger.info("socket成功關(guān)閉連接...");super.afterConnectionClosed(session, status);}}

6. WSSessionLocalCache的實(shí)現(xiàn)

package cn.bridgeli.websocket;import java.io.Serializable;import java.util.ArrayList;import java.util.HashMap;import java.util.List;import java.util.Map;/*** @Description :本地緩存WebSocketSession實(shí)例* @Date : 16-3-7*/public class WSSessionLocalCache implements Serializable {private static Map<String, UserSocketVo> wsSessionCache = new HashMap<>();public static boolean exists(String userEmail){if(!wsSessionCache.containsKey(userEmail)){return false;}else{return true;}}public static void put(String userEmail, UserSocketVo UserSocketVo){wsSessionCache.put(userEmail, UserSocketVo);}public static UserSocketVo get(String userEmail){return wsSessionCache.get(userEmail);}public static void remove(String userEmail){wsSessionCache.remove(userEmail);}public static List<UserSocketVo> getAllSessions(){return new ArrayList<>(wsSessionCache.values());}}

看了其實(shí)現(xiàn),作用就比較明顯了吧,存放每個(gè)UserSocketVo的最新數(shù)據(jù),其實(shí)到這里我們websocket的實(shí)現(xiàn)已經(jīng)算完了,但還有一個(gè)核心類(關(guān)于業(yè)務(wù)邏輯查理的類)沒有實(shí)現(xiàn),下篇Spring整合WebSocket應(yīng)用示例(下),我們就看怎么實(shí)現(xiàn)這個(gè)類。

WebSocket協(xié)議介紹

WebSocket協(xié)議是RFC-6455規(guī)范定義的一個(gè)Web領(lǐng)域的重要的功能:全雙工,即客戶端和服務(wù)器之間的雙向通信。它是一個(gè)令人興奮的功能,業(yè)界在此領(lǐng)域上已經(jīng)探索很久,使用的技術(shù)包括Java Applet、XMLHttpRequest、Adobe Flash、ActiveXObject、各種Comet技術(shù)、服務(wù)器端的發(fā)送事件等。

需要理解一點(diǎn),在使用WebSocket協(xié)議前,需要先使用HTTP協(xié)議用于構(gòu)建最初的握手。這依賴于一個(gè)機(jī)制――建立HTTP,請(qǐng)求協(xié)議升級(jí)(或叫協(xié)議轉(zhuǎn)換)。當(dāng)服務(wù)器同意后,它會(huì)響應(yīng)HTTP狀態(tài)碼101,表示同意切換協(xié)議。假設(shè)通過TCP套接字成功握手,HTTP協(xié)議升級(jí)請(qǐng)求通過,那么客戶端和服務(wù)器端都可以彼此互發(fā)消息。

Spring框架4.0以上版本引入了一個(gè)新模塊,即spring-websocket模塊。它對(duì)WebSocket通信提供了支持。它兼容Java WebSocket API規(guī)范JSR-356,同時(shí)提供了額外的功能。

什么場(chǎng)景下該使用WebSocket

在Web應(yīng)用中,客戶端和服務(wù)器端需要以較高頻率和較低延遲來交換事件時(shí),適合用WebSocket。因此WebSocket適合財(cái)經(jīng)、游戲、協(xié)作等應(yīng)用場(chǎng)景。
對(duì)于其他應(yīng)用場(chǎng)景則未必適合。例如,某個(gè)新聞?dòng)嗛喰枰@示突發(fā)新聞,使用間隔幾分鐘的長(zhǎng)輪詢也是可以的,這里的延遲可以接受。
即使在要求低延遲的應(yīng)用場(chǎng)景,如果傳輸?shù)南?shù)很低(比如監(jiān)測(cè)網(wǎng)絡(luò)故障的場(chǎng)景),那么應(yīng)該考慮使用長(zhǎng)輪詢技術(shù)。

而只有在低延遲和高頻消息通信的場(chǎng)景下,選用WebSocket協(xié)議才是非常適合的。即使是這樣的應(yīng)用場(chǎng)景,仍然存在是選擇WebSocket通信呢?又或者是選擇REST HTTP通信呢?
答案是會(huì)根據(jù)應(yīng)用程序的需求而定。但是,也可能同時(shí)使用這兩種技術(shù),把需要頻繁交換的數(shù)據(jù)放到WebSocket中實(shí)現(xiàn),而把REST API作為過程性的業(yè)務(wù)的實(shí)現(xiàn)技術(shù)。另外,當(dāng)REST API的調(diào)用中需要把某個(gè)信息廣播給多個(gè)客戶端是,也可以通過WebSocket連接來實(shí)現(xiàn)。

Spring框架提供了@Controller注釋和@RestController注釋,兩者都可以用于HTTP請(qǐng)求的處理以及WebSocket消息的處理。另外,Spring MVC的請(qǐng)求處理方法,或其它應(yīng)用程序的請(qǐng)求處理方法,都可以很容易地使用WebSocket協(xié)議來廣播消息到所有感興趣的客戶端或指定用戶。

發(fā)表評(píng)論 共有條評(píng)論
用戶名: 密碼:
驗(yàn)證碼: 匿名發(fā)表
主站蜘蛛池模板: 丰台区| 永胜县| 淮阳县| 济宁市| 宁城县| 天峨县| 海丰县| 邓州市| 化隆| 邹城市| 临汾市| 绩溪县| 龙门县| 无极县| 临海市| 大关县| 毕节市| 平罗县| 新建县| 台中市| 九寨沟县| 四川省| 江山市| 琼结县| 女性| 桂平市| 都江堰市| 渭源县| 阿拉尔市| 和田市| 静安区| 定兴县| 华容县| 浦城县| 大安市| 定陶县| 汶川县| 稻城县| 泸定县| 铁岭市| 和静县|