springboot+websocket客服聊天

news2024/11/29 10:36:46

续:spring boot 完整后端接口案例_cc&的博客-CSDN博客

后台代码

1.在pom.xml中添加spring-boot-starter-websocket

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

 2. 添加配置,先在src\main\resources\application.yml中添加:

server:
  max-http-header-size: 8192

 如果不加的话可能导致无法进行访问。 

3.新建一个配置类,主要一个Bean,用来启动服务是也启动WebSocket服务

 

package com.cc.springServer.config;

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

@Configuration
public class webSocketConfig {
    //WebSocket
    @Bean
    public ServerEndpointExporter serverEndpointExporter() {
        return new ServerEndpointExporter();
    }

}

 注意:这个类必须有@Configuration注解

4.新建一个model来封装进行对话的对象

 

package com.cc.springServer.entity;

import javax.websocket.Session;

public class SocketUserInfo {
    //用户sessionId
    private String sessionId;

    //用户session
    private Session session;

    //目标用户sessionid
    private String targetSessionId;

    //用户角色
    private String userRole;

    public String getUserRole() {
        return userRole;
    }

    public void setUserRole(String userRole) {
        this.userRole = userRole;
    }

    public String getSessionId() {
        return sessionId;
    }

    public void setSessionId(String sessionId) {
        this.sessionId = sessionId;
    }

    public Session getSession() {
        return session;
    }

    public void setSession(Session session) {
        this.session = session;
    }

    public String getTargetSessionId() {
        return targetSessionId;
    }

    public void setTargetSessionId(String targetSessionId) {
        this.targetSessionId = targetSessionId;
    }
}

 5.新建一个Controller类来管理Socket会话,它主要完成如下场景业务:

1.用户连接上线:如果是一个客服上线,就保存一个客服信息,同时去查找有没有再排队中的用户,如果有就给他们俩建立会话关系;如果是一个用户上线,先建立保存用户信息,再去查找有没有空闲客服,如果有就建立会话关系,如果没有就告诉他系统繁忙,让他进入等待状态。
2.用户下线:如果是客户下线,就删除客服信息,为了方便,我直接让用户刷新页面重新匹配客服,其实这样做不是很好;如果是用户下线,就删除用户信息,让空闲下来的客服和排队中的用户建立会话关系。
3.发送消息:如果是用户发的消息,就将消息推送给相应客服;如果是客服发的消息,就推送给相应用户。

package com.cc.springServer.controller;

import com.alibaba.fastjson.JSON;
import com.cc.springServer.entity.SocketUserInfo;
import org.springframework.stereotype.Component;

import javax.websocket.*;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

//参数role判断用户角色0是客服,1是用户
@ServerEndpoint(value = "/websocket/{role}")
@Component
public class webSocketController {

    //用本地线程保存session
    private static ThreadLocal<Session> sessions = new ThreadLocal<Session>();
    //保存所有连接上的用户的session
    private static Map<String, SocketUserInfo> userSessionMap = new ConcurrentHashMap<>();
    //保存在线客服的session
    private static Map<String, SocketUserInfo> serverSessionMap = new ConcurrentHashMap<>();

