树型表查询方法 —— SQL递归

article/2025/8/23 2:38:25

目录

引言:

自链接查询: 

 递归查询: 

编写service接口实现:


引言:

看下图,这是 course_category 课程分类表的结构:

这张表是一个树型结构,通过父结点id将各元素组成一个树。

我们可以看下该表的数据,下图是一部分数据:

现在的需求是需要在内容管理服务中编写一个接口读取该课程分类表的数据,组成一个树型结构返回给前端。


树形表的根本在于它有一个 parentid 字段,而这个字段是为了记录当前结点的父节点的 id 值。所以每一个树型表都会有一个这样的字段。

通过查阅接口文档,此接口要返回全部课程分类,以树型结构返回,如下所示:

 [{"childrenTreeNodes" : [{"childrenTreeNodes" : null,"id" : "1-1-1","isLeaf" : null,"isShow" : null,"label" : "HTML/CSS","name" : "HTML/CSS","orderby" : 1,"parentid" : "1-1"},{"childrenTreeNodes" : null,"id" : "1-1-2","isLeaf" : null,"isShow" : null,"label" : "JavaScript","name" : "JavaScript","orderby" : 2,"parentid" : "1-1"},{"childrenTreeNodes" : null,"id" : "1-1-3","isLeaf" : null,"isShow" : null,"label" : "jQuery","name" : "jQuery","orderby" : 3,"parentid" : "1-1"},{"childrenTreeNodes" : null,"id" : "1-1-4","isLeaf" : null,"isShow" : null,"label" : "ExtJS","name" : "ExtJS","orderby" : 4,"parentid" : "1-1"},{"childrenTreeNodes" : null,"id" : "1-1-5","isLeaf" : null,"isShow" : null,"label" : "AngularJS","name" : "AngularJS","orderby" : 5,"parentid" : "1-1"},{"childrenTreeNodes" : null,"id" : "1-1-6","isLeaf" : null,"isShow" : null,"label" : "ReactJS","name" : "ReactJS","orderby" : 6,"parentid" : "1-1"},{"childrenTreeNodes" : null,"id" : "1-1-7","isLeaf" : null,"isShow" : null,"label" : "Bootstrap","name" : "Bootstrap","orderby" : 7,"parentid" : "1-1"},{"childrenTreeNodes" : null,"id" : "1-1-8","isLeaf" : null,"isShow" : null,"label" : "Node.js","name" : "Node.js","orderby" : 8,"parentid" : "1-1"},{"childrenTreeNodes" : null,"id" : "1-1-9","isLeaf" : null,"isShow" : null,"label" : "Vue","name" : "Vue","orderby" : 9,"parentid" : "1-1"},{"childrenTreeNodes" : null,"id" : "1-1-10","isLeaf" : null,"isShow" : null,"label" : "其它","name" : "其它","orderby" : 10,"parentid" : "1-1"}],"id" : "1-1","isLeaf" : null,"isShow" : null,"label" : "前端开发","name" : "前端开发","orderby" : 1,"parentid" : "1"},{"childrenTreeNodes" : [{"childrenTreeNodes" : null,"id" : "1-2-1","isLeaf" : null,"isShow" : null,"label" : "微信开发","name" : "微信开发","orderby" : 1,"parentid" : "1-2"},{"childrenTreeNodes" : null,"id" : "1-2-2","isLeaf" : null,"isShow" : null,"label" : "iOS","name" : "iOS","orderby" : 2,"parentid" : "1-2"},{"childrenTreeNodes" : null,"id" : "1-2-3","isLeaf" : null,"isShow" : null,"label" : "手游开发","name" : "手游开发","orderby" : 3,"parentid" : "1-2"},{"childrenTreeNodes" : null,"id" : "1-2-4","isLeaf" : null,"isShow" : null,"label" : "Swift","name" : "Swift","orderby" : 4,"parentid" : "1-2"},{"childrenTreeNodes" : null,"id" : "1-2-5","isLeaf" : null,"isShow" : null,"label" : "Android","name" : "Android","orderby" : 5,"parentid" : "1-2"},{"childrenTreeNodes" : null,"id" : "1-2-6","isLeaf" : null,"isShow" : null,"label" : "ReactNative","name" : "ReactNative","orderby" : 6,"parentid" : "1-2"},{"childrenTreeNodes" : null,"id" : "1-2-7","isLeaf" : null,"isShow" : null,"label" : "Cordova","name" : "Cordova","orderby" : 7,"parentid" : "1-2"},{"childrenTreeNodes" : null,"id" : "1-2-8","isLeaf" : null,"isShow" : null,"label" : "其它","name" : "其它","orderby" : 8,"parentid" : "1-2"}],"id" : "1-2","isLeaf" : null,"isShow" : null,"label" : "移动开发","name" : "移动开发","orderby" : 2,"parentid" : "1"}]

