025-从零搭建微服务-文件服务(一)

写在最前

如果这个项目让你有所收获,记得 Star 关注哦,这对我是非常不错的鼓励与支持。

源码地址(后端):https://gitee.com/csps/mingyue

源码地址(前端):https://gitee.com/csps/mingyue-ui

文档地址:https://gitee.com/csps/mingyue/wikis

对象存储服务

对象存储服务(Object Storage Service,简称 OSS)是一种云计算服务,用于存储和管理大规模数据、多媒体文件、备份和归档数据等。它采用了对象存储的方式,将数据以对象的形式存储在云端,并为用户提供了可靠、高可用、高扩展性、低成本的存储解决方案。

以下是对象存储服务的一些关键特点和功能:

  1. 无限扩展性: 对象存储服务具有高度的扩展性,用户可以根据需要动态扩展存储容量,无需关心硬件限制。
  2. 高可用性: 数据在多个地理位置和设备上复制存储,以确保数据的高可用性。如果某个存储节点发生故障,系统会自动切换到备用节点,以保证数据不丢失。
  3. 数据安全: 对象存储服务提供多层次的数据安全措施,包括数据加密、访问控制、身份验证、审计日志等,以确保数据的安全性和隐私性。
  4. 低成本: 对象存储服务采用了灵活的计费模型,用户只需支付实际使用的存储容量和数据传输流量,没有预付费要求。
  5. 多种数据类型支持: 用户可以在对象存储服务上存储各种类型的数据,包括文本、图像、音频、视频、备份文件等。
  6. 数据管理: 提供了丰富的数据管理功能,如数据迁移、数据备份、数据归档、数据版本控制等,使用户能够有效管理存储的数据。
  7. 云端计算集成: 可与云计算服务(如云服务器 ECS、云函数 Function Compute 等)无缝集成,以支持构建更强大的云端应用和解决方案。

对象存储服务通常用于各种云计算场景,包括网站托管、数据备份和恢复、多媒体存储和分发、大数据分析等。它提供了可靠的数据存储和管理解决方案,帮助用户降低存储成本、提高数据可用性,并支持灵活的数据访问和操作。

国内常用的 OSS 服务

  1. 阿里云 OSS(Object Storage Service): 阿里云的 OSS 是中国领先的对象存储服务,提供高可用性、高可靠性、高扩展性的存储解决方案。它支持多种数据类型的存储,具有数据安全和数据管理功能。OSS 也支持多区域部署,以确保数据的高可用性。
  2. 腾讯云 COS(Cloud Object Storage): 腾讯云的 COS 是一个可扩展的对象存储服务,具有高度的可用性和安全性。它支持多媒体文件存储、备份和归档数据,还可以与其他腾讯云服务无缝集成,用于构建各种应用。
  3. 华为云 OBS(Object Storage Service): 华为云的 OBS 是一种高性能、高可用性的对象存储服务,适用于大规模数据存储和管理。它支持数据多副本存储、数据加密、数据版本控制等功能,以确保数据的安全性和可用性。

开源的 OSS 服务

  1. Ceph: Ceph 是一个开源的分布式存储系统,它提供了对象存储、块存储和文件存储的功能。Ceph 的对象存储部分被称为 RADOS(可扩展可自修复的对象存储),它具有高度的可扩展性和可用性。Ceph 可以在私有云环境中部署,也可以与公共云服务集成。
  2. Minio: Minio 是一个开源的对象存储服务器,专注于提供 S3 兼容的存储服务。它易于部署和管理,支持多种操作系统和云平台。Minio 可以用于构建私有云对象存储解决方案或者作为开发和测试环境中的对象存储服务器。
  3. Swift: Swift 是由 OpenStack 社区开发的对象存储服务,特别适用于构建大规模分布式存储基础设施。它提供了 RESTful API,可用于存储和检索数据,支持多租户和数据冗余。
  4. OpenIO: OpenIO 是一个面向对象存储和数据管理的开源平台,具有高可用性和可扩展性。它支持多种存储介质,包括硬盘、固态硬盘和内存,并且可以自动优化数据存储和检索。
  5. Rook: Rook 是一个云原生存储编排框架,它可以用来管理和部署各种存储解决方案,包括 Ceph、Minio 和 NFS 等。Rook 可以轻松地将这些存储解决方案集成到 Kubernetes 集群中,以支持容器化应用程序的持久性存储需求。

