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

Minio文件分片上传实现

资源准备
MacM1Pro 安装Parallels19.1.0请参考 https://blog.csdn.net/qq_41594280/article/details/135420241
MacM1Pro Parallels安装CentOS7.9请参考 https://blog.csdn.net/qq_41594280/article/details/135420461
部署Minio和整合SpringBoot请参考 https://blog.csdn.net/qq_41594280/article/details/135613722

Minio Paralles虚拟机文件百度网盘获取地址: MinioParallelsVMFile
代码(含前后端)可参考 minio-chunk-upload-demo

# 1.ide拉取代码启动(AppMain)后端服务
# 2.cd vue-minio-upload-sample
# 3.npm install
# 4.npm run dev
# 5.访问 http:127.0.0.1:8080 进行测试

一、准备表结构

1.1 文件上传信息表

CREATE TABLE minio_file_upload_info(`id` BIGINT(20) PRIMARY KEY AUTO_INCREMENT NOT NULL COMMENT '自增主键',`file_name` VARCHAR(255) NOT NULL DEFAULT '' COMMENT '文件名称',`file_md5` VARCHAR(128) NOT NULL DEFAULT '' COMMENT '文件MD5',`upload_id` VARCHAR(128) NOT NULL DEFAULT '' COMMENT '文件上传Id',`file_url` VARCHAR(255) NOT NULL DEFAULT '' COMMENT '文件路径',`total_chunk` INT(10) NOT NULL DEFAULT 0 COMMENT '文件总分块数',`file_status` VARCHAR(50) NOT NULL DEFAULT '' COMMENT '文件状态',`update_time` DATETIME DEFAULT NULL COMMENT '修改时间') ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='文件上传信息';

1.2 分块上传信息表

CREATE TABLE minio_chunk_upload_info(`id` BIGINT(20) PRIMARY KEY AUTO_INCREMENT NOT NULL COMMENT '自增主键',`chunk_number` INT(10) NOT NULL DEFAULT 0 COMMENT '文件分片号',`file_md5` VARCHAR(128) NOT NULL DEFAULT '' COMMENT '文件MD5',`upload_id` VARCHAR(128) NOT NULL DEFAULT '' COMMENT '文件上传Id',`chunk_upload_url` VARCHAR(1000) NOT NULL DEFAULT '' COMMENT '文件分片路径',`expiry_time` DATETIME DEFAULT NULL COMMENT '失效时间') ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='文件分片信息';

二、Minio文件相关基操

2.1 Entity

/*** 文件上传信息*/
@TableName(schema = "minio_demo", value = "minio_file_upload_info")
@Data
public class MinioFileUploadInfo {/*** 自增ID*/@TableId(type = IdType.AUTO)private Long id;/*** 文件名称*/private String fileName;/*** 文件Md5值*/private String fileMd5;/*** 文件上传ID*/private String uploadId;/*** 文件路径*/private String fileUrl;/*** 总分块数*/private Integer totalChunk;/*** 文件上传状态*/private String fileStatus;/*** 修改时间*/private Date updateTime;}
/*** 文件分片信息*/
@TableName(schema = "minio_demo", value = "minio_chunk_upload_info")
@Data
public class MinioFileChunkUploadInfo implements Serializable {/*** 自增ID*/@TableId(type = IdType.AUTO)private Long id;/*** 文件Md5值*/private String fileMd5;/*** 上传ID*/private String uploadId;/*** 文件块号*/private Integer chunkNumber;/*** 文件块上传URL*/private String chunkUploadUrl;/*** 过期时间*/private LocalDateTime expiryTime;}

2.2 Mapper

public interface MinioFileUploadInfoMapper extends MyBaseMapper<MinioFileUploadInfo> {
}
public interface MinioFileChunkUploadInfoMapper extends MyBaseMapper<MinioFileChunkUploadInfo> {
}

2.3 Service

