当前位置: 首页 > news >正文

树形结构的三级分类如何实现?

概述:

本三级联动分类服务端使用的是: Springboot + MyBatis-plus,前端使用的是:Vue+ElementUI,树形控件使用的是el-tree。本三级联动分类可以把任一子项拖拽到其它目录,可以添加、编辑、删除分类。

效果图:

在这里插入图片描述

实现流程:

一、树形数据展示实现

1、创建表

  • cat_id使用bigint类型目的是为了使用雪花算法,加快查询的速度;
  • parent_cid父ID,用于子节点指向父亲节点,同理我们可根据当前节点等于子节点点父ID,然后递归,找到所属的所有子节点
  • cat_level层级,用于识别当前节点是一级、二级还是三级节点
  • show_status是否显示,控制是否显示,使用了逻辑删除功能
  • product_unit计量单位,使用什么单位统计当前分类下产品的数量
  • product_count产品数量,在添加商品时进行统计更新
  • sort排序,进行分类排序
  • icon图表,类别的图片,使用iconfont
CREATE TABLE `kmall_product`.`pro_category`  (`cat_id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '分类id',`name` char(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '分类名称',`parent_cid` bigint(20) NULL DEFAULT NULL COMMENT '父分类id',`cat_level` int(4) NULL DEFAULT NULL COMMENT '层级',`show_status` tinyint(2) NULL DEFAULT NULL COMMENT '是否显示[0-不显示,1显示]',`sort` int(4) NULL DEFAULT NULL COMMENT '排序',`icon` char(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '图标地址',`product_unit` char(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '计量单位',`product_count` int(11) NULL DEFAULT NULL COMMENT '商品数量',PRIMARY KEY (`cat_id`) USING BTREE,INDEX `parent_cid`(`parent_cid`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 1433 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '商品三级分类' ROW_FORMAT = Dynamic;

2、生成实体类

把上面点表内能映射为实体类,便于java中操作

@Data
@TableName("pro_category")
public class CategoryEntity implements Serializable {private static final long serialVersionUID = 1L;/*** 分类id*/@TableIdprivate Long catId;/*** 分类名称*/private String name;/*** 父分类id*/private Long parentCid;/*** 层级*/private Integer catLevel;/*** 是否显示[0-不显示,1显示]*/@TableLogic(value = "1", delval = "0")private Integer showStatus;/*** 排序*/private Integer sort;/*** 图标地址*/private String icon;/*** 计量单位*/private String productUnit;/*** 商品数量*/private Integer productCount;@JsonInclude(value = JsonInclude.Include.NON_EMPTY)@TableField(exist = false)private List<CategoryEntity> children;}

说明:下面的children是用来保存子节点数据,是暂存在内存中,所以要加上@TableField(exist = false)注解

    @JsonInclude(value = JsonInclude.Include.NON_EMPTY)@TableField(exist = false)private List<CategoryEntity> children;

3、获取树形数据

创建CategoryController控制层,添加请求方法,使用的是get请求,查询到结果后以data为名称返回给前端

/*** 查出所有分类以及子分类,以树形结构组装起来*/@RequestMapping("/list/tree")public R listWithTree(){List<CategoryEntity> entities = categoryService.listWithTree();return R.ok().put("data", entities);}

4、查询封装树形数据

创建CategoryServiceImpl实现层,实现listWithTree方法

  • 首先查出所有分类
  • 选出一级分类
  • 递归获取一级分类的所有子节点,设置到children属性中
@Overridepublic List<CategoryEntity> listWithTree() {//查出所有分类List<CategoryEntity> entities = baseMapper.selectList(null);//组装成父子树形结构//1级分类List<CategoryEntity> menus = entities.stream().filter(entity -> entity.getParentCid() == 0).map(entity -> {entity.setChildren(getChildren(entity, entities));return entity;}).sorted((menu1, menu2) ->(menu1.getSort() == null ? 0 : menu1.getSort()) -(menu2.getSort() == null ? 0 : menu2.getSort())).collect(Collectors.toList());return menus;}
  /*** 递归查找所有菜单的子菜单*/private List<CategoryEntity> getChildren(CategoryEntity root, List<CategoryEntity> all) {List<CategoryEntity> children = all.stream().filter(entity -> entity.getParentCid().equals(root.getCatId())).map(entity -> {entity.setChildren(getChildren(entity, all)); //递归设置return entity;}).sorted((menu1, menu2) ->(menu1.getSort() == null ? 0 : menu1.getSort()) -(menu2.getSort() == null ? 0 : menu2.getSort())).collect(Collectors.toList());return children;}

5、前端展现实现

5.1、树形控件el-tree设置
  • :data=“menus”:绑定数据menus
  • :props=“defaultProps” :设置默认属性defaultProps,便于与后端数据转换
  • expand-on-click-node:设置为false,表示需要单击才展开
  • show-checkbox:显示checkbox复选框
  • node-key=“catId” :绑定主键
  • :default-expanded-keys=“expandedKey” :设置默认展开分类
  • :draggable=“draggable” :是否能拖拽节点数据
  • :allow-drop=“allowDrop”:拖拽时判定目标节点能否被放置。type 参数有三种情况:‘prev’、‘inner’ 和 ‘next’,分别表示放置在目标节点前、插入至目标节点和放置在目标节点后
  • @node-drop=“handleDrop”:拖拽成功完成时触发的事件
<el-tree :data="menus" :props="defaultProps" :expand-on-click-node="false" show-checkbox node-key="catId":default-expanded-keys="expandedKey" :draggable="draggable" :allow-drop="allowDrop" @node-drop="handleDrop"ref="menuTree">      </el-tree>
5.2、树形控件el-tree数据初始化
data() {return {pCid: [],draggable: false,updateNodes: [],maxLevel: 0,title: "",dialogType: "", //edit,addcategory: {name: "",parentCid: 0,catLevel: 0,showStatus: 1,sort: 0,productUnit: "",icon: "",catId: null},dialogVisible: false,menus: [],expandedKey: [],defaultProps: {children: "children",label: "name"}};},
5.3、加载menus数据,绑定到树形控件

说明:/product/category/list/tree此路径对应的是controller里查找树形数据的方法

getMenus() {this.$http({url: this.$http.adornUrl("/product/category/list/tree"),method: "get"}).then(({data}) => {console.log("成功获取到菜单数据...", data.data);this.menus = data.data;});},

二、添加编辑删除树形控件实现

1、前端添加、编辑、删除实现

1.1、 html内容
  • 只有叶子节点才显示删除功能
  • 所有的分类都可以编辑
  • 只有一级、二级分类有添加功能
<el-button v-if="draggable" @click="batchSave">批量保存</el-button>
<el-button size="mini" type="danger" @click="batchDelete">批量删除</el-button>
<el-tree :data="menus" :props="defaultProps" :expand-on-click-node="false" show-checkbox node-key="catId":default-expanded-keys="expandedKey" :draggable="draggable" :allow-drop="allowDrop" @node-drop="handleDrop"ref="menuTree"><span class="custom-tree-node" slot-scope="{ node, data }"><span>{{ node.label }}</span><span><el-button v-if="node.level <=2" type="text" size="mini" @click="() => append(data)">添加</el-button><el-button type="text" size="mini" @click="edit(data)">编辑</el-button><el-button v-if="node.childNodes.length==0" type="text" size="mini"@click="() => remove(node, data)">删除</el-button></span></span></el-tree>
1.2、js实现
  • 添加:
append(data) {console.log("append", data);this.dialogType = "add";this.title = "添加分类";this.dialogVisible = true;this.category.parentCid = data.catId;this.category.catLevel = data.catLevel * 1 + 1;this.category.catId = null;this.category.name = "";this.category.icon = "";this.category.productUnit = "";this.category.sort = 0;this.category.showStatus = 1;},
//添加三级分类addCategory() {console.log("提交的三级分类数据", this.category);this.$http({url: this.$http.adornUrl("/product/category/save"),method: "post",data: this.$http.adornData(this.category, false)}).then(({data}) => {this.$message({message: "菜单保存成功",type: "success"});//关闭对话框this.dialogVisible = false;//刷新出新的菜单this.getMenus();//设置需要默认展开的菜单this.expandedKey = [this.category.parentCid];});},
submitData() {if (this.dialogType == "add") {this.addCategory();}if (this.dialogType == "edit") {this.editCategory();}},
  • 批量添加
batchSave() {this.$http({url: this.$http.adornUrl("/product/category/update/sort"),method: "post",data: this.$http.adornData(this.updateNodes, false)}).then(({data}) => {this.$message({message: "菜单顺序等修改成功",type: "success"});//刷新出新的菜单this.getMenus();//设置需要默认展开的菜单this.expandedKey = this.pCid;this.updateNodes = [];this.maxLevel = 0;         });},
  • 编辑
edit(data) {console.log("要修改的数据", data);this.dialogType = "edit";this.title = "修改分类";this.dialogVisible = true;//发送请求获取当前节点最新的数据this.$http({url: this.$http.adornUrl(`/product/category/info/${data.catId}`),method: "get"}).then(({data}) => {//请求成功console.log("要回显的数据", data);this.category.name = data.data.name;this.category.catId = data.data.catId;this.category.icon = data.data.icon;this.category.productUnit = data.data.productUnit;this.category.parentCid = data.data.parentCid;this.category.catLevel = data.data.catLevel;this.category.sort = data.data.sort;this.category.showStatus = data.data.showStatus;         });},
//修改三级分类数据editCategory() {var {catId,name,icon,productUnit} = this.category;this.$http({url: this.$http.adornUrl("/product/category/update"),method: "post",data: this.$http.adornData({catId,name,icon,productUnit}, false)}).then(({data}) => {this.$message({message: "菜单修改成功",type: "success"});//关闭对话框this.dialogVisible = false;//刷新出新的菜单this.getMenus();//设置需要默认展开的菜单this.expandedKey = [this.category.parentCid];});},
  • 删除单个节点
remove(node, data) {var ids = [data.catId];this.$confirm(`是否删除【${data.name}】菜单?`, "提示", {confirmButtonText: "确定",cancelButtonText: "取消",type: "warning"}).then(() => {this.$http({url: this.$http.adornUrl("/product/category/delete"),method: "post",data: this.$http.adornData(ids, false)}).then(({data}) => {this.$message({message: "菜单删除成功",type: "success"});//刷新出新的菜单this.getMenus();//设置需要默认展开的菜单this.expandedKey = [node.parent.data.catId];});}).catch(() => {});console.log("remove", node, data);}
  • 批量删除

1)首先根据选中的节点获取选中的节点 catId
2)提示是否删除
3)如果确定删除,则调用服务层的批量删除方法
4)删除成功后提示,并重新加载菜单

batchDelete() {let catIds = [];let checkedNodes = this.$refs.menuTree.getCheckedNodes();console.log("被选中的元素", checkedNodes);for (let i = 0; i < checkedNodes.length; i++) {catIds.push(checkedNodes[i].catId);}this.$confirm(`是否批量删除【${catIds}】菜单?`, "提示", {confirmButtonText: "确定",cancelButtonText: "取消",type: "warning"}).then(() => {this.$http({url: this.$http.adornUrl("/product/category/delete"),method: "post",data: this.$http.adornData(catIds, false)}).then(({data}) => {this.$message({message: "菜单批量删除成功",type: "success"});this.getMenus();});}).catch(() => {});},

2、服务端添加、编辑、删除实现

  • 添加
	@RequestMapping("/save")public R save(@RequestBody CategoryEntity category){categoryService.save(category);return R.ok();}
  • 编辑
	@RequestMapping("/info/{catId}")public R info(@PathVariable("catId") Long catId){CategoryEntity category = categoryService.getById(catId);return R.ok().put("data", category);}@RequestMapping("/update")public R update(@RequestBody CategoryEntity category){categoryService.updateCascade(category);return R.ok();}
  • 删除
  	@RequestMapping("/delete")public R delete(@RequestBody Long[] catIds){//1.检查当前删除的分类,是否被别的地方引用categoryService.removeMenuByIds(Arrays.asList(catIds));return R.ok();}@Overridepublic void removeMenuByIds(List<Long> asList) {        //逻辑删除baseMapper.deleteBatchIds(asList);}

三、树形控件拖拽功能实现

1、前端实现

1.1、html部分,添加拖拽控制开关
	<el-switch v-model="draggable" active-text="开启拖拽" inactive-text="关闭拖拽"></el-switch><el-button v-if="draggable" @click="batchSave">批量保存</el-button><el-button size="mini" type="danger" @click="batchDelete">批量删除</el-button><el-tree :data="menus" :props="defaultProps" :expand-on-click-node="false" show-checkbox node-key="catId":default-expanded-keys="expandedKey" :draggable="draggable" :allow-drop="allowDrop" @node-drop="handleDrop"ref="menuTree"><span class="custom-tree-node" slot-scope="{ node, data }"><span>{{ node.label }}</span><span><el-button v-if="node.level <=2" type="text" size="mini" @click="() => append(data)">添加</el-button><el-button type="text" size="mini" @click="edit(data)">编辑</el-button><el-button v-if="node.childNodes.length==0" type="text" size="mini"@click="() => remove(node, data)">Delete</el-button></span></span></el-tree>
1.2、js部分
  • 计算可拖拽的信息,找到所有子节点,求出最大深度

1)被拖动的当前节点以及所在的父节点总层数不能大于3
2)计算当前节点所在的最大层级,一般是<= 3 ,
3)计算当前节点所在的最大深度,一般是<= 3 , 公式:let deep = Math.abs(this.maxLevel - draggingNode.level) + 1;
4)判断拖拽是在内部,还是前后,如果是拖拽到某节点的内部,必须:deep + dropNode.level <= 3;
5)否则 deep + dropNode.parent.level <= 3;

	allowDrop(draggingNode, dropNode, type) {//1、被拖动的当前节点以及所在的父节点总层数不能大于3//1)、被拖动的当前节点总层数console.log("allowDrop:", draggingNode, dropNode, type);//this.countNodeLevel(draggingNode);//当前正在拖动的节点+父节点所在的深度不大于3即可let deep = Math.abs(this.maxLevel - draggingNode.level) + 1;console.log("深度:", deep);//   this.maxLevelif (type == "inner") {      return deep + dropNode.level <= 3;} else {return deep + dropNode.parent.level <= 3;}},countNodeLevel(node) {//找到所有子节点,求出最大深度if (node.childNodes != null && node.childNodes.length > 0) {for (let i = 0; i < node.childNodes.length; i++) {if (node.childNodes[i].level > this.maxLevel) {this.maxLevel = node.childNodes[i].level;}this.countNodeLevel(node.childNodes[i]);}}else{this.maxLevel = node.level}},
  • 处理拖拽的节点,排序
handleDrop(draggingNode, dropNode, dropType, ev) {console.log("handleDrop: ", draggingNode, dropNode, dropType);//1、当前节点最新的父节点idlet pCid = 0;let siblings = null;if (dropType == "before" || dropType == "after") {pCid = dropNode.parent.data.catId == undefined ? 0 :  dropNode.parent.data.catId;siblings = dropNode.parent.childNodes;} else {pCid = dropNode.data.catId;siblings = dropNode.childNodes;}this.pCid.push(pCid);//2、当前拖拽节点的最新顺序,for (let i = 0; i < siblings.length; i++) {if (siblings[i].data.catId == draggingNode.data.catId) {//如果遍历的是当前正在拖拽的节点let catLevel = draggingNode.level;if (siblings[i].level != draggingNode.level) {//当前节点的层级发生变化catLevel = siblings[i].level;//修改他子节点的层级this.updateChildNodeLevel(siblings[i]);}this.updateNodes.push({catId: siblings[i].data.catId,sort: i,parentCid: pCid,catLevel: catLevel});} else {this.updateNodes.push({catId: siblings[i].data.catId,sort: i});}}//3、当前拖拽节点的最新层级console.log("updateNodes", this.updateNodes);},

2、服务端实现

	@RequestMapping("/update/sort")public R updateSort(@RequestBody List<CategoryEntity> categorys){categoryService.updateBatchById(categorys);return R.ok();}

源码下载:
https://gitee.com/charlinchenlin/koo-erp

相关文章:

树形结构的三级分类如何实现?

概述&#xff1a; 本三级联动分类服务端使用的是: Springboot MyBatis-plus&#xff0c;前端使用的是&#xff1a;VueElementUI&#xff0c;树形控件使用的是el-tree。本三级联动分类可以把任一子项拖拽到其它目录&#xff0c;可以添加、编辑、删除分类。 效果图&#xff1a…...

SSM整合完整流程

&#x1f3e0;个人主页&#xff1a;shark-Gao &#x1f9d1;个人简介&#xff1a;大家好&#xff0c;我是shark-Gao&#xff0c;一个想要与大家共同进步的男人&#x1f609;&#x1f609; &#x1f389;目前状况&#xff1a;23届毕业生&#xff0c;目前在某公司实习&#x1f…...

虹科方案 | 助力高性能视频存储解决方案-2

上篇文章《虹科方案 | 助力高性能视频存储解决方案-1》我们分享了虹科&ATTO 和 Avid 共同创建协作解决方案&#xff0c;助力高性能视频存储&#xff0c;今天我们再深入介绍一下我们的案例详情。 一、行业挑战 从高端广播设施到小型独立工作室的媒体后期制作环境都需要允许多…...

java版深圳 工程管理系统软件 自主研发,工程行业适用 软件源码

Java版工程项目管理系统 Spring CloudSpring BootMybatisVueElementUI前后端分离 功能清单如下&#xff1a; 首页 工作台&#xff1a;待办工作、消息通知、预警信息&#xff0c;点击可进入相应的列表 项目进度图表&#xff1a;选择&#xff08;总体或单个&#xff09;项目显示…...

云原生Istio架构和组件介绍

目录 1 Istio 架构2 Istio组件介绍2.1 Pilot2.2 Mixer2.3 Citadel2.4 Galley2.5 Sidecar-injector2.6 Proxy(Envoy)2.7 Ingressgateway2.8 其他组件 1 Istio 架构 Istio的架构&#xff0c;分为控制平面和数据面平两部分。 - 数据平面&#xff1a;由一组智能代理&#xff08;[En…...

吹爆,全网第一个手把手教你从零开始搭建Spring Cloud Alibaba的笔记

Spring Cloud Alibaba 是阿里巴巴提供的微服务开发一站式解决方案&#xff0c;是阿里巴巴开源中间件与 Spring Cloud 体系的融合。 Springcloud 和 Srpingcloud Alibaba 区别&#xff1f; SpringCloud&#xff1a; 部分组件停止维护和更新&#xff0c;给开发带来不便;SpringCl…...

企业短信遭疯狂盗用,可能是没配置验证码

手机短信作为一种快捷的通讯方式被广泛应用。不仅在个人日常生活中&#xff0c;企业也习惯使用手机短信来进行验证和提醒&#xff0c;以保证业务的正常进行。随着数字化的发展&#xff0c;手机短信也成为了不法分子滥用的目标之一&#xff0c;给个人和企业带来不同经济损失。 个…...

【UE】直升机沿样条线移动

效果 步骤 1. 将虚幻商城中的免费资产导入工程 下载完毕后可以看到如下文件 2. 新建一个Actor蓝图类&#xff0c;命名为“Track”&#xff0c;这个蓝图就是用来画样条线的 打开“Track”&#xff0c;添加样条组件 3. 打开“BP_West_Heli_AH64D” 在事件图表中先新建一个时间轴…...

GaussDB_200_6.5.1部署安装

目录 安装前准备 安装依赖 修改/etc/hosts 上传解压介质 预安装 拷贝安装包 预安装配置 编辑preinstall.ini配置文件 编辑host0配置文件 执行预安装命令 安装FusionInsight_Manager 修改install安装配置文件 执行安装命令 web操作安装数据库 GaussDB200测试 配…...

软件工具 | Python调用运筹优化求解器(一):以CVRPVRPTW为例

目录 1. 引言2. 求解器介绍3. 基础语言3.1 创建模型3.2 添加变量3.3 添加目标函数3.4 添加约束3.5 设置参数3.6 求解 4. 数学模型4.1 [CVRP数学模型](https://mp.weixin.qq.com/s/DYh-5WkrYxk1gCKo8ZjvAw)4.2 [VRPTW数学模型](https://mp.weixin.qq.com/s/tF-ayzjpZfuZvelvItue…...

如何在JAVA中实现网络编程?

在Java中实现网络编程通常需要使用Java提供的网络编程库——Java Networking API。Java Networking API支持常见的TCP和UDP协议&#xff0c;包括Socket、ServerSocket、DatagramSocket等类&#xff0c;通过这些类&#xff0c;我们可以创建、连接、监听和传输数据。 下面是在Ja…...

【redis】redis的缓存过期淘汰策略

【redis】redis的缓存过期淘汰策略 文章目录 【redis】redis的缓存过期淘汰策略前言一、面试题二、redis内存满了怎么办&#xff1f;1、redis默认内存是多少&#xff1f;在哪查看&#xff1f;如何修改?在conf配置文件中可以查看 修改&#xff0c;内存默认是0redis的默认内存有…...

ASP.NET动态Web开发技术第8章

第8章ASP.NET数据访问 一.预习笔记 1.SqlDataSource控件 SqlDataSource数据源控件支持连接SQL关系数据库&#xff0c;它使用SQL命令来检索和修改数据。通常将SqlDataSource数据源控件与数据绑定控件一起使用。 属性1&#xff1a;ID&#xff1a;当前数据源控件的唯一标识符 …...

【旋转编码器如何工作以及如何将其与Arduino一起使用】

在本教程中,我们将学习旋转编码器的工作原理以及如何将其与Arduino一起使用。您可以观看以下视频或阅读下面的书面教程。 1. 概述 旋转编码器是一种位置传感器,用于确定旋转轴的角度位置。它根据旋转运动产生模拟或数字电信号。 有许多不同类型的旋转编码器按输出信号或传感…...

Tre靶场通关过程(linpeas使用+启动项编辑器提权)

Tre靶场通关 通过信息收集获得到了普通用户账号密码&#xff0c;利用PEASS-ng的linpeas脚本进行提权的信息收集&#xff0c;根据已有信息进行提权。 靶机下载地址&#xff1a; https://download.vulnhub.com/tre/Tre.zip 信息收集 靶机IP探测&#xff1a;192.168.0.129 a…...

java多线程下

ThreadLocal ThreadLocal 有什么用&#xff1f;通常情况下&#xff0c;我们创建的变量是可以被任何一个线程访问并修改的。如果想实现每一个线程都有自己的专属本地变量该如何解决呢&#xff1f;JDK 中自带的ThreadLocal类正是为了解决这样的问题。 ThreadLocal类主要解决的就…...

使用无标注的数据训练Bert

文章目录 1、准备用于训练的数据集2、处理数据集3、克隆代码4、运行代码5、将ckpt模型转为bin模型使其可在pytorch中运用 Bert官方仓库&#xff1a;https://github.com/google-research/bert 1、准备用于训练的数据集 此处准备的是BBC news的数据集&#xff0c;下载链接&…...

《Netty》从零开始学netty源码(五十二)之PoolThreadCache

PoolThreadCache Netty有一个大的公共内存容器PoolArena&#xff0c;用来管理从操作系统中获得的内存&#xff0c;在高并发下如果所有线程都去这个大容器获取内存它的压力是非常大的&#xff0c;所以Netty为每个线程建立了一个本地缓存&#xff0c;即PoolThreadCache&#xff…...

放弃40k月薪的程序员工作,选择公务员,我来分享一下看法

我有一个朋友&#xff0c;拒绝了我为他提供的4万薪水的工作&#xff0c;去了一个体制内的银行&#xff0c;做程序员&#xff0c;即使薪水减半。他之前在北京一家大公司做程序员&#xff0c;一个月30k。当我开始创业时&#xff0c;我拉他来和我一起干&#xff0c;但那时我们太小…...

【MybatisPlus】高级版可视化、可配置 自动生成代码

今天看别人使用了一个更加智能的生成代码工具&#xff0c;可视化、可配置策略&#xff0c;非常方便&#xff0c;配置一次&#xff0c;在哪都可以使用&#xff0c;也不会跟项目藕合下面简单说一下使用方式。 1、介绍mybatis-plus-generator-ui 主要是封装了mybatis-plus-gener…...

《从零掌握MIPI CSI-2: 协议精解与FPGA摄像头开发实战》-- CSI-2 协议详细解析 (一)

CSI-2 协议详细解析 (一&#xff09; 1. CSI-2层定义&#xff08;CSI-2 Layer Definitions&#xff09; 分层结构 &#xff1a;CSI-2协议分为6层&#xff1a; 物理层&#xff08;PHY Layer&#xff09; &#xff1a; 定义电气特性、时钟机制和传输介质&#xff08;导线&#…...

【算法训练营Day07】字符串part1

文章目录 反转字符串反转字符串II替换数字 反转字符串 题目链接&#xff1a;344. 反转字符串 双指针法&#xff0c;两个指针的元素直接调转即可 class Solution {public void reverseString(char[] s) {int head 0;int end s.length - 1;while(head < end) {char temp …...

[Java恶补day16] 238.除自身以外数组的乘积

给你一个整数数组 nums&#xff0c;返回 数组 answer &#xff0c;其中 answer[i] 等于 nums 中除 nums[i] 之外其余各元素的乘积 。 题目数据 保证 数组 nums之中任意元素的全部前缀元素和后缀的乘积都在 32 位 整数范围内。 请 不要使用除法&#xff0c;且在 O(n) 时间复杂度…...

VM虚拟机网络配置(ubuntu24桥接模式):配置静态IP

编辑-虚拟网络编辑器-更改设置 选择桥接模式&#xff0c;然后找到相应的网卡&#xff08;可以查看自己本机的网络连接&#xff09; windows连接的网络点击查看属性 编辑虚拟机设置更改网络配置&#xff0c;选择刚才配置的桥接模式 静态ip设置&#xff1a; 我用的ubuntu24桌…...

排序算法总结(C++)

目录 一、稳定性二、排序算法选择、冒泡、插入排序归并排序随机快速排序堆排序基数排序计数排序 三、总结 一、稳定性 排序算法的稳定性是指&#xff1a;同样大小的样本 **&#xff08;同样大小的数据&#xff09;**在排序之后不会改变原始的相对次序。 稳定性对基础类型对象…...

软件工程 期末复习

瀑布模型&#xff1a;计划 螺旋模型&#xff1a;风险低 原型模型: 用户反馈 喷泉模型:代码复用 高内聚 低耦合&#xff1a;模块内部功能紧密 模块之间依赖程度小 高内聚&#xff1a;指的是一个模块内部的功能应该紧密相关。换句话说&#xff0c;一个模块应当只实现单一的功能…...

阿里云Ubuntu 22.04 64位搭建Flask流程(亲测)

cd /home 进入home盘 安装虚拟环境&#xff1a; 1、安装virtualenv pip install virtualenv 2.创建新的虚拟环境&#xff1a; virtualenv myenv 3、激活虚拟环境&#xff08;激活环境可以在当前环境下安装包&#xff09; source myenv/bin/activate 此时&#xff0c;终端…...

WebRTC调研

WebRTC是什么&#xff0c;为什么&#xff0c;如何使用 WebRTC有什么优势 WebRTC Architecture Amazon KVS WebRTC 其它厂商WebRTC 海康门禁WebRTC 海康门禁其他界面整理 威视通WebRTC 局域网 Google浏览器 Microsoft Edge 公网 RTSP RTMP NVR ONVIF SIP SRT WebRTC协…...

从零开始了解数据采集(二十八)——制造业数字孪生

近年来&#xff0c;我国的工业领域正经历一场前所未有的数字化变革&#xff0c;从“双碳目标”到工业互联网平台的推广&#xff0c;国家政策和市场需求共同推动了制造业的升级。在这场变革中&#xff0c;数字孪生技术成为备受关注的关键工具&#xff0c;它不仅让企业“看见”设…...

游戏开发中常见的战斗数值英文缩写对照表

游戏开发中常见的战斗数值英文缩写对照表 基础属性&#xff08;Basic Attributes&#xff09; 缩写英文全称中文释义常见使用场景HPHit Points / Health Points生命值角色生存状态MPMana Points / Magic Points魔法值技能释放资源SPStamina Points体力值动作消耗资源APAction…...