spring项目整合webSocket附带测试结果和源码

本文介绍了Spring项目整合WebSocket的方法。包括引入与项目Spring版本一致的jar包,如javax.websocket - api - 1.0.jar等;编写配置文件、主要实现类、测试接口和简单html页面;还进行了测试,启动项目和页面,用Postman发送请求。最后附上项目结构图和源码地址,2025年7月5日更新使用AI美化调试页面。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

源码可在CSDN 直接下载
1、引入jar包
maven项目

        <!-- WebSocket -->
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-websocket</artifactId>
			<version>2.1.0.RELEASE</version>
		</dependency>

如果是Java项目,引入以下jar包
在这里插入图片描述
红框为必须:
javax.websocket-api-1.0.jar
spring-context-4.2.5.RELEASE.jar
spring-websocket-4.2.5.RELEASE.jar
注意引入jar包和项目所用的spring版本保持一致,项目中用4.2.5我这demo也用这个
2、编写配置文件

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

@Configuration
public class WebSocketConfig {
    /**
     * 注入ServerEndpointExporter,
     * 这个bean会自动注册使用了@ServerEndpoint注解声明的Websocket endpoint
     */
    @Bean
    public ServerEndpointExporter serverEndpointExporter() {
        return new ServerEndpointExporter();
    }
}

2、编写主要的实现类

import com.alibaba.fastjson.JSON;
import org.springframework.stereotype.Component;

import javax.websocket.*;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.entity.SocketMessage;
import java.io.IOException;
import java.util.Date;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicInteger;

@ServerEndpoint("/webSocket/{userId}")
@Component
public class WebSocketServer {


	 //静态变量,用来记录当前在线连接数。应该把它设计成线程安全的。
    private static AtomicInteger onlineNum = new AtomicInteger();

    //concurrent包的线程安全Set,用来存放每个客户端对应的WebSocketServer对象。
    private static ConcurrentHashMap<String, Session> sessionPools = new ConcurrentHashMap<>();

    //发送消息
    public void sendMessage(Session session, String message) throws IOException {
        if(session != null){
            synchronized (session) {
                session.getBasicRemote().sendText(message);
            }
        }
    }
    //给指定用户发送信息
    public Integer sendInfo(String userId, String message){
        Session session = sessionPools.get(userId);
        try {
            sendMessage(session, message);
            return 1;
        }catch (Exception e){
            e.printStackTrace();
            return 0;
        }
    }
    // 群发消息
    public void broadcast(String message){
    	for (Session session: sessionPools.values()) {
            try {
                sendMessage(session, message);
            } catch(Exception e){
                e.printStackTrace();
                continue;
            }
        }
    }

    //建立连接成功调用
    @OnOpen
    public void onOpen(Session session, @PathParam(value = "userId") String userId){
        sessionPools.put(userId, session);
        addOnlineCount();
        // 广播上线消息
        SocketMessage msg = new SocketMessage();
        msg.setDate(new Date());
        msg.setTo("0");
        msg.setText(userId);
        broadcast(JSON.toJSONString(msg,true));
    }

    //关闭连接时调用
    @OnClose
    public void onClose(@PathParam(value = "userId") String userId){
        sessionPools.remove(userId);
        subOnlineCount();
        // 广播下线消息
        SocketMessage msg = new SocketMessage();
        msg.setDate(new Date());
        msg.setTo("-2");
        msg.setText(userId);
        broadcast(JSON.toJSONString(msg,true));
    }

    //收到客户端信息后,根据接收人的userId把消息推下去或者群发
    // to=-1群发消息
    @OnMessage
    public void onMessage(String message) throws IOException{
        SocketMessage msg= JSON.parseObject(message, SocketMessage.class);
		msg.setDate(new Date());
		if (msg.getTo().equals("-1")) {
			broadcast(JSON.toJSONString(msg,true));
		} else {
			sendInfo(msg.getTo(), JSON.toJSONString(msg,true));
		}
    }