    //连接
    @OnOpen
    public void onOpen(Session session, @PathParam(value="role") Integer role) {

        //默认返回错误状态
        Map<String, String> resultMap = new HashMap<>();
        resultMap.put("state", "error");

        //保证各个线程里的变量相对独立于其他线程内的变量
        sessions.set(session);

        //客服上线
        if (role.equals(0)) {

            //创建一个在线客服信息
            SocketUserInfo serverInfo = new SocketUserInfo();
            serverInfo.setSessionId(session.getId());
            serverInfo.setSession(session);
            serverInfo.setUserRole("客服");

            //告诉客服连接成功
            resultMap.put("state", "success");

            //去查询是否有排队中的用户
            //如果存在排队的用户,就将用户和客服绑定
            if (findLineUser() != null){
                SocketUserInfo userInfo = userSessionMap.get(findLineUser());
                //将用户绑定到客服
                serverInfo.setTargetSessionId(userInfo.getSessionId());
                //将客服绑定到用户
                userInfo.setTargetSessionId(serverInfo.getSessionId());
                userSessionMap.put(userInfo.getSessionId(), userInfo);
                System.out.println("客户"+ serverInfo.getSessionId() + "正在为用户" + userInfo.getSessionId()+"服务");

                Map<String, String> result = new HashMap<>();
                //客服显示用户信息
                result.put("msg", "正在为用户"+userInfo.getSessionId()+"服务!");
                sendMsg(serverInfo.getSession(), JSON.toJSONString(result));
                //告诉用户有客服为他服务
                result.put("msg", "客服"+serverInfo.getSessionId()+"正在为您服务!");
                sendMsg(userInfo.getSession(), JSON.toJSONString(result));
            }

            //将在线客服信息保存到map中
            serverSessionMap.put(session.getId(), serverInfo);
            System.out.println("客服:" + serverInfo.getSessionId() + "连接上服务器,当前在线客服共计:" + serverSessionMap.size());
        }
        if (role.equals(1)) {

            //创建一个在线用户信息
            SocketUserInfo userInfo = new SocketUserInfo();
            userInfo.setSessionId(session.getId());
            userInfo.setSession(session);
            userInfo.setUserRole("用户");

            //告诉用户连接成功
            resultMap.put("state", "success");

            //去查询是否有在线的客服
            //有空闲客服就将用户和客服绑定
            if (findFreeServer() != null){
                SocketUserInfo serverInfo = serverSessionMap.get(findFreeServer());
                //将用户绑定到客服
                serverInfo.setTargetSessionId(userInfo.getSessionId());
                serverSessionMap.put(serverInfo.getSessionId(), serverInfo);
                //将客服绑定到用户
                userInfo.setTargetSessionId(serverInfo.getSessionId());
                System.out.println("客户"+ serverInfo.getSessionId() + "正在为" + userInfo.getSessionId()+"服务");

                Map<String, String> result = new HashMap<>();
                //客服显示用户信息
                result.put("msg", "正在为用户"+userInfo.getSessionId()+"服务!");
                sendMsg(serverInfo.getSession(), JSON.toJSONString(result));
                result.put("msg", "客服"+serverInfo.getSessionId()+"正在为您服务!");
                sendMsg(userInfo.getSession(), JSON.toJSONString(result));
            } else {
                //告诉用户系统繁忙
                resultMap.put("msg", "系统繁忙!");
            }

            //将在线用户信息保存到map中
            userSessionMap.put(session.getId(), userInfo);
            System.out.println("用户编号:" + userInfo.getSessionId() + "连接上服务器,当前在线用户共计:" + userSessionMap.size());
        }
        //返回连接信息
        String result = JSON.toJSONString(resultMap);
        System.out.println(result);
        sendMsg(session, result);
    }

    //关闭连接
    @OnClose
    public void onClose(Session session) {
        SocketUserInfo serverInfo = serverSessionMap.get(session.getId());
        //客服下线
        if (serverInfo != null) {
            //将客户从map中移除
            serverSessionMap.remove(session.getId());

            //查看是否有服务服务对象
            if (null != serverInfo.getTargetSessionId()){
                //给用户说系统错误
                Map<String, String> result = new HashMap<>();
                result.put("msg", "系统错误,请刷新重试!");
                sendMsg(userSessionMap.get(serverInfo.getTargetSessionId()).getSession(), JSON.toJSONString(result));
            }
            System.out.println("客服编号:" + serverInfo.getSessionId() + "退出了连接,当前在线客服共计:" + serverSessionMap.size());
        } else {//用户下线
            //将用户从map中移除
            userSessionMap.remove(session.getId());

            //从客服中解绑
            for (SocketUserInfo serverSocketInfo: serverSessionMap.values()) {
                //查找绑定的客服,即客服绑定的用户不为空,并且绑定的用户id和现在下线的用户id一样
                if (serverSocketInfo.getTargetSessionId() != null && serverSocketInfo.getTargetSessionId().equals(session.getId())){
                    //解绑
                    serverSocketInfo.setTargetSessionId(null);
                    serverSessionMap.put(serverSocketInfo.getSessionId(), serverSocketInfo);
                    System.out.println("用户编号:" + session.getId() + "断开了与客服" + serverSocketInfo.getSessionId() + "的连接");

                    //客服解绑以后,可能还会有在线排队的用户,就让这个客服去
                    String lineUser = findLineUser();
                    if (lineUser != null){
                        //将用户绑定到客服
                        serverSocketInfo.setTargetSessionId(lineUser);
                        serverSessionMap.put(serverSocketInfo.getSessionId(), serverSocketInfo);
                        //将客服绑定到用户
                        userSessionMap.get(lineUser).setTargetSessionId(serverSocketInfo.getSessionId());
                        System.out.println("客户"+ serverSocketInfo.getSessionId() + "正在为" + lineUser+"服务");

                        Map<String, String> result = new HashMap<>();
                        //客服显示用户信息
                        result.put("msg", "正在为用户"+lineUser+"服务!");
                        sendMsg(serverSocketInfo.getSession(), JSON.toJSONString(result));
                        //用户显示客户信息
                        result.put("msg", "客服"+serverSocketInfo.getSessionId()+"正在为您服务!");
                        sendMsg(userSessionMap.get(lineUser).getSession(), JSON.toJSONString(result));
                    }
                }
            }
            System.out.println("用户编号:" + session.getId() + "退出了连接,当前在线用户共计:" + userSessionMap.size());
        }
    }

