美文网首页
springboot 3.0.3 webSocket stomp

springboot 3.0.3 webSocket stomp

作者: 不知不怪 | 来源:发表于2023-02-24 01:26 被阅读0次

点我下载源码

1 pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>com.gzz</groupId>
    <artifactId>04-boot-webSocket-stomp</artifactId>
    <version>1.0</version>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>3.0.3</version>
    </parent>
    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <java.version>17</java.version>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-websocket</artifactId>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
        </dependency>
    </dependencies>
    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>
</project>

2 WebSocketConfig

package com.gzz.config;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.messaging.simp.config.ChannelRegistration;
import org.springframework.messaging.simp.config.MessageBrokerRegistry;
import org.springframework.web.socket.config.annotation.StompEndpointRegistry;
import org.springframework.web.socket.config.annotation.WebSocketMessageBrokerConfigurer;
/**
 * @author https://www.jianshu.com/u/3bd57d5f1074
 * @date 2023-02-28 14:50:00
 */
//https://www.cnblogs.com/dream-flying/articles/13019597.html
@Configuration
public class WebSocketConfig implements WebSocketMessageBrokerConfigurer {

    @Autowired
    private ConnectIntercept connectIntercept;

    @Override
    public void configureMessageBroker(MessageBrokerRegistry registry) {
//设置消息代理的前缀 - '/topic' 被设置的前缀的消息会被转发到消息代理 消息代理再将消息广播给当前连接的客户端 - 群发
//      registry.enableSimpleBroker("/topic");
        
//前端stomp.send("/app/hello",.... 后端@MessageMapping("/hello")加上前缀
//      registry.setApplicationDestinationPrefixes("/app");
    }

    @Override
    public void registerStompEndpoints(StompEndpointRegistry registry) {
        //接入点标识 配合前端 Stomp.client("ws://localhost:8080/chat")
        registry.addEndpoint("/chat");
    }


    @Override
    public void configureClientInboundChannel(ChannelRegistration registration) {
        registration.interceptors(connectIntercept);
    }
}

3 ConnectIntercept

package com.gzz.config;

import java.security.Principal;

import org.springframework.messaging.Message;
import org.springframework.messaging.MessageChannel;
import org.springframework.messaging.simp.stomp.StompCommand;
import org.springframework.messaging.simp.stomp.StompHeaderAccessor;
import org.springframework.messaging.support.ChannelInterceptor;
import org.springframework.messaging.support.MessageHeaderAccessor;
import org.springframework.stereotype.Component;

import lombok.extern.slf4j.Slf4j;
/**
 * @author https://www.jianshu.com/u/3bd57d5f1074
 * @date 2023-02-28 14:50:00
 */
@Slf4j
@Component
public class ConnectIntercept implements ChannelInterceptor {
//1、设置拦截器 
//2、首次连接的时候,获取其Header信息,利用Header里面的信息进行权限认证 
//3、通过认证的用户,使用 accessor.setUser(user); 方法,将登陆信息绑定在该 StompHeaderAccessor 上,在Controller方法上可以获取 StompHeaderAccessor 的相关信息
    @Override
    public Message<?> preSend(Message<?> message, MessageChannel channel) {
        StompHeaderAccessor accessor = MessageHeaderAccessor.getAccessor(message, StompHeaderAccessor.class);
        // 1、判断是否首次连接
        if (StompCommand.CONNECT.equals(accessor.getCommand())) {
            // 2、判断用户名和密码
            String username = accessor.getLogin();
            String password = accessor.getPasscode();
            String nickName = accessor.getNativeHeader("nickName").get(0);
            accessor.setUser(new Principal() {
                @Override
                public String getName() {
                    return username;
                }
            });
            log.info("username={},password={},nickName={}", username, password, nickName);
        }
        return message;
    }
}

4 TestController

package com.gzz.controller;

import java.security.Principal;

import org.springframework.messaging.handler.annotation.MessageMapping;
import org.springframework.messaging.simp.annotation.SendToUser;
import org.springframework.web.bind.annotation.RestController;

import com.gzz.config.Message;
/**
 * @author https://www.jianshu.com/u/3bd57d5f1074
 * @date 2023-02-28 14:50:00
 */
