# 简单体验 websocket 编程

# 1、前往 spring 官网下载 websocket 的例子

这一步就不细说了:https://github.com/spring-guides/gs-messaging-stomp-websocket.git
从 github 上把这个项目拉下来。

# 2、创建一个自己的 springboot 项目

这里你可以用 IDEA 脚手架帮你直接创建一个 springboot 项目,也可以自己手动创建。

创建完之后你的目录应该是下面这个样子。

# 3、拷贝静态文件

将例子中 static 文件夹下的文件拷贝到自己的 springboot 项目中来,具体如下图所示:

其中 bullet.html 是下一篇会用到的弹幕例子。可以先不管他!

# 4、引入依赖并且修改编写文件

# 1、引入 pom 依赖

<dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-websocket</artifactId>
        </dependency>
        <dependency>
            <groupId>org.webjars</groupId>
            <artifactId>webjars-locator-core</artifactId>
        </dependency>
        <dependency>
            <groupId>org.webjars</groupId>
            <artifactId>sockjs-client</artifactId>
            <version>1.0.2</version>
        </dependency>
        <dependency>
            <groupId>org.webjars</groupId>
            <artifactId>stomp-websocket</artifactId>
            <version>2.3.3</version>
        </dependency>
        <dependency>
            <groupId>org.webjars</groupId>
            <artifactId>bootstrap</artifactId>
            <version>3.3.7</version>
        </dependency>
        <dependency>
            <groupId>org.webjars</groupId>
            <artifactId>jquery</artifactId>
            <version>3.1.1-1</version>
        </dependency>
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>2.0.14.graal</version>
        </dependency>
</dependencies>

# 2、在 app 文件夹下建一个 class 文件 WebsocketConfig

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;
@Configuration
@EnableWebSocketMessageBroker
public class WebsocketConfig implements WebSocketMessageBrokerConfigurer {
    @Override
    public void registerStompEndpoints(StompEndpointRegistry registry) {
//        registry.addEndpoint("/dreamlandWs").withSockJS();
        registry.addEndpoint("/dreamlandWs").setAllowedOrigins("*").withSockJS();
    }
    @Override
    public void configureMessageBroker(MessageBrokerRegistry registry) {
        registry.enableSimpleBroker("/topic/","/user/");
        registry.setApplicationDestinationPrefixes("/dreamlandBullet");
    }
}

解释:开启 websocket 通道,registerStompEndpoints 方法就是允许客户端向服务端注册 websocket 连接,addEndpoint 方法的作用是
限制连接的地址必须要携带你指定的路径,setAllowedOrigins 是设置域名,如果不设置可能会出现跨域问题,withSockJS 表示客户端用于连接
通道的方式。configureMessageBroker 方法是一些配置,enableSimpleBroker 是配置允许被订阅的通道,如果不配置这个客户端没法接收到
对应路径的消息,第二个 setApplicationDestinationPrefixes 是发送的通道路径。

# 3、在 web 文件夹下新建以下文件

BulletMessage

public class BulletMessage {
    private String message;
    private String videoId;
    private String user;
    private Long date;
    public String getMessage() {
        return message;
    }
    public void setMessage(String message) {
        this.message = message;
    }
    public String getVideoId() {
        return videoId;
    }
    public void setVideoId(String videoId) {
        this.videoId = videoId;
    }
    public String getUser() {
        return user;
    }
    public void setUser(String user) {
        this.user = user;
    }
    public Long getDate() {
        return date;
    }
    public void setDate(Long date) {
        this.date = date;
    }
}

MessageController

import com.alibaba.fastjson.JSONObject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.messaging.Message;
import org.springframework.messaging.handler.annotation.MessageMapping;
import org.springframework.messaging.simp.SimpMessagingTemplate;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
@Controller
public class MessageController {
    @Autowired
    SimpMessagingTemplate simpMessagingTemplate;
    //    @SendTo("/topic/message")
    @MessageMapping("/bullet")
    public void broadCast(Message<Object> message) {
        byte[] payload = (byte[]) message.getPayload();
        String content = new String(payload);
        System.out.println(content);
        JSONObject jsonObject = JSONObject.parseObject(content);
//        return jsonObject.getString("bullet");
        serverSend(jsonObject.getString("bullet"), jsonObject.getString("videoId"), jsonObject.getString("user"));
    }
    @GetMapping("serverSend")
    public void serverSend(String message, String id, String user) {
        BulletMessage bulletMessage = new BulletMessage();
        bulletMessage.setMessage(message);
        bulletMessage.setUser(user);
        bulletMessage.setVideoId(id);
        bulletMessage.setDate(System.currentTimeMillis());
//        simpMessagingTemplate.convertAndSend("/topic/message", message);
        simpMessagingTemplate.convertAndSendToUser(id, "/bullet", bulletMessage);
    }
}

这里需要稍微解释一下:

BulletMessage 这个文件是弹幕的一个载体,用于服务器接收到客户端的弹幕后,组装成 BulletMessage 然后广播给所有订阅了对应地址的客户端。

MessageController 注解 @MessageMapping 指定了一个地址,之前配置了发送通道是 /dreamlandBullet , 发送地址就需要配合 @MessageMapping 进行
组装,也就是消息发送的地址是 /dreamlandBullet/bullet;@SendTo 配合的是客户端的订阅,客户端订阅了你 sendTo 指定的地址后,服务器会将消息广播到
所有订阅了 sendTo 指定地址的客户端。这个不符合我们视频弹幕多对多的要求,这里不讨论。为了实现动态指定推送,我们需要动态的配置发送地址,所以
有了 SimpMessagingTemplate 这个类。从发送过来的消息我们解析出一个规定的 id,这个 id 用于订阅地址的拼接,这样就能实现在指定 id 的视频发送
的弹幕只能在指定 id 视频弹幕列表中看到。

# 5、修改静态文件

这里就大概修改一下 app.js 就够了

首先是修改 sendName 方法,路径指定修改,然后消息体我们可以先写死。

function sendName() {
    stompClient.send("/dreamlandBullet/bullet", {}, JSON.stringify({
        'bullet': $("#name").val(),
        'videoId': '19',
        'user': '123465'
    }));
}

然后我修改连接的方法:改成我们指定的通道,因为在同一个项目所以不需要利用 http 或者 ws 去连接 websocket 服务;第二个地址是订阅的地址,之所以需要用 /user/
是因为后端那个指定发送的时候会自动拼接上这个地址,所以我们必须开放这个并且订阅。

function connect() {
    var socket = new SockJS('/dreamlandWs');
    stompClient = Stomp.over(socket);
    stompClient.connect({}, function (frame) {
        setConnected(true);
        console.log('Connected: ' + frame);
        // stompClient.subscribe('/topic/message', function (greeting) {
        //     showGreeting(greeting.body);
        // });
        stompClient.subscribe('/user/19/bullet', function (greeting) {
            showGreeting(greeting.body);
        });
    });
}

# 6、启动项目并且验证

页面启动后访问 localhost:8080 即可

点击 connect,然后输入你要发送的消息,点击 send,会收到自己发送的消息

本篇内容就到此为止了,下一篇来基于此篇的内容实现弹幕效果