而上边的数据格式是一个数组结构,数组的元素即为分类信息,分类信息设计两级分类,第一级的分类信息示例如下:

"id" : "1-2",
"isLeaf" : null,
"isShow" : null,
"label" : "移动开发",
"name" : "移动开发",
"orderby" : 2,
"parentid" : "1"

第二级的分类是第一级分类中childrenTreeNodes属性,它是一个数组结构:

{
"id" : "1-2",
"isLeaf" : null,
"isShow" : null,
"label" : "移动开发",
"name" : "移动开发",
"orderby" : 2,
"parentid" : "1",
"childrenTreeNodes" : [{"childrenTreeNodes" : null,"id" : "1-2-1","isLeaf" : null,"isShow" : null,"label" : "微信开发","name" : "微信开发","orderby" : 1,"parentid" : "1-2"}}

所以我们采用下面的model来定义这张表:

package com.xuecheng.content.model.dto;import com.xuecheng.content.model.po.CourseCategory;
import lombok.Data;import java.io.Serializable;
import java.util.List;/*** @description 课程分类树型结点dto* @version 1.0*/
// Serializable 网络传输序列化
@Data
public class CourseCategoryTreeDto extends CourseCategory implements Serializable {List<CourseCategoryTreeDto> childrenTreeNodes;
}

接口定义如下:

package com.xuecheng.content.api;import com.xuecheng.content.model.dto.CourseCategoryTreeDto;
import com.xuecheng.content.service.CourseCategoryService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;import java.util.List;/*** <p>* 数据字典 前端控制器* </p>*/
@Slf4j
@RestController
public class CourseCategoryController {@GetMapping("/course-category/tree-nodes")public List<CourseCategoryTreeDto> queryTreeNodes() {return null;}
}

自链接查询: 

课程分类表是一个树型结构,其中parentid字段为父结点ID,它是树型结构的标志字段。

如果树的层级固定可以使用表的自链接去查询,比如:我们只查询两级课程分类,可以用下边的SQL:

select * from course_category oneinner join course_category two on one.id = two.parentid

我们让 course_category 表去 inner join 自己,之后起别名,one代表一级节点分类,two代表二级节点分类,所以通过查询 二级节点的父节点id = 一级节点id,这个就是查询条件。

如果不想显示根结点并且排序,参考下面代码: 

selectone.id            one_id,one.name          one_name,one.parentid      one_parentid,one.orderby       one_orderby,one.label         one_label,two.id            two_id,two.name          two_name,two.parentid      two_parentid,two.orderby       two_orderby,two.label         two_labelfrom course_category oneinner join course_category two on one.id = two.parentidwhere one.parentid = 1and one.is_show = 1and two.is_show = 1order by one.orderby,two.orderby

而如果我们还想要通过指定节点来查询另一张表的对应的数据,需要用到左右关联

如上两张图,左侧图是课程计划(树型表),每个课程计划都有所属课程。每个课程的课程计划有两个级别,第一级为大章节,grade 为1、第二级为小章节,grade 为2。第二级的 parentid 为第一级的 id。课程计划的显示顺序根据排序字段去显示。根据业务流程中的界面原型,课程计划列表展示时还有课程计划关联的视频信息

课程计划关联的视频信息在 teachplan_media 表,两张表是一对一关系,每个课程计划只能在teachplan_media表中存在一个视频

我们的需求是无论关联不关联都必须查出课程计划(即使没有课程视频也要查出课程计划),所以选择使用左关联(left join)。

selectone.id             one_id,one.pname          one_pname,one.parentid       one_parentid,one.grade          one_grade,one.media_type     one_mediaType,one.start_time     one_stratTime,one.end_time       one_endTime,one.orderby        one_orderby,one.course_id      one_courseId,one.course_pub_id  one_coursePubId,two.id             two_id,two.pname          two_pname,two.parentid       two_parentid,two.grade          two_grade,two.media_type     two_mediaType,two.start_time     two_stratTime,two.end_time       two_endTime,two.orderby        two_orderby,two.course_id      two_courseId,two.course_pub_id  two_coursePubId,m1.media_fileName mediaFilename,m1.id teachplanMeidaId,m1.media_id mediaIdfrom teachplan oneINNER JOIN teachplan two on one.id = two.parentidLEFT JOIN teachplan_media m1 on m1.teachplan_id = two.idwhere one.parentid = 0 and one.course_id=#{value}order by one.orderby,two.orderby

首先使用inner join自链接查询树型表,随后使用左关联根据课程视频的teachplan_id = 课程计划的id 来找到每个课程计划(二级分类)对应的课程视频。 

目前我们想要的数据是如上图,而目前查询到的数据如下图:

因为字段名与属性名不一致,所以需要定义 resultMap 手动映射。而且我们想要的数据格式内还有子节点,所以需要使用一对多映射(Collection),我们的数据模型如下图:

@Data
@ToString
public class TeachplanDto extends Teachplan {//课程计划关联的媒资信息TeachplanMedia teachplanMedia;//子结点List<TeachplanDto> teachPlanTreeNodes;
}

所以 property 映射的属性就是 teachPlanTreeNodes,而 ofType 的 List 中的对象类型就是 TeachplanDto。

<!-- 一级中包含多个二级数据 -->
<collection property="teachPlanTreeNodes" ofType="com.xuecheng.content.model.dto.TeachplanDto">

而在小章节内有一个视频,所以用到一对一映射(Assoiation),其中 property映射的就是"teachplanMedia"属性,也就是课程视频;而 javaType的类型就是"com.xuecheng.content.model.po.TeachplanMedia"。

<association property="teachplanMedia" javaType="com.xuecheng.content.model.po.TeachplanMedia">

下面是对应的mapper.xml文件:(通过单次 SQL 关联查询 + 结果集映射,一次性获取所有层级数据,减少数据库交互。)

<!-- 课程分类树型结构查询映射结果 -->
<resultMap id="treeNodeResultMap" type="com.xuecheng.content.model.dto.TeachplanDto"><!-- 一级数据映射 --><id     column="one_id"        property="id" /><result column="one_pname"      property="pname" /><result column="one_parentid"     property="parentid" /><result column="one_grade"  property="grade" /><result column="one_mediaType"   property="mediaType" /><result column="one_stratTime"   property="stratTime" /><result column="one_endTime"   property="endTime" /><result column="one_orderby"   property="orderby" /><result column="one_courseId"   property="courseId" /><result column="one_coursePubId"   property="coursePubId" /><!-- 一级中包含多个二级数据 --><collection property="teachPlanTreeNodes" ofType="com.xuecheng.content.model.dto.TeachplanDto"><!-- 二级数据映射 --><id     column="two_id"        property="id" /><result column="two_pname"      property="pname" /><result column="two_parentid"     property="parentid" /><result column="two_grade"  property="grade" /><result column="two_mediaType"   property="mediaType" /><result column="two_stratTime"   property="stratTime" /><result column="two_endTime"   property="endTime" /><result column="two_orderby"   property="orderby" /><result column="two_courseId"   property="courseId" /><result column="two_coursePubId"   property="coursePubId" /><association property="teachplanMedia" javaType="com.xuecheng.content.model.po.TeachplanMedia"><result column="teachplanMeidaId"   property="id" /><result column="mediaFilename"   property="mediaFilename" /><result column="mediaId"   property="mediaId" /><result column="two_id"   property="teachplanId" /><result column="two_courseId"   property="courseId" /><result column="two_coursePubId"   property="coursePubId" /></association></collection>
</resultMap>
<!--课程计划树型结构查询-->
<select id="selectTreeNodes" resultMap="treeNodeResultMap" parameterType="long" >selectone.id             one_id,one.pname          one_pname,one.parentid       one_parentid,one.grade          one_grade,one.media_type     one_mediaType,one.start_time     one_stratTime,one.end_time       one_endTime,one.orderby        one_orderby,one.course_id      one_courseId,one.course_pub_id  one_coursePubId,two.id             two_id,two.pname          two_pname,two.parentid       two_parentid,two.grade          two_grade,two.media_type     two_mediaType,two.start_time     two_stratTime,two.end_time       two_endTime,two.orderby        two_orderby,two.course_id      two_courseId,two.course_pub_id  two_coursePubId,m1.media_fileName mediaFilename,m1.id teachplanMeidaId,m1.media_id mediaIdfrom teachplan oneINNER JOIN teachplan two on one.id = two.parentidLEFT JOIN teachplan_media m1 on m1.teachplan_id = two.idwhere one.parentid = 0 and one.course_id=#{value}order by one.orderby,two.orderby
</select>

递归查询: 

如果树的层级不确定,此时可以使用MySQL递归实现,使用with语法,如下:

WITH [RECURSIVE]cte_name [(col_name [, col_name] ...)] AS (subquery)[, cte_name [(col_name [, col_name] ...)] AS (subquery)] ...

cte_name :公共表达式的名称,可以理解为表名,用来表示as后面跟着的子查询

col_name :公共表达式包含的列名,可以写也可以不写

下边是一个递归的简单例子:

with RECURSIVE t1  AS
(SELECT 1 as nUNION ALLSELECT n + 1 FROM t1 WHERE n < 5
)
SELECT * FROM t1;

通过上述SQL,其中 t1 相当于一个表名,select 1 相当于这个表的初始值,这里使用UNION ALL 不断将每次递归得到的数据加入到表中,而 n<5 为递归执行的条件,当 n>=5 时结束递归调用:

下边我们使用递归实现课程分类的查询:

with recursive t1 as (
select * from  course_category p where  id= '1'
union allselect t.* from course_category t inner join t1 on t1.id = t.parentid
)
select *  from t1 order by t1.id, t1.orderby

最开始根结点id=1,然后通过 union all 不断将每次递归得到的数据加入到 t1 表中(t1表存储查完的数据),随后向下递归,使用 inner join 去拿 course_category 表关联 t1 表,来查询当前 t1 表下的树枝,所以查询 t1.id = course_category.parentid,因为 parentid 中记录的是当前结点的父节点。

所以查询完的数据最终会保存到 t1表并且使用 order by 按照顺序输出。

查询结果如下:

t1表中初始的数据是id等于1的记录,即根结点。

那如何向上递归?

下边的sql实现了向上递归:

with recursive t1 as (
select * from  course_category p where  id= '1-1-1'
union allselect t.* from course_category t inner join t1 on t1.parentid = t.id
)
select *  from t1 order by t1.id, t1.orderby

初始节点为1-1-1,通过递归找到它的父级节点,父级节点包括所有级别的节点。

以上是我们研究了树型表的查询方法,通过递归的方式查询课程分类比较灵活,因为它可以不限制层级。

mysql为了避免无限递归默认递归次数为1000,可以通过设置cte_max_recursion_depth参数增加递归深度,还可以通过max_execution_time限制执行时间,超过此时间也会终止递归操作。

mysql递归相当于在存储过程中执行若干次sql语句,java程序仅与数据库建立一次链接执行递归操作,所以只要控制好递归深度,控制好数据量性能就没有问题。

思考:如果java程序在递归操作中连接数据库去查询数据组装数据,这个性能高吗?


下边我们可自定义mapper方法查询课程分类,最终将查询结果映射到List<CourseCategoryTreeDto>中。

生成课程分类表的mapper文件并拷贝至内容管理模块 的service工程中。

public interface CourseCategoryMapper extends BaseMapper<CourseCategory> {public List<CourseCategoryTreeDto> selectTreeNodes(String id);
}

找到对应的mapper.xml文件,编写sql语句:

<select id="selectTreeNodes" resultType="com.xuecheng.content.model.dto.CourseCategoryTreeDto" parameterType="string">with recursive t1 as (select * from  course_category p where  id= #{id}union allselect t.* from course_category t inner join t1 on t1.id = t.parentid)select *  from t1 order by t1.id, t1.orderby</select>

编写service接口实现:

由于现在我们查询是直接将所有的数据查出,而没有适应接口所返回的数据格式,所以我们要在Service层处理。

所以现在分为两步进行:

  1. 使用刚刚定义的mapper接口查询数据
  2. 将查询到的数据封装成 List<CourseCategoryTreeDto> 数据格式: 
    @Data
    public class CourseCategoryTreeDto extends CourseCategory implements Serializable {List<CourseCategoryTreeDto> childrenTreeNodes;
    }
    

 下面我们讲述如何将查询到的数据封装成 List<CourseCategoryTreeDto> 数据格式。

  1. 将list转为map,key就是结点id,value就是CourseCategoryTreeDto对象,目的是为了方面从map获取结点。
  2. 从头遍历List<CourseCategoryTreeDto>,将遍历到的子节点放在父节点的childrenTreeNodes中。

首先List转map可以使用stream流,并给key、value赋值,但是也会遇到两个key重复,这个时候以第二个key为主,随后在使用filter将根结点过滤(判断查询id与当前id是否相等来判断是否为根结点,因为是通过根结点查询) :

//将list转map,以备使用,排除根节点
Map<String, CourseCategoryTreeDto> mapTemp = courseCategoryTreeDtos.stream().filter(item->!id.equals(item.getId())).collect(Collectors.toMap(key -> key.getId(), value -> value, (key1, key2) -> key2));

先定义一个带返回的List数组对象: 

List<CourseCategoryTreeDto> categoryTreeDtos = new ArrayList<>();

随后同样使用stream流进行处理,如果当前节点的parentid=根结点的id,那么就将其放进 List<CourseCategoryTreeDto> categoryTreeDtos ,随后在判断当前结点是否有父节点(通过map的get(parentid)方法找),如果没有父节点就new一个集合放入(因为要向该集合中放入其子节点),如果要是找到其父节点,那么就将该节点放入其父节点的集合中。

下面是完整代码:

package com.xuecheng.content.service.impl;import com.xuecheng.content.mapper.CourseCategoryMapper;
import com.xuecheng.content.model.dto.CourseCategoryTreeDto;
import com.xuecheng.content.service.CourseCategoryService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;@Slf4j
@Service
public class CourseCategoryServiceImpl implements CourseCategoryService {@AutowiredCourseCategoryMapper courseCategoryMapper;public List<CourseCategoryTreeDto> queryTreeNodes(String id) {List<CourseCategoryTreeDto> courseCategoryTreeDtos = courseCategoryMapper.selectTreeNodes(id);//将list转map,以备使用,排除根节点Map<String, CourseCategoryTreeDto> mapTemp = courseCategoryTreeDtos.stream().filter(item->!id.equals(item.getId())).collect(Collectors.toMap(key -> key.getId(), value -> value, (key1, key2) -> key2));//最终返回的listList<CourseCategoryTreeDto> categoryTreeDtos = new ArrayList<>();//依次遍历每个元素,排除根节点courseCategoryTreeDtos.stream().filter(item->!id.equals(item.getId())).forEach(item->{if(item.getParentid().equals(id)){categoryTreeDtos.add(item);}//找到当前节点的父节点CourseCategoryTreeDto courseCategoryTreeDto = mapTemp.get(item.getParentid());if(courseCategoryTreeDto!=null){if(courseCategoryTreeDto.getChildrenTreeNodes() ==null){courseCategoryTreeDto.setChildrenTreeNodes(new ArrayList<CourseCategoryTreeDto>());}//下边开始往ChildrenTreeNodes属性中放子节点courseCategoryTreeDto.getChildrenTreeNodes().add(item);}});return categoryTreeDtos;}}


http://www.hkcw.cn/article/HGJHVLBpVE.shtml

相关文章

高校大数据采集平台产品特色

大数据采集平台是专为高校大数据相关专业打造的智能化数据采集教学与实训工具。平台具有以下核心优势&#xff1a;采用可视化图形界面&#xff0c;无需编程基础&#xff0c;通过简单配置即可快速抓取网页中的文本、链接、图片、视频及文档等全类型数据&#xff0c;并自动存储至…

石家庄铁道大学回应书记打人 学生直播见证冲突

5月28日,石家庄铁道大学一名学生在宿舍里被学院书记殴打,还见了血。当时学生正在直播,许多网友目睹了整个过程。当这件事上了热搜后,学校的回应令人气愤,称学院书记没有问题,是学生先动手的。网友们表示不信,质疑书记去学生宿舍是为了让学生打他。事件起因是石家庄铁道大…

PGSQL结合linux cron定期执行vacuum_full_analyze命令

‌VACUUM FULL ANALYZE 详解‌ 一、核心功能 ‌空间回收与重组‌ 完全重写表数据文件&#xff0c;将碎片化的存储空间合并并返还操作系统&#xff08;普通 VACUUM 仅标记空间可重用&#xff09;。彻底清理死元组&#xff08;已删除或更新的旧数据行&#xff09;&#xff0c;解…

吴艳妮摘铜哽咽鞠躬道歉 带伤参赛展现坚韧精神

5月29日,亚洲田径锦标赛女子100米栏决赛中,吴艳妮以13秒07的成绩获得铜牌。赛后,她走路时显得有些一瘸一拐。在接受采访时,吴艳妮哽咽着向大家道歉,表示很感谢现场观众的支持,但没能为中国队拿到冠军感到非常抱歉。她提到自己的伤还没有完全恢复,不想过多解释,但仍坚信…

XCVP1902-2MSEVSVA6865 Xilinx FPGA Versal Premium SoC/ASIC

XCVP1902-2MSEVSVA6865 Versal Premium SoC/ASIC 单片 FPGA&#xff0c;可提供大容量 FPGA 逻辑仿真和原型设计目标。VP1902的逻辑单元数量增加了 2.2 倍&#xff0c;达到 1850 万个。 VP1902 自适应 SoC 提供最大容量和连接能力&#xff0c;具有可随机存取的逻辑密度和 2.4 倍…

TripGenie:畅游济南旅行规划助手:个人工作纪实(二十一)

这次&#xff0c;我新增了一个济南公交线路的展示界面&#xff0c;济南的公交线路多&#xff0c;且经过的站点覆盖范围广&#xff0c;价格实惠&#xff0c;是出行旅游交通工具的不二之选&#xff0c;我基于此现实情况&#xff0c;觉得做一个新的页面全面展示济南交通。 我选择把…

激励电平与频差的微妙平衡:晶振选型不可忽视的细节

在电子设备的设计中&#xff0c;晶振作为提供稳定时钟信号的关键元件&#xff0c;其选型的正确性直接关系到整个系统的性能与稳定性。而在晶振选型过程中&#xff0c;激励电平与频差之间的微妙平衡常常被工程师们所忽视&#xff0c;然而这一细节却可能对电路的正常运行产生深远…

数字人引领政务新风尚:智能设备助力政务服务

在信息技术飞速发展的今天&#xff0c;政府机构不断探索提升服务效率和改善服务质量的新途径。实时交互数字人在政务服务中的应用正成为一大亮点&#xff0c;通过将“数字公务员”植入各种横屏智能设备中&#xff0c;为民众办理业务提供全程辅助。这种创新不仅优化了政务大厅的…

练习小项目9:打字效果文字展示(多段文字循环+删除+光标闪烁)

项目简介&#xff1a; 本文介绍如何用原生JavaScript实现一个简洁的打字效果&#xff0c;支持&#xff1a; 多段文字循环播放 打字完后暂停一会儿 逐字删除&#xff0c;形成打字机动画感 打字光标闪烁效果 项目适合用于首页欢迎语、提示语等动态文本展示&#xff0c;能提…

【从零开始超详细】Linux系统使用docker + docker-compose部署nacos以及SpringBoot+vue项目详细

Linux系统使用dockerdocker-compose部署nacos以及SpringBootvue项目详细文档 本文章Linux发行版为openEuler 22.03 (LTS-SP2), 多数命令与centos一致, 使用centos的小伙伴也可以参考 不知道自己的服务器是什么发行版的小伙伴可以执行如下命令查看: cat /etc/os-release执行结果…

利用Python制作环保志愿者招募海报

1. 文档概述 本研究文档详细论述了运用Python编程语言中的Pillow库&#xff08;PIL&#xff09;进行设计并制作一张专业环保志愿者招募海报的完整流程。该海报以“守护绿色家园”为主题&#xff0c;旨在激励社会公众积极参与森林保护的志愿活动。通过编程实现&#xff0c;海报中…

软考-系统架构设计师-第十五章 信息系统架构设计理论与实践

信息系统架构设计理论与实践 15.2 信息系统架构风格和分类15.3 信息系统常用的架构模型15.4 企业信息系统总体框架15.5 信息系统架构设计方法 15.2 信息系统架构风格和分类 信息系统架构风格 数据流体系结构风格&#xff1a;批处理、管道-过滤器调用/返回体系结构风格&#x…

德思特新闻 | 德思特与es:saar正式建立合作伙伴关系

德思特新闻 2025年5月9日&#xff0c;德思特科技有限公司&#xff08;以下简称“德思特”&#xff09;与德国嵌入式系统专家es:saar GmbH正式达成合作伙伴关系。此次合作旨在将 es:saar 的先进嵌入式开发与测试工具引入中国及亚太市场&#xff0c;助力本地客户提升产品开发效率…

【Simulink模型标准化开发】需求管理与基线测试--- Requirements ManagementSimulinkTest

前言&#xff1a;Simulink模型是嵌入于Matlab之中的一个模块化开发工具&#xff0c;它在嵌入式领域和应用层逻辑的搭建上享有声誉。并且&#xff0c;Simulink与C语言一样有着一套标准化的开发流程&#xff0c;因此它也具备安全性、可靠性、可移植性等优势。而在本篇文章中&…

前端 jQuery 简单实现一个网页格斗游戏示例

效果图 源代码&#xff1a; <!DOCTYPE html> <html lang"zh-CN"> <head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title>简易格斗游戏</t…

stm32 + ads1292心率检测报警设置上下限

这个项目是在做心率检测的时候一个小伙伴提出来的&#xff0c;今年五一的时候提出来的想法&#xff0c;五一假期的时候没时间&#xff0c;也没心情做这个&#xff0c;就把这个事情搁置了&#xff0c;在月中做工作计划的时候&#xff0c;就把这个小项目排进来了&#xff0c;五一…

git+svn+sourcetree客户端下载和安装教程

1.引言 本文带来git、svn、sourcetree的软件的下载链接和安装介绍。git、svn是文件版本控制工具&#xff0c;电脑安装后需要使用cmd命令来提交或拉取文件。非常麻烦&#xff0c;推荐使用sourcetree等工具来提交代码 sourcetree界面 压缩包内容&#xff0c;git、svn、svn汉化工…

华为湖南总部大楼刷新马栏山风景线:已经进入内部装修阶段

华为湖南总部大楼刷新马栏山风景线。5月29日,航拍镜头下的位于马栏山视频文创产业园的华为湖南总部大楼项目大楼十分引人注目,三栋楼体采用金色线条和玻璃元素,成为拔节生长的马栏山里一道亮丽的风景。从现场施工来看,该项目园林绿化已经完成,已经进入内部装修阶段。该项目…

小学生捡到手机后交给民警被送锦旗:失主准备了一面“哪吒锦旗”

小学生捡到手机后交给民警被送锦旗。近日,四川成都。7岁的小学生廖元祎在路边捡到一部手机,送到了派出所。巧合的是,就在廖元祎走进派出所不久,失主也来到派出所报失。看到手机物归原主,廖元祎开心地跳起来。为了给廖元祎一个表扬,失主准备了一面“哪吒锦旗”,和民警一起…

王力宏称为癌症研究者哥哥感到骄傲

王力宏称为癌症研究者哥哥感到骄傲。5月29日下午,知名歌手王力宏在社交媒体晒出哥哥王力德的演讲视频,以及和哥哥的合影。王力宏表示:“为我哥哥王力德博士感到骄傲!他在香港举行的ASGH亚洲医疗健康高峰会上发表演讲,思路清晰、充满远见。哥哥介绍了自己在希望之城实验室的…