1. 程式人生 > >SpringBoot 實現WebSocket進行訊息傳送(適用於SpringMVC)

SpringBoot 實現WebSocket進行訊息傳送(適用於SpringMVC)

Spring框架中自帶了WebSocket的jar包,利用它可以實現與H5中WebSocket進行對接,實現互動。使用Spring WebSocket並不複雜,下面一起來看下怎麼實現吧(注:本例子是通過SpringBoot構建的專案,除了專案的啟動程式碼配置不一樣外,WebSocket的配置程式碼可在SpringMVC上無縫使用)。

這個例子會通過模擬登陸,在Session中儲存使用者資訊,然後進行WebSocket通訊時,從Session中將使用者資訊取出來,並將資訊轉發給指定使用者。

一、所需POM配置

SpringMVC配置:

<dependency>
    <groupId
>
org.springframework</groupId> <artifactId>spring-websocket</artifactId> <version>4.3.10.RELEASE</version> </dependency>

通過SpringMVC來構建專案的話,除了一些基本的Spring jar包之外,只需要新增上面這個jar包即可。

SpringBoot配置:

<build>
    <plugins>
      <plugin>
        <groupId
>
org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId
>
<version>1.5.6.RELEASE</version> <relativePath/> </parent> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-thymeleaf</artifactId> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-websocket</artifactId> </dependency> </dependencies>

使用SpringBoot來構建專案的話,需要使用上面這些jar包,上面的jar包包含了SpringBoot的配置、WebSocket的配置。

二、程式碼實現

啟動類

@SpringBootApplication
@Controller
@ComponentScan(basePackages={"com.test.spring.boot"})   //自定義自動掃描
public class Application {

    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }
}

上面程式碼是SpringBoot的一個專案啟動類,執行main方法就可以啟動服務,相關配置在這篇文章裡不是重點,就不寫出來了,感興趣可以看這篇文章:SpringBoot+Thymeleaf整合開發例項

這裡需要注意的是 @ComponentScan(basePackages={"com.test.spring.boot"}),代表了掃描的包名。

訪問Controller

@Controller
@RequestMapping("/")
public class HelloController {

    private static final String SESSION_USER = "user";

    @Autowired
    private MyWebSocketHandler myWebSocketHandler;

    // 訪問跳轉到websocket.html頁面
    @RequestMapping("/socket")
    public String websocket() {
        return "websocket";
    }

    // 模擬登陸操作,將使用者資訊存入Session
    @RequestMapping("/login")
    public @ResponseBody String login(UserBean userBean, HttpServletRequest request) {
        System.out.println("========================== 開始登入 ===================");
        System.out.println("userId="+userBean.getId());
        System.out.println("userId="+userBean.getUsername());
        System.out.println("userId="+userBean.getPhone());

        request.getSession().setAttribute(SESSION_USER, userBean);
        System.out.println("========================== 登入成功 ===================");
        return "success";
    }

    // 普通操作,觸發WebSocket通訊
    @RequestMapping("/send/message")
    public @ResponseBody String sendMessage(HttpServletRequest request) {
        UserBean userBean = (UserBean) request.getSession().getAttribute(SESSION_USER);
        boolean isSuccess = myWebSocketHandler.sendMessageToUser(userBean.getId(), "測試傳送訊息");
        System.out.println(isSuccess);
        return "message";
    }
}

註冊WebSocket處理類

@Configuration
@EnableWebSocket
public class WebSocketConfig implements WebSocketConfigurer {

    @Override
    public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
        registry.addHandler(new MyWebSocketHandler(), "/websocket").addInterceptors(new WebSocketInterceptor());
    }

}

這是一個WebSocket配置類,實現介面來配置Websocket請求的路徑和攔截器。 這裡是將請求路徑 /websocket繫結到MyWebSocketHandler()類,並設定一個攔截器WebSocketInterceptor()
註解不要忘掉,否則無法註冊這個配置類。

WebSocket攔截器

/**
 * WebSocket 攔截器,用於將使用者資訊從session中存入map,方便後面websocket請求時從map中找到指定的使用者session資訊
 * @author Administrator
 *
 */
public class WebSocketInterceptor implements HandshakeInterceptor {

    private static final String SESSION_USER = "user";