    //用户和客户端互相传递消息
    @OnMessage
    public void onMessage(String message, Session session) {
        //消息
        Map<String, String> result = new HashMap<>();

        SocketUserInfo serverInfo = serverSessionMap.get(session.getId());
        //客服消息
        if (serverInfo != null) {
            System.out.println("客服"+ session.getId()+"发送消息:\""+ message +"\"给用户"+serverSessionMap.get(session.getId()).getTargetSessionId());
            result.put("msg", "客服"+session.getId()+":"+message);
            //将消息发送给用户
            //要判断是否绑定到有用户如果有就将消息传递到用户
            if (null != serverSessionMap.get(session.getId()).getTargetSessionId()){
                sendMsg(userSessionMap.get(serverSessionMap.get(session.getId()).getTargetSessionId()).getSession(), JSON.toJSONString(result));
            } else {//如果没有就将消息给自己,嘻嘻嘻
                sendMsg(session, JSON.toJSONString(result));
            }

        } else {//用户消息
            System.out.println("用户"+ session.getId()+"发送消息:\""+ message +"\"给客户"+userSessionMap.get(session.getId()).getTargetSessionId());
            result.put("msg", "用户"+session.getId()+":"+message);
            //将消息发送给客服
            //判断是否绑定了客服,如果有就发送消息
            if (null != userSessionMap.get(session.getId()).getTargetSessionId()){
                sendMsg(serverSessionMap.get(userSessionMap.get(session.getId()).getTargetSessionId()).getSession(), JSON.toJSONString(result));
            } else{//同上
                sendMsg(session,JSON.toJSONString(result));
            }
        }
    }

    //异常
    @OnError
    public void onError(Session session, Throwable throwable) {
        System.out.println("发生异常!");
        throwable.printStackTrace();
    }