public interface MinioFileUploadInfoService extends IService<MinioFileUploadInfo> {/*** 根据文件 md5 查询** @param fileMd5 文件 md5*/MinioFileUploadInfoDTO getByFileMd5(String fileMd5);/*** 保存** @param param 参数对象*/MinioFileUploadInfoDTO saveMinioFileUploadInfo(MinioFileUploadInfoParam param);/*** 修改文件状态** @param param 参数对象*/int updateFileStatusByFileMd5(MinioFileUploadInfoParam param);}
@Service
public class MinioFileUploadInfoServiceImplextends ServiceImpl<MinioFileUploadInfoMapper, MinioFileUploadInfo>implements MinioFileUploadInfoService {@Overridepublic MinioFileUploadInfoDTO getByFileMd5(String fileMd5) {MinioFileUploadInfo minioFileUploadInfo = this.baseMapper.selectOne(new LambdaQueryWrapper<MinioFileUploadInfo>().eq(MinioFileUploadInfo::getFileMd5, fileMd5));if (null == minioFileUploadInfo) {return null;}return ExtBeanUtils.doToDto(minioFileUploadInfo, MinioFileUploadInfoDTO.class);}@Overridepublic MinioFileUploadInfoDTO saveMinioFileUploadInfo(MinioFileUploadInfoParam param) {MinioFileUploadInfo minioFileUploadInfo;if (null == param.getId()) {minioFileUploadInfo = new MinioFileUploadInfo();} else {minioFileUploadInfo = this.baseMapper.selectById(param.getId());if (null == minioFileUploadInfo) {throw new MinioDemoException(MinioDemoExceptionTypes.DATA_NOT_EXISTED);}minioFileUploadInfo.setUpdateTime(new Date());}BeanUtils.copyProperties(param, minioFileUploadInfo, "id");int result;if (null == param.getId()) {result = this.baseMapper.insert(minioFileUploadInfo);} else {result = this.baseMapper.updateById(minioFileUploadInfo);}if (result == 0) {throw new MinioDemoException(MinioDemoExceptionTypes.USER_OPERATE_FAILED);}return ExtBeanUtils.doToDto(minioFileUploadInfo, MinioFileUploadInfoDTO.class);}@Overridepublic int updateFileStatusByFileMd5(MinioFileUploadInfoParam param) {MinioFileUploadInfo minioFileUploadInfo = this.baseMapper.selectOne(new LambdaQueryWrapper<MinioFileUploadInfo>().eq(MinioFileUploadInfo::getFileMd5, param.getFileMd5()));if (null == minioFileUploadInfo) {throw new MinioDemoException(MinioDemoExceptionTypes.DATA_NOT_EXISTED);}minioFileUploadInfo.setFileStatus(param.getFileStatus());minioFileUploadInfo.setFileUrl(param.getFileUrl());return this.baseMapper.updateById(minioFileUploadInfo);}
}
public interface MinioFileChunkUploadInfoService extends IService<MinioFileChunkUploadInfo> {boolean saveMinioFileChunkUploadInfo(MinioFileChunkUploadInfoParam chunkUploadInfoParam);List<MinioFileChunkUploadInfoDTO> listByFileMd5AndUploadId(String fileMd5, String uploadId);
}
@Service
public class MinioFileChunkUploadInfoServiceImplextends ServiceImpl<MinioFileChunkUploadInfoMapper, MinioFileChunkUploadInfo>implements MinioFileChunkUploadInfoService {@Overridepublic boolean saveMinioFileChunkUploadInfo(MinioFileChunkUploadInfoParam param) {List<MinioFileChunkUploadInfo> list = new ArrayList<>();for (int i = 0; i < param.getUploadUrls().size(); i++) {MinioFileChunkUploadInfo tempObj = new MinioFileChunkUploadInfo();tempObj.setChunkNumber(i + 1);tempObj.setFileMd5(param.getFileMd5());tempObj.setUploadId(param.getUploadId());tempObj.setExpiryTime(param.getExpiryTime());tempObj.setChunkUploadUrl(param.getUploadUrls().get(i));list.add(tempObj);}int result = this.baseMapper.insertBatchSomeColumn(list);return result != 0;}@Overridepublic List<MinioFileChunkUploadInfoDTO> listByFileMd5AndUploadId(String fileMd5, String uploadId) {List<MinioFileChunkUploadInfo> list = this.baseMapper.selectList(Wrappers.<MinioFileChunkUploadInfo>lambdaQuery().select(MinioFileChunkUploadInfo::getChunkUploadUrl).eq(MinioFileChunkUploadInfo::getFileMd5, fileMd5).eq(MinioFileChunkUploadInfo::getUploadId, uploadId));return ExtBeanUtils.doListToDtoList(list, MinioFileChunkUploadInfoDTO.class);}
}