    //错误时调用
    @OnError
    public void onError(Session session, Throwable throwable){
        throwable.printStackTrace();
    }

    public static void addOnlineCount(){
        onlineNum.incrementAndGet();
    }

    public static void subOnlineCount() {
        onlineNum.decrementAndGet();
    }

    public static AtomicInteger getOnlineNumber() {
        return onlineNum;
    }

    public static ConcurrentHashMap<String, Session> getSessionPools() {
        return sessionPools;
    }
}

引入了额外的jar包也是为了这里使用的,其中在这里插入图片描述
这个实体类是为了方便发送消息添加的,也可删掉这块相关的代码,不影响,我这里也贴出,方便大家使用

import com.alibaba.fastjson.annotation.JSONField;

import java.util.Date;

public class SocketMessage {

	//发送者name
	public String from;
	//接收者name
	public String to;
	//发送的文本
	public String text;
	//发送时间
	@JSONField(format="yyyy-MM-dd HH:mm:ss")
	public Date date;

	public String getFrom() {
		return from;
	}

	public void setFrom(String from) {
		this.from = from;
	}

	public String getTo() {
		return to;
	}

	public void setTo(String to) {
		this.to = to;
	}

	public String getText() {
		return text;
	}

	public void setText(String text) {
		this.text = text;
	}

	public Date getDate() {
		return date;
	}

	public void setDate(Date date) {
		this.date = date;
	}

	@Override
	public String toString() {
		return "SocketMessage{" +
				"from='" + from + '\'' +
				", to='" + to + '\'' +
				", text='" + text + '\'' +
				", date=" + date +
				'}';
	}
}

3、编写测试接口

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;

import java.service.WebSocketServer;

@Controller
@RequestMapping("/web")
public class WebSocketController {

    @Autowired
    WebSocketServer webSocketServer;

    /**
     * 发送单人消息
     *
     * @param userId 接收人用户ID
     * @param mes    消息
     * @return 1 发送成功  0 发送失败
     */
    @RequestMapping("/sendInfo")
    @ResponseBody
    public Integer sendInfo(@RequestParam("userId") String userId, @RequestParam("mes") String mes) {
        Integer num = webSocketServer.sendInfo(userId, mes);
        return num;
    }


    /**
     * 群发消息
     *
     * @param mes 消息
     * @return 1 发送成功  0 发送失败
     */
    @RequestMapping("/broadcast")
    @ResponseBody
    public void broadcast(@RequestParam String mes) {
        webSocketServer.broadcast(mes);
    }


    /**
     * 测试发送多条
     */
    @RequestMapping("/sendInfoFor")
    @ResponseBody
    public Integer sendInfo() {
        for (int i = 0; i < 100; i++) {
            webSocketServer.sendInfo(1 + "", i + "");
        }

        return 1;
    }

}

4、简单的html页面

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width,initial-scale=1.0">
    <!-- 最新版本的 Bootstrap 核心 CSS 文件 -->
    <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@3.3.7/dist/css/bootstrap.min.css"
          integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous">
    <title>websocket测试页面</title>
</head>
<body>
<div class="panel panel-default">
    <div class="panel-body">
        <div class="row">
            <div class="col-md-6">
                <div class="input-group">
                    <span class="input-group-addon">ws地址</span>
                    <input type="text" id="address" class="form-control" placeholder="ws地址"
                           aria-describedby="basic-addon1" value="ws://localhost:8010/webSocket/admin">
                    <div class="input-group-btn">
                        <button class="btn btn-default" type="submit" id="connect">连接</button>
                    </div>
                </div>
            </div>
        </div>
        <div class="row" style="margin-top: 10px;display: none;" id="msg-panel">
            <div class="col-md-6">
                <div class="input-group">
                    <span class="input-group-addon">消息</span>
                    <input type="text" id="msg" class="form-control" placeholder="消息内容" aria-describedby="basic-addon1">
                    <div class="input-group-btn">
                        <button class="btn btn-default" type="submit" id="send">发送</button>
                    </div>
                </div>
            </div>
        </div>
        <div class="row" style="margin-top: 10px; padding: 10px;">
            <div class="panel panel-default">
                <div class="panel-body" id="log" style="height: 450px;overflow-y: auto;">
                </div>
            </div>
        </div>
    </div>