    //统一的发送消息方法
    private synchronized void sendMsg(Session session, String msg) {
        try {
            session.getBasicRemote().sendText(msg);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    //查询排队用户
    private synchronized String findLineUser(){
        //判断是否有用户
        if (userSessionMap.size() > 0){
            //遍历所有用户,查找一个排队的用户
            for (SocketUserInfo UserInfo: userSessionMap.values()) {
                if (null == UserInfo.getTargetSessionId()){
                    return UserInfo.getSessionId();
                }
            }
        }
        return null;
    }

    //查询在线空闲客服
    private  synchronized String findFreeServer(){
        //判断是否有客服
        if (serverSessionMap.size() > 0){
            //遍历所有客服,查找一个空闲的客服
            for (SocketUserInfo serverInfo: serverSessionMap.values()) {
                if (null == serverInfo.getTargetSessionId()){
                    return serverInfo.getSessionId();
                }
            }
        }
        return null;
    }
}

后台代码到这来就完成了。


前端代码

1) 客户端


<!DOCTYPE html>
<html>
<head>
	<meta charset="utf-8">
	<title>辕门-在线咨询</title>
    <script src="https://code.jquery.com/jquery-3.1.1.min.js"></script>
</head>
<body>
	<p id="message"></p>
	<form id="clientChat">
		<input type="text" style="display: none;" id="userName"  />
		<input type="text" style="display: none;" id="targetUserName" />
		<input type="text" id="sendMsg"></input>
		<button type="button" onclick="send()">发送</button>
	</form>
</body>
<script>
var websocket = null;

var userId = null;

//判断当前浏览器是否支持WebSocket
if('WebSocket' in window){
    websocket = new WebSocket("ws://127.0.0.1:9999/websocket/1");
} else {
    alert("Don't support websocket!")
}

//连接发生错误的回调方法
websocket.onerror = function(){
    alert("Connect error!");
};

//连接成功建立的回调方法
websocket.onopen = function(event){
    setMessageInnerHTML("连接已建立!");
}

//接收到消息的回调方法
websocket.onmessage = function(event){
	var result = event.data
	var ob = JSON.parse(result)
	//判断用户状态
	if(ob.state != undefined && ob.state != "success"){
		setMessageInnerHTML("非法连接!");
		websocket.close();
	}
	
	//判断是否有消息
	if(ob.msg != undefined){
		setMessageInnerHTML(ob.msg);
	}
}

//连接关闭的回调方法
websocket.onclose = function(){
    setMessageInnerHTML("close");
}

//监听窗口关闭事件,当窗口关闭时,主动去关闭websocket连接,防止连接还没断开就关闭窗口,server端会抛异常。
window.onbeforeunload = function(){
    websocket.close();
}

//将消息显示在网页上
function setMessageInnerHTML(innerHTML){
    document.getElementById('message').innerHTML += innerHTML + '<br/>';
}

//关闭连接
function closeWebSocket(){
    websocket.close();
}

//发送消息
function send(){
	var sendMsg = $("#sendMsg").val();
	setMessageInnerHTML("我 :" + sendMsg)
    websocket.send(sendMsg);
    $("#sendMsg").val("");
}
</script>
</html>

 

2)服务端

<!DOCTYPE html>
<html>
<head>
	<meta charset="utf-8">
	<title>辕门-IM</title>
	<script src="https://code.jquery.com/jquery-3.1.1.min.js"></script>
</head>
<body>
	<p id="message"></p>
	<form id="clientChat">
		<input type="text" style="display: none;" id="userName"  />
		<input type="text" style="display: none;" id="targetUserName" />
		<input type="text" id="sendMsg"></input>
		<button type="button" onclick="send()">发送</button>
	</form>
</body>
<script>
var websocket = null;

var userId = null;

//判断当前浏览器是否支持WebSocket
if('WebSocket' in window){
    websocket = new WebSocket("ws://127.0.0.1:9999/websocket/0");
} else {
    alert("Don't support websocket!")
}

//连接发生错误的回调方法
websocket.onerror = function(){
    alert("Connect error!");
};

//连接成功建立的回调方法
websocket.onopen = function(event){
    setMessageInnerHTML("连接已建立!");
}

//接收到消息的回调方法
websocket.onmessage = function(event){
	var result = event.data
	var ob = JSON.parse(result)
	//判断用户状态
	if(ob.state != undefined && ob.state != "success"){
		setMessageInnerHTML("非法连接!");
		websocket.close();
	}
	
	//判断是否有消息
	if(ob.msg != undefined){
		setMessageInnerHTML(ob.msg);
	}
}

//连接关闭的回调方法
websocket.onclose = function(){
    setMessageInnerHTML("close");
}

//监听窗口关闭事件,当窗口关闭时,主动去关闭websocket连接,防止连接还没断开就关闭窗口,server端会抛异常。
window.onbeforeunload = function(){
    websocket.close();
}

//将消息显示在网页上
function setMessageInnerHTML(innerHTML){
    document.getElementById('message').innerHTML += innerHTML + '<br/>';
}

//关闭连接
function closeWebSocket(){
    websocket.close();
}

//发送消息
function send(){
	var sendMsg = $("#sendMsg").val();
	setMessageInnerHTML("我 :" + sendMsg)
    websocket.send(sendMsg);
    $("#sendMsg").val("");
}
</script>
</html>

 

 

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/626328.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