愿景

本文件服务将兼容所有S3协议的云厂商均支持,测试集成厂商如下:Minio、阿里云 OSS(aliyun)、七牛Kodo(qiniu)、腾讯 COS(qcloud)

接下来先从 Minio 开始~

Minio

Minio 是一个开源的对象存储服务器,专注于提供 S3 兼容的存储服务。Minio 的主要用途包括构建私有云对象存储解决方案、存储和管理大规模数据、备份和归档数据、构建容器化应用程序的持久性存储等。它是一个强大而灵活的对象存储服务器,适用于各种不同的应用和场景。

它具有以下主要特点和功能:

  1. S3 兼容性: Minio 完全兼容 Amazon S3 的 API,这意味着您可以使用现有的 S3 客户端工具和库来与 Minio 进行交互。这使得迁移到 Minio 或者在 Minio 上构建应用程序变得非常容易。
  2. 易于部署: Minio 非常容易部署和配置。您可以在各种操作系统上安装 Minio,包括 Linux、macOS 和 Windows。此外,Minio 还提供了 Docker 镜像,可以轻松地在容器中运行。
  3. 高可用性: Minio 支持分布式部署,可以创建多个节点,以提供高可用性和容错性。如果一个节点发生故障,数据仍然可以通过其他节点访问。
  4. 数据安全: Minio 支持数据加密,您可以选择在传输和存储数据时启用加密,以确保数据的安全性。此外,Minio 还支持访问控制,允许您定义访问策略和权限。
  5. 灵活的存储后端: Minio 支持多种存储后端,包括本地磁盘、分布式文件系统(如GlusterFS、Ceph)和云存储(如Amazon S3、Google Cloud Storage)。这使得 Minio 适用于不同的部署需求。
  6. 监控和日志: Minio 提供了监控和日志功能,可以帮助您跟踪存储的使用情况、性能指标和错误日志,以便及时发现和解决问题。
  7. 社区支持: Minio 拥有活跃的开源社区,提供了丰富的文档、教程和支持资源,以帮助用户更好地使用和管理 Minio。

Docker 部署 Minio

docker-compose 部署 minio,版本 RELEASE.2023-09-04T19-57-37Z

version: '3.8'
services:  mingyue-minio:image: minio/minio:RELEASE.2023-09-04T19-57-37Zcontainer_name: mingyue-minioports:- 5000:9000 # api 端口- 5001:9001 # 控制台端口environment:MINIO_ACCESS_KEY: minioadmin  #管理后台用户名MINIO_SECRET_KEY: minioadmin  #管理后台密码,最小8个字符volumes:- ./minio/data:/data              #映射当前目录下的data目录至容器内/data目录- ./minio/config:/root/.minio/     #映射配置目录command: server --console-address ':9001' /data  #指定容器中的目录 /dataprivileged: truerestart: always

登录访问

访问地址用户名密码
http://mingyue-minio:5001/loginminioadminminioadmin

image-20230908135008015

创建桶

image-20230908140111214

上传测试

image-20230908140424709

上传完成

image-20230908140536053

访问测试

http://minio服务器ip:5000/存储目录/文件名

http://mingyue-minio:5000/mingyue/logo_sm.jpg,页面报错,因为匿名(游客没登录)用户没有访问权限

This XML file does not appear to have any style information associated with it. The document tree is shown below.
<Error><Code>AccessDenied</Code><Message>Access Denied.</Message><Key>logo_sm.jpg</Key><BucketName>mingyue</BucketName><Resource>/mingyue/logo_sm.jpg</Resource><RequestId>1782D77A870F45C7</RequestId><HostId>dd9025bab4ad464b049177c95eb6ebf374d3b3fd1af9251148b658df7ac2e3e8</HostId>
</Error>

如果我们需要我们上传的文件可以被匿名用户访问,那么需要添加访问权限 - Anonymous Access

再次访问测试,就可以看到上传的图片了

image-20230908144619076

创建 Access Key

Access Key 用于后续接口调用的身份认证使用。例:

Access Key:d6zVm5AP07uGCqSmsTxe

