Spring Boot轻松整合Minio实现文件上传下载功能【建议收藏】
一、Linux 安装Minio
安装
在/root/xxkfz/soft目录下面创建文件minio文件夹,进入minio文件夹,并创建data目录;
[root@xxkfz soft]# mkdir minio
[root@xxkfz soft]# cd minio
[root@xxkfz minio]# mkdir data
执行如下命令进行下载
[root@xxkfz minio]# wget https://dl.min.io/server/minio/release/linux-amd64/minio
[root@xxkfz minio]# chmod +x minio # 赋权
下载完成后如下所示:

设置账号密码
minio 默认账号密码为 minioadmin/minioadmin
[root@xxkfz minio]# export MINIO_ACCESS_KEY=admin # 设置控制台账号(最少3位)
[root@xxkfz minio]# export MINIO_SECRET_KEY=12345678 # 设置密码(最少8位)
直接设置管理员账号密码 编辑 /etc/profile 文件即可
[root@xxkfz minio]# vim /etc/profile
编辑/etc/profile文件,追加如下内容:
#===============================Minio=============================================
# set minio environment
export MINIO_ROOT_USER=admin
export MINIO_ROOT_PASSWORD=admin123
可省略 设置账号密码 此步骤!12
启动
进入执行文件目录/root/xxkfz/soft/minio,自定义端口启动(默认端口:9000)
[root@xxkfz minio]# nohup /root/xxkfz/soft/minio/minio server --address :9001 --console-address :9002 /root/xxkfz/soft/minio/data >/root/xxkfz/soft/minio/minio.log 2>&1 &
说明:
-
nohup为后台启动 -
./minio server启动命令 -
--address :9001指定API端口 -
--console-address :9002指定控制台端口 -
/usr/local/minio/data指定存储目录 -
>/usr/local/minio/minio.log 2>&1控制台日志重定向到/usr/local/minio/minio.log文件中 -
&后台运行
启动成功:

注意:浏览器访问需要开启防火墙端口!
阿里云配置开放9001、9002端口

测试访问:http://IP地址:9002
输入账号密码: admin/12345678 登录成功!

设置开机自启动
设置Minio服务器宕机后自动重启
进入init.d目录
[root@xxkfz minio]# cd /etc/rc.d/init.d
新建minio.sh shell脚本文件
[root@xxkfz init.d]# vim minio.sh
shell脚本内容
#!/bin/bash
#chkconfig: 2345 10 90
#description: ping10
nohup /root/xxkfz/soft/minio/minio server --address :9001 --console-address :9002 /root/xxkfz/soft/minio/data >/root/xxkfz/soft/minio/minio.log 2>&1 &
给shell脚本赋权
chmod +x minio.sh
添加到开机自启动服务中
chkconfig --add minio.sh
设置开机自启动
chkconfig minio.sh on
查看是否添加成功
chkconfig --list

二、Spring Boot整合Minio
项目搭建

