springboot+vue+websockt+stomp+spring-security


直奔主題:

  一般的web項目都是短連接,主動權是交給客戶端手里,在客戶端不發請求的情況下,服務端是沒辦法主動給客戶端發送消息。但是有些情況下,我們需要長連接,比如常見到的聊天室。網上有很多的案例這里就不多說了!()

java后端部分  

首先,我們是需要導入maven節點

     <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-websocket</artifactId>
        </dependency>

傳統的玩法,需要一個配置類WebSocketConfiguration,他需要實現WebSocketMessageBrokerConfigurer。重寫兩個方法configureMessageBroker,registerStompEndpoints

package com.lhf.novel.config.socket;

import org.springframework.context.annotation.Configuration;
import org.springframework.messaging.simp.config.MessageBrokerRegistry;
import org.springframework.web.socket.config.annotation.EnableWebSocketMessageBroker;
import org.springframework.web.socket.config.annotation.StompEndpointRegistry;
import org.springframework.web.socket.config.annotation.WebSocketMessageBrokerConfigurer;

/**
 * WebSocketConfigufation實體類
 *
 * @author zy
 * @since 2020/3/20$
 */
@Configuration
@EnableWebSocketMessageBroker
//@Deprecated
public class WebSocketConfiguration implements WebSocketMessageBrokerConfigurer {

    @Override
    public void configureMessageBroker(MessageBrokerRegistry registry) {
        registry.enableSimpleBroker("/topic");//注冊一個隊列,主要用來做消息區分的(在我看來)
    }

    @Override
    public void registerStompEndpoints(StompEndpointRegistry registry) {
        registry.addEndpoint("/api").setAllowedOrigins("*").addInterceptors().withSockJS();//通俗易懂簡單的來講,addEndpoint("/api")就是客戶端連接的時候url地址,后邊的就不解釋了。。。
} }

這樣客戶端就可以連接了。

現在添加一個測試,主動給客戶端推送消息********

package com.lhf.novel.config.socket;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.messaging.simp.SimpMessagingTemplate;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

/**
 * MessageService實體類
 *
 * @author zy 
 * @since 2020/3/22
 */
@Component
public class MessageService {
    @Autowired
    private SimpMessagingTemplate messagingTemplate;

    @Scheduled(fixedDelay = 5000)//spring的計划任務,這里表示每五秒執行一次,需要在配置類或者啟動類上加一個注解@EnableScheduling,這樣才能生效
public void mes() { messagingTemplate.convertAndSend("/topic","125"); } }

這里SimpMessagingTemplate是內置的一個消息模板,這里使用他的convertAndSend()方法,第一個參數是表示向那個通道發送、第二個參數是發送的內容這樣客戶端就可以連接了。

vue前端部分

首先需要導入兩個依賴

npm install socket-client

npm install stompjs

 

import SockJS from 'sockjs-client';
    import Stomp from 'stompjs';

    export default {
        name: "Index",
        data() {
            return {
                socket: null,
                stompClient: null,
                name: 'admin',
                mes: '',
                cmes: '',
            }
        },
        mounted() {
            this.init();
        },
        destroyed() {
            this.stompClient.destroyed();
        },
        methods: {
            init() {
                let _that = this;
          //連接socket
this.socket = new SockJS('http://localhost:8080/api'); let stompClient = Stomp.over(this.socket); stompClient.connect({ login: 'admin', passcode: '123456' }, function (frame) { window.console.log(frame)
          //訂閱,這里訂閱服務端注冊過的topic stompClient.subscribe(
'/topic', function (message) { window.console.warn(message); _that.cmes = message.body // window.console.log(JSON.parse(message.body)); }); }) this.stompClient = stompClient; }, send() {
          //這是發送消息
this.stompClient.send("/mes", {}, "客戶端發來消息") } }, }

這樣前端也差不多完成了

打開開發者模式  F12可以看到,每五秒服務端都會推送一條消息過來。

以上是服務端主動發送消息,聊天窗一定是點多點,或者點對多的模式的,那么就需要有用戶的概念,這是就需要加上springsecurity了。

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-security</artifactId>
        </dependency>  

security配置部分省略。。。我的配置用有兩個用戶admin 和 root

這樣需要一個controller

package com.lhf.novel.config.socket;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.messaging.handler.annotation.DestinationVariable;
import org.springframework.messaging.handler.annotation.MessageMapping;
import org.springframework.messaging.handler.annotation.SendTo;
import org.springframework.messaging.simp.SimpMessagingTemplate;
import org.springframework.web.bind.annotation.RestController;

import java.security.Principal;

/**
 * TestController實體類
 *
 * @author zy 
 * @since 2020/3/22
 */
@RestController
public class TestController {

    @Autowired
    private SimpMessagingTemplate messagingTemplate;


    @MessageMapping("/mes")
    //@SendTo("/topic")
    public void mes(Principal principal, String mess) {
        System.out.println("name:"+principal.getName());
        System.out.println("mes = " + mess);
        messagingTemplate.convertAndSendToUser("admin","/topic","我來了");
//        return principal.getName()+":發來致電";
    }
}

@MessageMapping和RequestMapping作用是一樣的,設置請求路徑

@SendTo是在有返回值的情況下返回通道

Principal是SpringSecurity的對象,里邊包含用戶的所有信息,當然是你自己的。

mess 是接受的消息,這里為了簡單我是直接寫了一個String類型的,你也可以分裝一個對象,這樣會好一些,畢竟點對點你得告訴服務器你要發送給誰,發送的內容。

SimpMessagingTemplate: 消息模板 上邊用了 convertAndSend()的方法,現在我們需要用到convertAndSendToUser()看方法名字也能看出來,這個是發送給指定用戶的,第一個參數是要發送的指定用戶,第二個參數通道、第三個是發送的內容(不要被我迷惑了,第                       三個參數是個Object的)

 

<template>
    <div>
        {{ $store.state.realName }}:
        <el-input v-model="mes"/>
        {{ cmes }}
        <el-button @click="send">點擊</el-button>
    </div>
</template>

<script>
    import SockJS from 'sockjs-client';
    import Stomp from 'stompjs';

    export default {
        name: "Index",
        data() {
            return {
                socket: null,
                stompClient: null,
                name: 'admin',
                mes: '',
                cmes: '',
            }
        },
        mounted() {
            this.init();
        },
        destroyed() {
            // this.stompClient.destroyed();
        },
        methods: {
            init() {
                let _that = this;
                this.socket = new SockJS('http://localhost:8080/api');
                let stompClient = Stomp.over(this.socket);
                stompClient.connect({
                    login: 'admin',
                    passcode: '123456'
                }, function (frame) {
                    window.console.log(frame)
                    stompClient.subscribe('/user/topic', function (message) {
                        window.console.warn(message);
                        _that.cmes = message.body
                        // window.console.log(JSON.parse(message.body));
                    });
                })
                this.stompClient = stompClient;
            },
            send() {
                this.stompClient.send("/mes", {}, "客戶端發來消息")
            }
        },
    }
</script>

<style scoped>

</style>

上訴代碼有一點不同就是客戶端定訂閱的多了一個spring提供的/user,也就是說現在需要訂閱 /user/topic兩個了

然后看效果圖

 

 

 

 至此結束,文筆不好,歡迎吐槽    1490030544,備注+ 葬月


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM