一、项目结构
在这里插入图片描述

二、依赖和配置

<?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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.1.17.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.xxxx</groupId>
    <artifactId>webrtcspringboot</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>webrtcspringboot</name>
    <description>Demo project for Spring Boot</description>

    <properties>
        <java.version>1.8</java.version>
    </properties>

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

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

        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <scope>runtime</scope>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <!-- fastJson-->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>1.2.60</version>
        </dependency>

        <!--热加载-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
            <optional>true</optional>
            <scope>true</scope>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>

server.port=8443
server.ssl.enabled=true
server.ssl.keyStore=tomcat.keystore
server.ssl.keyAlias=tomcat
server.ssl.keyStorePassword=123456
server.ssl.keyStoreType=JKS

三、代码

1、config

package com.xxxx.webrtcspringboot.config;

import javax.servlet.ServletRequestEvent;
import javax.servlet.ServletRequestListener;
import javax.servlet.annotation.WebListener;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;

/**
 * 根据JFR-356,Tomcat提供的WebSocket API并没有获取客户端IP地址的方法。
 * 我们无法直接在WebSocket类里面获取客户端IP地址等信息。
 * 但是通过监听ServletRequest并使用HttpSession和ServerEndpointConfig里面的Attributes传递信息,
 * 就可以实现直接在WebSocket类中获得客户端IP地址,弥补了WebSocket的一些先天不足。
 */
@WebListener
public class ClientIpServletListener implements ServletRequestListener {

    @Override
    public void requestDestroyed(ServletRequestEvent servletRequestEvent) {

    }

    @Override
    public void requestInitialized(ServletRequestEvent servletRequestEvent) {
        HttpServletRequest request=(HttpServletRequest) servletRequestEvent.getServletRequest();
        HttpSession session=request.getSession();
        //把HttpServletRequest中的IP地址放入HttpSession中,关键字可任取,此处为clientIp
        session.setAttribute("clientIp", servletRequestEvent.getServletRequest().getRemoteAddr());
    }
}

package com.xxxx.webrtcspringboot.config;

import javax.servlet.http.HttpSession;
import javax.websocket.HandshakeResponse;
import javax.websocket.server.HandshakeRequest;
import javax.websocket.server.ServerEndpointConfig;

/**
 * 在modifyHandshake方法中,可以将储存在httpSession中的clientIp,转移到ServerEndpointConfig中
 */
public class ConfiguratorForClientIp extends ServerEndpointConfig.Configurator {

    /**
     * 把HttpSession中保存的ClientIP放到ServerEndpointConfig中
     * @param config
     * @param request
     * @param response
     */
    @Override
    public void modifyHandshake(ServerEndpointConfig config, HandshakeRequest request, HandshakeResponse response) {
        HttpSession httpSession = (HttpSession) request.getHttpSession();
        config.getUserProperties().put("clientIp", httpSession.getAttribute("clientIp"));
    }
}

package com.xxxx.webrtcspringboot.config;

import org.apache.catalina.Context;
import org.apache.catalina.connector.Connector;
import org.apache.tomcat.util.descriptor.web.SecurityCollection;
import org.apache.tomcat.util.descriptor.web.SecurityConstraint;
import org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory;
import org.springframework.context.annotation.Bean;

/**
 * 将http请求,自动转换成https请求
 */
public class HttpConfig {

    @Bean
    public Connector connector(){
        Connector connector=new Connector("org.apache.coyote.http11.Http11NioProtocol");
        connector.setScheme("http");
        connector.setPort(80);
        connector.setSecure(false);
        connector.setRedirectPort(8443);
        return connector;
    }
    @Bean
    public TomcatServletWebServerFactory tomcatServletWebServerFactory(Connector connector){
        TomcatServletWebServerFactory tomcat = new TomcatServletWebServerFactory() {
            @Override
            protected void postProcessContext(Context context) {
                SecurityConstraint securityConstraint = new SecurityConstraint();
                securityConstraint.setUserConstraint("CONFIDENTIAL");
                SecurityCollection collection = new SecurityCollection();
                collection.addPattern("/*");
                securityConstraint.addCollection(collection);
                context.addConstraint(securityConstraint);
            }
        };
        tomcat.addAdditionalTomcatConnectors(connector);
        return tomcat;
    }
}

package com.xxxx.webrtcspringboot.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.socket.server.standard.ServerEndpointExporter;

/**
 * websocket 初始化配置
 */

@Configuration
public class WebSocketConfig {

    /**
     * 开启WebSocket支持
      * @return
     */
    @Bean
    public ServerEndpointExporter serverEndpointExporter() {
        return new ServerEndpointExporter();
    }
}


2、controller

package com.xxxx.webrtcspringboot.controller;

import com.xxxx.webrtcspringboot.service.RoomService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.servlet.http.HttpServletRequest;
import java.net.Inet4Address;
import java.net.InetAddress;
import java.net.NetworkInterface;
import java.net.SocketException;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;

@RestController
@Slf4j
public class IndexController {

    private static String ipOfInet4Address;

    private static final String IP_CODE = "127.0.0.1";

    //拿到本机在wifi中的局域网ip
    static {
        // 获得本机的所有网络接口
        Enumeration<NetworkInterface> naifs;
        try {
            naifs = NetworkInterface.getNetworkInterfaces();
            while (naifs.hasMoreElements()) {
                NetworkInterface nif = naifs.nextElement();
                // 获得与该网络接口绑定的 IP 地址,一般只有一个
                Enumeration<InetAddress> addresses = nif.getInetAddresses();
                while (addresses.hasMoreElements()) {
                    InetAddress addr = addresses.nextElement();
                    // 获取IPv4 地址
                    if (addr instanceof Inet4Address) {
                        ipOfInet4Address = addr.getHostAddress();
                        log.info("网卡接口名称:{}",nif.getName());
                        log.info("网卡接口地址:{}",addr.getHostAddress());
                    }
                }
            }
        } catch (SocketException e) {
            log.error("获取数据失败:{}",e);
        }
    }

    @Value("${server.port}")
    private Integer port;

    @Autowired
    private RoomService roomService;

    @GetMapping("/getWebSocketUrl")
    public Map<String, String> getIpAddress(HttpServletRequest request) {
        Map<String, String> result = new HashMap<>(1);
        if(IP_CODE.equals(request.getRemoteAddr())){
            //本地访问
            result.put("url", "wss:"+request.getRemoteAddr()+":"+port+ "/websocket");
        }else{
            //服务IP访问
            result.put("url", "wss:" + ipOfInet4Address +":"+port+ "/websocket");
        }
        return result;
    }

    @GetMapping("/queryCountInRoom")
    public Map<String, String> queryCountInRoom(String roomId) {
        Map<String, String> result = new HashMap<>(1);
        result.put("count", String.valueOf(roomService.queryCountInRoom(roomId)));
        return result;
    }
}

3、entity

package com.xxxx.webrtcspringboot.entity;

import lombok.Data;

@Data
public class Message {

    /**
     * 创建房间
     */
    public static final String TYPE_COMMAND_ROOM_ENTER = "enterRoom";
    /**
     * 获取房间
     */
    public static final String TYPE_COMMAND_ROOM_LIST = "roomList";
    /**
     * 对话
     */
    public static final String TYPE_COMMAND_DIALOGUE = "dialogue";
    /**
     * 准备
     */
    public static final String TYPE_COMMAND_READY = "ready";
    /**
     * 离开
     */
    public static final String TYPE_COMMAND_OFFER = "offer";
    /**
     * 回答
     */
    public static final String TYPE_COMMAND_ANSWER = "answer";
    /**
     * 申请人
     */
    public static final String TYPE_COMMAND_CANDIDATE = "candidate";

    private String command;
    private String userId;
    private String roomId;
    private String message;
}

4、service

package com.xxxx.webrtcspringboot.service;

import org.springframework.stereotype.Service;

/**
 * 命令处理服务
 */
@Service
public class CommandService {
}

package com.xxxx.webrtcspringboot.service;


import com.alibaba.fastjson.JSON;
import com.xxxx.webrtcspringboot.entity.Message;
import com.xxxx.webrtcspringboot.websocket.Connection;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.io.IOException;
import java.util.Collection;
import java.util.Set;

/**
 * 消息处理服务
 */

@Slf4j
@Service
public class MessageService {

    @Autowired
    private RoomService roomService;

    /**
     * 给房间内的所有人发送消息(包括自己)
     */
    public void sendMessageForEveryInRoom(Message message) {
        Set<Connection> room = roomService.queryRoomById(message.getRoomId());
        room.stream().forEach(t->{
            try {
                 t.getSession().getBasicRemote().sendText(JSON.toJSONString(message));
            } catch (IOException e) {
                log.error("发送消息失败: {}, {}", message.getUserId(), e);
            }
        });
    }


    /**
     * 给房间除自己之外的所有人发送消息
     */
    public void sendMessageForEveryExcludeSelfInRoom(Message message) {
        Set<Connection> room = roomService.queryRoomById(message.getRoomId());
        room.stream().forEach(t->{
            try {
                if (!message.getUserId().equals(t.getUserId())) {
                     t.getSession().getBasicRemote().sendText(JSON.toJSONString(message));
                }
            } catch (IOException e) {
                log.error("{}->向房间:{}发送消息失败,{}",message.getUserId(), message.getRoomId(),e);
            }
        });
    }


    /**
     * 给在线的所有人发送消息(包括自己)
     */
    public void sendMessageForAllOnline(Message message) {
        Collection<Set<Connection>> rooms = roomService.queryAllRoom();
        rooms.stream().forEach(t-> t.stream().forEach(k->{
            try {
                k.getSession().getBasicRemote().sendText(JSON.toJSONString(message));
            } catch (IOException e) {
                log.error("{}用户发送广播失败:{}", message.getUserId(), e);
            }
        }));
    }
}

package com.xxxx.webrtcspringboot.service;

import com.xxxx.webrtcspringboot.websocket.Connection;
import org.springframework.stereotype.Service;

import java.util.Collection;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;


/**
 * 房间处理服务
 */
@Service
public class RoomService {

    private Map<String, Set<Connection>> rooms = new ConcurrentHashMap<>();

    /**
     * 加入到大厅
     */
    public void enterLobby(Connection connection) {
        Set<Connection> lobby = rooms.get("lobby");
        if (lobby == null) {
            rooms.put("lobby", new HashSet<>());
            lobby = rooms.get("lobby");
            lobby.add(connection);
        } else {
            lobby.add(connection);
        }
    }

    /**
     * 离开大厅
     */
    public void leaveLobby(Connection connection) {
        Set<Connection> lobby = rooms.get("lobby");
        lobby.remove(connection);
    }

    /**
     * 加入指定的房间
     */
    public String enterRoom(String roomId, Connection connection) {
        String operate;
        Set<Connection> room = rooms.get(roomId);
        if (room == null) {
            rooms.put(roomId, new HashSet<>());
            room = rooms.get(roomId);
            room.add(connection);
            operate = "created";
        } else {
            room.add(connection);
            operate = "joined";
        }
        //离开大厅
        leaveLobby(connection);
        return operate;
    }

    /**
     * 离开指定的房间
     */
    public void leaveRoom(String roomId, Connection connection) {
        if (roomId != null) {
            Set<Connection> room = rooms.get(roomId);
            if (room != null) {
                room.remove(connection);
                if (room.size() == 0) {
                    rooms.remove(roomId);
                }
            }
        }

    }

    /**
     * 查询指定房间人数(包括自己)
     */
    public Integer queryCountInRoom(String roomId) {
        Set<Connection> room = rooms.get(roomId);
        return room == null ? 0 : room.size();
    }

    /**
     * 将用户踢出房间
     */
    public void removeUserFromRoom(String roomId, String userId) {
        Set<Connection> room = rooms.get(roomId);
        if (room != null) {
            room.stream().forEach(e->{
                if (e.getUserId().equals(userId)) {
                    room.remove(e);
                }
            });
        }
    }

    /**
     * 通过房间Id查询房间
     */
    public Set<Connection> queryRoomById(String roomId) {
        return rooms.get(roomId);
    }

    /**
     * 查询所有存在的房间名称
     */
    public Set<String> queryAllRoomName() {
        return rooms.keySet();
    }

    /**
     * 查询所有存在的房间
     */
    public Collection<Set<Connection>> queryAllRoom() {
        return rooms.values();
    }
}

5、websocket

package com.xxxx.webrtcspringboot.websocket;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.serializer.SerializerFeature;
import com.xxxx.webrtcspringboot.config.ConfiguratorForClientIp;
import com.xxxx.webrtcspringboot.entity.Message;
import com.xxxx.webrtcspringboot.service.CommandService;
import com.xxxx.webrtcspringboot.service.MessageService;
import com.xxxx.webrtcspringboot.service.RoomService;
import lombok.Getter;
import lombok.Setter;
import lombok.ToString;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import javax.websocket.*;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * @Data 由于@Data重写了hashCode()和equals()方法,
 * 会导致Set<Connection> remove元素时,找不到正确的元素,
 * 应用@Setter @Getter @ToString替换
 * @ServerEndpoint 不是单例模式
 */
@ServerEndpoint(value = "/websocket", configurator = ConfiguratorForClientIp.class)
@Component
@Slf4j
@Getter
@Setter
@ToString
public class Connection {


    /**
     * 在线总人数
     */
    private static volatile AtomicInteger onlineCount = new AtomicInteger(0);


    private static RoomService roomService;


    private static MessageService messageService;


    private static CommandService commandService;

    @Autowired
    public void setRoomService(RoomService roomService) {
        Connection.roomService = roomService;
    }

    @Autowired
    public void setMessageService(MessageService messageService) {
        Connection.messageService = messageService;
    }

    @Autowired
    public void setCommandService(CommandService commandService) {
        Connection.commandService = commandService;
    }

    /**
     * 某个客户端的ip
     */
    private String ip;

    /**
     * 某个客户端的userID
     */
    private String userId;

    /**
     * 某个客户端的roomNo
     */
    private String roomId;

    /**
     * 与某个客户端的连接会话,需要通过它来给客户端发送数据
     */
    private Session session;


    /**
     * 连接建立成功调用的方法
     */
    @OnOpen
    public void onOpen(Session session) {
        this.session = session;
        ip = (String) session.getUserProperties().get("clientIp");
        //未进任何房间时,将本次连接放到大厅里面
        roomService.enterLobby(this);
        log.info("用户: {}, 连接到服务器,当前在线人数为:{}", ip, onlineCount.incrementAndGet());
    }
    /**
     * 连接关闭调用的方法
     */
    @OnClose
    public void onClose(Session session) {
        //离开大厅
        roomService.leaveLobby(this);
        //即使连接错误,回调了onError方法,最终也会回调onClose方法,所有退出房间写在这里比较合适
        roomService.leaveRoom(roomId, this);
        //在线数减1
        log.info("用户: {}, 关闭连接,退出房间: {}, 当前在线人数为:{}", ip, roomId, onlineCount.addAndGet(-1));
    }

    /**
     * 连接发生错误时调用的方法
     */
    @OnError
    public void onError(Session session, Throwable error) {
        log.error("用户主动关闭连接失败: {}",ip);
        try {
            session.close();
        } catch (Exception e) {
            log.error("关闭连接失败:{}",e);
        }
    }

    /**
     * 收到客户端消息后调用的方法
     * @param stringMessage 客户端发送过来的消息
     * */
    @OnMessage
    public void onMessage(Session session, String stringMessage) {
        Message message = JSON.parseObject(stringMessage, Message.class);
        log.info("收到来自: {}, 信息:{}", ip, JSON.toJSONString(message));
        switch (message.getCommand()) {
            case Message.TYPE_COMMAND_ROOM_ENTER:
                this.userId = message.getUserId();
                this.roomId = message.getRoomId();
                enterRoom(message);
                //服务器主动向所有在线的人推送房间列表
                pushRoomList();
                break;
            case Message.TYPE_COMMAND_DIALOGUE:
                messageService.sendMessageForEveryInRoom(message);
                break;
            case Message.TYPE_COMMAND_ROOM_LIST:
                //前端从服务器拉取房间列表
                pullRoomList(message);
                break;
            case Message.TYPE_COMMAND_READY:
            case Message.TYPE_COMMAND_OFFER:
            case Message.TYPE_COMMAND_ANSWER:
            case Message.TYPE_COMMAND_CANDIDATE:
                messageService.sendMessageForEveryExcludeSelfInRoom(message);
                break;
            default:
        }
    }

    /**
     * 返回给自己是加入房间还是创建房间
     * @param message
     */
    private void enterRoom(Message message) {
        message.setMessage(roomService.enterRoom(roomId, this));
        try {
            session.getBasicRemote().sendText(JSON.toJSONString(message));
        } catch (IOException e) {
            log.error("加入房间还是创建房间失败: {}", e);
        }
    }

    private void pullRoomList(Message message) {
        message.setMessage(JSON.toJSONString(roomService.queryAllRoomName(), SerializerFeature.WriteNullListAsEmpty));
        try {
            session.getBasicRemote().sendText(JSON.toJSONString(message));
        } catch (IOException e) {
           log.error("获取数据失败:{}", e);
        }
    }

    private void pushRoomList() {
        //告诉每个终端更新房间列表
        Message roomListMessage = new Message();
        roomListMessage.setCommand(Message.TYPE_COMMAND_ROOM_LIST);
        roomListMessage.setMessage(JSON.toJSONString(roomService.queryAllRoomName(),SerializerFeature.WriteNullListAsEmpty));
        messageService.sendMessageForAllOnline(roomListMessage);
    }
}


6、启动类

package com.xxxx.webrtcspringboot;

import com.alibaba.fastjson.serializer.SerializerFeature;
import com.alibaba.fastjson.support.config.FastJsonConfig;
import com.alibaba.fastjson.support.spring.FastJsonHttpMessageConverter;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.http.HttpMessageConverters;
import org.springframework.boot.web.servlet.ServletComponentScan;
import org.springframework.context.annotation.Bean;
import org.springframework.http.MediaType;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.scheduling.annotation.EnableScheduling;

import java.util.ArrayList;
import java.util.List;

@SpringBootApplication
@EnableScheduling
@ServletComponentScan
public class WebrtcspringbootApplication {

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


    /**
     * 替换json框架为fastjson
     */
    @Bean
    public HttpMessageConverters fastJsonHttpMessageConverters() {
        //1.需要定义一个convert转换消息的对象;
        FastJsonHttpMessageConverter fastConverter = new FastJsonHttpMessageConverter();
        //2:添加fastJson的配置信息;
        FastJsonConfig fastJsonConfig = new FastJsonConfig();
        //指定当属性值为null是否输出:pro:null
        fastJsonConfig.setSerializerFeatures(SerializerFeature.WriteMapNullValue,SerializerFeature.WriteNullListAsEmpty);
        //3处理中文乱码问题
        List<MediaType> fastMediaTypes = new ArrayList<>();
        fastMediaTypes.add(MediaType.APPLICATION_JSON_UTF8);
        //4.在convert中添加配置信息.
        fastConverter.setSupportedMediaTypes(fastMediaTypes);
        fastConverter.setFastJsonConfig(fastJsonConfig);
        //返回构成用的组件Bean
        return new HttpMessageConverters((HttpMessageConverter<?>) fastConverter);
    }
}

代码下载地址:https://elasti.oss-cn-beijing.aliyuncs.com/webrtcspringboot.zip

参考:https://github.com/weicaiwei/webrtc

四、题外话:websocket和stomp兼容配置

package com.xxxx.webrtcspringboot.config;

import com.xxxx.webrtcspringboot.service.SocketService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.messaging.simp.config.MessageBrokerRegistry;
import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;
import org.springframework.web.socket.config.annotation.*;
import org.springframework.web.socket.server.standard.ServerEndpointExporter;

/**
 * websocket 初始化配置
 */
@EnableWebSocketMessageBroker
@EnableWebSocket
@Configuration
@Slf4j
public class WebSocketConfig implements WebSocketMessageBrokerConfigurer, WebSocketConfigurer {

    /**
     * stomp 协议
     * @param registry
     */
    @Override
    public void registerStompEndpoints(StompEndpointRegistry registry) {
        registry.addEndpoint("/v1/websocket-stomp").setAllowedOrigins("*").withSockJS();
        registry.addEndpoint("/v1/websocket-stomp").setAllowedOrigins("*");
    }

    /**
     * 原生websocket协议
     * @param registry
     */
    @Override
    public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
        SocketService socketService = new SocketService();
        registry.addHandler(socketService, "/v1/websocket").setAllowedOrigins("*").withSockJS();
        registry.addHandler(socketService, "/v1/websocket").setAllowedOrigins("*");
    }

    /**
     * 开启WebSocket支持
     * @return
     */
    @Bean
    public ServerEndpointExporter serverEndpointExporter() {
        return new ServerEndpointExporter();
    }

    /**
     * stomp 订阅服务
     * @param registry
     */
    @Override
    public void configureMessageBroker(MessageBrokerRegistry registry) {
        // 自定义调度器,用于控制心跳线程
        ThreadPoolTaskScheduler taskScheduler = new ThreadPoolTaskScheduler();
        // 线程池线程数,心跳连接开线程
        taskScheduler.setPoolSize(1);
        // 线程名前缀
        taskScheduler.setThreadNamePrefix("websocket-thread-");
        // 初始化
        taskScheduler.initialize();
        registry.enableSimpleBroker("/v1").setHeartbeatValue(new long[]{10000, 10000})
                .setTaskScheduler(taskScheduler);
        registry.setUserDestinationPrefix("/user/");
        registry.setCacheLimit(Integer.MAX_VALUE);
    }
}
package com.xxxx.webrtcspringboot.service;

import lombok.extern.slf4j.Slf4j;
import org.springframework.web.socket.BinaryMessage;
import org.springframework.web.socket.CloseStatus;
import org.springframework.web.socket.TextMessage;
import org.springframework.web.socket.WebSocketSession;
import org.springframework.web.socket.handler.AbstractWebSocketHandler;

/**
 * 原生websocket方法
 */
@Slf4j
public class SocketService extends AbstractWebSocketHandler {

    @Override
    public void afterConnectionEstablished(WebSocketSession webSocketSession) {
        log.debug("创建连接");
    }

    @Override
    protected void handleTextMessage(WebSocketSession session, TextMessage message) {
        log.debug("业务处理");
    }

    @Override
    protected void handleBinaryMessage(WebSocketSession session, BinaryMessage message) {
        log.debug("发送消息");
    }

    @Override
    public void afterConnectionClosed(WebSocketSession webSocketSession, CloseStatus closeStatus) {
        log.info("关闭通道===>closeStatus={},webSocketSession={}", closeStatus, webSocketSession);
    }
}

Logo

致力于链接即构和开发者,提供实时互动和元宇宙领域的前沿洞察、技术分享和丰富的开发者活动,共建实时互动世界。

更多推荐