从小白到架构师:万字长文 | 社交媒体应用系统设计

移动互联网时代,社交媒体应用彻底改变了我们联系和共享信息的方式。这些平台在幕后处理庞大的用户群、数据存储和实时交互。

在本文中,我们将深入探讨如何设计一个可扩展且高性能的社交媒体应用系统。我们将探讨关键组件、流程图、功能需求以及容量规划策略,这些都是构建成功社交媒体平台所必需的。

上图是整个系统的架构图,每个服务或模块这里先简单介绍:

  1. API Gateway:作为客户端流量通往后端服务的入口,处理所有的API请求,路由请求到相应的服务、身份验证、负载均衡。
  2. Follower Service:处理用户关注和被关注的关系。
  3. Profile Service:管理用户的个人信息和资料。
  4. Post Service:处理用户发布内容(帖子)。
  5. URL Shortener:缩短URL地址,可能用于分享帖子链接。
  6. User Feed Service::生成和管理用户的动态(feed),包括用户关注的人的新帖通知。
  7. Comment & Like Service:管理用户对帖子进行的评论和点赞。
  8. Chat Service:处理用户之间的实时聊天功能。
  9. Search Service:提供搜索功能,允许用户搜索其他用户或内容。
  10. Load Balancer (LB):分发请求到多个后端服务,确保系统的高可用性和负载均衡。
  11. CloudFront (CDN):用于缓存和快速访问存储在S3中的媒体文件。

要求

功能要求

功能需求定义了系统或软件应用程序应该做什么来满足用户的需求。以下是基于社交媒体系统的功能需求:

  • 发布帖子
  • 点赞、评论他人帖子
  • 关注/取消关注其他用户
  • 搜索用户
  • 用户Feed流
  • 聊天功能

非功能性需求

非功能需求指定了系统的质量,而不是具体的功能。以下是一些非功能需求:

  • 低延迟
  • 高可用性

数据模型设计

用户管理

用户数据表(user_data)

该表将存储每个用户的基本信息,例如其姓名、生日、描述、用户名、电话号码和个人资料图片。“id”属性作为主键,用于唯一标识表中的每个用户。

CREATE TABLE user_data (user_id INT AUTO_INCREMENT PRIMARY KEY,name VARCHAR(255) NOT NULL,password VARCHAR(255) NOT NULL,user_bday DATE,user_desc TEXT,user_name VARCHAR(255) NOT NULL,user_phone VARCHAR(20),user_pic VARCHAR(255)
);* user_id:每个用户的唯一标识符(主键)。
* name:用户的全名。
* user_bday:用户的出生日期。
* user_desc:用户的描述或简历。
* user_name:用户选择的用户名(应该是唯一的)。
* user_phone:用户的联系电话。
* user_pic:用户个人资料图片的文件路径或引用。  
用户-关注者表(user_follower)

对于“user_follower”表,它表示用户和他的粉丝/关注者之间的关系,它主要有以下字段:

CREATE TABLE User_Followers (id INT AUTO_INCREMENT PRIMARY KEY,follower INT,following INT,FOREIGN KEY (follower) REFERENCES user_data(user_id),FOREIGN KEY (following) REFERENCES user_data(user_id)
);* id:表中每个条目的唯一标识符(主键)。
* follower:引用关注者的用户的外键(引用 user.id)。
* following:引用被关注用户的外键(引用 user.id)。

“user_follower”表中的每条记录代表一个用户关注另一个用户。“follower”字段引用正在关注的用户(粉丝),“following”字段引用被关注的用户。“id”字段作为主键,唯一标识表中的每条记录。

帖子管理

帖子表(post_data)

对于帖子管理,“帖子”表代表用户发布的帖子,具有以下属性:

CREATE TABLE post_data (post_id INT AUTO_INCREMENT PRIMARY KEY,user_id INT,content TEXT,date_posted DATE,media VARCHAR(255),likes INT,FOREIGN KEY (user_id) REFERENCES user_data(user_id)
);* post_id:每个 帖子的唯一标识符。
* content:帖子文本内容。
* media:FileField,允许用户上传与帖子相关的媒体(例如图像、视频)。
* user_id:引用发布帖子的用户的 ForeignKey。这在 user_data 和 post_data 表之间建立了一对多关系,其中一个用户可以发布多篇帖子。这意味着单个 user_id 可以与多篇帖子相关联,但单个 post_id 不能与多个 user_id 相关联。
* likes:一个 ManyToManyField,表示对帖子的喜欢。它在 Post 和 User 表之间建立多对多关系,允许多个用户喜欢一个帖子,并且一个用户可以喜欢多个帖子。
评论表(comment)

“评论”表代表用户对特定帖子发表的评论,评论表一般具有以下字段:

CREATE TABLE Comment (comment_id INT AUTO_INCREMENT PRIMARY KEY,post_id INT,user_id INT,comment TEXT,created_date DATE,FOREIGN KEY (post_id) REFERENCES post_data(post_id),FOREIGN KEY (user_id) REFERENCES user_data(user_id)
);* comment_id:每个评论的主键。
* comment:评论内容。
* created_id:一个 DateTimeField,表示评论创建的日期和时间。
* user_id:引用发表评论的用户的外键。User 表和 Comment 表之间存在一对多关系,其中一个用户可以有多条评论。这里,单个 user_id 可以与多条评论相关联,但单个 commet_id 不能与多个用户相关联。
* post:与评论相关联的帖子,引用帖子表的主键(foreign_key)。这在帖子和评论表之间建立了一对多的关系,其中一个帖子可以有多条评论。

聊天管理

聊天消息(chat_message)

对于聊天管理,“chat_message”表代表对话线程内的单个消息,其主要字段如下:

CREATE TABLE chat_message (id INT AUTO_INCREMENT PRIMARY KEY,thread_id INT,user_id INT,message TEXT,timestamp DATE,FOREIGN KEY (thread_id) REFERENCES Thread(thread_id),FOREIGN KEY (user_id) REFERENCES User_Data(user_id)
);* id :每个聊天消息的主键。
* thread_id:引用 thread 模型的 ForeignKey。它表示消息所属的线程。 
* user_id:引用 user_data 的 ForeignKey。它代表发送消息的用户。
* message:存储消息文本内容的 CharField。
* timestamp: 存储消息创建日期和时间的 DateField
线程表(thread)

“thread”表代表两个用户之间的对话线程:

CREATE TABLE thread (thread_id INT AUTO_INCREMENT PRIMARY KEY,user1 INT,user2 INT,timestamp DATE,FOREIGN KEY (user1) REFERENCES User_Data(user_id),FOREIGN KEY (user2) REFERENCES User_Data(user_id)
);* thread_id:每个线程的主键。
* user1:引用 User 模型并代表参与对话的用户之一的 ForeignKey。
* user2:引用 User 模型并代表参与对话的其他用户的 ForeignKey。 
* timestamp: 一个 DateField,存储线程创建的日期和时间。

这里介绍下聊天管理中的Thread 模型,Thread 模型代表两个用户之间的对话。这种对话被称为线程,每个线程都有一个唯一的 thread_id 来标识。通过 Thread 模型,可以捕获两个用户之间的关系,并在这个线程中存储和组织聊天消息。每条消息通过 chat_message 表与特定的线程和发送消息的用户相关联。

举个例子,用户 A 和用户 B 进行聊天对话,那么thread 表中:

  • thread_id: 1
  • user1: 用户 A
  • user2: 用户 B
  • timestamp: 2024-07-28 10:00:00

如果A和B只进行了一来一回两次对话,那么chat_message表有2条记录:
第一条记录:

  • id: 101
  • thread: 1
  • user: 用户 A
  • message: “你好,B!”
  • timestamp: 2024-07-28 10:01:00

第二条记录:

  • id: 102
  • thread: 1
  • user: 用户 B
  • message: “你好,A!”
  • timestamp: 2024-07-28 10:02:00

用户资料和关注服务