    @Override
    public boolean beforeHandshake(ServerHttpRequest request, ServerHttpResponse response, 
            WebSocketHandler wsHandler, Map<String, Object> map) throws Exception {
        if (request instanceof ServletServerHttpRequest) {
            ServletServerHttpRequest serverHttpRequest = (ServletServerHttpRequest) request;
            HttpSession session = serverHttpRequest.getServletRequest().getSession();
            if (session != null) {
                map.put(SESSION_USER, session.getAttribute(SESSION_USER));
            }

        }
        return true;
    }

    @Override
    public void afterHandshake(ServerHttpRequest request,
            ServerHttpResponse response, WebSocketHandler wsHandler, Exception exception) {

    }

}

這個攔截器的作用是在請求WebSocket時,將Session中的使用者資訊轉存到map中,方便後面WebSocket請求處理時,能夠從map中獲取到使用者資訊。

WebSocket具體請求處理類

在貼程式碼之前,我們先來看下WebSocket具體請求處理類中的那些方法可以重寫,他們是什麼含義:

  1. afterConnectionEstablished連線建立成功之後,記錄使用者的連線標識,便於後面發信息,這裡我是記錄將id記錄在Map集合中。

  2. handleTextMessage中可以對H5 Websocket的send方法進行處理。

  3. handleTransportError連接出錯處理,主要是關閉出錯會話的連線,和刪除在Map集合中的記錄。

  4. afterConnectionClosed連線已關閉,移除在Map集合中的記錄。

@Component
public class MyWebSocketHandler extends TextWebSocketHandler {

    //線上使用者列表
    private static final Map<Integer, WebSocketSession> users = new HashMap<Integer, WebSocketSession>();
    //使用者標識
    private static final String SESSION_USER = "user";

    /**
     * 連線已關閉,移除在Map集合中的記錄
     */
    @Override
    public void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception {
        users.remove(getUserId(session));
    }

    @Override
    public void handleTransportError(WebSocketSession session, Throwable exception) throws Exception {
        if (session.isOpen()) {
            session.close();
        }
        System.out.println("連接出錯");
        users.remove(getUserId(session));
    }

    /**
     * 連線建立成功之後,記錄使用者的連線標識,便於後面發信息
     */
    @Override
    public void afterConnectionEstablished(WebSocketSession session) throws Exception {
        System.out.println("成功建立連線");
        Integer userId = getUserId(session);
        System.out.println(userId);
        if (userId != null) {
            users.put(userId, session);
            session.sendMessage(new TextMessage("成功建立socket連線"));
            System.out.println(userId);
            System.out.println(session);
        }
    }

    /**
     * 處理收到的websocket資訊
     */
    @Override
    protected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception {

    }

     /**
     * 傳送資訊給指定使用者
     * @param clientId
     * @param message
     * @return
     */
    public boolean sendMessageToUser(Integer clientId, String message) {
        if (users.get(clientId) == null) {
            return false;
        }

        WebSocketSession session = users.get(clientId);
        System.out.println("sendMessage:" + session);

        if (!session.isOpen()) {
            return false;
        }
        try {
            int count = 1;
            TextMessage textMessage = null; 
            String newMessage = "";

            // 迴圈向客戶端傳送資料
            while(true) {
                newMessage = message + String.valueOf(count);
                textMessage = new TextMessage(newMessage);
                session.sendMessage(textMessage);
                Thread.sleep(5000);
                newMessage = "";
            }
        } catch (IOException e) {
            e.printStackTrace();
            return false;
        } catch (InterruptedException e) {
            e.printStackTrace();
            return false;
        }
    }

    /**
     * 廣播資訊
     * @param message
     * @return
     */
    public boolean sendMessageToAllUsers(TextMessage message) {
        boolean allSendSuccess = true;
        Set<Integer> clientIds = users.keySet();
        WebSocketSession session = null;
        for (Integer clientId : clientIds) {
            try {
                session = users.get(clientId);
                if (session.isOpen()) {
                    session.sendMessage(message);
                }
            } catch (IOException e) {
                e.printStackTrace();
                allSendSuccess = false;
            }
        }
        return  allSendSuccess;
    }

     /**
     * 獲取使用者標識
     * @param session
     * @return
     */
    private Integer getUserId(WebSocketSession session) {
        try {
            UserBean userBean = (UserBean) session.getAttributes().get(SESSION_USER);
            return userBean.getId();
        } catch (Exception e) {
            return null;
        }
    }
}

前端實現

