最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

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

 更新時間:2016年04月05日 09:53:13   作者:Bridge Li  
以下教程是小編在參與開發(fā)公司的一個crm系統(tǒng),整理些相關(guān)資料,在該系統(tǒng)中有很多消息推送功能,在其中用到了websocket技術(shù)。下面小編整理分享到腳本之家平臺供大家參考

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

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/beans
http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.1.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc-3.1.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-3.1.xsd
http://www.springframework.org/schema/websocket
http://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對應(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);
@Override
public 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);
}
@Override
public void afterHandshake(ServerHttpRequest request,
ServerHttpResponse response, WebSocketHandler wsHandler,
Exception ex) {
logger.info("建立握手后...");
super.afterHandshake(request, response, wsHandler, ex);
}
}

因?yàn)槔戏虿皇呛芏?,所以最大限度的保留原代碼,這其實(shí)就是從單點(diǎn)登錄中取出當(dāng)前登錄用戶,轉(zhuǎn)成UserSocketVo對象,放到Map中。所以接下來我們看看UserSocketVo對象的定義

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; //成功連接時間
private Date preRequestTime; //上次請求時間
private Date newRequestTime; //新請求時間
private Date lastSendTime = new Date(); //下架消息最近一次發(fā)送時間
private Date lastTaskSendTime = new Date(); //待處理任務(wù)最近一次發(fā)送時間
private WebSocketSession webSocketSession; //用戶對應(yīng)的wsSession 默認(rèn)僅緩存一個
// getXX and setXX 
}

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

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);
@Autowired
private NewsListenerImpl newsListener;
@Override
protected 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
*/
@Override
public 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);
}
@Override
public 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),作用就比較明顯了吧,存放每個UserSocketVo的最新數(shù)據(jù),其實(shí)到這里我們websocket的實(shí)現(xiàn)已經(jīng)算完了,但還有一個核心類(關(guān)于業(yè)務(wù)邏輯查理的類)沒有實(shí)現(xiàn),下篇Spring整合WebSocket應(yīng)用示例(下),我們就看怎么實(shí)現(xiàn)這個類。

WebSocket協(xié)議介紹

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

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

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

什么場景下該使用WebSocket

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

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

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

相關(guān)文章

  • SpringIOC的注解應(yīng)用方式

    SpringIOC的注解應(yīng)用方式

    在Spring框架中,除了通過xml配置文件進(jìn)行Bean管理外,還可以采用注解的方式實(shí)現(xiàn)Bean的注冊和自動裝配,通過在類上添加@Component、@Service、@Repository、@Controller等注解,可以將Bean注冊到IOC容器中
    2024-11-11
  • 使用Hibernate根據(jù)實(shí)體類自動生成表的方法

    使用Hibernate根據(jù)實(shí)體類自動生成表的方法

    這篇文章主要介紹了使用Hibernate根據(jù)實(shí)體類自動生成表的方法,該篇提供了兩種方法,可以根據(jù)需要選擇其一,希望對你有所幫助,如有不對的地方還望指正
    2023-03-03
  • ActiveMQ整合Spring入門用法解析

    ActiveMQ整合Spring入門用法解析

    這篇文章主要介紹了ActiveMQ整合Spring入門用法解析,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下
    2020-10-10
  • Java main方法String[]args原理實(shí)例解析

    Java main方法String[]args原理實(shí)例解析

    這篇文章主要介紹了Java main方法String[]args原理實(shí)例解析,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下
    2020-06-06
  • Java程序運(yùn)行時出現(xiàn)亂碼問題的排查與解決方法

    Java程序運(yùn)行時出現(xiàn)亂碼問題的排查與解決方法

    本文主要介紹了Java程序運(yùn)行時出現(xiàn)亂碼問題的排查與解決方法,包括檢查Java源文件編碼、檢查編譯時的編碼設(shè)置、檢查運(yùn)行時的編碼設(shè)置、檢查命令提示符的代碼頁、檢查命令提示符的字體、檢查 Java 程序的輸出代碼以及檢查環(huán)境變量,需要的朋友可以參考下
    2025-03-03
  • Java8 自定義CompletableFuture的原理解析

    Java8 自定義CompletableFuture的原理解析

    這篇文章主要介紹了Java8 自定義CompletableFuture的原理解析,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2021-11-11
  • Java泛型定義與用法實(shí)例詳解

    Java泛型定義與用法實(shí)例詳解

    這篇文章主要介紹了Java泛型定義與用法,結(jié)合實(shí)例形式較為詳細(xì)的分析了Java中泛型的概念、原理、定義、使用方法及相關(guān)操作注意事項(xiàng),需要的朋友可以參考下
    2018-08-08
  • Springboot整合ActiveMQ實(shí)現(xiàn)消息隊列的過程淺析

    Springboot整合ActiveMQ實(shí)現(xiàn)消息隊列的過程淺析

    昨天仔細(xì)研究了activeMQ消息隊列,也遇到了些坑,下面這篇文章主要給大家介紹了關(guān)于SpringBoot整合ActiveMQ的相關(guān)資料,文中通過實(shí)例代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2023-02-02
  • java實(shí)現(xiàn)jdbc查詢結(jié)果集result轉(zhuǎn)換成對應(yīng)list集合

    java實(shí)現(xiàn)jdbc查詢結(jié)果集result轉(zhuǎn)換成對應(yīng)list集合

    本文給大家匯總介紹了java實(shí)現(xiàn)jdbc查詢結(jié)果集result轉(zhuǎn)換成對應(yīng)list集合,十分的簡單,有相同需求的小伙伴可以參考下。
    2015-12-12
  • Java 時間轉(zhuǎn)換的實(shí)例代碼

    Java 時間轉(zhuǎn)換的實(shí)例代碼

    下面小編就為大家?guī)硪黄狫ava 時間轉(zhuǎn)換的實(shí)例代碼。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2016-07-07

最新評論

平潭县| 葫芦岛市| 澄迈县| 洛隆县| 揭西县| 肇源县| 兴义市| 镶黄旗| 福清市| 平昌县| 科尔| 雅江县| 桐柏县| 恭城| 贵南县| 丰城市| 会昌县| 凤凰县| 油尖旺区| 龙里县| 特克斯县| 吴桥县| 延边| 靖西县| 定安县| 贵溪市| 长阳| 天门市| 高阳县| 绥江县| 宜阳县| 昌图县| 永宁县| 海口市| 连山| 东兰县| 孝义市| 剑阁县| 理塘县| 财经| 东海县|