//@MessageMapping必须在Controller中有效
//以下两个方法作用一致
@RestController
public class TestController {
    @MessageMapping("/app/hello") // 接收/app/hello路径发来的消息
    @SendToUser("/greetings") // 转发到/topic/greetings
    public Message greeting(Principal principal,Message message) {
        System.out.println(message);
        return message;
    }

//  @Autowired
//  private SimpMessagingTemplate template;
//  @MessageMapping("/app/hello") // 接收/app/hello路径发来的消息
//  public void greeting(Principal principal, Message message) {
//      System.out.println(principal.getName());
//      template.convertAndSendToUser(principal.getName(), "/greetings", message);
//  }

}

//Spring-messaging(STOMP)@SendTo与@SendToUser的区别
//@SendTo 与 @SendToUser 是Spring的STOMP协议中注解的标签。
//@SendTo会将接收到的消息发送到指定的路由⽬的地,所有订阅该消息的⽤户都能收到,属于⼴播。
//@SendToUser消息⽬的地有UserDestinationMessageHandler来处理,会将消息路由到发送者对应的⽬的地。默认该注解前缀为/user。
//如:⽤户订阅/user/hi ,在@SendToUser('/hi')查找⽬的地时,会将⽬的地的转化为/user/{name}/hi,这个name就是principal的name值,
//该操作是认为⽤户登录并且授权认证,使⽤principal的name作为⽬的地标识。
//发给消息来源的那个⽤户。(就是谁请求给谁,不会发给所有⽤户,区分就是依照principal-name来区分的)。
//此外该注解还有个broadcast属性,表明是否⼴播。就是当有同⼀个⽤户登录多个session时,是否都能收到。取值true/false.

5 Message

package com.gzz.config;

import lombok.Data;
/**
 * @author https://www.jianshu.com/u/3bd57d5f1074
 * @date 2023-02-28 14:50:00
 */
@Data
public class Message {
    /** 昵称 */
    private String name;
    /** 消息内容 */
    private String content;
}

6 index.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>vue3.2.45,stomp1.7.1</title>
</head>
<script src="/js/vue.min.js"></script>
<script src="/js/stomp.min.js"></script>
<body>
    <div id='app'>
        <div>
            <label for="name">请输入用户名:</label> <input type="text" v-model="userName" placeholder="用户名">
        </div>
        <div>
            <button type="button" @click="doConnect()" :disabled="status">连接</button>
            <button type="button" @click="disconnect()" :disabled="!status">断开</button>
        </div>
        <div v-show="status">
            <div>
                <label for="content">请输入聊天内容:</label><br><textarea type="text" v-model="content"  rows='10' cols='50'></textarea>
                <button type="button" @click="sendMessage()">发送</button>
            </div>
            <div>
                <textarea v-model="conversation" rows='10' cols='50'></textarea>
            </div>
        </div>
    </div>
</body>
<script type="text/javascript">
    let stomp=null;
    const app = Vue.createApp({
        data() {
            return {  status: false, userName: "gzz", content: null,conversation:"" }
        },
        methods: {
            doConnect() {
                let that = this;
                let headers = { login: 'gzz', passcode: '12345', 'nickName': this.userName };
                stomp = Stomp.client("ws://localhost:8080/chat");
                stomp.connect(headers, function (frame) {//连接
                    that.status = true;
                    stomp.subscribe('/user/'+that.userName+'/greetings', function (res) {//订阅
                        that.conversation += res.body + "\r";
                    });
                });
            },
            disconnect() {//断开
                if (stomp != null) stomp.disconnect();
                this.status = false;
            },
            sendMessage() {//发送
                stomp.send("/app/hello", {}, JSON.stringify({ 'name': this.userName, 'content': this.content }));
                this.content="";
            },
        }
    });
    app.mount("#app");
</script>

</html>

7 Application

package com.gzz;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.web.socket.config.annotation.EnableWebSocketMessageBroker;
/**
 * @author https://www.jianshu.com/u/3bd57d5f1074
 * @date 2023-02-28 14:50:00
 */
@EnableWebSocketMessageBroker // 开启WebSocket消息代理
@SpringBootApplication
public class Application {
    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }
}

1677259489403.png image.png

点我下载源码

相关文章

网友评论

      本文标题:springboot 3.0.3 webSocket stomp

      本文链接:https://www.haomeiwen.com/subject/njotldtx.html