<!DOCTYPE HTML>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<title>WebSocket Test</title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />

<link rel="stylesheet" th:href="@{/css/main.css}"/>
<script th:src="@{/js/jQuery-2.1.4.min.js}" type="text/javascript"></script>

</head>
<body>
    <div>
        <input type="button" id="btn_test" value="點選獲取資料"/>
    </div>
    <div>
        <div id="test_1">
        </div>
    </div>
</body>
<script type="text/javascript">
//<![CDATA[ 
$(document).ready(function() {
    var websocket =  null;
    var sendData = {"id": 1, "username": "tanjin", "phone": "1888221322122"};
    // 模擬登陸
    $.post("login", sendData, function(data) {
        // 初始化一個WebSocket連線
        websocket = new WebSocket("ws://localhost:8082/websocket");
        websocket.onerror = function(event) {onError(event);};
        websocket.onopen = function(event) {onOpen(event);};
        // websocket接收的資訊會通過這個回撥方法返回給前端
        websocket.onmessage = function(event) {onMessage(event);};
    })

    // 列印收到的websocket返回資訊
    function onMessage(event) {
        $("#test_1").append("<label class='navbar-label'>" + event.data + "</label>").append("</br>");
        $("#test_1").scrollTop( $("#test_1")[0].scrollHeight);
    }

    // 開啟websocket請求回撥處理
    function onOpen(event) {
        $("#test_1").empty();
        var label = $("<label>").html("開始執行....");
        $("#test_1").append(label).append("<br>").append("<br>");
    }

    //報錯處理回撥函式
    function onError(event) {
        alert(event.data);
    }

    //點選頁面上的一個按鈕,通過一個普通方法來開始一個websocket請求
    $("#btn_test").click(function() {
        $.post("send/message", null, function() {})
    })
})
//]]>
</script>
</html>

//<![CDATA[ 這個標籤在這裡是由於thymeleaf的語法限制使用的,如果是JSP則不需要。

處理結果

這裡寫圖片描述

相關推薦

SpringBoot 實現WebSocket進行訊息傳送用於SpringMVC