浅谈数明深力科隔离驱动器SLMi8235BD 车载充电器(OBC)方案

数明深力科SLMi823x系列SLMi8235BD隔离驱动技术优势&#xff1a;具有高性能、高性价比、高可靠性的产品特性&#xff0c;应用覆盖UPS、充电桩、服务器电源、通信电源、新能源汽车动力总成系统的车载 OBC 领域。通过CQC认证的。 车载充电器&#xff08;OBC&#xff09;是电动汽…

在线电子书创建:MkDocs + Github + ReadTheDocs

MkDocs是一个静态站点生成器&#xff0c;可用于构建项目文档。文档文件使用Markdown语法编写&#xff0c;本文记录如何使用MkDocs生成项目文档&#xff0c;并部署到Read the Docs上。 目录 安装mkdocs搭建文档项目创建项目启动项目编写文档Markdown语法站内链接图片 文档结构 配…

聚观早报 | 苹果收购AR头显初创公司Mira;抖音将尝试自营电商

今日要闻&#xff1a;苹果收购AR头显初创公司Mira&#xff1b;抖音将尝试自营电商&#xff1b;特斯拉股价实现九连涨&#xff1b;《黑镜》主创曾试用ChatGPT写剧本&#xff1b;携程集团发布2023Q1财报 苹果收购AR头显初创公司Mira 6 月 7 日消息&#xff0c;据 The Verge 报道…

2023免费电脑录视频软件Camtasia

Camtasia 2023是专业又好用的录屏软件&#xff0c;既可以用来录视频、ppt、直播课程等&#xff0c;也能够处理视频&#xff0c;添加各种效果&#xff0c;制作出更加满意的视频作品。Camtasia凭借愈发强大的功能收获了一大批忠实用户和如潮好评&#xff0c;已成为屏幕录制的必备…

6.16 @ 广州丨相约泛娱乐出海论坛,探寻市场突围的核心要义

1979 年&#xff0c;“出国办企业”第一次被有关部门提出&#xff0c;开启了中国企业对外投资的积极探索与尝试。经过 40 多年的耕耘&#xff0c;不少出海品牌已经站稳了脚跟&#xff0c;品牌影响力与日俱增&#xff0c;甚至在部分核心细分赛道上&#xff0c;中国企业凸显出了明…

TiDB 7.1 LTS 发版:为关键业务提供业务稳定性和多租户场景支持

近日&#xff0c;企业级开源分布式数据库厂商 PingCAP 正式发布 TiDB 7.1 版本&#xff0c;这也是 2023 年度发布的首个 LTS&#xff08;Long Term Support&#xff09; 版本&#xff0c;汇集了来自 20 个真实场景带来的功能增强&#xff0c;累计优化和修复 140 功能&#xff0…

easyui5

1.1准备工作. 今天我们的主要任务是完成分页功能&#xff1b; 导入数据表 t_book&#xff0c;数据文件在课件&#xff1b; 介绍拼音字段&#xff0c;拼音工具类&#xff0c;拼音jar包&#xff1b; 模糊查询还要实现拼音模糊查询&#xff0c;如&#xff1a;百度输入拼音也可以…

飞凌嵌入式AM62x系列核心板配置新增,单核/双核/四核随心选

新时代&#xff0c;工业、电力、交通、医疗等众多行业纷纷从信息化向着智能化转型&#xff0c;这就对主控的综合性能提出了全新的要求。在这样的背景下 TI AM62x Sitara™处理器应运而生&#xff0c;为AIoT时代带来了新的突破可能。作为TI官方合作伙伴&#xff0c;飞凌嵌入式于…

RabbitMQ - 发布确认高级

RabbitMQ - 发布确认高级 发布确认 springboot 版本回退消息备份交换机 在生产环境中由于一些不明原因&#xff0c;导致 RabbitMQ 重启&#xff0c;在 RabbitMQ 重启期间生产者消息投递失败&#xff0c; 导致消息丢失&#xff0c;需要手动处理和恢复。于是&#xff0c;我们开始…

Steemit 会颠覆 Quora/知乎 甚至 Facebook 吗?