引入依赖
pom.xml
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><optional>true</optional></dependency><dependency><groupId>io.minio</groupId><artifactId>minio</artifactId><version>8.2.2</version></dependency><dependency><groupId>org.apache.commons</groupId><artifactId>commons-lang3</artifactId><version>3.11</version></dependency>
配置MinIo
application.yml
minio:endpoint: http://IP地址:9001accessKey: adminsecretKey: 12345678bucketName: xk-admin# 配置端口号
server:port: 8099
编写配置类
MinioConfig.java
/*** @program: xxkfz-minio* @ClassName MinioConfig.java* @author: 公众号:小小开发者* @create: 2024-03-13 10:53* @description: Minio 配置类**/
@Data
@Configuration
public class MinioConfig {/*** 访问地址*/@Value("${minio.endpoint}")private String endpoint;/*** accessKey类似于用户ID,用于唯一标识你的账户*/@Value("${minio.accessKey}")private String accessKey;/*** secretKey是你账户的密码*/@Value("${minio.secretKey}")private String secretKey;/*** 默认存储桶*/@Value("${minio.bucketName}")private String bucketName;@Beanpublic MinioClient minioClient() {MinioClient minioClient = MinioClient.builder().endpoint(endpoint).credentials(accessKey, secretKey).build();return minioClient;}
}
编写Minio操作工具类
MinioUtils.java
/*** @program: xxkfz-minio* @ClassName MinioUtils.java* @author: 公众号:小小开发者* @create: 2024-03-13 10:55* @description: MinIO操作工具类**/
@Slf4j
@Component
public class MinioUtils {@Autowiredprivate MinioClient minioClient;/*** 启动SpringBoot容器的时候初始化Bucket* 如果没有Bucket则创建** @param bucketName*/public void createBucket(String bucketName) {try {if (!bucketExists(bucketName)) {minioClient.makeBucket(MakeBucketArgs.builder().bucket(bucketName).build());log.info("创建bucketName = {}完成!", bucketName);return;}log.info("bucketName = {}已存在!策略为:{}", bucketName, getBucketPolicy(bucketName));} catch (Exception e) {log.error("创建bucketName = {}异常!e = {}", bucketName, e);}}/*** 判断Bucket是否存在,true:存在,false:不存在** @param bucketName* @return*/@SneakyThrowspublic boolean bucketExists(String bucketName) {return minioClient.bucketExists(BucketExistsArgs.builder().bucket(bucketName).build());}/*** 获得Bucket的策略** @param bucketName* @return*/@SneakyThrowspublic String getBucketPolicy(String bucketName) {return minioClient.getBucketPolicy(GetBucketPolicyArgs.builder().bucket(bucketName).build());}/*** 获得所有Bucket列表** @return*/@SneakyThrowspublic List<Bucket> getAllBuckets() {return minioClient.listBuckets();}/*** 根据bucketName获取其相关信息** @param bucketName* @return*/@SneakyThrows(Exception.class)public Optional<Bucket> getBucket(String bucketName) {return getAllBuckets().stream().filter(b -> b.name().equals(bucketName)).findFirst();}/*** 根据bucketName删除Bucket,true:删除成功; false:删除失败,文件或已不存在** @param bucketName* @throws Exception*/@SneakyThrows(Exception.class)public void removeBucket(String bucketName) {minioClient.removeBucket(RemoveBucketArgs.builder().bucket(bucketName).build());}/*** 判断文件是否存在** @param bucketName* @param objectName* @return*/public boolean isObjectExist(String bucketName, String objectName) {boolean exist = true;try {minioClient.statObject(StatObjectArgs.builder().bucket(bucketName).object(objectName).build());} catch (Exception e) {log.error("[Minio工具类]>>>> 判断文件是否存在, 异常:", e);exist = false;}return exist;}/*** 判断文件夹是否存在** @param bucketName* @param objectName* @return*/public boolean isFolderExist(String bucketName, String objectName) {boolean exist = false;try {Iterable<Result<Item>> results = minioClient.listObjects(ListObjectsArgs.builder().bucket(bucketName).prefix(objectName).recursive(false).build());for (Result<Item> result : results) {Item item = result.get();if (item.isDir() && objectName.equals(item.objectName())) {exist = true;}}} catch (Exception e) {log.error("[Minio工具类]>>>> 判断文件夹是否存在,异常:", e);exist = false;}return exist;}/*** 根据文件前置查询文件** @param bucketName 存储桶* @param prefix 前缀* @param recursive 是否使用递归查询* @return MinioItem 列表*/@SneakyThrows(Exception.class)public List<Item> getAllObjectsByPrefix(String bucketName, String prefix, boolean recursive) {List<Item> list = new ArrayList<>();Iterable<Result<Item>> objectsIterator = minioClient.listObjects(ListObjectsArgs.builder().bucket(bucketName).prefix(prefix).recursive(recursive).build());if (objectsIterator != null) {for (Result<Item> o : objectsIterator) {Item item = o.get();list.add(item);}}return list;}/*** 获取文件流** @param bucketName 存储桶* @param objectName 文件名* @return 二进制流*/@SneakyThrows(Exception.class)public InputStream getObject(String bucketName, String objectName) {return minioClient.getObject(GetObjectArgs.builder().bucket(bucketName).object(objectName).build());}/*** 断点下载** @param bucketName 存储桶* @param objectName 文件名称* @param offset 起始字节的位置* @param length 要读取的长度* @return 二进制流*/@SneakyThrows(Exception.class)public InputStream getObject(String bucketName, String objectName, long offset, long length) {return minioClient.getObject(GetObjectArgs.builder().bucket(bucketName).object(objectName).offset(offset).length(length).build());}/*** 获取路径下文件列表** @param bucketName 存储桶* @param prefix 文件名称* @param recursive 是否递归查找,false:模拟文件夹结构查找* @return 二进制流*/public Iterable<Result<Item>> listObjects(String bucketName, String prefix, boolean recursive) {return minioClient.listObjects(ListObjectsArgs.builder().bucket(bucketName).prefix(prefix).recursive(recursive).build());}/*** 使用MultipartFile进行文件上传** @param bucketName 存储桶* @param file 文件名* @param objectName 对象名* @param contentType 类型* @return*/@SneakyThrows(Exception.class)public ObjectWriteResponse uploadFile(String bucketName, MultipartFile file, String objectName, String contentType) {InputStream inputStream = file.getInputStream();return minioClient.putObject(PutObjectArgs.builder().bucket(bucketName).object(objectName).contentType(contentType).stream(inputStream, inputStream.available(), -1).build());}/*** 图片上传** @param bucketName* @param imageBase64* @param imageName* @return*/public ObjectWriteResponse uploadImage(String bucketName, String imageBase64, String imageName) {if (!StringUtils.isEmpty(imageBase64)) {InputStream in = base64ToInputStream(imageBase64);String newName = System.currentTimeMillis() + "_" + imageName + ".jpg";String year = String.valueOf(new Date().getYear());String month = String.valueOf(new Date().getMonth());return uploadFile(bucketName, year + "/" + month + "/" + newName, in);}return null;}public static InputStream base64ToInputStream(String base64) {ByteArrayInputStream stream = null;try {byte[] bytes = Base64.getEncoder().encode(base64.trim().getBytes());stream = new ByteArrayInputStream(bytes);} catch (Exception e) {e.printStackTrace();}return stream;}/*** 上传本地文件** @param bucketName 存储桶* @param objectName 对象名称* @param fileName 本地文件路径* @return*/@SneakyThrows(Exception.class)public ObjectWriteResponse uploadFile(String bucketName, String objectName, String fileName) {return minioClient.uploadObject(UploadObjectArgs.builder().bucket(bucketName).object(objectName).filename(fileName).build());}/*** 通过流上传文件** @param bucketName 存储桶* @param objectName 文件对象* @param inputStream 文件流* @return*/@SneakyThrows(Exception.class)public ObjectWriteResponse uploadFile(String bucketName, String objectName, InputStream inputStream) {return minioClient.putObject(PutObjectArgs.builder().bucket(bucketName).object(objectName).stream(inputStream, inputStream.available(), -1).build());}/*** 创建文件夹或目录** @param bucketName 存储桶* @param objectName 目录路径* @return*/@SneakyThrows(Exception.class)public ObjectWriteResponse createDir(String bucketName, String objectName) {return minioClient.putObject(PutObjectArgs.builder().bucket(bucketName).object(objectName).stream(new ByteArrayInputStream(new byte[]{}), 0, -1).build());}/*** 获取文件信息, 如果抛出异常则说明文件不存在** @param bucketName 存储桶* @param objectName 文件名称* @return*/@SneakyThrows(Exception.class)public String getFileStatusInfo(String bucketName, String objectName) {return minioClient.statObject(StatObjectArgs.builder().bucket(bucketName).object(objectName).build()).toString();}/*** 拷贝文件** @param bucketName 存储桶* @param objectName 文件名* @param srcBucketName 目标存储桶* @param srcObjectName 目标文件名*/@SneakyThrows(Exception.class)public ObjectWriteResponse copyFile(String bucketName, String objectName, String srcBucketName, String srcObjectName) {return minioClient.copyObject(CopyObjectArgs.builder().source(CopySource.builder().bucket(bucketName).object(objectName).build()).bucket(srcBucketName).object(srcObjectName).build());}/*** 删除文件** @param bucketName 存储桶* @param objectName 文件名称*/@SneakyThrows(Exception.class)public void removeFile(String bucketName, String objectName) {minioClient.removeObject(RemoveObjectArgs.builder().bucket(bucketName).object(objectName).build());}/*** 批量删除文件** @param bucketName 存储桶* @param keys 需要删除的文件列表* @return*/public void removeFiles(String bucketName, List<String> keys) {List<DeleteObject> objects = new LinkedList<>();keys.forEach(s -> {objects.add(new DeleteObject(s));try {removeFile(bucketName, s);} catch (Exception e) {log.error("[Minio工具类]>>>> 批量删除文件,异常:", e);}});}/*** 获取文件外链** @param bucketName 存储桶* @param objectName 文件名* @param expires 过期时间 <=7 秒 (外链有效时间(单位:秒))* @return url*/@SneakyThrows(Exception.class)public String getPresignedObjectUrl(String bucketName, String objectName, Integer expires) {GetPresignedObjectUrlArgs args = GetPresignedObjectUrlArgs.builder().expiry(expires).bucket(bucketName).object(objectName).build();return minioClient.getPresignedObjectUrl(args);}/*** 获得文件外链** @param bucketName* @param objectName* @return url*/@SneakyThrows(Exception.class)public String getPresignedObjectUrl(String bucketName, String objectName) {GetPresignedObjectUrlArgs args = GetPresignedObjectUrlArgs.builder().bucket(bucketName).object(objectName).method(Method.GET).build();return minioClient.getPresignedObjectUrl(args);}/*** 将URLDecoder编码转成UTF8** @param str* @return* @throws UnsupportedEncodingException*/public String getUtf8ByURLDecoder(String str) throws UnsupportedEncodingException {String url = str.replaceAll("%(?![0-9a-fA-F]{2})", "%25");return URLDecoder.decode(url, "UTF-8");}
}
项目启动初始化配置
创建配置类InitConfig.java,并实现了InitializingBean接口,重写afterPropertiesSet方法。
该方法主要实现逻辑:在项目启动的时候初始化Bucket,如果没有则进行创建!
InitConfig.java
/*** @program: xxkfz-minio* @ClassName Init.java* @author: wust* @create: 2024-03-16 10:34* @description: 项目启动初始化配置**/
@Component
@Slf4jpublic class InitConfig implements InitializingBean {@Autowiredprivate MinioUtils minioUtils;@Autowiredprivate MinioConfig minioConfig;@Overridepublic void afterPropertiesSet() throws Exception {// 项目启动创建Bucket,不存在则进行创建minioUtils.createBucket(minioConfig.getBucketName());}
}
编写测试接口
MinioController.java
/*** @program: xxkfz-minio* @ClassName OSSController.java* @author: wust* @create: 2024-03-13 11:01* @description:**/
@Slf4j
@RestController
@RequestMapping("/oss")
public class MinioController {@Autowiredprivate MinioUtils minioUtils;@Autowiredprivate MinioConfig minioConfig;/*** 文件上传** @param file*/@PostMapping("/upload")public String upload(@RequestParam("file") MultipartFile file) {try {//文件名String fileName = file.getOriginalFilename();String newFileName = System.currentTimeMillis() + "." + StringUtils.substringAfterLast(fileName, ".");//类型String contentType = file.getContentType();minioUtils.uploadFile(minioConfig.getBucketName(), file, newFileName, contentType);return "上传成功,文件名:" + newFileName;} catch (Exception e) {e.printStackTrace();return "上传失败";}}/*** 删除** @param fileName*/@DeleteMapping("/")public void delete(@RequestParam("fileName") String fileName) {minioUtils.removeFile(minioConfig.getBucketName(), fileName);}/*** 获取文件信息** @param fileName* @return*/@GetMapping("/info")public String getFileStatusInfo(@RequestParam("fileName") String fileName) {return minioUtils.getFileStatusInfo(minioConfig.getBucketName(), fileName);}/*** 获取文件外链** @param fileName* @return*/@GetMapping("/url")public String getPresignedObjectUrl(@RequestParam("fileName") String fileName) {return minioUtils.getPresignedObjectUrl(minioConfig.getBucketName(), fileName);}/*** 文件下载** @param fileName* @param response*/@GetMapping("/download")public void download(@RequestParam("fileName") String fileName, HttpServletResponse response) {try {InputStream fileInputStream = minioUtils.getObject(minioConfig.getBucketName(), fileName);response.setHeader("Content-Disposition", "attachment;filename=" + fileName);response.setContentType("application/force-download");response.setCharacterEncoding("UTF-8");IOUtils.copy(fileInputStream, response.getOutputStream());} catch (Exception e) {log.error("下载失败");}}
}
测试验证
启动项目:

上传图片
测试接口:http://localhost:8099/oss/upload

进入服务器查看文件上传情况。
进入目录:/root/xxkfz/soft/minio/data/xk-admin

当然,也可以直接访问minio的地址:http://IP地址:9001/xk-admin/1710558001536.jpg。验证文件是否上传成功。

获取文件信息
测试接口:http://localhost:8099/oss/info

获取文件外链
测试接口:http://localhost:8099/oss/url

下载文件
测试接口:http://localhost:8099/oss/download

相关文章:
Spring Boot轻松整合Minio实现文件上传下载功能【建议收藏】
一、Linux 安装Minio 安装 在/root/xxkfz/soft目录下面创建文件minio文件夹,进入minio文件夹,并创建data目录; [rootxxkfz soft]# mkdir minio [rootxxkfz soft]# cd minio [rootxxkfz minio]# mkdir data执行如下命令进行下载 [rootxxkf…...
MySql入门教程--MySQL数据库基础操作
꒰˃͈꒵˂͈꒱ write in front ꒰˃͈꒵˂͈꒱ ʕ̯•͡˔•̯᷅ʔ大家好,我是xiaoxie.希望你看完之后,有不足之处请多多谅解,让我们一起共同进步૮₍❀ᴗ͈ . ᴗ͈ აxiaoxieʕ̯•͡˔•̯᷅ʔ—CSDN博客 本文由xiaoxieʕ̯•͡˔•̯᷅ʔ 原创 CSDN …...
鸿蒙Harmony应用开发—ArkTS声明式开发(基础手势:Slider)
滑动条组件,通常用于快速调节设置值,如音量调节、亮度调节等应用场景。 说明: 该组件从API Version 7开始支持。后续版本如有新增内容,则采用上角标单独标记该内容的起始版本。 子组件 无 接口 Slider(options?: SliderOption…...
第五十六回 徐宁教使钩镰枪 宋江大破连环马-飞桨图像分类套件PaddleClas初探
宋江等人学会了钩镰枪,大胜呼延灼。呼延灼损失了很多人马,不敢回京,一个人去青州找慕容知府。一天在路上住店,马被桃花山的人偷走了,于是到了青州,带领官兵去打莲花山。 莲花山的周通打不过呼延灼…...
springboot/ssm企业内部人员绩效量化管理系统Java员工绩效管理系统web
springboot/ssm企业内部人员绩效量化管理系统Java员工绩效管理系统web 基于springboot(可改ssm)vue项目 开发语言:Java 框架:springboot/可改ssm vue JDK版本:JDK1.8(或11) 服务器:tomcat 数据库&…...
XML语言的学习记录2-XMLHttpRequest
学习笔记:XMLHttpRequest 特点: 在不重新加载页面的情况下更新网页在页面已加载后从服务器请求数据在页面已加载后从服务器接收数据在后台向服务器发送数据创建XMLHttpRequest对象 xmlhttpnew XMLHttpRequest();IE5 和 IE6,使用 …...
力扣爆刷第95天之hot100五连刷61-65
力扣爆刷第95天之hot100五连刷61-65 文章目录 力扣爆刷第95天之hot100五连刷61-65一、131. 分割回文串二、51. N 皇后三、35. 搜索插入位置四、74. 搜索二维矩阵五、34. 在排序数组中查找元素的第一个和最后一个位置 一、131. 分割回文串 题目链接:https://leetcod…...
聊聊powerjob的执行机器地址
序 本文主要研究一下powerjob的执行机器地址(designatedWorkers) SaveJobInfoRequest powerjob-common/src/main/java/tech/powerjob/common/request/http/SaveJobInfoRequest.java Data public class SaveJobInfoRequest {/*** id of the job. set null to create or non-…...
Android Kotlin知识汇总(三)Kotlin 协程
Kotlin的重要优势及特点之——结构化并发 Kotlin 协程让异步代码像阻塞代码一样易于使用。协程可大幅简化后台任务管理,例如网络调用、本地数据访问等任务的管理。本主题介绍如何使用 Kotlin 协程解决以下问题,从而让您能够编写出更清晰、更简洁的应用代…...
JVM垃圾收集器-serial.parNew,parallelScavnge,serialOld,parallelOld,CMS,G1
垃圾收集器 分代模型 适用于新生代: serial parNew parallel Scaavenge 适用于老年代: CMS serial Old(msc) paraller Old 分区模型 适用于超大容量: G1 分代模型 serial /serial Old收集器 1.单线程收集器 2.收集时会暂停其他线程&…...
docker搭建upload-labs
Upload-labs 是一个专门设计用于学习和练习文件上传安全的开源工具。它提供了各种场景的文件上传漏洞,供用户通过实践来学习如何发现和利用这些漏洞,同时也能学习到防御措施。使用 Docker 来搭建 upload-labs 环境是一种快速、简便的方法,它可…...
超详细外贸单证汇总!
今天给大家汇总了外贸单证的种类与使用相关知识,东西齐全,赶紧码住! 1、合同 CONTRACT是统称,买卖双方均可出具。如系卖方制作,可称为销售确认书,买方出具则可称为采购。 买卖双方均可出具合同。卖方出具的,可称为销售确认书(Sales Confir…...
Docker部署ChatGLM3、One API、FastGPT
创建并运行chatglm3容器 docker run --name chatglm3 -p 8000:8000 registry.cn-hangzhou.aliyuncs.com/ryyan/chatglm.cpp:chatglm3-q5_1 创建并运行one-api容器 (其中挂载路径 D:\one-api 可以选择你自己喜欢的目录) docker run --name oneapi -d -p 3000:3000 -e TZAsia…...
【Linux-网络编程】
Linux-网络编程 ■ 网络结构■ C/S结构■ B/S结构 ■ 网络模型■ OSI七层模型■ TCP/IP四层模型 ■ TCP■ TCP通信流程■ TCP三次握手■ TCP四次挥手 ■ 套接字:socket 主机IP 主机上的进程(端口号)■ TCP传输文件 ■ 网络结构 ■ C/S结构…...
win10虚拟机安装驱动教程
在虚拟机菜单栏中选择安装VMware Tools: 安装好后,在虚拟机中打开此电脑,双击DVD驱动器进行安装: 一直点击下一步: 安装完成: 此时重启虚拟机,发面小屏幕页面的虚拟机自动占满了全部屏幕&#x…...
SpringBoot实战项目——博客笔记项目
提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录 前言一、项目介绍二、项目的整体框架 2.1 数据库模块 2.2 前端模块 2.3 后端模块三、项目图片展示四、项目的实现 4.1 准备工作 4.…...
【海贼王的数据航海】排序——直接选择排序|堆排序
目录 1 -> 选择排序 1.1 -> 基本思想 1.2 -> 直接选择排序 1.2.1 -> 代码实现 1.3 -> 堆排序 1.3.1 -> 代码实现 1 -> 选择排序 1.1 -> 基本思想 每一次从待排序的数据元素中选出最小(或最大)的一个元素,存放在序列的起始位置&…...
Flutter 的 switch 语句补遗
我的 App 里,一个消息气泡变成空白了,非常奇怪,此前一直是没问题的,经过调试定位我发现: static TextSpan _buildRootSpan(BuildContext ctx, List<LinkifyElement> parts, TextStyle? style) {List<InlineS…...
Linux动态库*.so函数名修改
在某些学习或者特殊需求的情况下要对linux下动态库*.so文件内部的函数名进行修改。 比如一个函数ADD(int a,int b);修改为Add(int a,int b); 通过这篇文章你将了解到在linux下动态库函数名寻址的规则,截止2024年3月linux动态库的寻址规则已经出现多种,这…...
adb shell 指令集
1.connect device连接设备: adb devices #return: List of devices attached 0123456789ABCDEF device2.连接终端 adb shell从设备拷贝文件到本地 adb pull <remote> [local] 如: adb pull /sdcard/demo.txt e:\从到本地拷贝文件到设备 adb push &…...
React Native 导航系统实战(React Navigation)
导航系统实战(React Navigation) React Navigation 是 React Native 应用中最常用的导航库之一,它提供了多种导航模式,如堆栈导航(Stack Navigator)、标签导航(Tab Navigator)和抽屉…...
AI Agent与Agentic AI:原理、应用、挑战与未来展望
文章目录 一、引言二、AI Agent与Agentic AI的兴起2.1 技术契机与生态成熟2.2 Agent的定义与特征2.3 Agent的发展历程 三、AI Agent的核心技术栈解密3.1 感知模块代码示例:使用Python和OpenCV进行图像识别 3.2 认知与决策模块代码示例:使用OpenAI GPT-3进…...
【入坑系列】TiDB 强制索引在不同库下不生效问题
文章目录 背景SQL 优化情况线上SQL运行情况分析怀疑1:执行计划绑定问题?尝试:SHOW WARNINGS 查看警告探索 TiDB 的 USE_INDEX 写法Hint 不生效问题排查解决参考背景 项目中使用 TiDB 数据库,并对 SQL 进行优化了,添加了强制索引。 UAT 环境已经生效,但 PROD 环境强制索…...
Android Bitmap治理全解析:从加载优化到泄漏防控的全生命周期管理
引言 Bitmap(位图)是Android应用内存占用的“头号杀手”。一张1080P(1920x1080)的图片以ARGB_8888格式加载时,内存占用高达8MB(192010804字节)。据统计,超过60%的应用OOM崩溃与Bitm…...
Fabric V2.5 通用溯源系统——增加图片上传与下载功能
fabric-trace项目在发布一年后,部署量已突破1000次,为支持更多场景,现新增支持图片信息上链,本文对图片上传、下载功能代码进行梳理,包含智能合约、后端、前端部分。 一、智能合约修改 为了增加图片信息上链溯源,需要对底层数据结构进行修改,在此对智能合约中的农产品数…...
纯 Java 项目(非 SpringBoot)集成 Mybatis-Plus 和 Mybatis-Plus-Join
纯 Java 项目(非 SpringBoot)集成 Mybatis-Plus 和 Mybatis-Plus-Join 1、依赖1.1、依赖版本1.2、pom.xml 2、代码2.1、SqlSession 构造器2.2、MybatisPlus代码生成器2.3、获取 config.yml 配置2.3.1、config.yml2.3.2、项目配置类 2.4、ftl 模板2.4.1、…...
elementUI点击浏览table所选行数据查看文档
项目场景: table按照要求特定的数据变成按钮可以点击 解决方案: <el-table-columnprop"mlname"label"名称"align"center"width"180"><template slot-scope"scope"><el-buttonv-if&qu…...
Vue ③-生命周期 || 脚手架
生命周期 思考:什么时候可以发送初始化渲染请求?(越早越好) 什么时候可以开始操作dom?(至少dom得渲染出来) Vue生命周期: 一个Vue实例从 创建 到 销毁 的整个过程。 生命周期四个…...
协议转换利器,profinet转ethercat网关的两大派系,各有千秋
随着工业以太网的发展,其高效、便捷、协议开放、易于冗余等诸多优点,被越来越多的工业现场所采用。西门子SIMATIC S7-1200/1500系列PLC集成有Profinet接口,具有实时性、开放性,使用TCP/IP和IT标准,符合基于工业以太网的…...
Linux中《基础IO》详细介绍
目录 理解"文件"狭义理解广义理解文件操作的归类认知系统角度文件类别 回顾C文件接口打开文件写文件读文件稍作修改,实现简单cat命令 输出信息到显示器,你有哪些方法stdin & stdout & stderr打开文件的方式 系统⽂件I/O⼀种传递标志位…...