Secret Key:Vsm6qQDHgGchukEpyEoeX3dTe7fic60nTi8D9a0I

image-20230911140012528

新建 mingyue-common-oss 模块

添加依赖

<dependencies><dependency><groupId>com.csp.mingyue</groupId><artifactId>mingyue-common-core</artifactId></dependency><dependency><groupId>com.amazonaws</groupId><artifactId>aws-java-sdk-s3</artifactId></dependency>
</dependencies>

创建配置类

@Data
@ConfigurationProperties(prefix = "oss")
public class OssProperties {/*** 配置key*/private String configKey;/*** 域名*/private String endpoint;/*** 自定义域名*/private String domain;/*** 前缀*/private String prefix;/*** ACCESS_KEY*/private String accessKey;/*** SECRET_KEY*/private String secretKey;/*** 存储空间名*/private String bucketName;/*** 存储区域*/private String region;/*** 是否https(Y:是;N:否)*/private String isHttps;/*** 桶权限类型(0:private;1:public;2:custom)*/private String accessPolicy;}

新建 mingyue-oss-biz.yml Nacos 配置

# 文件服务配置
oss:configKey: minioendpoint: mingyue-minio:5000domain:prefix:accessKey: d6zVm5AP07uGCqSmsTxesecretKey: Vsm6qQDHgGchukEpyEoeX3dTe7fic60nTi8D9a0IbucketName: mingyueregion: isHttps: NaccessPolicy: 1

编写 Oss Client

所有兼容S3协议的云厂商均支持(阿里云 腾讯云 七牛云 minio)