Steemit是基于区块链技术的社交媒体平台&#xff0c;其独特的激励机制吸引了众多用户。然而&#xff0c;是否能够真正颠覆Quora、知乎甚至Facebook这些已经成为社交巨头的平台&#xff0c;仍然存在着许多未知因素。本文将探讨Steemit的优势和挑战&#xff0c;以及其在社交领域中…

数据分析第15课pandas和matplotlib实战

01实战:911 导入: 读取数据: 转换类型:

java html导出添加空行和空格

情景&#xff1a; 要求导出签批单&#xff1a; 格式如下&#xff0c; 要获取“主办处室负责人”和“相关处室会签”环节的处理意见、处理人员和处理日期进行替换&#xff0c;导出word文档。 处理&#xff1a; 主要是如何拼接内容&#xff1f; 方法一&#xff1a; 导出word&…

爬虫如何发送 HTTP 请求

爬虫可以使用 Python 中的 requests 库来发送 HTTP 请求。requests 库提供了简单易用的 API&#xff0c;可以方便地发送 GET、POST 等请求&#xff0c;并且支持设置请求头、请求参数、代理等功能。 以下是一个使用 requests 库发送 GET 请求的示例代码&#xff1a; import re…

国产触控笔哪个牌子好?第三方电容笔推荐

对于那些把iPad当做学习工具的人来说&#xff0c;这已经成为了他们生活中不可缺少的一部分。但没有人买得起苹果原装电容笔&#xff0c;因为苹果电容笔的售价太贵了。因此&#xff0c;最好还是用一支普通的电容笔。我是个一个苹果粉&#xff0c;同时也是个数字发烧友&#xff0…

十年之约 记账表格(会员专享)

* * * 原创&#xff1a;刘教链 * * * 6号&#xff0c;教链发起了十年之约加密投资实证计划。 很多读者、会员纷纷同行。 有朋友问及教链所用记账表格。可根据文章中的介绍自制。为方便会员&#xff0c;教链已将该表格上传至刘教链的加密投资星球&#xff0c;供下载。 另外&…

喜报 | 小米智能语音通讯技术获“深圳人工智能行业应用奖”

日前&#xff0c;2022年度第二届“深圳人工智能奖”正式揭晓。 “小米智能语音技术在手机实时通信中的应用”项目&#xff0c;凭借丰硕的创新成果、广泛的应用场景&#xff0c;获得“深圳人工智能行业应用奖”&#xff01; “深圳人工智能行业应用奖”旨在表彰人工智能行业应用…

springcloud使用nacos搭建注册中心

nacos安装这里就不细说了&#xff0c;(Nacos下载以及搭建环境_你非柠檬为何心酸142的博客-CSDN博客) 大家也可以去网上安装好&#xff0c;这里主要讲搭建 &#xff0c;我们需要手动启动nacos, 输入(.\startup.cmd -m standalone),出现一下图标就代表ok 首先是父工程所需要的依…

Java009——Java数据类型变量的简单认识

一、Java数据类型 围绕以下3点学习&#xff1a; 1、什么是Java数据类型&#xff1f; 2、Java数据类型的作用&#xff1f; 3、Java有哪些数据类型&#xff1f; 4、熟悉Java8大基本数据类型 1.1、什么是Java数据类型&#xff1f; 当我们写Java代码时&#xff0c;需要把数据保存…

react设计模式,jsx

1.修改配置项&#xff1a; eject&#xff1a;暴露配置项&#xff01;&#xff01;&#xff01;一旦暴露了就无法还原回去 会报错。这个错误:我们刚才把代码改了&#xff0c;在暴露之前&#xff0c;先让我们把代码提交到git历史区保留下来—防止暴露后的代码覆盖了我们该的代码 …

02_MySQL的索引结构

1. BTree索引 B-Tree即B树&#xff0c;Balance Tree&#xff0c;平衡树,它的高度远小于平衡二叉树的高度。2-3树是最简单的B树结构。B树的阶&#xff1a;节点的最多子节点个数。比如2-3树的阶是3&#xff0c;2-3-4树的阶是4。 1.1 初始化介绍 一颗b树&#xff0c;浅蓝色的块我们…