Spring框架中自帶了WebSocket的jar包,利用它可以實現與H5中WebSocket進行對接,實現互動。使用Spring WebSocket並不複雜,下面一起來看下怎麼實現吧(注:本例子是通過SpringBoot構建的專案,除了專案的啟動程式碼配置不一

SpringBoot實現簡單的郵件傳送收件人可選擇,郵件內容可編輯

1.配置專案檔案目錄,我配置的是這樣的: 2:配置pom.xml 參照對比新增包依賴 <dependency> <groupId>org.springframework.boot</groupId>

使用微信公眾號模板訊息傳送基於.NET開發

使用微信公眾號模板訊息傳送,能夠在使用者操作網站時對指定使用者傳送訊息提示,不僅能夠及時反饋,還能使用者一個好的體驗,還可以節約短息推送的成本; 下面是比較重要的部分我做了一個擷取展示,詳細介面介紹請移步到, 微信官網地址:https://mp

2019 模板開發基礎指南用於emlog5

本文分析emlog5下的模板基本結構以及基本變數、函式的作用,詳細瞭解本文,有助於更快掌握emlog5的模板開發基礎。 emlog的模板位於安裝目錄content\templates\資料夾下,每個模板都是一個單獨的資料夾,資料夾以模板名字命名。通過後臺上傳安裝的模板都儲存在這個目錄下。 模板檔

eclipse + maven 配置 SSM 專案環境用於 idea

idea 編輯器自己新建一個 maven 專案後,其他的照著下面做就行。 開始寫教程前,我已經建立了一個用於 web 開發的 maven 專案了,所以還不會建立 maven 專案的同學,可以看我的上一篇部落格,教程比較簡單的,跟著一步步做就行,很適合小白看的:https:/

Angular 解決跨域 配置代理 用於Angular2+

1. 新建proxy.conf.json 檔案 內容如下:{    "/api": {        "target": "http://124.77.3.162:8888",        "secure": false,        "router" : {      

Angular primeng tree 元件資料解析用於Angular2+

1.專案中引入 primeng tree元件 import{TreeModule}from'primeng/tree'; import{TreeNode}from'primeng/api'; 2.本文講解把一個後臺返回資料,轉化成tree需要的型別 後臺返回json如下:

為升級後的Linux核心打包用於ubuntu

打包替換核心 打包替換新核心使用的是make-kpkg命令,所以此方法只適合支援make-kpkg命令的系統版本,一般適合Ubuntu、Debian等系統,不適合RedHat系統。 1、定製核心 #make mrprobe ,清理原始碼樹。 #make menuco

SQL Server2012遠端訪問設定用於2008

SQL2008或者SQL2012出現未開啟遠端連線的錯誤。下面總結了下開啟的方法。 1.開啟SQL server2012,使用windows身份登入 2.登入server後,右鍵“屬性”。左側選擇“安全性”,選中右側的“SQL Server 和 Windows 身份驗證模

小程式訊息推送含原始碼java實現小程式推送,springboot實現微信訊息推送

最近需要開發微信和小程式的推送功能,需要用java後臺實現推送,自己本身java和小程式都做,所以就自己動手實現下小程式的模版推送功能推送。 實現思路 1 小程式獲取使用者openid,收集formid傳給java後臺 2 java推送訊息給指定小程式使用

springboot整合rabbitmq,根據查詢的資訊建立多個訊息中心和訊息佇列,並實現不同的訊息傳送到不同的訊息中心

      今天接到一個需求,就是在傳送訊息到rabbitmq訊息中心的時候,需要根據裝置型別,將訊息傳送到不同的訊息佇列,因此要建立不同的訊息佇列。       修改之前是把配置資訊寫在配置文中,專案啟動時,獲取配置檔案中的配置資訊,建立訊息佇列。       修改後的邏輯

SpringBoot中使用Websocket進行訊息推送

WebsocketConfig.java @Configuration public class WebSocketConfig { @Bean public ServerEndpointExporter serverEndpointExporter() { return

使用Async和Await進行異步編程C#版 用於VS2015

send click cli inpu 成員 出錯 obj aging ros 你可以使用異步編程來避免你的應用程序的性能瓶頸並且加強總體的響應。然而,用傳統的技術來寫異步應用是復雜的,同時編寫,調試和維護都很困難。VS2012介紹了簡單的方法,那就是異步編程,它在.Net

使用websocket進行訊息推送服務

Websocket主要做訊息推送,簡單,輕巧,比comet好用 入門瞭解:https://www.cnblogs.com/xdp-gacl/p/5193279.html   /** * A Web Socket session represents a conversation bet

php微信公眾號模版訊息傳送群發

public function sendall(){ $all_openid=$this->tosendall(); foreach($all_openid as $value){ $this->set_msg($value); } } publ

用c語言實現兩個陣列中的內容進行交換。陣列一樣大

方法一:建立新的陣列。 #include<stdio.h> #include<stdlib.h> int main() { int arr1[5] = { 1, 2, 3, 4, 5, }; int arr2[5] = { 0, 6, 7, 8, 9, }

springboot整合redis進行資料操作

redis是一種常見的nosql,日常開發中,我們使用它的頻率比較高,因為它的多種資料介面,很多場景中我們都可以用到,並且redis對分散式這塊做的非常好。 springboot整合redis比較簡單,並且使用redistemplate可以讓我們更加方便的對資料進行操作。 1、新增依賴

1 行程式碼,實現微信訊息傳送

還是接食行生鮮簽到的問題,之前我們講到,將簽到結果通過簡訊傳送到手機,但是我發現 twilio 有些不穩定,為了防止漏籤,我在伺服器上設定了兩次定時任務,通常情況下第一個收不到簡訊,第二個才會收到。 看到最近好多大神寫操作微信的文章,於是,我又想,是不是可以將訊息傳送到微信上? 微信傳送訊息有如下幾個思路:

C# 實現自定義的USB設備與上位機進行通信上位機部分

lob filename 參考 EDA 文件 inpu sha red file   因為以前沒用過USB,對USB也不了解,於是上網查了很多資料,不過網上的資料都是零零散散,不清不楚的,於是我自己總結了一下,下面幾個鏈接是網上這麽多零散資料裏,我覺得比較有參考意義的。  

netty做服務端支援ssl協議實現websocket的wss協議客戶端為瀏覽器

也是在網上查的資料,整理一下相互學習下第一步:生成SSL證書:    因為是測試,直接使用jdk自帶的keytool工具生成自簽名證書(注:自簽名證書是不被瀏覽器認可的,只能用於測試),    --開啟cmd   --輸入命令(複製啊):keytool -genkey -ke