public class OssClient {private final String configKey;private final OssProperties properties;private final AmazonS3 client;public OssClient(String configKey, OssProperties ossProperties) {this.configKey = configKey;this.properties = ossProperties;try {AwsClientBuilder.EndpointConfiguration endpointConfig = new AwsClientBuilder.EndpointConfiguration(properties.getEndpoint(), properties.getRegion());AWSCredentials credentials = new BasicAWSCredentials(properties.getAccessKey(), properties.getSecretKey());AWSCredentialsProvider credentialsProvider = new AWSStaticCredentialsProvider(credentials);ClientConfiguration clientConfig = new ClientConfiguration();if (OssConstant.IS_HTTPS.equals(properties.getIsHttps())) {clientConfig.setProtocol(Protocol.HTTPS);}else {clientConfig.setProtocol(Protocol.HTTP);}AmazonS3ClientBuilder build = AmazonS3Client.builder().withEndpointConfiguration(endpointConfig).withClientConfiguration(clientConfig).withCredentials(credentialsProvider).disableChunkedEncoding();if (!StrUtil.containsAny(properties.getEndpoint(), OssConstant.CLOUD_SERVICE)) {// minio 使用https限制使用域名访问 需要此配置 站点填域名build.enablePathStyleAccess();}this.client = build.build();createBucket();}catch (Exception e) {if (e instanceof OssException) {throw e;}throw new OssException("配置错误! 请检查系统配置:[" + e.getMessage() + "]");}}public void createBucket() {try {String bucketName = properties.getBucketName();if (client.doesBucketExistV2(bucketName)) {return;}CreateBucketRequest createBucketRequest = new CreateBucketRequest(bucketName);AccessPolicyType accessPolicy = getAccessPolicy();createBucketRequest.setCannedAcl(accessPolicy.getAcl());client.createBucket(createBucketRequest);client.setBucketPolicy(bucketName, getPolicy(bucketName, accessPolicy.getPolicyType()));}catch (Exception e) {throw new OssException("创建Bucket失败, 请核对配置信息:[" + e.getMessage() + "]");}}public UploadResult upload(byte[] data, String path, String contentType) {return upload(new ByteArrayInputStream(data), path, contentType);}public UploadResult upload(InputStream inputStream, String path, String contentType) {if (!(inputStream instanceof ByteArrayInputStream)) {inputStream = new ByteArrayInputStream(IoUtil.readBytes(inputStream));}try {ObjectMetadata metadata = new ObjectMetadata();metadata.setContentType(contentType);metadata.setContentLength(inputStream.available());PutObjectRequest putObjectRequest = new PutObjectRequest(properties.getBucketName(), path, inputStream,metadata);// 设置上传对象的 Acl 为公共读putObjectRequest.setCannedAcl(getAccessPolicy().getAcl());client.putObject(putObjectRequest);}catch (Exception e) {throw new OssException("上传文件失败,请检查配置信息:[" + e.getMessage() + "]");}return UploadResult.builder().fileUrl(getUrl() + "/" + path).fileName(path).build();}public UploadResult upload(File file, String path) {try {PutObjectRequest putObjectRequest = new PutObjectRequest(properties.getBucketName(), path, file);// 设置上传对象的 Acl 为公共读putObjectRequest.setCannedAcl(getAccessPolicy().getAcl());client.putObject(putObjectRequest);}catch (Exception e) {throw new OssException("上传文件失败,请检查配置信息:[" + e.getMessage() + "]");}return UploadResult.builder().fileUrl(getUrl() + "/" + path).fileName(path).build();}public void delete(String path) {path = path.replace(getUrl() + "/", "");try {client.deleteObject(properties.getBucketName(), path);}catch (Exception e) {throw new OssException("删除文件失败,请检查配置信息:[" + e.getMessage() + "]");}}public UploadResult uploadSuffix(byte[] data, String suffix, String contentType) {return upload(data, getPath(properties.getPrefix(), suffix), contentType);}public UploadResult uploadSuffix(InputStream inputStream, String suffix, String contentType) {return upload(inputStream, getPath(properties.getPrefix(), suffix), contentType);}public UploadResult uploadSuffix(File file, String suffix) {return upload(file, getPath(properties.getPrefix(), suffix));}/*** 获取文件元数据* @param path 完整文件路径*/public ObjectMetadata getObjectMetadata(String path) {path = path.replace(getUrl() + "/", "");S3Object object = client.getObject(properties.getBucketName(), path);return object.getObjectMetadata();}public InputStream getObjectContent(String path) {path = path.replace(getUrl() + "/", "");S3Object object = client.getObject(properties.getBucketName(), path);return object.getObjectContent();}public String getUrl() {String domain = properties.getDomain();String endpoint = properties.getEndpoint();String header = OssConstant.IS_HTTPS.equals(properties.getIsHttps()) ? "https://" : "http://";// 云服务商直接返回if (StrUtil.containsAny(endpoint, OssConstant.CLOUD_SERVICE)) {if (StrUtil.isNotBlank(domain)) {return header + domain;}return header + properties.getBucketName() + "." + endpoint;}// minio 单独处理if (StrUtil.isNotBlank(domain)) {return header + domain + "/" + properties.getBucketName();}return header + endpoint + "/" + properties.getBucketName();}public String getPath(String prefix, String suffix) {// 生成uuidString uuid = IdUtil.fastSimpleUUID();// 文件路径String path = DateUtil.today() + "/" + uuid;if (StrUtil.isNotBlank(prefix)) {path = prefix + "/" + path;}return path + suffix;}public String getConfigKey() {return configKey;}/*** 获取私有 URL 链接* @param objectKey 对象KEY* @param second 授权时间*/public String getPrivateUrl(String objectKey, Integer second) {GeneratePresignedUrlRequest generatePresignedUrlRequest = new GeneratePresignedUrlRequest(properties.getBucketName(), objectKey).withMethod(HttpMethod.GET).withExpiration(new Date(System.currentTimeMillis() + 1000L * second));URL url = client.generatePresignedUrl(generatePresignedUrlRequest);return url.toString();}/*** 检查配置是否相同*/public boolean checkPropertiesSame(OssProperties properties) {return this.properties.equals(properties);}/*** 获取当前桶权限类型* @return 当前桶权限类型 code*/public AccessPolicyType getAccessPolicy() {return AccessPolicyType.getByType(properties.getAccessPolicy());}private static String getPolicy(String bucketName, PolicyType policyType) {StringBuilder builder = new StringBuilder();builder.append("{\n\"Statement\": [\n{\n\"Action\": [\n");if (policyType == PolicyType.WRITE) {builder.append("\"s3:GetBucketLocation\",\n\"s3:ListBucketMultipartUploads\"\n");}else if (policyType == PolicyType.READ_WRITE) {builder.append("\"s3:GetBucketLocation\",\n\"s3:ListBucket\",\n\"s3:ListBucketMultipartUploads\"\n");}else {builder.append("\"s3:GetBucketLocation\"\n");}builder.append("],\n\"Effect\": \"Allow\",\n\"Principal\": \"*\",\n\"Resource\": \"arn:aws:s3:::");builder.append(bucketName);builder.append("\"\n},\n");if (policyType == PolicyType.READ) {builder.append("{\n\"Action\": [\n\"s3:ListBucket\"\n],\n\"Effect\": \"Deny\",\n\"Principal\": \"*\",\n\"Resource\": \"arn:aws:s3:::");builder.append(bucketName);builder.append("\"\n},\n");}builder.append("{\n\"Action\": ");switch (policyType) {case WRITE:builder.append("[\n\"s3:AbortMultipartUpload\",\n\"s3:DeleteObject\",\n\"s3:ListMultipartUploadParts\",\n\"s3:PutObject\"\n],\n");break;case READ_WRITE:builder.append("[\n\"s3:AbortMultipartUpload\",\n\"s3:DeleteObject\",\n\"s3:GetObject\",\n\"s3:ListMultipartUploadParts\",\n\"s3:PutObject\"\n],\n");break;default:builder.append("\"s3:GetObject\",\n");break;}builder.append("\"Effect\": \"Allow\",\n\"Principal\": \"*\",\n\"Resource\": \"arn:aws:s3:::");builder.append(bucketName);builder.append("/*\"\n}\n],\n\"Version\": \"2012-10-17\"\n}\n");return builder.toString();}}

编写 Oss Factory

采用工厂设计,为后续引入阿里云、腾讯云、七牛云等不同OSS服务做准备

@Slf4j
@Component
@RequiredArgsConstructor
public class OssFactory {private static final Map<String, OssClient> CLIENT_CACHE = new ConcurrentHashMap<>();private final OssProperties ossProperties;/*** 获取实例*/public OssClient instance() {String configKey = ossProperties.getConfigKey();// 配置不相同则重新构建CLIENT_CACHE.put(configKey, new OssClient(configKey, ossProperties));log.info("创建 OSS 实例 key => {}", configKey);return CLIENT_CACHE.get(configKey);}}

OSS 文件服务

OSS 对象存储服务逻辑接口实现

@Override
public SysOssVo upload(MultipartFile file) {String originalFilename = file.getOriginalFilename();String suffix = StrUtil.sub(originalFilename, originalFilename.lastIndexOf("."), originalFilename.length());OssClient storage = ossFactory.instance();UploadResult uploadResult;try {uploadResult = storage.uploadSuffix(file.getBytes(), suffix, file.getContentType());}catch (IOException e) {throw new ServiceException(e.getMessage());}// 保存文件信息SysOssVo vo = new SysOssVo();BeanUtil.copyProperties(uploadResult, vo);vo.setOssId(System.currentTimeMillis());return vo;
}

对象存储服务

@Slf4j
@Tag(name = "对象存储服务")
@RestController
@RequestMapping("oss")
@RequiredArgsConstructor
public class OssController {private final OssService ossService;@PostMapping(value = "/upload", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)@Operation(summary = "上传文件")public R<UploadVo> upload(@RequestPart("file") MultipartFile file) {if (ObjectUtil.isNull(file)) {return R.fail("上传文件不能为空");}SysOssVo oss = ossService.upload(file);UploadVo vo = new UploadVo();vo.setFileUrl(oss.getUrl());vo.setFileName(oss.getFileName());vo.setOssId(oss.getOssId());return R.ok(vo);}}

启动服务

启动服务,打开接口文档,上传文件测试

http://mingyue-gateway:9100/webjars/swagger-ui/index.html?urls.primaryName=oss#/%E5%AF%B9%E8%B1%A1%E5%AD%98%E5%82%A8%E6%9C%8D%E5%8A%A1/upload

成功后接口返回如下:

{"code": 200,"msg": "操作成功","data": {"fileUrl": "http://mingyue-minio:5000/mingyue/2023-09-11/a6987303827148b983c84ac415240480.png","fileName": "2023-09-11/a6987303827148b983c84ac415240480.png","ossId": 1694414731976}
}

改进空间

1. 上传文件后未保存文件信息,无法溯源

解决方案:添加 OSS 文件存储表

2. 配置通过 Nacos 单一 OSS 服务支持

解决方案:添加 OSS 配置表

小结

本节完成了 Minio 的部署,并且通过编码的方式将文件上传至 Minio。接下来先围绕【改进空间】优化上传服务,然后再接入其他 OSS 存储服务,逐步完善文件服务。

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

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

相关文章

c#查看代码的执行耗时( Stopwatch )

我们如果需要看某段代码的执行耗时&#xff0c;会通过如下的方式进行查看 using System.Diagnostics; private void button1_Click(object sender, EventArgs e){Stopwatch sw Stopwatch.StartNew();//sw.Start();StringBuilder sb new StringBuilder();for(int i 0; i <…

楼顶空地适合建造气膜体育馆吗?

众所周知&#xff0c;传统建筑的荷载太大&#xff0c;出于安全考虑&#xff0c;是不适合继续在楼顶加盖传统结构体育馆的&#xff0c;但是&#xff0c;气膜体育馆作为一种装配式建筑&#xff0c;它是可以在城市高空上建造一个轻盈又新颖独特的全天候气膜馆。 气膜体育馆作为一种…

Pixillion Pro for Mac:将您的图像转换为艺术佳作

Pixillion for Mac有着非常强大的图像转换功能和简单的使用方法&#xff0c;帮助你快速完成大批量图像转换的工作&#xff0c;支持一键转换jpeg、jpg、bmp、png、gif、raf、heic等各种格式的图像文件&#xff0c;同时pixillion mac激活版还提供了图像旋转、添加水印、调整图像大…

原型-设计模式

原型设计模式 原型模式应用场景&#xff1a;创建一个对象比较复杂&#xff0c;当前存在一个和需要创建的对象极其相似&#xff0c;我们就可以采用原型模式&#xff0c;在原来的对象上进行一个修改。 修改方案&#xff1a;在原来的基础上进行拷贝&#xff0c;在进行部分的修改。…

Spring Boot 中的 @CacheEvict 注解使用

Spring Boot 中的 CacheEvict 注解 在 Spring Boot 中&#xff0c;缓存是提高应用性能的重要手段。为了更好地管理缓存&#xff0c;Spring Boot 提供了一系列的缓存注解&#xff0c;其中 CacheEvict 注解用于清空缓存。 本文将介绍 CacheEvict 注解的含义、原理以及如何使用。…

【LeetCode-中等题】34. 在排序数组中查找元素的第一个和最后一个位置

文章目录 题目方法一&#xff1a;二分查找&#xff08;先找到mid&#xff0c;在根据mid确定左右区间&#xff09;方法二&#xff1a;分两次二分查找&#xff0c;一次用于找左区间&#xff0c;一次用于找右区间 题目 方法一&#xff1a;二分查找&#xff08;先找到mid&#xff0…

Apache HTTPD 多后缀名解析漏洞复现

什么是多后缀名解析漏洞加粗样式: 多后缀名解析漏洞&#xff08;Multiple Extension Handling Vulnerability&#xff09;指的是一种安全漏洞&#xff0c;发生在某些操作系统或网络服务中的文件扩展名处理机制中。 这种漏洞的本质是当文件具有多个后缀名&#xff08;例如file.…

MT4移动端应用指南:随时随地进行交易

如今&#xff0c;随着科技的不断发展&#xff0c;我们可以随时随地通过手机进行各种操作&#xff0c;包括进行金融交易。本文将为大家介绍一款优秀的金融交易软件——MT4&#xff08;可在mtw.so/6gwPno这点下&#xff09;移动端应用&#xff0c;并提供详细的使用指南&#xff0…

合宙Air724UG LuatOS-Air LVGL API控件-加载器(Spinner)

加载器(Spinner) 示例代码 spinner lvgl.spinner_create(lvgl.scr_act(), nil) lvgl.obj_set_size(spinner, 100, 100) lvgl.obj_align(spinner, nil, lvgl.ALIGN_CENTER, 0, 0) 创建 通过 lvgl.spinner_create 就可创建一个加载器&#xff0c;本身自带动画效果。 spinner …

同步FIFO的verilog实现(2)——高位扩展法

一、前言 在之前的文章中&#xff0c;我们介绍了同步FIFO的verilog的一种实现方法&#xff1a;计数法。其核心在于&#xff1a;在同步FIFO中&#xff0c;我们可以很容易的使用计数来判断FIFO中还剩下多少可读的数据&#xff0c;从而可以判断空、满。 关于计数法实现同步FIFO的详…

【数据库】MySQL基础知识全解

系列综述&#xff1a; &#x1f49e;目的&#xff1a;本系列是个人整理为了秋招面试的&#xff0c;整理期间苛求每个知识点&#xff0c;平衡理解简易度与深入程度。 &#x1f970;来源&#xff1a;材料主要源于拓跋阿秀、小林coding等大佬博客进行的&#xff0c;每个知识点的修…

企业架构LNMP学习笔记30

1、upstream 中server的关键字&#xff1a;语法&#xff1a; upstream中的分发之后的几个关键字&#xff1a; 1&#xff09;backup 备 其他的没有backup标识的都不可用了&#xff0c;才分发到backup&#xff1b; 2&#xff09;down 此条配置&#xff0c;不会被分发到。 syst…

OmniGraffle Pro for Mac 中文正式版(附注册码) 苹果电脑 思维导图软件

OmniGraffle Pro是OmniGraffle的高级版本&#xff0c;它提供了更多的功能和工具&#xff0c;可以帮助用户创建更为复杂和高级的图表和流程图。OmniGraffle Pro支持自定义形状、图形、线条和箭头等&#xff0c;可以让用户创建出更加精细的图表。此外&#xff0c;OmniGraffle Pro…

字符编码(idea)

File----------settings-------------Editor------------File Encodings

详细解析如何用“双指针“解题(面试必备,小白一看就会系类)

一、前言 大家在平时的训练和交流中肯定多少都会听过或者见过用"双指针"去快速的解题&#xff0c;那么大家有没有想过&#xff0c;为什么要用"双指针"呢&#xff1f;这里的"双指针"和我们平时了解的指针一样吗&#xff1f; 其实&#xff0c;这里…

永辉上半年净利润扭亏为盈,是“科技重启”的功劳吗?

你有多久没逛超市了&#xff1f;你记忆中的超市是怎样的&#xff1f;现在逛超市的原因又是什么&#xff1f; 其实&#xff0c;对于很多年轻人来说&#xff0c;现在的“快递点”就是“新时代超市”。而传统“超市”“大卖场”被新型超市、电商抢走不少人流量后&#xff0c;逐渐…

个人主页网站动态星空背景源码(带后台版本)

动态星空背景个人主页网站源码是一种用于创建个人主页的开源项目。它具有一个令人印象深刻的动态星空背景&#xff0c;为用户提供了一个独特而吸引人的网页设计。此源码还包含一个后台版本&#xff0c;使用户能够轻松管理和更新他们的个人主页内容。 通过该源码&#xff0c;用…

亿发软件:智慧门店商超系统,2023新零售POS数字运营一体化管理

2023年9月6日&#xff0c;山东济宁一家超市因为酸奶价格标签错误而引发了广泛关注。标签原本显示几十个人为9.9元&#xff0c;但特价销售价却标为10元。这一小小的错误却在社交媒体上引发了轩然大波&#xff0c;让超市一度处于舆论的风口浪尖。超市工作人员回应&#xff0c;表示…

华为云云耀云服务器L实例评测 | 华为云云耀云服务器L实例使用教学

文章目录 前言一、登录华为云二、创建云服务器L实例三、登录云服务器L实例四、使用云服务器L实例后记 前言 华为云是中国领先的云计算服务提供商之一&#xff0c;旗下的云耀云服务器是一种高性能、高可靠性、灵活可扩展的云服务器。 下面&#xff0c;我将为大家介绍华为云云耀云…

【算法】希尔 (Shell) 排序 详解

希尔排序 详解 希尔排序代码实现 排序&#xff1a; 排序&#xff0c;就是使一串记录&#xff0c;按照其中的某个或某些关键字的大小&#xff0c;递增或递减的排列起来的操作。 稳定性&#xff1a; 假定在待排序的记录序列中&#xff0c;存在多个具有相同的关键字的记录&#x…