至此 Entity、Mapper、Service 准备完毕

三、Minio分片实现

3.1 文件状态枚举

@Getter
public enum MinioFileStatus {UN_UPLOADED("UN_UPLOADED", "待上传"),UPLOADED("UPLOADED", "已上传"),UPLOADING("", "上传中");final String code;final String msg;MinioFileStatus(String code, String msg) {this.code = code;this.msg = msg;}
}

3.2 MinioService新增方法

public interface MinioService {/*** 初始化获取 uploadId** @param objectName  文件名* @param partCount   分片总数* @param contentType contentType* @return uploadInfo*/MinioUploadInfo initMultiPartUpload(String objectName,int partCount,String contentType);/*** 分片合并** @param objectName 文件名* @param uploadId   uploadId* @return region*/String mergeMultiPartUpload(String objectName, String uploadId);/*** 获取已上传的分片列表** @param objectName 文件名* @param uploadId   uploadId* @return 分片列表*/List<Integer> listUploadChunkList(String objectName, String uploadId);
}
@Component
@Slf4j
@RequiredArgsConstructor
public class MinioServiceImpl implements MinioService {public MinioUploadInfo initMultiPartUpload(String objectName, int partCount, String contentType) {HashMultimap<String, String> headers = HashMultimap.create();headers.put("Content-Type", contentType);String uploadId = "";List<String> partUrlList = new ArrayList<>();try {// 获取 uploadIduploadId = minioClient.getUploadId(minIoClientConfig.getBucketName(),null,objectName,headers,null);Map<String, String> paramsMap = new HashMap<>(2);paramsMap.put("uploadId", uploadId);for (int i = 1; i <= partCount; i++) {paramsMap.put("partNumber", String.valueOf(i));// 获取上传 urlString uploadUrl = minioClient.getPresignedObjectUrl(GetPresignedObjectUrlArgs.builder()// 注意此处指定请求方法为 PUT,前端需对应,否则会报 `SignatureDoesNotMatch` 错误.method(Method.PUT).bucket(minIoClientConfig.getBucketName()).object(objectName)// 指定上传连接有效期// .expiry(paramConfig.getChunkUploadExpirySecond(), TimeUnit.SECONDS).extraQueryParams(paramsMap).build());partUrlList.add(uploadUrl);}} catch (Exception e) {log.error("initMultiPartUpload Error:" + e);return null;}// 过期时间 TODO 过期LocalDateTime expireTime = LocalDateTime.now().minusHours(1);MinioUploadInfo result = new MinioUploadInfo();result.setUploadId(uploadId);result.setExpiryTime(expireTime);result.setUploadUrls(partUrlList);return result;}/*** 分片合并** @param objectName 文件名* @param uploadId   uploadId*/public String mergeMultiPartUpload(String objectName, String uploadId) {// todo 最大1000分片 这里好像可以改吧Part[] parts = new Part[1000];int partIndex = 0;ListPartsResponse partsResponse = listUploadPartsBase(objectName, uploadId);if (null == partsResponse) {log.error("查询文件分片列表为空");throw new RuntimeException("分片列表为空");}for (Part partItem : partsResponse.result().partList()) {parts[partIndex] = new Part(partIndex + 1, partItem.etag());partIndex++;}ObjectWriteResponse objectWriteResponse;try {objectWriteResponse = minioClient.mergeMultipart(minIoClientConfig.getBucketName(), null, objectName, uploadId, parts, null, null);} catch (Exception e) {log.error("分片合并失败:" + e);throw new RuntimeException("分片合并失败:" + e.getMessage());}if (null == objectWriteResponse) {log.error("合并失败,合并结果为空");throw new RuntimeException("分片合并失败");}return objectWriteResponse.region();}/*** 获取已上传的分片列表** @param objectName 文件名* @param uploadId   uploadId*/public List<Integer> listUploadChunkList(String objectName, String uploadId) {ListPartsResponse partsResponse = listUploadPartsBase(objectName, uploadId);if (null == partsResponse) {return Collections.emptyList();}return partsResponse.result().partList().stream().map(Part::partNumber).collect(Collectors.toList());}private ListPartsResponse listUploadPartsBase(String objectName, String uploadId) {int maxParts = 1000;ListPartsResponse partsResponse;try {partsResponse = minioClient.listMultipart(minIoClientConfig.getBucketName(), null, objectName, maxParts, 0, uploadId, null, null);} catch (ServerException | InsufficientDataException | ErrorResponseException | NoSuchAlgorithmException |IOException | XmlParserException | InvalidKeyException | InternalException |InvalidResponseException e) {log.error("查询文件分片列表错误:{},uploadId:{}", e, uploadId);return null;}return partsResponse;}}

3.3 分片文件Service

public interface FileUploadService {/*** 获取分片上传信息** @param param 参数* @return Minio上传信息*/MinioUploadInfo getUploadId(GetMinioUploadInfoParam param);/*** 检查文件是否存在** @param md5 md5* @return true存在 false不存在*/MinioOperationResult checkFileExistsByMd5(String md5);/*** 查询已上传的分片序号** @param objectName 文件名* @param uploadId   uploadId* @return 已上传的分片序号列表*/List<Integer> listUploadParts(String objectName, String uploadId);/*** 分片合并** @param param 参数* @return url*/String mergeMultipartUpload(MergeMinioMultipartParam param);
}
@Slf4j
@Service
public class FileUploadServiceImpl implements FileUploadService {@Resourceprivate MinioService minioService;@Resourceprivate MinioFileUploadInfoService minioFileUploadInfoService;@Resourceprivate MinioFileChunkUploadInfoService minioFileChunkUploadInfoService;@Overridepublic MinioUploadInfo getUploadId(GetMinioUploadInfoParam param) {MinioUploadInfo uploadInfo;MinioFileUploadInfoDTO minioFileUploadInfo = this.minioFileUploadInfoService.getByFileMd5(param.getFileMd5());if (null == minioFileUploadInfo) {// 计算分片数量double partCount = Math.ceil(param.getFileSize() * 1.0 / param.getChunkSize());log.info("总分片数:" + partCount);uploadInfo = minioService.initMultiPartUpload(param.getFileName(), (int) partCount, param.getContentType());if (null != uploadInfo) {MinioFileUploadInfoParam saveParam = new MinioFileUploadInfoParam();saveParam.setUploadId(uploadInfo.getUploadId());saveParam.setFileMd5(param.getFileMd5());saveParam.setFileName(param.getFileName());saveParam.setTotalChunk((int) partCount);saveParam.setFileStatus(MinioFileStatus.UN_UPLOADED.getCode());// 保存文件上传信息MinioFileUploadInfoDTO minioFileUploadInfoDTO = minioFileUploadInfoService.saveMinioFileUploadInfo(saveParam);log.info("文件上传信息保存成功 {}", JSON.toJSONString(minioFileUploadInfoDTO));MinioFileChunkUploadInfoParam chunkUploadInfoParam = new MinioFileChunkUploadInfoParam();chunkUploadInfoParam.setUploadUrls(uploadInfo.getUploadUrls());chunkUploadInfoParam.setUploadId(uploadInfo.getUploadId());chunkUploadInfoParam.setExpiryTime(uploadInfo.getExpiryTime());chunkUploadInfoParam.setFileMd5(param.getFileMd5());chunkUploadInfoParam.setFileName(param.getFileName());// 保存分片上传信息boolean chunkUploadResult = minioFileChunkUploadInfoService.saveMinioFileChunkUploadInfo(chunkUploadInfoParam);log.info("文件分片信息保存{}", chunkUploadResult ? "成功" : "失败");}return uploadInfo;}// 查询分片上传地址List<MinioFileChunkUploadInfoDTO> list = minioFileChunkUploadInfoService.listByFileMd5AndUploadId(minioFileUploadInfo.getFileMd5(), minioFileUploadInfo.getUploadId());List<String> uploadUrlList = list.stream().map(MinioFileChunkUploadInfoDTO::getChunkUploadUrl).collect(Collectors.toList());uploadInfo = new MinioUploadInfo();uploadInfo.setUploadUrls(uploadUrlList);uploadInfo.setUploadId(minioFileUploadInfo.getUploadId());return uploadInfo;}@Overridepublic MinioOperationResult checkFileExistsByMd5(String md5) {MinioOperationResult result = new MinioOperationResult();MinioFileUploadInfoDTO minioFileUploadInfo = this.minioFileUploadInfoService.getByFileMd5(md5);if (null == minioFileUploadInfo) {result.setStatus(MinioFileStatus.UN_UPLOADED.getCode());return result;}// 已上传if (Objects.equals(minioFileUploadInfo.getFileStatus(), MinioFileStatus.UPLOADED.getCode())) {result.setStatus(MinioFileStatus.UPLOADED.getCode());result.setUrl(minioFileUploadInfo.getFileUrl());return result;}// 查询已上传分片列表并返回已上传列表List<Integer> chunkUploadedList = listUploadParts(minioFileUploadInfo.getFileName(), minioFileUploadInfo.getUploadId());result.setStatus(MinioFileStatus.UPLOADING.getCode());result.setChunkUploadedList(chunkUploadedList);return result;}@Overridepublic List<Integer> listUploadParts(String objectName, String uploadId) {return minioService.listUploadChunkList(objectName, uploadId);}@Overridepublic String mergeMultipartUpload(MergeMinioMultipartParam param) {String result = minioService.mergeMultiPartUpload(param.getFileName(), param.getUploadId());if (!StringUtils.isBlank(result)) {MinioFileUploadInfoParam fileUploadInfoParam = new MinioFileUploadInfoParam();fileUploadInfoParam.setFileUrl(result);fileUploadInfoParam.setFileMd5(param.getMd5());fileUploadInfoParam.setFileStatus(MinioFileStatus.UPLOADED.getCode());// 更新状态int updateRows = minioFileUploadInfoService.updateFileStatusByFileMd5(fileUploadInfoParam);log.info("update file by file md5 updated count {}", updateRows);}return result;}
}

3.4 Controller新增

@RequestMapping(value = "file")
@RestController
public class FileController {@Resourceprivate FileUploadService fileUploadService;@PostMapping("/upload")public R getUploadId(@Validate @RequestBody GetMinioUploadInfoParam param) {MinioUploadInfo minioUploadId = fileUploadService.getUploadId(param);return R.ok().setData(minioUploadId);}@GetMapping("/upload/check")public R checkFileUploadedByMd5(@RequestParam("md5") String md5) {return R.ok().setData(fileUploadService.checkFileExistsByMd5(md5));}@PostMapping("/upload/merge")public R mergeUploadFile(@Validated MergeMinioMultipartParam param) {String result = fileUploadService.mergeMultipartUpload(param);if (StringUtils.isEmpty(result)) {throw new MinioDemoException(MinioDemoExceptionTypes.CHUNK_MERGE_FAILED);}return R.ok().setData(result); // url}
}

3.5 文件分片上传测试

在这里插入图片描述
在这里插入图片描述

select * from minio_file_upload_info;

在这里插入图片描述

select * from minio_chunk_upload_info;

在这里插入图片描述

FAQ

