zoukankan      html  css  js  c++  java
  • 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,备注+ 葬月

  • 相关阅读:
    使用片段嵌入进行文档搜索
    详解支持向量机
    使用NLP检测和对抗AI生成的假新闻
    Detectron2 API 之 config | 十五
    用Python可视化卷积神经网络
    六种用于文本分类的开源预训练模型
    解空间树(回溯算法,分支界限法)
    日记2
    C编程(C语言程序设计,大连理工大学MOOC)
    编程题(C/C++程序设计,同济大学mooc)
  • 原文地址:https://www.cnblogs.com/Tiandaochouqin1/p/12546757.html
Copyright © 2011-2022 走看看