在我们的系统设计中,用户资料服务用于处理和存储用户信息,如用户名、地址和年龄等。其他服务可以来请求用户资料服务的接口获取用户的详细信息(带上用户ID作为参数)。

另一方面,关注服务管理用户之间的关系。当一个用户关注另一个用户时,带有用户ID的API请求会发送到关注服务,后者更新其数据库。在访问用户资料时,用户资料服务需要与关注服务通信以获取其关注者和其粉丝的数量。

此外,关注服务还可以根据用户 ID 与与用户资料服务通信来获取用户详细信息,以显示关注者和被关注者的信息。

注:两个服务的代码逻辑见文末代码部分。

帖子服务与媒体管理

帖子服务会提供3个API,分别用于发布帖子,获取帖子,更新帖子:

  • /createPost (POST)
  • /getPost/:id (GET)
  • /updatePost/:id (POST)

这些请求通过 API 网关路由,然后 API 网关将它们定向到 Post 服务。Post 服务将帖子内容、用户 ID 和其他相关数据保存在数据库中。任何附带的文件或媒体都会上传到 Amazon S3(一种分布式对象存储服务)。

为了优化内容交付,我们将 CloudFront 用作 S3 前面的 CDN 层。上传文件的 URL 存储在数据库中。此外,我们可以实施 URL 缩短服务来缩短 S3 生成的长 URL。

注:帖子服务的代码逻辑见文末代码部分。

用户动态服务


在我们的系统中,用户动态服务负责为用户提供相关的动态。为了实现这一点,我们遵循一个简单的算法:我们显示他们关注的用户的最新帖子,然后是其他相关推荐。

处理数百万条帖子并直接加载数千条帖子到用户的动态中这个操作会非常昂贵,会导致高延迟。

为了解决这个问题,我们实现了分页系统。当用户向下滚动时,客户端发出类似于/getUserFeed/:userId/?offset=10/?page=page_number的API请求,其中偏移量表示要跳过的帖子数量。通过逐步加载帖子,我们减少了服务器的负载。

为了优化性能,我们在服务器上预先计算了feed,并根据客户端的请求对数据进行切片。这种方法可确保客户端收到最新的帖子,而无需过多的服务器请求。

为了让用户及时了解最新帖子,我们在用户资料服务和用户动态服务之间建立了关联。这使我们能够同步用户信息并保持相关的动态。

为了增强可扩展性,我们使用了基于最近最少使用(LRU)缓存模型的分布式缓存服务。信息流数据存储在缓存中,访问频率较低的帖子将从缓存中剔除。这种方法确保缓存中存储的最小数据,提高了系统性能和可扩展性。

后面会单独写一篇关于Feed流设计的文章。

搜索服务

搜索服务允许用户根据用户名查找其他用户。当用户使用/search/:username API 发出搜索请求时,搜索服务会通过用户输入的用户名与发出请求的用户关注的用户及其关注者的用户名进行匹配来执行搜索。此外,它还包括其他用户在搜索结果中。

上面这段话比较拗口,为了让它更容易理解,我们可以把它拆开理解,当用户在搜索框中输入一个用户名例如tom时,系统会进行以下操作:

  1. 搜索其关注的用户:首先,系统会查看当前用户tom关注的所有用户。
  2. 匹配其关注者:接着,系统会查看所有关注了用户tom的用户(即tom的粉丝)
  3. 包括其他用户:最后,系统还会在搜索结果中包括其他与输入的用户名匹配的用户,这些用户可能既不是用户关注的也不是用户的关注者。

为了检索搜索结果中的用户详细信息,搜索服务会调用个人资料服务的接口。它会获取必要的用户信息并将其纳入搜索推荐中。

为了优化性能并减少数据库查询,我们实现了缓存机制。搜索服务将最常搜索的用户名其对应的详细信息存储在分布式缓存中。这使我们能够直接从缓存中检索用户名,而不必每次都查询数据库,从而缩短响应时间并提高效率。

聊天服务

会单独写一篇关于聊天系统设计的文章。

相关代码

注:以下代码只是为了展示以上服务相关接口的主要逻辑帮助大家理解整个系统,因此没有考虑到参数校验、异常处理、性能优化等方面。