  • 上传失败,code码为403,请同步minio服务器时间。

相关文章:

Minio文件分片上传实现

资源准备 MacM1Pro 安装Parallels19.1.0请参考 https://blog.csdn.net/qq_41594280/article/details/135420241 MacM1Pro Parallels安装CentOS7.9请参考 https://blog.csdn.net/qq_41594280/article/details/135420461 部署Minio和整合SpringBoot请参考 https://blog.csdn.net/…...

C语言总结十一:自定义类型:结构体、枚举、联合(共用体)

本篇博客详细介绍C语言最后的三种自定义类型&#xff0c;它们分别有着各自的特点和应用场景&#xff0c;重点在于理解这三种自定义类型的声明方式和使用&#xff0c;以及各自的特点&#xff0c;最后重点掌握该章节常考的考点&#xff0c;如&#xff1a;结构体内存对齐问题&…...

解决Spring Boot应用打包后文件访问问题

在Spring Boot项目的开发过程中&#xff0c;一个常见的挑战是如何有效地访问和操作资源文件。这一挑战尤其显著当应用从IDE环境&#xff08;如IntelliJ IDEA&#xff09;迁移到被打包成JAR文件后的生产环境。开发者经常遇到的问题是&#xff0c;在IDE中运行正常的代码&#xff…...

循环神经网络的变体模型-LSTM、GRU

一.LSTM&#xff08;长短时记忆网络&#xff09; 1.1基本介绍 长短时记忆网络&#xff08;Long Short-Term Memory&#xff0c;LSTM&#xff09;是一种深度学习模型&#xff0c;属于循环神经网络&#xff08;Recurrent Neural Network&#xff0c;RNN&#xff09;的一种变体。…...

视频图像的color range简介

介绍 研究FFmpeg发现&#xff0c;在avcodec.h中有关于color的解释&#xff0c;主要有四个属性&#xff0c;primaries、transfer、space和range。 color primaries&#xff1a; 基于RGB空间对应的绝对颜色XYZ的变换&#xff0c;决定了最终三原色RGB分别是什么颜色&#xff1b;…...

tcp的三次握手

http 和 https 都是是基于 TCP 的请求&#xff0c;https 是 http 加上 tls 连接。TCP 是面向连接的协议。 对于 http1.1 协议chrome 限制在同一个域名下最多可以建立 6 个 tcp 连接&#xff0c;所以如果在同一个域名下&#xff0c;同时有超过 6 个请求发生&#xff0c;那么多余…...

unity 矩阵探究

public void MatrixTest1(){ ///Matrix4x4 是列矩阵&#xff0c;就是一个vector4表示一列&#xff0c;所以在c#中矩阵和Vector4只能矩阵右乘坐标。但是在shader中是矩阵左乘坐标&#xff0c;所以在shader中是行矩阵 Matrix4x4 moveMatrix1 new Matrix4x4(new Vector4(1,0,0,0)…...

MySQL---单表查询综合练习

创建emp表 CREATE TABLE emp( empno INT(4) NOT NULL COMMENT 员工编号, ename VARCHAR(10) COMMENT 员工名字, job VARCHAR(10) COMMENT 职位, mgr INT(4) COMMENT 上司, hiredate DATE COMMENT 入职时间, sal INT(7) COMMENT 基本工资, comm INT(7) COMMENT 补贴, deptno INT…...

Python项目——搞怪小程序(PySide6+Pyinstaller)

1、介绍 使用python编写一个小程序&#xff0c;回答你是猪吗。 点击“是”提交&#xff0c;弹窗并退出。 点击“不是”提交&#xff0c;等待5秒&#xff0c;重新选择。 并且隐藏了关闭按钮。 2、实现 新建一个项目。 2.1、设计UI 使用Qt designer设计一个UI界面&#xff0c…...

MySQL练习题

参考&#xff1a;https://blog.csdn.net/paul0127/article/details/82529216 数据表介绍 --1.学生表 Student(SId,Sname,Sage,Ssex) --SId 学生编号,Sname 学生姓名,Sage 出生年月,Ssex 学生性别 --2.课程表 Course(CId,Cname,TId) --CId 课程编号,Cname 课程名称,TId 教师编号…...

vue-项目打包、配置路由懒加载

1. 简介 在现代前端开发中&#xff0c;Vue.js因其简洁、灵活和高效的特点&#xff0c;已经成为许多开发者的首选框架。 在Vue项目中&#xff0c;打包部署和路由懒加载是两个非常重要的环节。 打包Vue项目是为了将源代码转换为浏览器可以解析的JavaScript文件&#xff0c;以便…...

词语的魔力:语言在我们生活中的艺术与影响

Words That Move Mountains: The Art and Impact of Language in Our Lives 词语的魔力&#xff1a;语言在我们生活中的艺术与影响 Hello there, wonderful people! Today, I’d like to gab about the magical essence of language that’s more than just a chatty tool in o…...

android List,Set,Map区别和介绍

List 元素存放有序&#xff0c;元素可重复 1.LinkedList 链表&#xff0c;插入删除&#xff0c;非线性安全&#xff0c;插入和删除操作是双向链表操作&#xff0c;增加删除快&#xff0c;查找慢 add(E e)//添加元素 addFirst(E e)//向集合头部添加元素 addList(E e)//向集合…...

Mysql 编译安装部署

Mysql 编译安装部署 环境&#xff1a; 172.20.26.198&#xff08;Centos7.6&#xff09; 源码安装Mysql-5.7 大概步骤如下&#xff1a; 1、上传mysql-5.7.28.tar.gz 、boost_1_59_0.tar 到/usr/src 目录下 2、安装依赖 3、cmake 4、make && make install 5、…...

【目标检测】YOLOv5算法实现(九):模型预测

本系列文章记录本人硕士阶段YOLO系列目标检测算法自学及其代码实现的过程。其中算法具体实现借鉴于ultralytics YOLO源码Github&#xff0c;删减了源码中部分内容&#xff0c;满足个人科研需求。   本系列文章主要以YOLOv5为例完成算法的实现&#xff0c;后续修改、增加相关模…...

centos宝塔远程服务器怎么链接?

要远程连接CentOS宝塔服务器&#xff0c;可以按照以下步骤操作&#xff1a; 打开终端或远程连接工具&#xff0c;比如PuTTY。输入服务器的IP地址和SSH端口号&#xff08;默认为22&#xff09;&#xff0c;点击连接。输入用户名和密码进行登录。 如果你已经安装了宝塔面板&…...

C语言练习day8

变种水仙花 变种水仙花_牛客题霸_牛客网 题目&#xff1a; 思路&#xff1a;我们拿到题目的第一步可以先看一看题目给的例子&#xff0c;1461这个数被从中间拆成了两部分&#xff1a;1和461&#xff0c;14和61&#xff0c;146和1&#xff0c;不知道看到这大家有没有觉得很熟…...

蓝凌OA-sysuicomponent-任意文件上传_exp-漏洞复现

0x01阅读须知 技术文章仅供参考&#xff0c;此文所提供的信息只为网络安全人员对自己所负责的网站、服务器等&#xff08;包括但不限于&#xff09;进行检测或维护参考&#xff0c;未经授权请勿利用文章中的技术资料对任何计算机系统进行入侵操作。利用此文所提供的信息而造成的…...

C#,入门教程(38)——大型工程软件中类(class)修饰词partial的使用方法

上一篇&#xff1a; C#&#xff0c;入门教程(37)——优秀程序员的修炼之道https://blog.csdn.net/beijinghorn/article/details/125011644 一、大型&#xff08;工程应用&#xff09;软件倚重 partial 先说说大型&#xff08;工程应用&#xff09;软件对源代码的文件及函数“…...

C++播放音乐:使用EGE图形库

——开胃菜&#xff0c;闲话篓子一大片 最近&#xff0c;我发现ege图形库不是个正经的图形库—— 那天&#xff0c;我又在打趣儿地翻代码时&#xff0c;无意间看到了这个&#xff1a; 图形库&#xff1f;&#xff01;你哪来的音乐&#xff08;Music&#xff09;呢&#xff1f…...

网络六边形受到攻击

大家读完觉得有帮助记得关注和点赞&#xff01;&#xff01;&#xff01; 抽象 现代智能交通系统 &#xff08;ITS&#xff09; 的一个关键要求是能够以安全、可靠和匿名的方式从互联车辆和移动设备收集地理参考数据。Nexagon 协议建立在 IETF 定位器/ID 分离协议 &#xff08;…...

电脑插入多块移动硬盘后经常出现卡顿和蓝屏

当电脑在插入多块移动硬盘后频繁出现卡顿和蓝屏问题时&#xff0c;可能涉及硬件资源冲突、驱动兼容性、供电不足或系统设置等多方面原因。以下是逐步排查和解决方案&#xff1a; 1. 检查电源供电问题 问题原因&#xff1a;多块移动硬盘同时运行可能导致USB接口供电不足&#x…...

什么是库存周转?如何用进销存系统提高库存周转率?

你可能听说过这样一句话&#xff1a; “利润不是赚出来的&#xff0c;是管出来的。” 尤其是在制造业、批发零售、电商这类“货堆成山”的行业&#xff0c;很多企业看着销售不错&#xff0c;账上却没钱、利润也不见了&#xff0c;一翻库存才发现&#xff1a; 一堆卖不动的旧货…...

2025 后端自学UNIAPP【项目实战:旅游项目】6、我的收藏页面

代码框架视图 1、先添加一个获取收藏景点的列表请求 【在文件my_api.js文件中添加】 // 引入公共的请求封装 import http from ./my_http.js// 登录接口&#xff08;适配服务端返回 Token&#xff09; export const login async (code, avatar) > {const res await http…...

linux 下常用变更-8

1、删除普通用户 查询用户初始UID和GIDls -l /home/ ###家目录中查看UID cat /etc/group ###此文件查看GID删除用户1.编辑文件 /etc/passwd 找到对应的行&#xff0c;YW343:x:0:0::/home/YW343:/bin/bash 2.将标红的位置修改为用户对应初始UID和GID&#xff1a; YW3…...

全志A40i android7.1 调试信息打印串口由uart0改为uart3

一&#xff0c;概述 1. 目的 将调试信息打印串口由uart0改为uart3。 2. 版本信息 Uboot版本&#xff1a;2014.07&#xff1b; Kernel版本&#xff1a;Linux-3.10&#xff1b; 二&#xff0c;Uboot 1. sys_config.fex改动 使能uart3(TX:PH00 RX:PH01)&#xff0c;并让boo…...

AI语音助手的Python实现

引言 语音助手(如小爱同学、Siri)通过语音识别、自然语言处理(NLP)和语音合成技术,为用户提供直观、高效的交互体验。随着人工智能的普及,Python开发者可以利用开源库和AI模型,快速构建自定义语音助手。本文由浅入深,详细介绍如何使用Python开发AI语音助手,涵盖基础功…...

基于开源AI智能名片链动2 + 1模式S2B2C商城小程序的沉浸式体验营销研究

摘要&#xff1a;在消费市场竞争日益激烈的当下&#xff0c;传统体验营销方式存在诸多局限。本文聚焦开源AI智能名片链动2 1模式S2B2C商城小程序&#xff0c;探讨其在沉浸式体验营销中的应用。通过对比传统品鉴、工厂参观等初级体验方式&#xff0c;分析沉浸式体验的优势与价值…...

MySQL体系架构解析(三):MySQL目录与启动配置全解析

MySQL中的目录和文件 bin目录 在 MySQL 的安装目录下有一个特别重要的 bin 目录&#xff0c;这个目录下存放着许多可执行文件。与其他系统的可执行文件类似&#xff0c;这些可执行文件都是与服务器和客户端程序相关的。 启动MySQL服务器程序 在 UNIX 系统中&#xff0c;用…...

Shell 解释器​​ bash 和 dash 区别

bash 和 dash 都是 Unix/Linux 系统中的 ​​Shell 解释器​​&#xff0c;但它们在功能、语法和性能上有显著区别。以下是它们的详细对比&#xff1a; ​​1. 基本区别​​ ​​特性​​​​bash (Bourne-Again SHell)​​​​dash (Debian Almquist SHell)​​​​来源​​G…...