</div>

<script src="https://cdn.jsdelivr.net/npm/jquery@1.12.4/dist/jquery.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@3.3.7/dist/js/bootstrap.min.js"
        integrity="sha384-Tc5IQib027qvyjSMfHjOMaLkfuWVxZxUPnCJA7l2mCWNIpG9mGCD8wGNIcPD7Txa"
        crossorigin="anonymous"></script>

<script type="text/javascript">
    $(function () {
        var _socket;

        $("#connect").click(function () {
            _socket = new _websocket($("#address").val());
            _socket.init();
        });

        $("#send").click(function () {
            var _msg = $("#msg").val();
            output("发送消息:" + _msg);
            _socket.client.send(JSON.stringify(_msg));
        });
    });

    function output(e) {
        var _text = $("#log").html();
        $("#log").html(_text + "<br>" + e);
    }

    function _websocket(address) {
        this.address = address;
        this.client;

        this.init = function () {
            if (!window.WebSocket) {
                this.websocket = null;
                return;
            }

            var _this = this;
            var _client = new window.WebSocket(_this.address);

            _client.onopen = function () {
                output("websocket打开");
                $("#msg-panel").show();
            };

            _client.onclose = function () {
                _this.client = null;
                output("websocket关闭");
                $("#msg-panel").hide();
            };

            _client.onmessage = function (evt) {
                output(evt.data);
            };

            _this.client = _client;
        };

        return this;
    }
</script>
</body>
</html>

可以把这里修改成自己项目的访问地址,方便每次访问
在这里插入图片描述
5、进行测试
启动项目,启动html页面,点击连接
在这里插入图片描述
连接成功会如图所示
打开postman发送请求
在这里插入图片描述
这里的1是发送成功之后的返回值,也可根据实际情况来修改
html页面已接受到消息
在这里插入图片描述
最后附上项目的结构图,demo项目有点粗糙
在这里插入图片描述

源码地址: https://download.csdn.net/download/weixin_45352783/12881996

2025-07-05更新,使用AI美化调试页面
效果图
在这里插入图片描述