用户服务

用户服务主要有2个接口,创建新用户,查询用户。

//UserController.java
@RestController
@RequestMapping("/users")
public class UserController {@Autowiredprivate UserService userService;@GetMapping("/{userId}")public ResponseEntity<User> getUserById(@PathVariable Long userId) {User user = userService.getUserById(userId);return user != null ? ResponseEntity.ok(user) : ResponseEntity.notFound().build();}@PostMappingpublic ResponseEntity<User> createUser(@RequestBody User user) {//还有一系列新建用户的流程,如校验密码等这里省略了User savedUser = userService.saveUser(user);return ResponseEntity.status(HttpStatus.CREATED).body(savedUser);}@PostMapping("/login")public ResponseEntity<?> login(@RequestParam String userName, @RequestParam String password) {User user = userService.authenticate(userName, password);if (user != null) {return ResponseEntity.ok(user);}return ResponseEntity.status(401).body("Invalid username or password");}    
}//UserService.java
@Service
public class UserService {@Autowiredprivate UserMapper userMapper;@Autowiredprivate RedisTemplate<String, User> redisTemplate;private static final String USER_CACHE = "USER";public User getUserById(Long userId) {// Check cache firstUser user = redisTemplate.opsForValue().get(USER_CACHE + userId);if (user != null) {return user;}// Fetch from database if not in cacheuser = userMapper.selectUserById(userId);if (user != null) {redisTemplate.opsForValue().set(USER_CACHE + userId, user);}return user;}public User saveUser(User user) {// 加密密码user.setPassword(passwordEncoder.encode(user.getPassword()));userMapper.insertUser(user);redisTemplate.opsForValue().set(USER_CACHE + user.getUserId(), user);return user;}public User authenticate(String userName, String rawPassword) {User user = userMapper.getUserByName(userName);if (user != null && passwordEncoder.matches(rawPassword, user.getPassword())) {return user;}return null;}    
}

关注服务

关注服务主要提供以下几个功能:

  • 查询粉丝数量
  • 查询关注者数量
  • 关注
  • 取关
//FollowController.java
@RestController
@RequestMapping("/follows")
public class FollowController {@Autowiredprivate FollowService followService;@GetMapping("/followers/count/{userId}")public ResponseEntity<Long> countFollowers(@PathVariable Long userId) {long count = followService.countFollowers(userId);return ResponseEntity.ok(count);}@GetMapping("/following/count/{userId}")public ResponseEntity<Long> countFollowing(@PathVariable Long userId) {long count = followService.countFollowing(userId);return ResponseEntity.ok(count);}@PostMapping("/{followerId}/{followingId}")public ResponseEntity<Follow> followUser(@PathVariable Long followerId, @PathVariable Long followingId) {Follow follow = followService.followUser(followerId, followingId);return ResponseEntity.status(HttpStatus.CREATED).body(follow);}
}//FollowService.java
@Service
public class FollowService {@Autowiredprivate FollowMapper followMapper;@Autowiredprivate UserService userService;@Autowiredprivate RedisTemplate<String, Long> redisTemplate;private static final String FOLLOWERS_COUNT_CACHE = "FOLLOWERS_COUNT_";private static final String FOLLOWING_COUNT_CACHE = "FOLLOWING_COUNT_";public long countFollowers(Long userId) {String cacheKey = FOLLOWERS_COUNT_CACHE + userId;Long count = redisTemplate.opsForValue().get(cacheKey);if (count != null) {return count;}User user = userService.getUserById(userId);if (user == null) {throw new IllegalArgumentException("User not found");}count = followMapper.countFollowers(userId);redisTemplate.opsForValue().set(cacheKey, count);return count;}public long countFollowing(Long userId) {String cacheKey = FOLLOWING_COUNT_CACHE + userId;Long count = redisTemplate.opsForValue().get(cacheKey);if (count != null) {return count;}User user = userService.getUserById(userId);if (user == null) {throw new IllegalArgumentException("User not found");}count = followMapper.countFollowing(userId);redisTemplate.opsForValue().set(cacheKey, count);return count;}public Follow followUser(Long followerId, Long followingId) {User follower = userService.getUserById(followerId);User following = userService.getUserById(followingId);if (follower == null || following == null) {throw new IllegalArgumentException("User not found");}Follow follow = new Follow();follow.setFollowerId(followerId);follow.setFollowingId(followingId);followMapper.insertFollow(follow);return follow;}
}

帖子服务与媒体管理

帖子服务主要提供以下几个功能:

  • 发布帖子
  • 获取帖子
  • 更新帖子
其它配置
......
# AWS S3 Configuration
aws.s3.bucket-name=your_bucket_name
aws.s3.region=your_region
//PostController.java
@RestController
@RequestMapping("/posts")
public class PostController {@Autowiredprivate PostService postService;@PostMapping("/createPost")public ResponseEntity<Post> createPost(@RequestParam("userId") Long userId,@RequestParam("content") String content,@RequestParam("mediaFile") MultipartFile mediaFile) throws IOException {Post post = new Post();post.setUserId(userId);post.setContent(content);Post createdPost = postService.createPost(post, mediaFile);return ResponseEntity.status(HttpStatus.CREATED).body(createdPost);}@GetMapping("/getPost/{postId}")public ResponseEntity<Post> getPost(@PathVariable Long postId) {Post post = postService.getPostById(postId);return post != null ? ResponseEntity.ok(post) : ResponseEntity.notFound().build();}@PostMapping("/updatePost/{postId}")public ResponseEntity<Post> updatePost(@PathVariable Long postId,@RequestParam("content") String content,@RequestParam("mediaFile") MultipartFile mediaFile) throws IOException {Post updatedPost = new Post();updatedPost.setContent(content);Post post = postService.updatePost(postId, updatedPost, mediaFile);return ResponseEntity.ok(post);}
}//PostService.java
@Service
public class PostService {@Autowiredprivate PostMapper postMapper;@Autowiredprivate RedisTemplate<String, Post> redisTemplate;@Autowiredprivate AmazonS3 amazonS3;@Value("${aws.s3.bucket-name}")private String bucketName;private static final String POST_CACHE = "POST_";public Post getPostById(Long postId) {// Check cache firstPost post = redisTemplate.opsForValue().get(POST_CACHE + postId);if (post != null) {return post;}// Fetch from database if not in cachepost = postMapper.selectPostById(postId);if (post != null) {redisTemplate.opsForValue().set(POST_CACHE + postId, post);}//这里拿到mediaUrl后还要请求S3拿内容,这里省略了return post;}public Post createPost(Post post, MultipartFile mediaFile) throws IOException {// Upload media file to S3String mediaUrl = uploadFileToS3(mediaFile);post.setMedia(mediaUrl);post.setDatePosted(new Date());postMapper.insertPost(post);//可以进行优化:只有大V或者热门帖子才缓存下来,这样可以节省成本redisTemplate.opsForValue().set(POST_CACHE + post.getPostId(), post);return post;}public Post updatePost(Long postId, Post updatedPost, MultipartFile mediaFile) throws IOException {Post existingPost = getPostById(postId);if (existingPost == null) {throw new IllegalArgumentException("Post not found");}if (mediaFile != null && !mediaFile.isEmpty()) {String mediaUrl = uploadFileToS3(mediaFile);updatedPost.setMedia(mediaUrl);} else {updatedPost.setMedia(existingPost.getMedia());}updatedPost.setPostId(postId);updatedPost.setDatePosted(new Date());postMapper.updatePost(updatedPost);redisTemplate.opsForValue().set(POST_CACHE + postId, updatedPost);return updatedPost;}private String uploadFileToS3(MultipartFile file) throws IOException {String fileName = System.currentTimeMillis() + "_" + file.getOriginalFilename();ObjectMetadata metadata = new ObjectMetadata();metadata.setContentLength(file.getSize());amazonS3.putObject(bucketName, fileName, file.getInputStream(), metadata);return amazonS3.getUrl(bucketName, fileName).toString();}
}

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

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

相关文章

科普文:分布式数据一致性协议Paxos

1 什么是Paxos Paxos协议其实说的就是Paxos算法, Paxos算法是基于消息传递且具有高度容错特性的一致性算 法&#xff0c;是目前公认的解决分布式一致性问题最有效的算法之一。 Paxos由 莱斯利兰伯特(Leslie Lamport)于1998年在《The Part-Time Parliament》论文中首次公 开&…

Gitops-Argo-Cli安装与使用

一、安装Argo-Cli工具 Release v2.9.21 argoproj/argo-cd GitHub **选择合适的符合你操作系统以及CPU架构的二进制文件 #依v2.9.21-X86-64-Linux操作系统为例 wget https://github.com/argoproj/argo-cd/releases/download/v2.9.21/argocd-linux-amd64 #添加执行权限并且移…

论文中的流程图参考图片

写论文的时候&#xff0c;在绘制流程图时&#xff0c;一直纠结n是大写还是小写&#xff0c;用不用斜体&#xff0c;号两边要不要空格。今天找到了一张标准的流程图来参考。图片来自 Zhi-Chang Ba et al, Combination of DCE-MRI and NME-DWI via Deep Neural Network for Predi…

虚拟机复制后网络不可用,报错“network.service - LSB: Bring up/down networking”

查询IP地址&#xff0c;eth33 没有显示IP地址 尝试重启&#xff0c;有报错&#xff0c;并且有提示&#xff0c;按照提示执行下看看 解决办法 chkconfig NetworkManager offsystemctl disable NetworkManager.serviceservice NetworkManager stopservice network restart 之后检…

边缘计算网关项目(含上报进程、32Modbus采集进程、设备搜索响应进程源码)

目录 边缘层 架构说明 包含知识点 数据上报进程 功能描述 功能开发 上报线程 数据存储线程 指令处理线程 项目源码 上报模块.c代码&#xff1a; 上报模块Makefile代码&#xff1a; STM32采集模块.c代码 设备搜索响应模块Linux部分.c代码 设备搜索响应模块Qt端代码.h …

C语言画蜡烛图

GPT-4o (OpenAI) 在C语言中&#xff0c;绘制蜡烛图&#xff08;Candlestick Chart&#xff09;不是直接的任务&#xff0c;因为C语言本身不包含高级图形绘制库。然而&#xff0c;可以通过某些图形库来完成这项任务&#xff0c;例如使用GTK、SDL、OpenGL等。 以下是通过GTK库绘…

Hive3:Hive初体验

1、创建表 CREATE TABLE test(id INT, name STRING, gender STRING);2、新增数据 INSERT INTO test VALUES(1, 王力红, 男); INSERT INTO test VALUES(2, 钉钉盯, 女); INSERT INTO test VALUES(3, 咔咔咔, 女);3、查询数据 简单查询 select * from test;带聚合函数的查询 …

论文写作之latex配置(VSCODE+TEXT LIVE)

1.overleaf 初学者学习latex可以用这个练习&#xff0c;可以在线编辑十分方便&#xff0c;但是编译时间受限制 网站&#xff1a;https://www.overleaf.com/project 2.Tex live 选择一个.iso文件下载 网站&#xff1a;Index of /CTAN/systems/texlive/Images/ 下载成功&am…

2024第三届钉钉杯大学生大数据挑战赛【A题】完整分享

2024第三届钉钉杯大学生大数据挑战赛已经开赛&#xff0c;小编给大家带来非常实用的助力【A题】完整&#xff0c;&#xff08;看图片下方的说明&#xff09;&#xff0c;资料预览&#xff1a; 微信公众号

进阶篇,内附代码:锂电池二阶模型-离线与在线参数辨识

锂电池二阶模型-在线参数辨识 背景二阶等效电路模型介绍二阶模型的离线参数辨识二阶模型的RLS表达式递推代码已知问题背景 锂电池一阶戴维南等效模型的参数辨识方法,已经在前面两期详细地讲解了一轮。 一阶模型-离线参数辨识一阶模型-在线参数辨识本期继续讲解一下如何进行二…

多线程初阶(三)- 线程案例

目录 1.单例模式 &#xff08;1&#xff09;饿汉模式 &#xff08;2&#xff09;懒汉模式 前言 懒汉式1-synchronized加锁 懒汉式2-双重if保障 懒汉式3-volatile防止误判 2.生产者消费者模型 &#xff08;1&#xff09;阻塞队列 &#xff08;2&#xff09;优点 解耦…

鸿蒙OpenHarmony Native API【结构体】 头文件

OH_Drawing_BitmapFormat Overview Related Modules: [Drawing] Description: 结构体用于描述位图像素的格式&#xff0c;包括颜色类型和透明度类型 Since: 8 Version: 1.0 Summary Public Attributes Public Attribute NameDescriptioncolorFormatalphaFormat De…

PlantUML学习笔记-嵌入式系统设计常用图例

在嵌入式系统设计过程中&#xff0c;需要使用一些图例对系统框架及业务流程进行说明&#xff0c;以便于多人协同开发及后期的系统维护&#xff0c;提高团队开发效率。 1. 嵌入式设计开发常使用的图例&#xff1a; 1.1 用例图&#xff08;Use Case Diagram&#xff09; 用例图…

KamaCoder 99. 岛屿数量 + Leetcode 200. Number of Islands

99. 岛屿数量 题目描述&#xff1a; 给定一个由 1&#xff08;陆地&#xff09;和 0&#xff08;水&#xff09;组成的矩阵&#xff0c;你需要计算岛屿的数量。岛屿由水平方向或垂直方向上相邻的陆地连接而成&#xff0c;并且四周都是水域。你可以假设矩阵外均被水包围。 输…

【LeetCode】栈 - 20.有效的括号、150.逆波兰表达式求值、155.最小栈、栈的压入、弹出序列

Hi~&#xff01;这里是奋斗的明志&#xff0c;很荣幸您能阅读我的文章&#xff0c;诚请评论指点&#xff0c;欢迎欢迎 ~~ &#x1f331;&#x1f331;个人主页&#xff1a;奋斗的明志 &#x1f331;&#x1f331;所属专栏&#xff1a;数据结构 &#x1f4da;本系列文章为个人学…

【前端/js】使用js读取本地文件(xml、二进制)内容

目录 说在前面FileReaderDOMParser文本文件二进制文件 说在前面 浏览器版本&#xff1a;Microsoft Edge 126.0.2 (正式版本) (64 位) FileReader MDNFileReader 接口允许 Web 应用程序异步读取存储在用户计算机上的文件&#xff08;或原始数据缓冲区&#xff09;的内容&#x…

分布式光伏并网AM5SE-IS防孤岛保护装置介绍——安科瑞 叶西平

产品简介 功能&#xff1a; AM5SE-IS防孤岛保护装置主要适用于35kV、10kV及低压380V光伏发电、燃气发电等新能源并网供电系统。当发生孤岛现象时&#xff0c;可以快速切除并网点&#xff0c;使本站与电网侧快速脱离&#xff0c;保证整个电站和相关维护人员的生命安全。 应用…

模拟实现c++中的vector模版

目录 一vector简述&#xff1a; 二vector的一些接口函数&#xff1a; 1初始化&#xff1a; 2.vector增长&#xff1a; 3vector增删查改&#xff1a; 三vector模拟实现部分主要函数&#xff1a; 1.size,capacity,empty,clear接口&#xff1a; 2.reverse的实现&#xff1…

Golang | Leetcode Golang题解之第292题Nim游戏

题目&#xff1a; 题解&#xff1a; func canWinNim(n int) bool {return n%4 ! 0 }

【一图学技术】SDK和API有什么关系?

API&#xff08;应用程序编程接口&#xff09;&#xff1a; API是一组定义了软件组件之间交互的规则和协议。 它定义了如何请求某个功能或服务&#xff0c;并指定了数据的格式和传输方式。API 可以用于不同的编程语言和平台。 API提供了一种标准化的方式&#xff0c;使不同的应…