<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width,initial-scale=1.0">
    <title>WebSocket测试工具</title>
    <!-- Bootstrap 5 CSS -->
    <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css" rel="stylesheet">
    <!-- Font Awesome 图标 -->
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0/css/all.min.css">
    <style>
        /* 原有样式保持不变 */
        :root {
            --primary-color: #4e73df;
            --success-color: #1cc88a;
            --danger-color: #e74a3b;
            --dark-color: #2e3a59;
            --light-color: #f8f9fc;
        }

        body {
            background: linear-gradient(135deg, #f5f7fa 0%, #e4edf5 100%);
            min-height: 100vh;
            padding: 20px;
            font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
        }

        .card {
            border-radius: 10px;
            box-shadow: 0 4px 20px rgba(0, 0, 0, 0.08);
            border: none;
            overflow: hidden;
        }

        .card-header {
            background: var(--primary-color);
            color: white;
            font-weight: 600;
            padding: 15px 20px;
            border-bottom: none;
        }

        .card-body {
            padding: 25px;
        }

        .btn-primary {
            background-color: var(--primary-color);
            border-color: var(--primary-color);
            transition: all 0.3s;
        }

        .btn-primary:hover {
            background-color: #3a56c4;
            border-color: #3a56c4;
            transform: translateY(-2px);
        }

        .btn-success {
            background-color: var(--success-color);
            border-color: var(--success-color);
            transition: all 0.3s;
        }

        .btn-success:hover {
            background-color: #17a673;
            border-color: #17a673;
            transform: translateY(-2px);
        }

        .btn-danger {
            background-color: var(--danger-color);
            border-color: var(--danger-color);
            transition: all 0.3s;
        }

        .btn-danger:hover {
            background-color: #d62c1a;
            border-color: #d62c1a;
            transform: translateY(-2px);
        }

        .input-group-text {
            background-color: var(--light-color);
            border: 1px solid #e3e6f0;
        }

        .form-control:focus, .form-select:focus {
            border-color: var(--primary-color);
            box-shadow: 0 0 0 0.2rem rgba(78, 115, 223, 0.25);
        }

        .log-container {
            background-color: var(--dark-color);
            color: #e9ecef;
            border-radius: 8px;
            padding: 15px;
            height: 400px;
            overflow-y: auto;
            font-family: 'Consolas', 'Monaco', monospace;
            font-size: 14px;
            line-height: 1.5;
        }

        .log-container::-webkit-scrollbar {
            width: 8px;
        }

        .log-container::-webkit-scrollbar-track {
            background: #2a3650;
            border-radius: 4px;
        }

        .log-container::-webkit-scrollbar-thumb {
            background: var(--primary-color);
            border-radius: 4px;
        }

        .log-entry {
            margin-bottom: 8px;
            padding: 5px 10px;
            border-radius: 4px;
            word-break: break-word;
        }

        .log-entry.info {
            background-color: rgba(78, 115, 223, 0.15);
            border-left: 3px solid var(--primary-color);
        }

        .log-entry.success {
            background-color: rgba(28, 200, 138, 0.15);
            border-left: 3px solid var(--success-color);
        }

        .log-entry.error {
            background-color: rgba(231, 74, 59, 0.15);
            border-left: 3px solid var(--danger-color);
        }

        .log-entry.received {
            background-color: rgba(46, 58, 89, 0.15);
            border-left: 3px solid #6c757d;
        }

        .status-indicator {
            display: inline-block;
            width: 12px;
            height: 12px;
            border-radius: 50%;
            margin-right: 8px;
        }

        .status-connected {
            background-color: var(--success-color);
            box-shadow: 0 0 8px var(--success-color);
        }

        .status-disconnected {
            background-color: var(--danger-color);
        }

        .status-connecting {
            background-color: #f6c23e;
            animation: pulse 1.5s infinite;
        }

        @keyframes pulse {
            0% { opacity: 1; }
            50% { opacity: 0.4; }
            100% { opacity: 1; }
        }

        .connection-status {
            display: flex;
            align-items: center;
            padding: 8px 15px;
            background-color: rgba(46, 58, 89, 0.05);
            border-radius: 6px;
            margin-top: 15px;
            font-size: 14px;
        }

        .section-title {
            font-size: 16px;
            font-weight: 600;
            color: var(--dark-color);
            margin-bottom: 15px;
            display: flex;
            align-items: center;
        }

        .section-title i {
            margin-right: 10px;
            color: var(--primary-color);
        }

        .action-buttons {
            display: flex;
            gap: 10px;
            margin-top: 15px;
        }

        .footer {
            text-align: center;
            margin-top: 20px;
            color: #6e707e;
            font-size: 13px;
        }

        @media (max-width: 768px) {
            .card-body {
                padding: 15px;
            }

            .action-buttons {
                flex-direction: column;
            }

            .log-container {
                height: 300px;
            }
        }
    </style>
</head>
<body>
<div class="container">
    <div class="row justify-content-center">
        <div class="col-lg-8">
            <div class="card">
                <div class="card-header d-flex justify-content-between align-items-center">
                    <div>
                        <i class="fas fa-plug me-2"></i>WebSocket测试工具
                    </div>
                    <div class="connection-status">
                        <span class="status-indicator status-disconnected"></span>
                        <span id="status-text">未连接</span>
                    </div>
                </div>

                <div class="card-body">
                    <div class="section-title">
                        <i class="fas fa-link"></i>连接设置
                    </div>

                    <div class="mb-4">
                        <label class="form-label">WebSocket地址</label>
                        <div class="input-group">
                            <span class="input-group-text"><i class="fas fa-globe"></i></span>
                            <input type="text" id="address" class="form-control" placeholder="ws://地址" value="ws://127.0.0.1:8100/webSocket/123456">
                            <button class="btn btn-primary" type="button" id="connect">
                                <i class="fas fa-plug me-1"></i>连接
                            </button>
                        </div>
                    </div>

                    <div id="msg-panel" style="display: none;">
                        <div class="section-title">
                            <i class="fas fa-paper-plane"></i>发送消息
                        </div>

                        <div class="mb-3">
                            <label class="form-label">来源(From)</label>
                            <div class="input-group">
                                <span class="input-group-text"><i class="fas fa-user"></i></span>
                                <input type="text" id="from" class="form-control" placeholder="来源" readonly>
                            </div>
                        </div>

                        <div class="mb-3">
                            <label class="form-label">接收方(To)</label>
                            <div class="input-group">
                                <span class="input-group-text"><i class="fas fa-user-friends"></i></span>
                                <input type="text" id="to" class="form-control" placeholder="输入接收方ID">
                            </div>
                        </div>

                        <div class="mb-3">
                            <label class="form-label">消息内容(Text)</label>
                            <div class="input-group">
                                <span class="input-group-text"><i class="fas fa-comment"></i></span>
                                <input type="text" id="msg" class="form-control" placeholder="输入要发送的消息">
                            </div>
                        </div>

                        <div class="d-grid">
                            <button class="btn btn-success" type="button" id="send">
                                <i class="fas fa-paper-plane me-1"></i>发送消息
                            </button>
                        </div>
                    </div>

                    <div class="section-title">
                        <i class="fas fa-clipboard-list"></i>通信日志
                    </div>

                    <div class="log-container" id="log"></div>

                    <div class="action-buttons">
                        <button class="btn btn-danger" id="disconnect" disabled>
                            <i class="fas fa-power-off me-1"></i>断开连接
                        </button>
                        <button class="btn btn-secondary" id="clear-log">
                            <i class="fas fa-trash-alt me-1"></i>清除日志
                        </button>
                    </div>
                </div>
            </div>

            <div class="footer">
                <p>WebSocket测试工具 &copy; 2025 | 实时通信调试助手</p>
            </div>
        </div>
    </div>
</div>

<!-- jQuery -->
<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
<!-- Bootstrap 5 JS Bundle -->
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/js/bootstrap.bundle.min.js"></script>

<script>
    $(function () {
        var _socket;
        var isConnected = false;
        var fromId = ''; // 存储从地址中提取的from ID

        // 更新连接状态显示
        function updateStatus(status, text) {
            var indicator = $('.status-indicator');
            var statusText = $('#status-text');

            indicator.removeClass('status-connected status-disconnected status-connecting');

            switch(status) {
                case 'connected':
                    indicator.addClass('status-connected');
                    statusText.text('已连接');
                    break;
                case 'disconnected':
                    indicator.addClass('status-disconnected');
                    statusText.text('未连接');
                    break;
                case 'connecting':
                    indicator.addClass('status-connecting');
                    statusText.text('连接中...');
                    break;
                case 'error':
                    indicator.addClass('status-disconnected');
                    statusText.text(text || '连接错误');
                    break;
            }

            // 更新按钮状态
            $('#connect').prop('disabled', status === 'connecting' || status === 'connected');
            $('#disconnect').prop('disabled', status !== 'connected');
            $('#send').prop('disabled', status !== 'connected');
        }

        // 输出日志
        function output(message, type = 'info') {
            var timestamp = new Date().toLocaleTimeString();
            var logEntry = $('<div>').addClass('log-entry ' + type)
                .html(`<span class="text-muted">[${timestamp}]</span> ${message}`);

            $('#log').append(logEntry);
            // 自动滚动到底部
            $('#log').scrollTop($('#log')[0].scrollHeight);
        }

        // 连接按钮点击事件
        $("#connect").click(function () {
            var address = $("#address").val().trim();
            if (!address) {
                output('请输入WebSocket地址', 'error');
                return;
            }

            // 从地址中提取from ID
            var parts = address.split('/');
            fromId = parts[parts.length - 1]; // 获取最后一部分作为from ID
            if (!fromId) {
                output('无法从地址中提取来源ID,请检查地址格式', 'error');
                return;
            }

            // 设置来源输入框的值
            $("#from").val(fromId);

            updateStatus('connecting');
            output(`正在连接: ${address}`, 'info');
            output(`来源ID: ${fromId}`, 'info');

            try {
                _socket = new _websocket(address);
                _socket.init();
            } catch (e) {
                updateStatus('error', '连接失败');
                output('连接失败: ' + e.message, 'error');
            }
        });

        // 断开连接按钮
        $("#disconnect").click(function () {
            if (_socket && _socket.client) {
                _socket.client.close();
                output('已主动断开连接', 'info');
            }
        });

        // 清除日志按钮
        $("#clear-log").click(function () {
            $("#log").empty();
            output('日志已清除', 'info');
        });

        // 发送按钮点击事件
        $("#send").click(function () {
            if (!_socket || !_socket.client || _socket.client.readyState !== WebSocket.OPEN) {
                output('未连接到WebSocket服务器', 'error');
                return;
            }

            var to = $("#to").val().trim();
            var text = $("#msg").val().trim();

            if (!to) {
                output('请输入接收方ID', 'error');
                return;
            }

            if (!text) {
                output('请输入要发送的消息', 'error');
                return;
            }

            // 构建新的JSON消息
            var message = {
                from: fromId,
                to: to,
                text: text
            };

            try {
                var jsonMessage = JSON.stringify(message);
                output("发送消息: " + jsonMessage, 'success');
                _socket.client.send(jsonMessage);
                $("#msg").val(''); // 清空消息内容输入框
            } catch (e) {
                output('发送失败: ' + e.message, 'error');
            }
        });

        // 按Enter键发送消息(在消息内容输入框)
        $("#msg").keypress(function (e) {
            if (e.which == 13) { // Enter键
                $("#send").click();
            }
        });

        function _websocket(address) {
            this.address = address;
            this.client;

            this.init = function () {
                if (!window.WebSocket) {
                    output('您的浏览器不支持WebSocket', 'error');
                    updateStatus('error', '浏览器不支持');
                    return;
                }

                var _this = this;
                var _client = new window.WebSocket(_this.address);

                _client.onopen = function () {
                    output("WebSocket连接已建立", 'success');
                    updateStatus('connected');
                    $("#msg-panel").show();
                };

                _client.onclose = function (event) {
                    _this.client = null;
                    isConnected = false;

                    if (event.wasClean) {
                        output("WebSocket连接已关闭", 'info');
                    } else {
                        output("WebSocket连接异常断开", 'error');
                    }

                    updateStatus('disconnected');
                    $("#msg-panel").hide();
                };

                _client.onerror = function (error) {
                    output("WebSocket错误: " + error, 'error');
                    updateStatus('error');
                };

                _client.onmessage = function (evt) {
                    try {
                        // 尝试解析JSON消息
                        var data = JSON.parse(evt.data);
                        output("收到消息: " + JSON.stringify(data), 'received');
                    } catch (e) {
                        // 如果不是JSON,直接显示原始数据
                        output("收到消息: " + evt.data, 'received');
                    }
                };

                _this.client = _client;
            };

            return this;
        }

        // 初始日志
        output('WebSocket测试工具已就绪', 'info');
        output('请输入WebSocket地址并点击连接按钮', 'info');
    });
</script>
</body>
</html>
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值