首页
壁纸
留言板
友链
更多
统计归档
Search
1
TensorBoard:训练日志及网络结构可视化工具
12,588 阅读
2
主板开机跳线接线图【F_PANEL接线图】
7,043 阅读
3
Linux使用V2Ray 原生客户端
6,156 阅读
4
移动光猫获取超级密码&开启公网ipv6
4,695 阅读
5
NVIDIA 显卡限制功率
3,133 阅读
好物分享
实用教程
linux使用
wincmd
学习笔记
mysql
java学习
nginx
综合面试题
大数据
网络知识
linux
放码过来
python
javascript
java
opencv
蓝桥杯
leetcode
深度学习
开源模型
相关知识
数据集和工具
模型轻量化
语音识别
计算机视觉
杂七杂八
硬件科普
主机安全
嵌入式设备
其它
bug处理
登录
/
注册
Search
标签搜索
好物分享
学习笔记
linux
MySQL
nvidia
typero
内网穿透
webdav
vps
java
cudann
gcc
cuda
树莓派
CNN
图像去雾
ssh安全
nps
暗通道先验
阿里云
jupiter
累计撰写
354
篇文章
累计收到
71
条评论
首页
栏目
好物分享
实用教程
linux使用
wincmd
学习笔记
mysql
java学习
nginx
综合面试题
大数据
网络知识
linux
放码过来
python
javascript
java
opencv
蓝桥杯
leetcode
深度学习
开源模型
相关知识
数据集和工具
模型轻量化
语音识别
计算机视觉
杂七杂八
硬件科普
主机安全
嵌入式设备
其它
bug处理
页面
壁纸
留言板
友链
统计归档
搜索到
354
篇与
的结果
2023-08-16
sqlite3学习笔记
1.sqlite3简介1.1 什么是 SQLite?SQLite,是一款轻型的数据库,是遵守ACID的关系型数据库管理系统,它包含在一个相对小的C库中。它是D.RichardHipp建立的公有领域项目。它的设计目标是嵌入式的,而且目前已经在很多嵌入式产品中使用了它,它占用资源非常的低,在嵌入式设备中,可能只需要几百K的内存就够了。它能够支持Windows/Linux/Unix等等主流的操作系统,同时能够跟很多程序语言相结合,比如 Tcl、C#、PHP、Java等,还有ODBC接口,同样比起Mysql、PostgreSQL这两款开源的世界著名数据库管理系统来讲,它的处理速度比他们都快。SQLite第一个Alpha版本诞生于2000年5月。 至2015年已经有15个年头,SQLite也迎来了一个版本 SQLite 3已经发布。1.2 为什么要用 SQLite?不需要一个单独的服务器进程或操作的系统(无服务器的)。SQLite 不需要配置,这意味着不需要安装或管理。一个完整的 SQLite 数据库是存储在一个单一的跨平台的磁盘文件。SQLite 是非常小的,是轻量级的,完全配置时小于 400KiB,省略可选功能配置时小于250KiB。SQLite 是自给自足的,这意味着不需要任何外部的依赖。SQLite 事务是完全兼容 ACID 的,允许从多个进程或线程安全访问。SQLite 支持 SQL92(SQL2)标准的大多数查询语言的功能。SQLite 使用 ANSI-C 编写的,并提供了简单和易于使用的 API。SQLite 可在 UNIX(Linux, Mac OS-X, Android, iOS)和 Windows(Win32, WinCE, WinRT)中运行。1.3 SQLite 局限性在 SQLite 中,SQL92 不支持的特性如下所示:特性描述RIGHT OUTER JOIN只实现了 LEFT OUTER JOIN。FULL OUTER JOIN只实现了 LEFT OUTER JOIN。ALTER TABLE支持 RENAME TABLE 和 ALTER TABLE 的 ADD COLUMN variants 命令,不支持 DROP COLUMN、ALTER COLUMN、ADD CONSTRAINT。Trigger 支持支持 FOR EACH ROW 触发器,但不支持 FOR EACH STATEMENT 触发器。VIEWs在 SQLite 中,视图是只读的。您不可以在视图上执行 DELETE、INSERT 或 UPDATE 语句。GRANT 和 REVOKE可以应用的唯一的访问权限是底层操作系统的正常文件访问权限。1.4 SQLite 命令与关系数据库进行交互的标准 SQLite 命令类似于 SQL。命令包括 CREATE、SELECT、INSERT、UPDATE、DELETE 和 DROP。这些命令基于它们的操作性质可分为以下几种:DDL - 数据定义语言命令描述CREATE创建一个新的表,一个表的视图,或者数据库中的其他对象。ALTER修改数据库中的某个已有的数据库对象,比如一个表。DROP删除整个表,或者表的视图,或者数据库中的其他对象。DML - 数据操作语言命令描述INSERT创建一条记录。UPDATE修改记录。DELETE删除记录。DQL - 数据查询语言命令描述SELECT从一个或多个表中检索某些记录。2.SQLite 命令如需获取可用的点命令的清单,可以在任何时候输入 ".help"。例如:sqlite>.help常用命令:命令描述.backup ?DB? FILE备份 DB 数据库(默认是 "main")到 FILE 文件。.databases列出数据库的名称及其所依附的文件。.dump ?TABLE?以 SQL 文本格式转储数据库。如果指定了 TABLE 表,则只转储匹配 LIKE 模式的 TABLE 表。.exit退出 SQLite 提示符。.header(s) ON或OFF开启或关闭头部显示。.help显示所有命令列表和帮助信息。.import FILE TABLE导入来自 FILE 文件的数据到 TABLE 表中。.mode MODE设置输出模式,MODE 可以是下列之一:csv 逗号分隔的值column 左对齐的列html HTML 的 \<table\> 代码insert TABLE 表的 SQL 插入(insert)语句line 每行一个值list 由 .separator 字符串分隔的值tabs 由 Tab 分隔的值tcl TCL 列表元素.quit退出 SQLite 提示符。.read FILENAME执行 FILENAME 文件中的 SQL。.schema ?TABLE?显示 CREATE 语句。如果指定了 TABLE 表,则只显示匹配 LIKE 模式的 TABLE 表。.separator STRING改变输出模式和 .import 所使用的分隔符。.show显示各种设置的当前值。.tables ?PATTERN?列出匹配 LIKE 模式的表的名称。3.SQLite 数据类型3.1 SQLite 存储类每个存储在 SQLite 数据库中的值都具有以下存储类之一:存储类描述NULL值是一个 NULL 值。INTEGER值是一个带符号的整数,根据值的大小存储在 1、2、3、4、6 或 8 字节中。REAL值是一个浮点值,存储为 8 字节的 IEEE 浮点数字。TEXT值是一个文本字符串,使用数据库编码(UTF-8、UTF-16BE 或 UTF-16LE)存储。BLOB值是一个 blob 数据,完全根据它的输入存储。SQLite 的存储类稍微比数据类型更普遍。INTEGER 存储类,例如,包含 6 种不同的不同长度的整数数据类型。3.2 SQLite 亲和(Affinity)类型SQLite支持列的亲和类型概念。任何列仍然可以存储任何类型的数据,当数据插入时,该字段的数据将会优先采用亲缘类型作为该值的存储方式。下表列出了当创建 SQLite3 表时可使用的各种数据类型名称,同时也显示了相应的亲和类型:数据类型亲和类型INT、INTEGER、TINYINT、SMALLINT、MEDIUMINT、BIGINT、UNSIGNED BIG INT、INT2、INT8INTEGERCHARACTER(20)、VARCHAR(255)、VARYING CHARACTER(255)、NCHAR(55)、NATIVE CHARACTER(70)、NVARCHAR(100)、TEXT、CLOBTEXTBLOB、未指定类型BLOBREAL、DOUBLE、DOUBLE PRECISION、FLOATREALNUMERIC、DECIMAL(10,5)、BOOLEAN、DATE、DATETIMENUMERIC3.3 Date 与 Time 数据类型SQLite 没有一个单独的用于存储日期和/或时间的存储类,但 SQLite 能够把日期和时间存储为 TEXT、REAL 或 INTEGER 值。存储类日期格式TEXT格式为 "YYYY-MM-DD HH:MM:SS.SSS" 的日期。REAL从公元前 4714 年 11 月 24 日格林尼治时间的正午开始算起的天数。INTEGER从 1970-01-01 00:00:00 UTC 算起的秒数。您可以以任何上述格式来存储日期和时间,并且可以使用内置的日期和时间函数来自由转换不同格式。4.SQLite 创建数据库4.1 语法sqlite3 命令的基本语法如下:$ sqlite3 DatabaseName.db通常情况下,数据库名称在 RDBMS 内应该是唯一的。另外我们也可以使用 .open 来建立新的数据库文件:sqlite>.open test.db上面的命令创建了数据库文件 test.db,位于 sqlite3 命令同一目录下。打开已存在数据库也是用 .open 命令,以上命令如果 test.db 存在则直接会打开,不存在就创建它。4.2 dump 命令您可以在命令提示符中使用 SQLite .dump 点命令来导出完整的数据库在一个文本文件中,如下所示:$sqlite3 testDB.db .dump > testDB.sql上面的命令将转换整个 testDB.db 数据库的内容到 SQLite 的语句中,并将其转储到 ASCII 文本文件 testDB.sql 中。您可以通过简单的方式从生成的 testDB.sql 恢复,如下所示:$sqlite3 testDB.db < testDB.sql4.SQLite表管理命令4.1 创建表CREATE TABLE database_name.table_name( column1 datatype, column2 datatype, column3 datatype, ..... columnN datatype, PRIMARY KEY( one or more columns ) );示例create table department( id integer not null, dept_name text not null, emp_id integet not null, primary key(id) );sqlite> .tables department4.2 查看表的完整信息可以使用 SQLite的 .schema 命令得到表的完整信息。sqlite> .schema department CREATE TABLE department( id integer not null, dept_name text not null, emp_id integet not null, primary key(id) );4.3 删除表DROP TABLE 语句的基本语法如下。您可以选择指定带有表名的数据库名称,如下所示:DROP TABLE database_name.table_name;4.4 修改表Alter 命令用来重命名已有的表的 ALTER TABLE 的基本语法如下:ALTER TABLE database_name.table_name RENAME TO new_table_name;用来在已有的表中添加一个新的列的 ALTER TABLE 的基本语法如下(新添加的列是以 NULL 值来填充的。):ALTER TABLE database_name.table_name ADD COLUMN column_def...;4.5 清空表Truncate操作在 SQLite 中,并没有 TRUNCATE TABLE 命令,但可以使用 SQLite 的 DELETE 命令从已有的表中删除全部的数据,但建议使用 DROP TABLE 命令删除整个表,然后再重新创建一遍。5.SQLite表数据增删改查、视图、事务与mysql等数据库基本保持一致6.java spring项目使用SQLite6.1 pom.xml<dependency> <groupId>org.xerial</groupId> <artifactId>sqlite-jdbc</artifactId> <version>3.25.2</version> </dependency>6.2 配置文件中设置datasource为sqlite# application-dev.yaml server: port: 80 spring: datasource: # url最容易出错,如果使用相对于项目的相对地址,那么填入 jdbc:sqlite::resource:sqlit数据库所在位置 # 注: # :resource: 指向项目的 resources 路径(resource前后两个 `:` 不能省略) url: jdbc:sqlite::resource:db/user.sqlite driver-class-name: org.sqlite.JDBC # username: 选用 sqlite 数据库不需要配置此项 # password: 选用 sqlite 数据库不需要配置此项 continue-on-error: true mybatis-plus: mapper-locations: classpath:mapper/*Mapper.xml type-aliases-package: com.example.springbootsqlite.model数据源配好以后,其他操作跟普通 springboot项目一致,mybatis及mybatis-plus 可用完整项目参考:https://gitee.com/cphovo/springboot-sqlite参考资料SQLite 教程 | 菜鸟教程 (runoob.com)sqlite3数据库小白入门(Linux) - 知乎 (zhihu.com)SQLite 教程_w3cschoolSpring Boot With SQLite | BaeldungIDEA中使用SQLite数据库_idea sqlite_牛右刀薛面的博客-CSDN博客Springboot 整合 Sqlite - kosihpc - 博客园 (cnblogs.com)springboot-sqlite: 一个以 sqlite 为数据库的 springboot-demo (gitee.com)
2023年08月16日
63 阅读
0 评论
0 点赞
2023-08-16
Hutool:小而全的Java工具类库
1.Hutool介绍1.1 简介Hutool是一个功能丰富且易用的Java工具库,通过诸多实用工具类的使用,旨在帮助开发者快速、便捷地完成各类开发任务。 这些封装的工具涵盖了字符串、数字、集合、编码、日期、文件、IO、加密、数据库JDBC、JSON、HTTP客户端等一系列操作, 可以满足各种不同的开发需求。1.2 Hutool名称的由来Hutool = Hu + tool,是原公司项目底层代码剥离后的开源库,“Hu”是公司名称的表示,tool表示工具。Hutool谐音“糊涂”,一方面简洁易懂,一方面寓意“难得糊涂”。1.3 Hutool理念来自官方:Hutool既是一个工具集,也是一个知识库,我们从不自诩代码原创,大多数工具类都是搬运而来,因此:你可以引入使用,也可以拷贝和修改使用,而不必标注任何信息,只是希望能把bug及时反馈回来。我们努力健全中文注释,为源码学习者提供良好地学习环境,争取做到人人都能看得懂。1.4 官方文档中文文档中文备用文档参考API视频介绍1.5 前端pom.xml引入全部包<dependency> <groupId>cn.hutool</groupId> <artifactId>hutool-all</artifactId> <version>5.8.16</version> </dependency>2.Hutool包含组件一个Java基础工具类,对文件、流、加密解密、转码、正则、线程、XML等JDK方法进行封装,组成各种Util工具类,同时提供以下组件:模块介绍hutool-aopJDK动态代理封装,提供非IOC下的切面支持hutool-bloomFilter布隆过滤,提供一些Hash算法的布隆过滤hutool-cache简单缓存实现hutool-core核心,包括Bean操作、日期、各种Util等hutool-cron定时任务模块,提供类Crontab表达式的定时任务hutool-crypto加密解密模块,提供对称、非对称和摘要算法封装hutool-dbJDBC封装后的数据操作,基于ActiveRecord思想hutool-dfa基于DFA模型的多关键字查找hutool-extra扩展模块,对第三方封装(模板引擎、邮件、Servlet、二维码、Emoji、FTP、分词等)hutool-http基于HttpUrlConnection的Http客户端封装hutool-log自动识别日志实现的日志门面hutool-script脚本执行封装,例如Javascripthutool-setting功能更强大的Setting配置文件和Properties封装hutool-system系统参数调用封装(JVM信息等)hutool-jsonJSON实现hutool-captcha图片验证码实现hutool-poi针对POI中Excel和Word的封装hutool-socket基于Java的NIO和AIO的Socket封装hutool-jwtJSON Web Token (JWT)封装实现可以根据需求对每个模块单独引入,也可以通过引入hutool-all方式引入所有模块。3.各模块功能使用参考官方文档:https://www.hutool.cn/docs参考资料hutool: 小而全的Java工具类库,使Java拥有函数式语言般的优雅,让Java语言也可以“甜甜的”。 (gitee.com)Hutool——国产良心工具包,让你的java变得更甜 - 知乎 (zhihu.com)入门和安装 (hutool.cn)
2023年08月16日
43 阅读
0 评论
0 点赞
2023-08-15
redis学习笔记
1.Redis介绍1.1 Redis 简介Redis 是完全开源的,遵守 BSD 协议,是一个高性能的 key-value 数据库。Redis 与其他 key - value 缓存产品有以下三个特点:Redis支持数据的持久化,可以将内存中的数据保存在磁盘中,重启的时候可以再次加载进行使用。Redis不仅仅支持简单的key-value类型的数据,同时还提供list,set,zset,hash等数据结构的存储。Redis支持数据的备份,即master-slave模式的数据备份。1.2 Redis 优势性能极高 – Redis能读的速度是110000次/s,写的速度是81000次/s 。丰富的数据类型 – Redis支持二进制案例的 Strings, Lists, Hashes, Sets 及 Ordered Sets 数据类型操作。原子 – Redis的所有操作都是原子性的,意思就是要么成功执行要么失败完全不执行。单个操作是原子性的。多个操作也支持事务,即原子性,通过MULTI和EXEC指令包起来。丰富的特性 – Redis还支持 publish/subscribe, 通知, key 过期等等特性。1.3 Redis与其他key-value存储有什么不同?Redis有着更为复杂的数据结构并且提供对他们的原子性操作,这是一个不同于其他数据库的进化路径。Redis的数据类型都是基于基本数据结构的同时对程序员透明,无需进行额外的抽象。Redis运行在内存中但是可以持久化到磁盘,所以在对不同数据集进行高速读写时需要权衡内存,因为数据量不能大于硬件内存。在内存数据库方面的另一个优点是,相比在磁盘上相同的复杂的数据结构,在内存中操作起来非常简单,这样Redis可以做很多内部复杂性很强的事情。同时,在磁盘格式方面他们是紧凑的以追加的方式产生的,因为他们并不需要进行随机访问。2.Redis安装和配置略3.Redis常用命令3.1 Redis 客户端连接服务器# 连接远程服务器语法 $ redis-cli -h host -p port -a password # 连接本机无密码redis服务器示例 并使用ping命令检测服务器是否启动 alpine1:/home/gitlab/etc# redis-cli -h 127.0.0.1 -p 6379 127.0.0.1:6379> ping PONG3.2 Redis 键(key)Redis 键命令用于管理 redis 的键。# Redis 键命令基本语法 redis 127.0.0.1:6379> COMMAND KEY_NAME # 删除key,如果键被删除成功,命令执行后输出 (integer) 1,否则将输出 (integer) 0 127.0.0.1:6379> del key (integer) 1 # 检查给定 key 是否存在。 127.0.0.1:6379> exists key (integer) 1 127.0.0.1:6379> exists noexistkey (integer) 0 # 为给定 key 设置过期时间,以秒计。 127.0.0.1:6379> expire key 100 (integer) 1 # 以秒为单位,返回给定 key 的剩余生存时间(TTL, time to live)。 127.0.0.1:6379> ttl key (integer) 44 # 设置 key 的过期时间以毫秒计。 127.0.0.1:6379> pexpire key 1000000 (integer) 1 # 以毫秒为单位返回 key 的剩余的过期时间。 127.0.0.1:6379> pttl key (integer) 994201 # 移除 key 的过期时间,key 将持久保持。 127.0.0.1:6379> persist key (integer) 1 127.0.0.1:6379> ttl key (integer) -1 # 查找所有符合给定模式( pattern)的 key 。 127.0.0.1:6379> keys * 1) "key" 2) "key1" # 修改 key 的名称 127.0.0.1:6379> get key1 "hello" 127.0.0.1:6379> rename key1 key2 OK 127.0.0.1:6379> get key2 "hello" # 仅当 newkey 不存在时,将 key 改名为 newkey 。 127.0.0.1:6379> renamenx key2 key (integer) 0 127.0.0.1:6379> renamenx key2 key3 (integer) 1 # 查看key 所储存的值的类型。 127.0.0.1:6379> type key string3.3 Redis 字符串命令# 设置指定 key 的值。 127.0.0.1:6379> set key helloworld OK # 获取指定 key 的值。 127.0.0.1:6379> get key "helloworld" # 将 key 中储存的数字值增一。 127.0.0.1:6379> set number 100 OK 127.0.0.1:6379> incr number (integer) 101 # 将 key 所储存的值加上给定的增量值(increment) 。 127.0.0.1:6379> incrby number 101 (integer) 202 # 将 key 中储存的数字值减一。 127.0.0.1:6379> decr number (integer) 201 # key 所储存的值减去给定的减量值(decrement) 。 127.0.0.1:6379> decrby number 100 (integer) 101 # 指定的 value 追加到该 key 原来值(value)的末尾。 127.0.0.1:6379> set appendstr hello OK 127.0.0.1:6379> append appendstr world (integer) 10 127.0.0.1:6379> get appendstr "helloworld" # 将值 value 关联到 key ,并将 key 的过期时间设为 seconds (以秒为单位)。 127.0.0.1:6379> setex key seconds value3.4 Redis 哈希(Hash)命令Redis hash 是一个 string 类型的 field(字段) 和 value(值) 的映射表,hash 特别适合用于存储对象。类似java中的HashMapRedis 中每个 hash 可以存储 $2^32$ - 1 键值对(40多亿)。# 批量设置hash对象的属性 # 语法 hmset key field value [field value ...] 127.0.0.1:6379> hmset person name zhangsan age 22 school caus OK # 获取在哈希表中指定 key 的所有字段和值 127.0.0.1:6379> hgetall person 1) "name" 2) "zhangsan" 3) "age" 4) "22" 5) "school" 6) "caus" # 将哈希表 key 中的字段 field 的值设为 value 。 # 语法 hset key field value 127.0.0.1:6379> hset person girlfirend xiaohong (integer) 1 127.0.0.1:6379> hgetall person 1) "name" 2) "zhangsan" 3) "age" 4) "22" 5) "school" 6) "caus" 7) "girlfirend" 8) "xiaohong" # 删除一个或多个哈希表字段 # 语法 hdel key field [field ...] 127.0.0.1:6379> hdel person girlfirend (integer) 1 127.0.0.1:6379> hgetall person 1) "name" 2) "zhangsan" 3) "age" 4) "22" 5) "school" 6) "caus" # 获取存储在哈希表中指定字段的值。 # 语法 hget key field 127.0.0.1:6379> hmget person name 1) "zhangsan"3.5 Redis 列表(List)命令Redis列表是简单的字符串列表,按照插入顺序排序。你可以添加一个元素到列表的头部(左边)或者尾部(右边)# 将一个或多个值插入到列表头部 # 语法 lpush key value [value ...] 127.0.0.1:6379> lpush list a b c d (integer) 4 # 查看列表指定区间元素、查看列表全部元素 # 语法 lrange key start stop 127.0.0.1:6379> lrange list 0 -1 1) "d" 2) "c" 3) "b" 4) "a" 127.0.0.1:6379> lrange list 0 2 1) "d" 2) "c" # 通过索引获取列表中的元素 # 语法 lindex key index 127.0.0.1:6379> lindex list 2 "b" # 获取列表长度 127.0.0.1:6379> llen list (integer) 4 # 移出并获取列表的第一个元素 127.0.0.1:6379> lpop list "d" # 对一个列表进行修剪(trim),就是说,让列表只保留指定区间内的元素,不在指定区间之内的元素都将被删除。 # 语法 ltrim key start stop 127.0.0.1:6379> ltrim list 0 1 OK 127.0.0.1:6379> lrange list 0 -1 1) "c" 2) "b" # 在列表中添加一个或多个值到列表尾部 # 语法 rpush key value [value ...] 127.0.0.1:6379> rpush list e f i g h i j k (integer) 10 127.0.0.1:6379> lrange list 0 -1 1) "c" 2) "b" 3) "e" 4) "f" 5) "i" 6) "g" 7) "h" 8) "i" 9) "j" 10) "k" # 移除列表的最后一个元素,返回值为移除的元素。 127.0.0.1:6379> rpop list "k"3.6 Redis 集合(Set)命令Redis 的 Set 是 String 类型的无序集合。集合成员是唯一的,这就意味着集合中不能出现重复的数据。集合对象的编码可以是 intset 或者 hashtable。Redis 中集合是通过哈希表实现的,所以添加,删除,查找的复杂度都是 O(1)。# 向集合添加一个或多个成员 # 语法 sadd key member [member ...] 127.0.0.1:6379> sadd myset hello world (integer) 2 # 查看集合所有元素 127.0.0.1:6379> smembers myset 1) "world" 2) "hello"3.7 Redis 有序集合(sorted set)命令Redis 有序集合和集合一样也是 string 类型元素的集合,且不允许重复的成员。不同的是每个元素都会关联一个 double 类型的分数。redis 正是通过分数来为集合中的成员进行从小到大的排序。有序集合的成员是唯一的,但分数(score)却可以重复。# 向有序集合添加一个或多个成员,或者更新已存在成员的分数 # 语法 zadd key score1 member1 [score2 member2] 127.0.0.1:6379> zadd sortedset 80 xiaoming 90 xiaohong 66 zhangsan (integer) 3 # 通过索引区间返回有序集合指定区间内的成员 # 语法 zrange key start stop [WITHSCORES] 127.0.0.1:6379> zrange sortedset 0 100 WITHSCORES 1) "zhangsan" 2) "66" 3) "xiaoming" 4) "80" 5) "xiaohong" 6) "90" 127.0.0.1:6379> zrange sortedset 0 100 1) "zhangsan" 2) "xiaoming" 3) "xiaohong" # 计算在有序集合中指定区间分数的成员数 # 语法 zcount key min max 127.0.0.1:6379> zcount sortedset 80 90 (integer) 2 # 有序集合中对指定成员的分数加上增量 increment # 语法 zincrby key increment member 127.0.0.1:6379> zincrby sortedset 10 zhangsan "76" # 移除有序集合中的一个或多个成员 # 语法 zrem key member [member ...] 127.0.0.1:6379> zrem sortedset xiaoming (integer) 1 127.0.0.1:6379> zrange sortedset 0 100 WITHSCORES 1) "zhangsan" 2) "76" 3) "xiaohong" 4) "90"4.Redis 发布订阅Redis 发布订阅 (pub/sub) 是一种消息通信模式:发送者 (pub) 发送消息,订阅者 (sub) 接收消息。Redis 客户端可以订阅任意数量的频道。下图展示了频道 channel1 , 以及订阅这个频道的三个客户端 —— client2 、 client3 和 client1 之间的关系:当有新消息通过 PUBLISH 命令发送给频道 channel1 时, 这个消息就会被发送给订阅它的三个客户端:# 订阅给定的一个或多个频道的信息。 # 语法 subscribe channel [channel ...] # 将信息发送到指定的频道。 # publish channel message示例# 第一个客户端--订阅者 127.0.0.1:6379> subscribe jupizhe Reading messages... (press Ctrl-C to quit) 1) "subscribe" 2) "jupiter" 3) (integer) 1 1) "message" 2) "jupiter" 3) "hello, welcom to subscribe" 1) "message" 2) "jupiter" 3) "who are you" # 第二个客户端--发布者 127.0.0.1:6379> publish jupiter "who are you" (integer) 15.Redis Stream6.Java maven项目使用 Redis6.1 pom.xml<dependency> <groupId>redis.clients</groupId> <artifactId>jedis</artifactId> <version>2.9.0</version> </dependency6.2 连接到 redis 服务@Test void testRedisConnect(){ //连接 Redis 服务 Jedis jedis = new Jedis("172.31.126.219"); // 如果 Redis 服务设置了密码,需要下面这行,没有就不需要 // jedis.auth("123456"); System.out.println("连接成功"); //查看服务是否运行 System.out.println("服务正在运行: "+jedis.ping()); }连接成功 服务正在运行: PONG6.3 Redis Java String(字符串) 实例@Test void testRedisString() throws InterruptedException { //连接 Redis 服务 Jedis jedis = new Jedis("172.31.126.219"); // 如果 Redis 服务设置了密码,需要下面这行,没有就不需要 // jedis.auth("123456"); System.out.println("连接成功"); //设置 redis 字符串数据 jedis.setex("verifycode",300,"387432"); // 获取存储的数据并输出 System.out.println("redis 存储的字符串为: "+ jedis.get("verifycode")); Thread.sleep(3000); System.out.println("redis 存储的字符串有效期为: "+ jedis.ttl("verifycode")+" 秒"); }连接成功 redis 存储的字符串为: 387432 redis 存储的字符串有效期为: 297 秒6.4 Redis Java List(列表) 实例@Test void testRedisList() { //连接Redis 服务 Jedis jedis = new Jedis("172.31.126.219"); // 如果 Redis 服务设置了密码,需要下面这行,没有就不需要 // jedis.auth("123456"); System.out.println("连接成功"); //存储数据到列表中 jedis.lpush("site-list", "JinDong"); jedis.lpush("site-list", "Google"); jedis.lpush("site-list", "Taobao"); // 获取存储的数据并输出 List<String> list = jedis.lrange("site-list", 0 ,2); for(int i=0; i<list.size(); i++) { System.out.println("列表项为: "+list.get(i)); }连接成功 列表项为: Taobao 列表项为: Google 列表项为: JinDong其他调用参考redis常用命令参考资料Redis 教程 | 菜鸟教程 (runoob.com)Redis命令大全(超详细) - 蚂蚁小哥 - 博客园 (cnblogs.com)Redis(第1期):如何在Java中优雅的使用Redis - 知乎 (zhihu.com)Redis命令大全(超详细) - 蚂蚁小哥 - 博客园 (cnblogs.com)
2023年08月15日
45 阅读
0 评论
0 点赞
2023-08-10
Git学习笔记
1.Git简介1.1 简介Git 是一个开源的分布式版本控制系统,用于敏捷高效地处理任何或小或大的项目。Git 是 Linus Torvalds 为了帮助管理 Linux 内核开发而开发的一个开放源码的版本控制软件。Git 与常用的版本控制工具 CVS, Subversion 等不同,它采用了分布式版本库的方式,不必服务器端软件支持。1.2 git工作流程克隆 Git 资源作为工作目录。在克隆的资源上添加或修改文件。如果其他人修改了,你可以更新资源。在提交前查看修改。提交修改。在修改完成后,如果发现错误,可以撤回提交并再次修改并提交。1.3 Git 工作区、暂存区和版本库工作区:就是你在电脑里能看到的目录。暂存区:英文叫 stage 或 index。一般存放在 .git 目录下的 index 文件(.git/index)中,所以我们把暂存区有时也叫作索引(index)。版本库:工作区有一个隐藏目录 .git,这个不算工作区,而是 Git 的版本库。2.Git 安装和配置用户信息Git 各平台安装包下载地址为:http://git-scm.com/downloads2.1 Linux 平台上安装Git 的工作需要调用 curl,zlib,openssl,expat,libiconv 等库的代码,所以需要先安装这些依赖工具。在有 yum 的系统上(比如 Fedora)或者有 apt-get 的系统上(比如 Debian 体系),可以用下面的命令安装:各 Linux 系统可以使用其安装包管理工具(apt-get、yum 等)进行安装:Debian/Ubuntu$ apt-get install libcurl4-gnutls-dev libexpat1-dev gettext libz-dev libssl-dev $ apt-get install gitCentos/RedHat$ yum install curl-devel expat-devel gettext-devel openssl-devel zlib-devel $ yum -y install git-core2.2 Windows 平台上安装在 Windows 平台上安装 Git 同样轻松,有个叫做 msysGit 的项目提供了安装包,可以到 GitHub 的页面上下载 exe 安装文件并运行:安装包下载地址:https://gitforwindows.org/官网慢,可以用国内的镜像:https://npm.taobao.org/mirrors/git-for-windows/。2.3 配置用户信息配置个人的用户名称和电子邮件地址:$ git config --global user.name "runoob" $ git config --global user.email test@runoob.com如果用了 --global 选项,那么更改的配置文件就是位于你用户主目录下的那个,以后你所有的项目都会默认使用这里配置的用户信息。如果要在某个特定的项目中使用其他名字或者电邮,只要去掉 --global 选项重新配置即可,新的设定保存在当前项目的 .git/config 文件里。要检查已有的配置信息,可以使用 git config --list 命令:$ git config --list http.postbuffer=2M user.name=runoob user.email=test@runoob.com3.Git 基本操作Git 常用的是以下 6 个命令:git clone、git push、git add 、git commit、git checkout、git pullworkspace:工作区staging area:暂存区/缓存区local repository:版本库或本地仓库remote repository:远程仓库3.1 创建仓库命令git init # 初始化仓库 git clone # 拷贝一份远程仓库,也就是下载一个项目。3.2 提交与修改git add # 添加文件到暂存区 git status # 查看仓库当前的状态,显示有变更的文件。 git diff # 比较文件的不同,即暂存区和工作区的差异。 git commit # 提交暂存区到本地仓库。 git reset # 回退版本。 git rm # 将文件从暂存区和工作区中删除。 git mv # 移动或重命名工作区文件。3.3 查看提交日志git log # 查看历史提交记录 git blame <file> # 以列表形式查看指定文件的历史修改记录3.4 远程操作git remote # 远程仓库操作 git fetch # 从远程获取代码库 git pull # 下载远程代码并合并 git push # 上传远程代码并合并4.Git 分支管理几乎每一种版本控制系统都以某种形式支持分支,一个分支代表一条独立的开发线。使用分支意味着你可以从开发主线上分离开来,然后在不影响主线的同时继续工作。创建的新分支会以当前分支的状态为基础。4.1 列出分支$ git branch * master4.2 创建分支如果我们要手动创建一个分支。执行 git branch (branchname) 即可。$ git branch testing $ git branch * master testing4.3 切换分支git checkout (branchname)4.4 创建和切换分支小实验(★★★)# 初始化仓库 $ mkdir GitStudy $ cd GitStudy $ git init # 在master分支下创建master-branch.txt文件并提交到master分支 $ touch master-branch.txt $ git add . $ git commit -m "master first commit" [master (root-commit) f2248bb] master first commit 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 master-branch.txt # 创建test分支,会以master分支为基础,这个时候ls看到的文件状态和master分支的是一致的 $ git branch test $ git checkout test Switched to branch 'test' $ ls master-branch.txt # 在test分支下创建test-branch.txt文件并提交到test分支 $ touch test-branch.txt $ ls master-branch.txt test-branch.txt $ git add . $ git commit -m "test branch firsh commit" [test 070c6a3] test branch firsh commit 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 test-branch.txt # 切换回master分支查看test分支的修改是否对master分支造成了影响 $ git checkout master Switched to branch 'master' $ ls master-branch.txt 4.5 合并分支一旦某分支有了独立内容,你终究会希望将它合并回到你的主分支。 你可以使用以下命令将任何分支合并到当前分支中去。git merge branchname执行合并命令会将指定分支合并到当前工作分支上,我们假设当前工作分支为main,合并过程如下图所示。合并完后就可以删除分支:$ git branch -d branchname 4.6 分支合并小实验# 查看主分支已提交的文件 $ git branch * master test $ ls master-branch.txt master.txt # 查看test分支文件已提交的文件 $ git checkout test Switched to branch 'test' $ git branch master * test $ ls master-branch.txt test-branch.txt # 合并test分支到master分支 $ git checkout master Switched to branch 'master' $ git merge test Merge made by the 'ort' strategy. test-branch.txt | 0 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 test-branch.txt # 查看合并后的文件,均为已提交的文件 $ ls master-branch.txt master.txt test-branch.txt # 删除test分支 $ git branch -d test Deleted branch test (was 070c6a3). $ git branch * master 4.7 分支合并冲突小实验# 该实验在空白文件夹进行实验 # 初始化master分支并创建init.txt文件并提交 $ git init Initialized empty Git repository in C:/Users/LuoJia/Desktop/WorkSpace/GitStudy/. git/ $ touch init.txt $ git add . $ git commit -m "master add init.txt" [master (root-commit) 8af249b] master add init.txt 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 init.txt # 新建test分支 $ git branch test $ git checkout test Switched to branch 'test' # 在test分支下创建test.txt和confict.txt文件并提交 $ touch test.txt $ vim confict.txt $ cat confict.txt <?php echo 'test'; ?> $ git add . warning: in the working copy of 'confict.txt', LF will be replaced by CRLF the n ext time Git touches it $ git commit -m "test write" [test 30bfb3c] test write 2 files changed, 3 insertions(+) create mode 100644 confict.txt create mode 100644 test.txt # 回到master分支,创建master.txt和confict.txt文件并提交 $ git checkout master Switched to branch 'master' $ ls init.txt $ touch master.txt $ vim confict.txt $ cat confict.txt <?php echo 'master'; ?> $ git add . warning: in the working copy of 'confict.txt', LF will be replaced by CRLF the n ext time Git touches it $ git commit -m "master write" [master dd7620b] master write 2 files changed, 3 insertions(+) create mode 100644 confict.txt create mode 100644 master.txt # 尝试合并test分支,会发现发生了文件冲突 $ git merge test Auto-merging confict.txt CONFLICT (add/add): Merge conflict in confict.txt Automatic merge failed; fix conflicts and then commit the result. $ cat confict.txt <?php <<<<<<< HEAD echo 'master'; ======= echo 'test'; >>>>>>> test ?> # 需要手动编辑解决冲突 $ vim confict.txt $ cat confict.txt <?php echo 'master'; echo 'test'; ?> # 手动解决冲突后需要对冲突文件进行重新提交 $ git add confict.txt $ git commit -m "solve confict of confict.txt" [master 9b4bbfc] solve confict of confict.txt 参考资料1. Git 教程 | 菜鸟教程 (runoob.com)2. Git 常用基本命令使用详细大全_git命令_坚强的小水滴的博客-CSDN博客3. 使用分支——Git Merge命令 - 知乎 (zhihu.com)
2023年08月10日
52 阅读
0 评论
0 点赞
2023-08-10
docker学习笔记
1.docker介绍1.1 简介Docker 是一个开源的应用容器引擎,基于 Go 语言 并遵从 Apache2.0 协议开源。Docker 可以让开发者打包他们的应用以及依赖包到一个轻量级、可移植的容器中,然后发布到任何流行的 Linux 机器上,也可以实现虚拟化。容器是完全使用沙箱机制,相互之间不会有任何接口(类似 iPhone 的 app),更重要的是容器性能开销极低。1.2 Docker的应用场景Web 应用的自动化打包和发布。自动化测试和持续集成、发布。在服务型环境中部署和调整数据库或其他的后台应用。从头编译或者扩展现有的 OpenShift 或 Cloud Foundry 平台来搭建自己的 PaaS 环境。1.3 Docker 的优点Docker 是一个用于开发,交付和运行应用程序的开放平台。Docker 使您能够将应用程序与基础架构分开,从而可以快速交付软件。借助 Docker,您可以与管理应用程序相同的方式来管理基础架构。通过利用 Docker 的方法来快速交付,测试和部署代码,您可以大大减少编写代码和在生产环境中运行代码之间的延迟。1、快速,一致地交付您的应用程序Docker 允许开发人员使用您提供的应用程序或服务的本地容器在标准化环境中工作,从而简化了开发的生命周期。容器非常适合持续集成和持续交付(CI / CD)工作流程,请考虑以下示例方案:您的开发人员在本地编写代码,并使用 Docker 容器与同事共享他们的工作。他们使用 Docker 将其应用程序推送到测试环境中,并执行自动或手动测试。当开发人员发现错误时,他们可以在开发环境中对其进行修复,然后将其重新部署到测试环境中,以进行测试和验证。测试完成后,将修补程序推送给生产环境,就像将更新的镜像推送到生产环境一样简单。2、响应式部署和扩展Docker 是基于容器的平台,允许高度可移植的工作负载。Docker 容器可以在开发人员的本机上,数据中心的物理或虚拟机上,云服务上或混合环境中运行。Docker 的可移植性和轻量级的特性,还可以使您轻松地完成动态管理的工作负担,并根据业务需求指示,实时扩展或拆除应用程序和服务。3、在同一硬件上运行更多工作负载Docker 轻巧快速。它为基于虚拟机管理程序的虚拟机提供了可行、经济、高效的替代方案,因此您可以利用更多的计算能力来实现业务目标。Docker 非常适合于高密度环境以及中小型部署,而您可以用更少的资源做更多的事情。2.Docker 架构Docker 包括三个基本概念:镜像(Image):Docker 镜像(Image),就相当于是一个 root 文件系统。比如官方镜像 ubuntu:16.04 就包含了完整的一套 Ubuntu16.04 最小系统的 root 文件系统。容器(Container):镜像(Image)和容器(Container)的关系,就像是面向对象程序设计中的类和实例一样,镜像是静态的定义,容器是镜像运行时的实体。容器可以被创建、启动、停止、删除、暂停等。仓库(Repository):仓库可看成一个代码控制中心,用来保存镜像。Docker 使用客户端-服务器 (C/S) 架构模式,使用远程API来管理和创建Docker容器。Docker 容器通过 Docker 镜像来创建。容器与镜像的关系类似于面向对象编程中的对象与类。Docker面向对象容器对象镜像类概念说明Docker 镜像(Images)Docker 镜像是用于创建 Docker 容器的模板,比如 Ubuntu 系统。Docker 容器(Container)容器是独立运行的一个或一组应用,是镜像运行时的实体。Docker 客户端(Client)Docker 客户端通过命令行或者其他工具使用 Docker SDK (https://docs.docker.com/develop/sdk/) 与 Docker 的守护进程通信。Docker 主机(Host)一个物理或者虚拟的机器用于执行 Docker 守护进程和容器。Docker RegistryDocker 仓库用来保存镜像,可以理解为代码控制中的代码仓库。Docker Hub(https://hub.docker.com) 提供了庞大的镜像集合供使用。一个 Docker Registry 中可以包含多个仓库(Repository);每个仓库可以包含多个标签(Tag);每个标签对应一个镜像。通常,一个仓库会包含同一个软件不同版本的镜像,而标签就常用于对应该软件的各个版本。我们可以通过 <仓库名>:<标签> 的格式来指定具体是这个软件哪个版本的镜像。如果不给出标签,将以 latest 作为默认标签。Docker MachineDocker Machine是一个简化Docker安装的命令行工具,通过一个简单的命令行即可在相应的平台上安装Docker,比如VirtualBox、 Digital Ocean、Microsoft Azure。3.Docker安装3.1 Alpineapk add docker service docker start docker version # 查看docker版本3.2 Ubuntu# 使用官方脚本自动安装 curl -fsSL https://test.docker.com -o test-docker.sh sudo sh test-docker.sh3.3 CenterOScurl -fsSL https://get.docker.com | bash -s docker --mirror Aliyun4.Docker常用命令4.1 镜像操作 / Image Operation查看镜像列表# 查看最新创建的镜像,以下两个命令等价 docker images docker image ls # 查看所有镜像 docker images --all docker images -a # 查看与Redis相关的镜像 docker images redis # 只显示镜像ID,可以与docker rmi命令结合使用 docker images -q搜索当前配置的远程仓库中的可用镜像docker search redis从镜像仓库拉取镜像# 拉取最新版,相当于docker pull redis:latest docker pull redis # 拉取指定版本 docker pull redis:7.0.5删除镜像(一个或多个)# 删除指定镜像 docker rmi redis:7.0.5 # 删除所有符合过滤条件的镜像 docker rmi $(docker images -f "dangling=true" -aq) # 删除所有Redis镜像 docker rmi $(docker images redis -aq)4.2 容器操作 / Container Operation查看容器列表docker ps # 查看所有容器,包含已停止的 docker ps -a # 查看容器ID, -q 等价于 --quiet docker ps -q根据某个镜像创建容器但不启动# 语法:docker create [OPTIONS] IMAGE [COMMAND] [ARG...] docker create -d --name redis-demo -p 6379:6379 redis:7.0.5根据某个镜像创建容器并启动# -d 让容器在后台运行,其实就是一个进程 # --name 指定容器名称 # -p 将容器的端口映射到宿主机的端口 # --cpus CPU核心数 # -m 等价于 --memory 指定最大内存 # -e 等价于 --env,设置环境变量 docker run -d \ --name redis-demo -p 6379:6379 \ --cpus 1 -m 100m \ -e REDIS_NAME=my-redis-demo \ redis:7.0.5以交互式的方式进入容器# docker exec -it containerId /bin/bash docker exec -it redis-demo /bin/bash启动/停止/暂停/重启容器# 启动容器,语法:docker start containerId / containerName docker start redis-demo # 停止容器,语法:docker stop containerId / containerName docker stop redis-demo # 暂停容器,语法:docker pause CONTAINER [CONTAINER...] docker pause redis-demo # 运行状态下重启容器,语法:docker restart containerId / containerName docker restart redis-demo删除容器(一个或多个)# 语法 docker rm [OPTIONS] CONTAINER [CONTAINER...] # 删除redis-demo,前提是redis-demo已停止 docker rm redis-demo # 删除redis-demo及其匿名Volume docker rm -v redis-demo # 删除所有已停止的容器 docker rm $(docker ps -f status=exited -q)根据容器的当前变更反向生成镜像# 语法 docker commit [OPTIONS] CONTAINER [REPOSITORY[:TAG]] # -m 等价于 --comment,备注 docker commit -m 'Image from Container' redis-demo local-redis-image:1.0.0 # 查看新建镜像的提交信息 docker image inspect local-redis-image:1.0.0 | grep Comment # 或者 docker inspect local-redis-image:1.0.0 | grep Comment查看容器详细信息# 语法 docker inspect [OPTIONS] NAME|ID [NAME|ID...] docker inspect redis-demo查看容器资源使用情况# 语法:docker stats [OPTIONS] [CONTAINER...] # 以流式的方式展示所有运行中的容器资源使用数据 docker stats # 所有容器资源使用数据 docker stats -a # 指定容器(redis-demo)资源使用数据 docker stats redis-demo # 资源使用快照 docker stats --no-stream redis-demo查看容器日志# 语法:docker logs [OPTIONS] CONTAINER docker logs redis-demo # 实时日志, -f 等价于 --follow,-n 等价于 --tail,显示倒数多少行日志 docker logs -f -n 12 redis-demo4.3 存储操作 / Storage Operation列举 Volumedocker volume ls创建 Volume# 语法:docker volume create [OPTIONS] [VOLUME] # 创建数据卷时,指定名称:v-redis docker volume create v-redis # 创建数据卷时,不指定名称,Docker会创建64位的随机名称 docker volume create查看 Volume 详情# 语法:docker volume inspect [OPTIONS] VOLUME [VOLUME...] docker volume inspect v-redis删除 Volume# 语法:docker volume rm [OPTIONS] VOLUME [VOLUME...] docker volume rm v-redis清理未使用的Volumedocker volume prune创建容器时挂载 Volume# 将数据卷v-redis挂载到容器内的/usr/local/redis目录 docker run -d --name redis-demo -p 6379:6379 \ -v v-redis:/usr/local/redis \ redis:7.0.54.4 网络操作 / Network Operation查看网络列表# 语法:docker network ls [OPTIONS] docker network ls创建 Docker 网络# 语法:docker network create [OPTIONS] NETWORK # -d 等价于 --driver docker network create -d bridge nw-redis-b创建容器时指定 Networkdocker run -d --name redis-demo-nw -p 6378:6379 \ --network nw-redis-b \ redis:7.0.5运行中的容器连接 Docker 网络# 语法:docker network connect [OPTIONS] NETWORK CONTAINER docker network connect nw-redis-b redis-demo运行中的容器断开Docker网络# 语法:docker network disconnect [OPTIONS] NETWORK CONTAINER docker network disconnect nw-redis-b redis-demo删除Docker网络# 语法:docker network rm NETWORK [NETWORK...] docker network rm nw-redis-b清理未使用的 Docker 网络# 语法:docker network prune [OPTIONS] docker network prune5.使用 Dockerfile 定制镜像TODO参考资料Docker 教程 | 菜鸟教程 (runoob.com)别再去找Docker常用命令了,你要的全都在这! - 知乎 (zhihu.com)超详细的 Docker 基本概念及常用命令 - 掘金 (juejin.cn)前言 · Docker -- 从入门到实践 (docker-practice.github.io)
2023年08月10日
120 阅读
0 评论
0 点赞
2023-08-09
轻量Alpine Linux 简介及虚拟机安装
1.Alpine 简介1. 1 Alpine Linux介绍alpine是一个轻量级的Linux发行版本,轻量级不仅体现在其占用空间的大小,还因为他没有图形化界面,只有命令行界面。 这个发行版本与我们常见的发现版本不同,其他版版本基本在安装完基本配置之后就可以使用了,而且基本配置如:磁盘,时区等都可以通过图形化的方式去点击进行配置,alpine需要我们在命令行进行手动配置1.2 Alpine的优点轻量:没有自带很多软件,安装完虚拟磁盘才150M。快速:没有图形界面,启动速度快。安全:面向安全的轻量发行版简单:提供APK包管理工具,软件的搜索、安装、删除、升级都非常方便。2. 虚拟机安装Alpine2.1 镜像下载下载地址:downloads | Alpine Linux本人下载的是STANDARD标准版本2.2 虚拟机安装采用HyperV、VMware'等虚拟机软件均可创建虚拟机和配置基本自行百度查看2.3 安装过程中的步骤选择1. 启动Live 默认用户名root,密码null 2. 输入 setup-alpine开始安装 3. 两次cn键盘布局 4. 主机hostname 5. 选择网卡 eth0 6. 地址获取方式dhcp 7. 是否手动配置网络相关no 8. 设置密码 9. 设置时区Asia, Shanghai 10. 是否使用代理none 11. 时间同步方式chrony 12. 选择源f(自动选择最快的) 13. SSH OpenSsh 14. 选择安装磁盘 sda 15. 选择安装到系统 sys3.系统相关配置3.1 启用远程sshvim /etc/ssh/sshd_config # 修改前 PermitRootLogin prohibit-password # 修改后 PermitRootLogin yes # 重启sshd service sshd restart3.2 启用社区源vim /etc/apk/repositories #/media/cdrom/apks http://mirrors.nju.edu.cn/alpine/v3.12/main http://mirrors.nju.edu.cn/alpine/v3.12/community #去掉此行注释 #http://mirrors.nju.edu.cn/alpine/edge/main #http://mirrors.nju.edu.cn/alpine/edge/community #http://mirrors.nju.edu.cn/alpine/edge/testing # 更新软件索引 apk update参考资料Alpine Linux 3.18 发布 | Linux 中国 - 知乎 (zhihu.com)本地虚拟机安装alpine-阿里云开发者社区 (aliyun.com)Apline Linux 详细安装及操作【保姆级教程】 - 知乎 (zhihu.com)
2023年08月09日
371 阅读
0 评论
0 点赞
2023-08-09
linux 的防火墙 ufw、firwalld、iptables
1.防火墙综述linux 防火墙,常用的包括三种:ufw 、 firewalld 和 iptables。UFW、firewall、iptables,其中,UFW是Debian系列的默认防火墙,firewall 是红帽系列7及以上的防火墙(如CentOS7.x),iptables是红帽系列6及以下(如CentOS6.x)的防火墙,3者学习难度依次递增。常见的防火墙分为两种,一种是3层防火墙,另一种是 7 层防火墙。在 TCP/IP 的七层网络中,第三层是网络层,三层防火墙会在这层对源地址和目标地址进行检测。但七层防火墙会对 源端口、目标端口、源ip、目标ip 全都进行检测。2.ufw2.1 概述因为原生的 iptable 配置麻烦,学习成本较高。 ufw全称 Uncomplicated Firewall 是 ubuntu提供的一个 iptables 的接口。同时支持 ipv4 和 ipv6。最新版的UFW默认启用了IPV6配置,你也可以通过以下命令进行检查:# cat /etc/default/ufw | grep -i ipv6 IPV6=yes2.2 默认策略默认情况下,UFW 设置了:禁止所有流量转入,允许所有流量转出。(这点和 iptable 的默认允许所有流量转入不同)。我们也可以更改此默认配置:cat /etc/default/ufw |grep -i default_input # 加 -i 是关闭大小写区分。 DEFAULT_INPUT_POLICY="DROP"2.3 安装启动与关闭sudo apt-get install ufw # 安装 sudo ufw enable # 启动防火墙并设置开机启动 sudo ufw default deny # 关闭外部主机对本机的访问(不影响本机对外部主机访问) sudo ufw disable # 关闭防火墙并关闭开机自启 sudo ufw status # 查看防火墙状态2.4 设置UFW规则sudo ufw allow port_number // 开放 port_number 端口 sudo ufw allow from 192.168.1.1 // 允许指定主机的访问 sudo ufw allow ssh // 禁止外部访问ssh服务 # 由于在/etc/services中, 22端口对应的服务名是ssh。 # 上面的命令也等价于sudo ufw allow 22 sudo ufw allow 80/tcp // 也可以指定端口号和协议 // 当没有给出协议的时候,UFW 同时创建tcp和udp的规则。 sudo ufw allow 7100:7200/tcp // 批量管理端口 sudo ufw allow from 64.63.62.61 to any port 22 // 允许指定 IP 地址访问指定端口 sudo ufw allow from 192.168.1.0/24 to any port 3306 // 允许子网 sudo ufw deny from 23.24.25.0/24 //禁止来自23.24.25.0/24的所有连接 sudo ufw allow in on eth2 to any port 3306 // 允许指定网络接口的连接 sudo ufw deny proto tcp from 23.24.25.0/24 to any port 80,443 //禁止从23.24.25.0/24对80和443端口的访问 2.5 删除 UFW 规则有两种不同的方式可以删除 UFW 规则。通过规则序号和通过指定的规则。通过规则序号来删除 UFW 规则很简单,特别是你刚接触 UFW。想要通过规则序号来删除,你需要找到你想删除的规则序号。想要这么做,运行下面的命令:sudo ufw status numbered输出:Status: active To Action From -- ------ ---- [ 1] 22/tcp ALLOW IN Anywhere [ 2] 80/tcp ALLOW IN Anywhere [ 3] 8080/tcp ALLOW IN Anywhere想要删除规则,序号为3,这个规则允许对端口8080的连接,你可以使用下面的命令:sudo ufw delete 3删除规则的第二种方法就是指定实际的规则。例如,如果你添加过一个打开端口8069的规则,你可以通过下面的命令删除它:sudo ufw delete allow 80692.6 重置 UFW重置 UFW 将会禁用 UFW,删除所有激活的规则。如果你想撤销所有的应用规则,并且重新开始时,这个很有用。想要重置 UFW,简单输入下面的命令:sudo ufw reset3.firewall3.1 概述Centos7以上的发行版都试自带了firewalld防火墙的,firewalld去带了iptables防火墙。其原因是iptables的防火墙策略是交由内核层面的netfilter网络过滤器来处理的,而firewalld则是交由内核层面的nftables包过滤框架来处理。 相较于iptables防火墙而言,firewalld支持动态更新技术并加入了区域(zone)的概念。简单来说,区域就是firewalld预先准备了几套防火墙策略集合(策略模板),用户可以根据生产场景的不同而选择合适的策略集合,从而实现防火墙策略之间的快速切换。关于 firewall 防火墙配置,需要注意的是:这里需要首先说明的是,在执行命令时,如果没有带 --permanent 参数表示配置立即生效,但是不会对该配置进行存储,相当于重启服务器就会丢失。如果带上则会将配置存储到配置文件,,但是这种仅仅是将配置存储到文件,却并不会实时生效,需要执行 firewall-cmd --reload 命令重载配置才会生效。3.2 规则配置查看默认域的配置firewall-cmd --list-all应急命令firewall-cmd --panic-on # 拒绝所有流量,远程连接会立即断开,只有本地能登陆 firewall-cmd --panic-off # 取消应急模式,但需要重启firewalld后才可以远程ssh firewall-cmd --query-panic # 查看是否为应急模式管理端口firewall-cmd --add-port=<port>/<protocol> # 添加端口/协议(TCP/UDP) firewall-cmd --remove-port=<port>/<protocol> # 移除端口/协议(TCP/UDP) firewall-cmd --list-ports # 查看开放的端口开放指定端口,并重新加载firewall-cmd --add-port=443/tcp --permanent # 开放端口 firewall-cmd --reload # 重新加载 firewall-cmd --query-port=443/tcp # 查询是否放开4.iptables通过四表五连进行管理,比较复杂,暂时放弃学习,等用到了再学。参考资料linux 的防火墙 ufw、firwalld、iptables 、 - 沧海一声笑rush - 博客园 (cnblogs.com)ubuntu防火墙设置 (ufw、iptables)-小白实操记录如何在 Ubuntu 20.04 上使用 UFW 来设置防火墙 - 知乎 (zhihu.com)Linux 防火墙教程:IPTables 表、链、规则基础-云社区-华为云 (huaweicloud.com)iptables的四表五链与NAT工作原理 - 知乎 (zhihu.com)
2023年08月09日
445 阅读
1 评论
0 点赞
2023-08-08
mysql主从复制学习笔记
1.主从复制原理基于二进制日志文件1.Master主库在事务提交时,会把数据变更记录在二进制日志文件binlog中。2.从库Slaver读取主库的二进制文件binlog,写入到从库的中继日志Relay log。3.Slave重做中继日志的事件,将变化反映到自身进行数据更新(复制)。2.主库配置2.1 防火墙设置# 开放指定的3306端口 firewall-cmd --zone=public --add-port=3306/tcp -pemanent firewall-cmd -reload2.2 修改配置文件/etc/my.cnf在最下面增加配置:# mysql服务id,保证是整个集群环境中唯一,取值范围1-2^32-1,默认为1 server-id=1 # 是否只读,1代表只读,0代表读写 read-only=02.3 重启Mysql服务systemctl restart mysqld2.4 创建数据同步的用户并授权登录mysql,并执行如下指令,创建用户并授权:mysql> CREATE USER 'jupiter'@'%' IDENTIFIED WITH mysql_native_password BY 'Root@123456'; # @'%':用户可以在任意主机访问当前服务器。 # IDENTIFIED WITH mysql_native_password BY 'Root@123456':设置访问密码为Root@123456 mysql> GRANT REPLICATION SLAVE ON *.* TO 'jupiter'@'%'; # 为'jupiter'@'%'用户分配主从复制的权限,即REPLICATION SLAVE权限MySQL密码复杂程度说明:mysql> show variables like 'validate_password_policy';目前 MySQL8.0.30 默认密码校验策略等级为 MEDIUM , 该等级要求密码组成为: 数字、小写字母、大写字母 、特殊字符、长度至少8位2.5 通过命令,查看二进制日志坐标mysql> show master status;3.从库配置3.1 防火墙设置# 开放指定的3306端口 firewall-cmd --zone=public --add-port=3306/tcp -pemanent firewall-cmd -reload3.2 修改配置文件/etc/my.cnf在最下面增加配置:# mysql服务id,保证是整个集群环境中唯一,取值范围1-2^32-1,与主库不一致即可 server-id=2 # 是否只读,1代表只读,0代表读写,只对非root用户生效 read-only=13.3 重启Mysql服务systemctl restart mysqld3.4 登录Mysql数据库,设置主库地址及同步位置master_log_file和master_log_pos的参数由 show master status;的执行结果决定。mysql> change master to master_host='192.168.36.168',master_user='jupiter',master_password='Root@123456',master_log_file='mysql-bin.000015',master_log_pos=157;参数说明:A. master_host : 主库的IP地址B. master_user : 访问主库进行主从复制的用户名(上面在主库创建的)C. master_password : 访问主库进行主从复制的用户名对应的密码D. master_log_file : 从哪个日志文件开始同步(上述查询master状态中展示的有)E. master_log_pos : 从指定日志文件的哪个位置开始同步(上述查询master状态中展示的有)3.5 开启同步操作mysql> start replica; # 8.0.22之后 mysql> start slave; # 8.0.22之前3.6 查看主从同步状态mysql> show replica status\G; # 8.0.22之后 mysql> show slave status\G; # 8.0.22之前然后通过状态信息中的 Slave_IO_running 和 Slave_SQL_running 可以看出主从同步是否就绪,如果这两个参数全为Yes,表示主从同步已经配置完成。4.验证测试我们只需要在主库Master执行操作,查看从库Slave中是否将数据同步过去即可。参考资料https://www.bilibili.com/video/BV1jT411r77sMySQL配置主从复制
2023年08月08日
46 阅读
0 评论
0 点赞
2023-06-20
Aircrack-ng破解无线WIFI密码
1.建议环境使用 kail Linux,如果 kail是装在虚拟机里面的话,是不能用物理机的无线网卡的。所以,如果我们要想进行无线破解,需要外接一个无线网卡设备,并且该设备要支持 monitor 监听模式2.具体步骤2.1 查看无线网卡名字$ iwconfig lo no wireless extensions. eth0 no wireless extensions. wlan0 IEEE 802.11 ESSID:off/any Mode:Managed Access Point: Not-Associated Tx-Power=0 dBm Retry short limit:7 RTS thr:off Fragment thr:off Power Management:on 2.2 开启网卡监听模式$ sudo airmon-ng start wlan0 Found 2 processes that could cause trouble. Kill them using 'airmon-ng check kill' before putting the card in monitor mode, they will interfere by changing channels and sometimes putting the interface back in managed mode PID Name 830 NetworkManager 989 wpa_supplicant PHY Interface Driver Chipset phy1 wlan0 mt7601u Ralink Technology, Corp. MT7601U (monitor mode enabled) 2.3 扫描附近的WIFI$ sudo airodump-ng wlan0BSSID代表路由器的 MAC 地址PWR 代表信号的强度,数值越大代表信息越强CH 代表信道ENC代表用的加密的方式AUTH 代表认证的方式ESSID是WIFI的名字需要选定一个准备破解的WIFI,这里选 FAST_2.4G_F3982.4 监听该路由器的流量$sudo airodump-ng -w FAST_2.4G_F398 -c 11 --bssid 74:54:27:41:F3:98 wlan0下面的 STATION 是连接该WIFI的客户端,下面这里只有一个客户端连接了该WIFI。如果有多个客户端连接的话,我们最好选择活跃点的客户端。2.5 开始攻击获取握手包重新打开一个命令行窗口# 50是发包的数量 -a指定路由器的MAC地址 -c指定连接的客户端的MAC地址 $sudo aireplay-ng -0 5 -a 74:54:27:41:F3:98 -c 76:54:27:01:F3:99 wlan0 该命令会打断连接客户端和WIFI之间的连接,等到客户端重新连接WIFI的时候,就会抓取他们之间的握手认证包!如果看到下面红色圈住的这些,就说明握手包抓取成功了可以看到会生成四个文件,其中我们有用的文件是以 cap 后缀结尾的文件$ ll total 1632 -rw-r--r-- 1 root root 515675 Jun 19 12:42 FAST_2.4G_F398-01.cap -rw-r--r-- 1 root root 498 Jun 19 12:42 FAST_2.4G_F398-01.csv -rw-r--r-- 1 root root 598 Jun 19 12:42 FAST_2.4G_F398-01.kismet.csv -rw-r--r-- 1 root root 3040 Jun 19 12:42 FAST_2.4G_F398-01.kismet.netxml -rw-r--r-- 1 root root 1132592 Jun 19 12:42 FAST_2.4G_F398-01.log.csv2.6 对抓取到的cap包进行破解这需要我们准备好破解的密码字典。所以,无论是任何破解,都需要一个强大的密码字典!kali下自带有一份无线密码字典——> /usr/share/wordlists/rockyou.txt.gz ,我们将其解压新开一个窗口$ cd /usr/share/wordlists/ $ sudo gzip -d rockyou.txt.gz $ ls amass dirb dirbuster fasttrack.txt fern-wifi john.lst legion metasploit nmap.lst rockyou.txt sqlmap.txt wfuzz wifite.txt在原来窗口执行#-w指定 密码字典 -b指定路由器的MAC地址 $sudo aircrack-ng -w /usr/share/wordlists/rockyou.txt -b 74:54:27:41:F3:98 FAST_2.4G_F398-01.cap 2.7 等待执行结果字典中不包含正确密码字典中保护包含正确密码略要想破解出WIFI的密码,还是得需要一个很强大的字典!参考资料Aircrack-ng破解无线WIFI密码kali linux破解wifi密码-超详细过程
2023年06月20日
557 阅读
0 评论
0 点赞
2023-06-06
ossfs:Linux挂载阿里云oss Bucket
1.简介ossfs允许您在Linux系统中将对象存储OSS的存储空间(Bucket)挂载到本地文件系统。挂载完成后,您能够像操作本地文件一样操作OSS的对象(Object),从而实现数据共享。下载地址Linux发行版下载Ubuntu 20.04 (x64)ossfs_1.80.7_ubuntu20.04_amd64.debUbuntu 18.04 (x64)ossfs_1.80.7_ubuntu18.04_amd64.debUbuntu 16.04 (x64)ossfs_1.80.7_ubuntu16.04_amd64.debUbuntu 14.04 (x64)ossfs_1.80.7_ubuntu14.04_amd64.debCentOS 8.0 (x64)ossfs_1.80.7_centos8.0_x86_64.rpmCentOS 7.0 (x64)ossfs_1.80.7_centos7.0_x86_64.rpmAnolis8/Alibaba Cloud Linux 3ossfs_1.80.7_anolisos8.0_x86_64.rpmAnolis7/Alibaba Cloud Linux 2ossfs_1.80.7_anolisos7.0_x86_64.rpm2.安装2.1 下载安装下载安装包。以下载CentOS 7.0 (x64)版本为例:sudo wget http://gosspublic.alicdn.com/ossfs/ossfs_1.80.6_centos7.0_x86_64.rpm安装ossfs。Ubuntu系统以Ubuntu 16.04 (x64)版本为例,安装命令如下:sudo apt-get update sudo apt-get install gdebi-core sudo gdebi ossfs_1.80.6_ubuntu16.04_amd64.debCentOS系统以CentOS 7.0(x64)版本为例,安装命令如下:sudo yum install ossfs_1.80.6_centos7.0_x86_64.rpm2.2 源码安装安装编译环境Ubuntu 14.04:sudo apt-get install automake autotools-dev g++ git libcurl4-gnutls-dev \ libfuse-dev libssl-dev libxml2-dev make pkg-configCentOS 7.0:sudo yum install automake gcc-c++ git libcurl-devel libxml2-devel \ fuse-devel make openssl-devel编译并安装git clone https://github.com/aliyun/ossfs.git cd ossfs ./autogen.sh ./configure make sudo make install3.使用3.1 配置账号访问信息。将Bucket名称以及具有该Bucket访问权限的AccessKey ID和AccessKey Secret信息存放在/etc/passwd-ossfs文件中。文件的权限建议设置为640。sudo echo BucketName:yourAccessKeyId:yourAccessKeySecret > /etc/passwd-ossfs sudo chmod 640 /etc/passwd-ossfsBucketName、yourAccessKeyId、yourAccessKeySecret请按需替换为您实际的Bucket名称、AccessKey ID和AccessKey Secret,例如:sudo echo bucket-test:LTAIbZcdVCmQ****:MOk8x0y9hxQ31coh7A5e2MZEUz**** > /etc/passwd-ossfs sudo chmod 640 /etc/passwd-ossfs3.2 将Bucket挂载到指定目录。sudo ossfs BucketName mountfolder -o url=Endpoint说明 如果是root用户,命令中不需要增加sudo。增加sudo会导致无法挂载,报错sudo: ossfs: command not found。将北京地域名称为caucshop的Bucket挂载到/ossfs目录下的示例如下:sudo mkdir /ossfs sudo ossfs caucshop /ossfs -o url=http://oss-cn-beijing.aliyuncs.com重要 如果您使用从阿里云购买的云服务器ECS来提供ossfs服务,您可以使用内网域名。例如,在该示例中您可以将OSS Endpoint 修改为oss-cn-hangzhou-internal.aliyuncs.com,从而节省流量费用。有关OSS内网域名的更多信息,请参见访问域名和数据中心。3.3 取消挂载sudo fusermount -u /tmp/ossfs参考资料快速安装 (aliyun.com)aliyun/ossfs: Export s3fs for aliyun oss. (github.com)
2023年06月06日
717 阅读
0 评论
0 点赞
2023-06-05
Win磁盘被写保护解除方法
1.操作步骤1、首先按“win+x”命令,找到Windows powershell(管理员)(A),打开命令提示符,执行diskpart命令。Windows PowerShell 版权所有 (C) Microsoft Corporation。保留所有权利。 尝试新的跨平台 PowerShell https://aka.ms/pscore6 PS C:\WINDOWS\system32> diskpart Microsoft DiskPart 版本 10.0.19041.964 Copyright (C) Microsoft Corporation. 在计算机上: DESKTOP-80KQHVC DISKPART>2、在diskpart命令的界面,执行list disk命令,查看列出系统中所有的硬盘,并获取其硬盘号(如磁盘0)。DISKPART> list disk 磁盘 ### 状态 大小 可用 Dyn Gpt -------- ------------- ------- ------- --- --- 磁盘 0 联机 238 GB 1024 KB *3、通过diskpart命令的select操作关联要操作的硬盘,这里仅有一个磁盘0,我们以0号硬盘为例。select disk 04、若是不知道哪个硬盘对应相应的硬盘号或者想确认硬盘的状态,可以通过attributes disk操作来查看关联的硬盘属性信息,其中“只读”属性就是表示的写保护,英文为:readonly,如果状态为“是”表示 有写保护,如果为“否”表示没有写保护。DISKPART> select disk 0 磁盘 0 现在是所选磁盘。5、如果有写保护,通过执行如下命令清除写保护属性即可。DISKPART>attributes disk clear readonly 说明: attributes:是属性操作 disk:指的硬盘 clear:清除 readonly:只读属性,也就是写保护6、清除完成,再次查看一下属性,就发现只读属性已经为否了,现在硬盘就可以正常定入文件了。DISKPART> attributes disk 当前只读状态: 否 只读: 否 启动磁盘: 是 页面文件磁盘: 是 休眠文件磁盘: 否 故障转储磁盘: 是 群集磁盘 : 否
2023年06月05日
344 阅读
0 评论
0 点赞
2023-05-28
yolov5-v6.0测速
1.树莓派4Byolov5s(base) pi@raspberrypi:/data/yolov5-6.0 $ python detect.py --source test.mp4 --weight yolov5s.pt /home/pi/miniconda3/lib/python3.7/site-packages/torchvision/io/image.py:13: UserWarning: Failed to load image Python extension: warn(f"Failed to load image Python extension: {e}") detect: weights=['yolov5s.pt'], source=test.mp4, imgsz=[640, 640], conf_thres=0.25, iou_thres=0.45, max_det=1000, device=, view_img=False, save_txt=False, save_conf=False, save_crop=False, nosave=False, classes=None, agnostic_nms=False, augment=False, visualize=False, update=False, project=runs/detect, name=exp, exist_ok=False, line_thickness=3, hide_labels=False, hide_conf=False, half=False, dnn=False YOLOv5 2021-10-12 torch 1.12.0 CPU Fusing layers... Model Summary: 213 layers, 7225885 parameters, 0 gradients /home/pi/miniconda3/lib/python3.7/site-packages/torch/functional.py:478: UserWarning: torch.meshgrid: in an upcoming release, it will be required to pass the indexing argument. (Triggered internally at /root/pytorch/aten/src/ATen/native/TensorShape.cpp:2894.) return _VF.meshgrid(tensors, **kwargs) # type: ignore[attr-defined] video 1/1 (1/985) /data/yolov5-6.0/test.mp4: 384x640 1 person, 2 airplanes, 2 trucks, Done. (0.791s) video 1/1 (2/985) /data/yolov5-6.0/test.mp4: 384x640 1 person, 2 airplanes, 3 trucks, Done. (0.741s) video 1/1 (3/985) /data/yolov5-6.0/test.mp4: 384x640 1 person, 2 airplanes, 3 trucks, Done. (0.731s) video 1/1 (4/985) /data/yolov5-6.0/test.mp4: 384x640 1 person, 2 airplanes, 3 trucks, Done. (0.731s) video 1/1 (5/985) /data/yolov5-6.0/test.mp4: 384x640 1 person, 2 airplanes, 3 trucks, Done. (0.731s) video 1/1 (6/985) /data/yolov5-6.0/test.mp4: 384x640 1 person, 2 airplanes, 3 trucks, Done. (0.725s) video 1/1 (7/985) /data/yolov5-6.0/test.mp4: 384x640 1 person, 2 airplanes, 3 trucks, Done. (0.716s) video 1/1 (8/985) /data/yolov5-6.0/test.mp4: 384x640 1 person, 2 airplanes, 3 trucks, Done. (0.732s) video 1/1 (9/985) /data/yolov5-6.0/test.mp4: 384x640 1 person, 2 airplanes, 3 trucks, Done. (0.731s) video 1/1 (10/985) /data/yolov5-6.0/test.mp4: 384x640 1 person, 2 airplanes, 3 trucks, Done. (0.752s)yolov5n(base) pi@raspberrypi:/data/yolov5-6.0 $ python detect.py --source test.mp4 --weight yolov5n.pt /home/pi/miniconda3/lib/python3.7/site-packages/torchvision/io/image.py:13: UserWarning: Failed to load image Python extension: warn(f"Failed to load image Python extension: {e}") detect: weights=['yolov5n.pt'], source=test.mp4, imgsz=[640, 640], conf_thres=0.25, iou_thres=0.45, max_det=1000, device=, view_img=False, save_txt=False, save_conf=False, save_crop=False, nosave=False, classes=None, agnostic_nms=False, augment=False, visualize=False, update=False, project=runs/detect, name=exp, exist_ok=False, line_thickness=3, hide_labels=False, hide_conf=False, half=False, dnn=False YOLOv5 2021-10-12 torch 1.12.0 CPU Fusing layers... Model Summary: 213 layers, 1867405 parameters, 0 gradients /home/pi/miniconda3/lib/python3.7/site-packages/torch/functional.py:478: UserWarning: torch.meshgrid: in an upcoming release, it will be required to pass the indexing argument. (Triggered internally at /root/pytorch/aten/src/ATen/native/TensorShape.cpp:2894.) return _VF.meshgrid(tensors, **kwargs) # type: ignore[attr-defined] video 1/1 (1/985) /data/yolov5-6.0/test.mp4: 384x640 1 person, 1 car, 1 truck, Done. (0.390s) video 1/1 (2/985) /data/yolov5-6.0/test.mp4: 384x640 1 car, 1 truck, Done. (0.379s) video 1/1 (3/985) /data/yolov5-6.0/test.mp4: 384x640 1 car, 1 truck, Done. (0.358s) video 1/1 (4/985) /data/yolov5-6.0/test.mp4: 384x640 1 person, 1 car, 1 truck, Done. (0.367s) video 1/1 (5/985) /data/yolov5-6.0/test.mp4: 384x640 1 person, 1 car, 1 truck, Done. (0.353s) video 1/1 (6/985) /data/yolov5-6.0/test.mp4: 384x640 1 car, 1 truck, Done. (0.358s) video 1/1 (7/985) /data/yolov5-6.0/test.mp4: 384x640 1 person, 1 car, 1 truck, Done. (0.352s) video 1/1 (8/985) /data/yolov5-6.0/test.mp4: 384x640 1 person, 1 car, 1 truck, Done. (0.353s) video 1/1 (9/985) /data/yolov5-6.0/test.mp4: 384x640 1 car, 1 truck, Done. (0.361s) video 1/1 (10/985) /data/yolov5-6.0/test.mp4: 384x640 1 person, 1 car, 1 truck, Done. (0.352s)2.Jetson AGX Xavieryolov5s(base-jupiter) nvidia@xavier:/data/yolov5-6.0$ python detect.py --source test.mp4 --weight yolov5s.pt detect: weights=['yolov5s.pt'], source=test.mp4, imgsz=[640, 640], conf_thres=0.25, iou_thres=0.45, max_det=1000, device=, view_img=False, save_txt=False, save_conf=False, save_crop=False, nosave=False, classes=None, agnostic_nms=False, augment=False, visualize=False, update=False, project=runs/detect, name=exp, exist_ok=False, line_thickness=3, hide_labels=False, hide_conf=False, half=False, dnn=False YOLOv5 2021-10-12 torch 1.10.0 CUDA:0 (Xavier, 31920.45703125MB) Fusing layers... /home/nvidia/archiconda3/envs/base-jupiter/lib/python3.6/site-packages/torch/functional.py:445: UserWarning: torch.meshgrid: in an upcoming release, it will be required to pass the indexing argument. (Triggered internally at /media/nvidia/NVME/pytorch/pytorch-v1.10.0/aten/src/ATen/native/TensorShape.cpp:2157.) return _VF.meshgrid(tensors, **kwargs) # type: ignore[attr-defined] Model Summary: 213 layers, 7225885 parameters, 0 gradients, 16.5 GFLOPs video 1/1 (1/985) /data/yolov5-6.0/test.mp4: 384x640 1 person, 2 airplanes, 2 trucks, Done. (0.071s) video 1/1 (2/985) /data/yolov5-6.0/test.mp4: 384x640 1 person, 2 airplanes, 3 trucks, Done. (0.064s) video 1/1 (3/985) /data/yolov5-6.0/test.mp4: 384x640 1 person, 2 airplanes, 3 trucks, Done. (0.064s) video 1/1 (4/985) /data/yolov5-6.0/test.mp4: 384x640 1 person, 2 airplanes, 3 trucks, Done. (0.063s) video 1/1 (5/985) /data/yolov5-6.0/test.mp4: 384x640 1 person, 2 airplanes, 3 trucks, Done. (0.064s) video 1/1 (6/985) /data/yolov5-6.0/test.mp4: 384x640 1 person, 2 airplanes, 3 trucks, Done. (0.063s) video 1/1 (7/985) /data/yolov5-6.0/test.mp4: 384x640 1 person, 2 airplanes, 3 trucks, Done. (0.064s) video 1/1 (8/985) /data/yolov5-6.0/test.mp4: 384x640 1 person, 2 airplanes, 3 trucks, Done. (0.064s) video 1/1 (9/985) /data/yolov5-6.0/test.mp4: 384x640 1 person, 2 airplanes, 3 trucks, Done. (0.063s) video 1/1 (10/985) /data/yolov5-6.0/test.mp4: 384x640 1 person, 2 airplanes, 3 trucks, Done. (0.063s) video 1/1 (11/985) /data/yolov5-6.0/test.mp4: 384x640 1 person, 2 airplanes, 3 trucks, Done. (0.064s) video 1/1 (12/985) /data/yolov5-6.0/test.mp4: 384x640 1 person, 2 airplanes, 3 trucks, Done. (0.063s) video 1/1 (13/985) /data/yolov5-6.0/test.mp4: 384x640 1 person, 2 airplanes, 2 trucks, Done. (0.064s) video 1/1 (14/985) /data/yolov5-6.0/test.mp4: 384x640 1 person, 2 airplanes, 3 trucks, Done. (0.064s) video 1/1 (15/985) /data/yolov5-6.0/test.mp4: 384x640 1 person, 2 airplanes, 3 trucks, Done. (0.064s) video 1/1 (16/985) /data/yolov5-6.0/test.mp4: 384x640 1 person, 2 airplanes, 3 trucks, Done. (0.063s) video 1/1 (17/985) /data/yolov5-6.0/test.mp4: 384x640 1 person, 2 airplanes, 2 trucks, Done. (0.064s) video 1/1 (18/985) /data/yolov5-6.0/test.mp4: 384x640 1 person, 2 airplanes, 2 trucks, Done. (0.063s) video 1/1 (19/985) /data/yolov5-6.0/test.mp4: 384x640 1 person, 2 airplanes, 2 trucks, Done. (0.064s) video 1/1 (20/985) /data/yolov5-6.0/test.mp4: 384x640 1 person, 2 airplanes, 1 truck, Done. (0.063s)yolov5n(base-jupiter) nvidia@xavier:/data/yolov5-6.0$ python detect.py --source test.mp4 --weight yolov5n.pt detect: weights=['yolov5n.pt'], source=test.mp4, imgsz=[640, 640], conf_thres=0.25, iou_thres=0.45, max_det=1000, device=, view_img=False, save_txt=False, save_conf=False, save_crop=False, nosave=False, classes=None, agnostic_nms=False, augment=False, visualize=False, update=False, project=runs/detect, name=exp, exist_ok=False, line_thickness=3, hide_labels=False, hide_conf=False, half=False, dnn=False YOLOv5 2021-10-12 torch 1.10.0 CUDA:0 (Xavier, 31920.45703125MB) Fusing layers... /home/nvidia/archiconda3/envs/base-jupiter/lib/python3.6/site-packages/torch/functional.py:445: UserWarning: torch.meshgrid: in an upcoming release, it will be required to pass the indexing argument. (Triggered internally at /media/nvidia/NVME/pytorch/pytorch-v1.10.0/aten/src/ATen/native/TensorShape.cpp:2157.) return _VF.meshgrid(tensors, **kwargs) # type: ignore[attr-defined] Model Summary: 213 layers, 1867405 parameters, 0 gradients, 4.5 GFLOPs video 1/1 (1/985) /data/yolov5-6.0/test.mp4: 384x640 1 person, 1 car, 1 truck, Done. (0.039s) video 1/1 (2/985) /data/yolov5-6.0/test.mp4: 384x640 1 car, 1 truck, Done. (0.030s) video 1/1 (3/985) /data/yolov5-6.0/test.mp4: 384x640 1 car, 1 truck, Done. (0.030s) video 1/1 (4/985) /data/yolov5-6.0/test.mp4: 384x640 1 person, 1 car, 1 truck, Done. (0.030s) video 1/1 (5/985) /data/yolov5-6.0/test.mp4: 384x640 1 person, 1 car, 1 truck, Done. (0.029s) video 1/1 (6/985) /data/yolov5-6.0/test.mp4: 384x640 1 car, 1 truck, Done. (0.030s) video 1/1 (7/985) /data/yolov5-6.0/test.mp4: 384x640 1 person, 1 car, 1 truck, Done. (0.029s) video 1/1 (8/985) /data/yolov5-6.0/test.mp4: 384x640 1 person, 1 car, 1 truck, Done. (0.030s) video 1/1 (9/985) /data/yolov5-6.0/test.mp4: 384x640 1 car, 1 truck, Done. (0.030s) video 1/1 (10/985) /data/yolov5-6.0/test.mp4: 384x640 1 person, 1 car, 1 truck, Done. (0.030s) video 1/1 (11/985) /data/yolov5-6.0/test.mp4: 384x640 1 person, 1 car, 1 truck, Done. (0.029s) video 1/1 (12/985) /data/yolov5-6.0/test.mp4: 384x640 1 car, 1 truck, Done. (0.030s) video 1/1 (13/985) /data/yolov5-6.0/test.mp4: 384x640 1 car, 1 bus, 1 truck, Done. (0.030s) video 1/1 (14/985) /data/yolov5-6.0/test.mp4: 384x640 1 car, 1 bus, 1 truck, Done. (0.029s) video 1/1 (15/985) /data/yolov5-6.0/test.mp4: 384x640 1 car, 1 bus, 1 truck, Done. (0.030s) video 1/1 (16/985) /data/yolov5-6.0/test.mp4: 384x640 1 car, 1 bus, 1 truck, Done. (0.030s) video 1/1 (17/985) /data/yolov5-6.0/test.mp4: 384x640 1 car, 1 bus, 1 truck, Done. (0.030s) video 1/1 (18/985) /data/yolov5-6.0/test.mp4: 384x640 1 car, 1 bus, 1 truck, Done. (0.029s) video 1/1 (19/985) /data/yolov5-6.0/test.mp4: 384x640 1 car, 1 bus, 1 truck, Done. (0.030s) video 1/1 (20/985) /data/yolov5-6.0/test.mp4: 384x640 1 car, 1 bus, 1 truck, Done. (0.030s) 3.Jetson Xavier NXyolov5s(base-jupiter) nvidia@nx:/data_jupiter/yolov5-6.0$ python detect.py --source test.mp4 --weight yolov5s.pt detect: weights=['yolov5s.pt'], source=test.mp4, imgsz=[640, 640], conf_thres=0.25, iou_thres=0.45, max_det=1000, device=, view_img=False, save_txt=False, save_conf=False, save_crop=False, nosave=False, classes=None, agnostic_nms=False, augment=False, visualize=False, update=False, project=runs/detect, name=exp, exist_ok=False, line_thickness=3, hide_labels=False, hide_conf=False, half=False, dnn=False YOLOv5 2023-5-28 torch 1.10.0 CUDA:0 (Xavier, 7765.4140625MB) Fusing layers... /home/nvidia/archiconda3/envs/base-jupiter/lib/python3.6/site-packages/torch/functional.py:445: UserWarning: torch.meshgrid: in an upcoming release, it will be required to pass the indexing argument. (Triggered internally at /media/nvidia/NVME/pytorch/pytorch-v1.10.0/aten/src/ATen/native/TensorShape.cpp:2157.) return _VF.meshgrid(tensors, **kwargs) # type: ignore[attr-defined] Model Summary: 213 layers, 7225885 parameters, 0 gradients, 16.5 GFLOPs video 1/1 (1/985) /data_jupiter/yolov5-6.0/test.mp4: 384x640 1 person, 2 airplanes, 2 trucks, Done. (0.061s) video 1/1 (2/985) /data_jupiter/yolov5-6.0/test.mp4: 384x640 1 person, 2 airplanes, 3 trucks, Done. (0.043s) video 1/1 (3/985) /data_jupiter/yolov5-6.0/test.mp4: 384x640 1 person, 2 airplanes, 3 trucks, Done. (0.040s) video 1/1 (4/985) /data_jupiter/yolov5-6.0/test.mp4: 384x640 1 person, 2 airplanes, 3 trucks, Done. (0.040s) video 1/1 (5/985) /data_jupiter/yolov5-6.0/test.mp4: 384x640 1 person, 2 airplanes, 3 trucks, Done. (0.040s) video 1/1 (6/985) /data_jupiter/yolov5-6.0/test.mp4: 384x640 1 person, 2 airplanes, 3 trucks, Done. (0.040s) video 1/1 (7/985) /data_jupiter/yolov5-6.0/test.mp4: 384x640 1 person, 2 airplanes, 3 trucks, Done. (0.040s) video 1/1 (8/985) /data_jupiter/yolov5-6.0/test.mp4: 384x640 1 person, 2 airplanes, 3 trucks, Done. (0.040s) video 1/1 (9/985) /data_jupiter/yolov5-6.0/test.mp4: 384x640 1 person, 2 airplanes, 3 trucks, Done. (0.040s) video 1/1 (10/985) /data_jupiter/yolov5-6.0/test.mp4: 384x640 1 person, 2 airplanes, 3 trucks, Done. (0.040s) video 1/1 (11/985) /data_jupiter/yolov5-6.0/test.mp4: 384x640 1 person, 2 airplanes, 3 trucks, Done. (0.040s) video 1/1 (12/985) /data_jupiter/yolov5-6.0/test.mp4: 384x640 1 person, 2 airplanes, 3 trucks, Done. (0.040s) video 1/1 (13/985) /data_jupiter/yolov5-6.0/test.mp4: 384x640 1 person, 2 airplanes, 2 trucks, Done. (0.040s) video 1/1 (14/985) /data_jupiter/yolov5-6.0/test.mp4: 384x640 1 person, 2 airplanes, 3 trucks, Done. (0.040s) video 1/1 (15/985) /data_jupiter/yolov5-6.0/test.mp4: 384x640 1 person, 2 airplanes, 3 trucks, Done. (0.040s) video 1/1 (16/985) /data_jupiter/yolov5-6.0/test.mp4: 384x640 1 person, 2 airplanes, 3 trucks, Done. (0.040s) video 1/1 (17/985) /data_jupiter/yolov5-6.0/test.mp4: 384x640 1 person, 2 airplanes, 2 trucks, Done. (0.040s) video 1/1 (18/985) /data_jupiter/yolov5-6.0/test.mp4: 384x640 1 person, 2 airplanes, 2 trucks, Done. (0.040s) video 1/1 (19/985) /data_jupiter/yolov5-6.0/test.mp4: 384x640 1 person, 2 airplanes, 2 trucks, Done. (0.040s) video 1/1 (20/985) /data_jupiter/yolov5-6.0/test.mp4: 384x640 1 person, 2 airplanes, 1 truck, Done. (0.040s)yolov5n(base-jupiter) nvidia@nx:/data_jupiter/yolov5-6.0$ python detect.py --source test.mp4 --weight yolov5n.pt detect: weights=['yolov5n.pt'], source=test.mp4, imgsz=[640, 640], conf_thres=0.25, iou_thres=0.45, max_det=1000, device=, view_img=False, save_txt=False, save_conf=False, save_crop=False, nosave=False, classes=None, agnostic_nms=False, augment=False, visualize=False, update=False, project=runs/detect, name=exp, exist_ok=False, line_thickness=3, hide_labels=False, hide_conf=False, half=False, dnn=False YOLOv5 2023-5-28 torch 1.10.0 CUDA:0 (Xavier, 7765.4140625MB) Fusing layers... /home/nvidia/archiconda3/envs/base-jupiter/lib/python3.6/site-packages/torch/functional.py:445: UserWarning: torch.meshgrid: in an upcoming release, it will be required to pass the indexing argument. (Triggered internally at /media/nvidia/NVME/pytorch/pytorch-v1.10.0/aten/src/ATen/native/TensorShape.cpp:2157.) return _VF.meshgrid(tensors, **kwargs) # type: ignore[attr-defined] Model Summary: 213 layers, 1867405 parameters, 0 gradients, 4.5 GFLOPs video 1/1 (1/985) /data_jupiter/yolov5-6.0/test.mp4: 384x640 1 person, 1 car, 1 truck, Done. (0.049s) video 1/1 (2/985) /data_jupiter/yolov5-6.0/test.mp4: 384x640 1 car, 1 truck, Done. (0.032s) video 1/1 (3/985) /data_jupiter/yolov5-6.0/test.mp4: 384x640 1 car, 1 truck, Done. (0.032s) video 1/1 (4/985) /data_jupiter/yolov5-6.0/test.mp4: 384x640 1 person, 1 car, 1 truck, Done. (0.033s) video 1/1 (5/985) /data_jupiter/yolov5-6.0/test.mp4: 384x640 1 person, 1 car, 1 truck, Done. (0.032s) video 1/1 (6/985) /data_jupiter/yolov5-6.0/test.mp4: 384x640 1 car, 1 truck, Done. (0.032s) video 1/1 (7/985) /data_jupiter/yolov5-6.0/test.mp4: 384x640 1 person, 1 car, 1 truck, Done. (0.032s) video 1/1 (8/985) /data_jupiter/yolov5-6.0/test.mp4: 384x640 1 person, 1 car, 1 truck, Done. (0.032s) video 1/1 (9/985) /data_jupiter/yolov5-6.0/test.mp4: 384x640 1 car, 1 truck, Done. (0.032s) video 1/1 (10/985) /data_jupiter/yolov5-6.0/test.mp4: 384x640 1 person, 1 car, 1 truck, Done. (0.032s) video 1/1 (11/985) /data_jupiter/yolov5-6.0/test.mp4: 384x640 1 person, 1 car, 1 truck, Done. (0.032s) video 1/1 (12/985) /data_jupiter/yolov5-6.0/test.mp4: 384x640 1 car, 1 truck, Done. (0.032s) video 1/1 (13/985) /data_jupiter/yolov5-6.0/test.mp4: 384x640 1 car, 1 bus, 1 truck, Done. (0.032s) video 1/1 (14/985) /data_jupiter/yolov5-6.0/test.mp4: 384x640 1 car, 1 bus, 1 truck, Done. (0.033s) video 1/1 (15/985) /data_jupiter/yolov5-6.0/test.mp4: 384x640 1 car, 1 bus, 1 truck, Done. (0.032s) video 1/1 (16/985) /data_jupiter/yolov5-6.0/test.mp4: 384x640 1 car, 1 bus, 1 truck, Done. (0.033s) video 1/1 (17/985) /data_jupiter/yolov5-6.0/test.mp4: 384x640 1 car, 1 bus, 1 truck, Done. (0.033s) video 1/1 (18/985) /data_jupiter/yolov5-6.0/test.mp4: 384x640 1 car, 1 bus, 1 truck, Done. (0.032s) video 1/1 (19/985) /data_jupiter/yolov5-6.0/test.mp4: 384x640 1 car, 1 bus, 1 truck, Done. (0.032s) video 1/1 (20/985) /data_jupiter/yolov5-6.0/test.mp4: 384x640 1 car, 1 bus, 1 truck, Done. (0.032s)4.Jetson Nanoyolov5s#TODOyolov5n#TODO汇总设备名Yolov5s测速Yolov5n测速CPUGPU显存成本/价格树莓派4B731ms/1.37FPS352ms/2.84FPS4 核ARM A72 @ 1.5 GHz无无约850Jetson Nano161ms/6.21FPS89ms/11.24FPS4 核ARM A57 @ 1.43 GHz128核Maxwell4GB 64 位 LPDDR4x25.6GB/s约1300Jetson Xavier NX40ms/25FPS32ms/31.25FPS6 核 NVIDIA Carmel ARM®v8.2 64 位 CPU6MB L2 + 4MB L348 个 Tensor Core+384 个 NVIDIA CUDA Core Volta™ GPU8 GB 128 位 LPDDR4x59.7GB/s约4500Jetson AGX Xavier64ms/15.63FPS29ms/34.48FPS8 核 NVIDIA Carmel Armv8.2 64 位 CPU8MB L2 + 4MB L364 个 Tensor Core+512 个 NVIDIA CUDA Core Volta™ GPU32GB 256 位 LPDDR4x136.5GB/秒约10000参考资料NVIDIA Jetson 嵌入式系统开发者套件和模组
2023年05月28日
237 阅读
0 评论
1 点赞
2023-05-17
python-opencv限制图片长宽实现图片压缩
1.业务背景图片压缩前的预处理,适配手机端图片大小显示且尽可能的减少图片存储空间的占用。通过限制图片的最大宽度和最大高度来减少图片的大小。2.核心代码import cv2 import os import shutil import math def img_compress_by_openCV(img_path_local,img_size_thresh = 300,max_height=2560,max_width=1440): # 压缩前图片大小 img_src_size = os.path.getsize(img_path_local)/1024 # 压缩后图片保存地址 img_path_compress = "./images/opencvs_"+img_path_local.split("/")[-1] # 若压缩前图片大小已经大小阈值img_size_thresh则跳过压缩 if(img_src_size<img_size_thresh): print("图片大小小于"+str(img_size_thresh)+"KB,跳过压缩"); shutil.copyfile(img_path_local,img_path_compress) else: print("openCV压缩前图片大小:"+str(int(img_src_size))+"KB") # 计算压缩比 img = cv2.imread(img_path_local) heigh, width = img.shape[:2] print("openCV压缩前图片尺寸(heigh, width)=:("+str(int(heigh))+","+str(int(width))+")") compress_rate = min(max_height/heigh,max_width/width,1) # 调用openCV进行图片压缩 img_compress = cv2.resize(img, (int(heigh*compress_rate), int(width*compress_rate)),interpolation=cv2.INTER_AREA) # 双三次插值 cv2.imwrite(img_path_compress, img_compress) # 压缩后图片大小 img_compress_size = os.path.getsize(img_path_compress)/1024 print("openCV压缩后图片大小:"+str(int(img_compress_size))+"KB") print("openCV压缩前图片尺寸(heigh, width)=:("+str(heigh*compress_rate)+","+str(int(width*compress_rate))+")") return img_path_compress img_path_local = "./images/1684155324391.jpg" img_path_compress = img_compress_by_openCV(img_path_local)运行结果openCV压缩前图片大小:2219KB openCV压缩前图片尺寸(heigh, width)=:(4000,3000) openCV压缩后图片大小:469KB openCV压缩前图片尺寸(heigh, width)=:(1920.0,1440)
2023年05月17日
503 阅读
0 评论
0 点赞
2023-05-15
python调用TinyPNG进行图片无损压缩
1.TinyPNG介绍TinyPNG是一种在线图片压缩工具,可以将图片压缩到更小的文件大小,而且不会对图片质量造成明显的影响。其实现原理主要是基于两个方面:压缩算法和颜色减少。压缩算法TinyPNG使用的是一种叫做Deflate的压缩算法。Deflate算法是一种无损压缩算法,可以将图片的二进制数据进行压缩,从而减小图片文件的大小。在Deflate算法中,压缩的主要思想是利用重复的数据进行替换,从而减小文件的大小。具体来说,Deflate算法主要包括两个步骤:压缩和解压缩。在压缩过程中,数据被分成多个块,并且每个块都有自己的压缩字典。在解压缩过程中,压缩字典用于还原压缩后的数据。2. 颜色减少另一个TinyPNG使用的技术是颜色减少。颜色减少是一种通过减少图片中使用的颜色数来减小文件大小的技术。在实践中,很多图片中使用的颜色实际上是不必要的,因此可以通过将这些颜色删除来减小文件的大小。具体来说,TinyPNG会先对图片进行一个预处理,找出图片中使用频率最低的颜色,并将其替换成使用频率更高的颜色。这个过程是基于一个叫做K-means的算法实现的。K-means算法是一种基于聚类的算法,可以将图片中使用的颜色分成多个聚类,从而找出使用频率最低的颜色。2.python调用TinyPNG API进行图片压缩安装依赖pip install tinify核心代码import tinify import os import shutil def img_compress_by_tinify(img_path_local,img_size_thresh = 200): if not os.path.exists("./images"): os.makedirs("./images") # 压缩前图片大小 img_src_size = os.path.getsize(img_path_local)/1024 # 压缩后图片保存地址 img_path_compress = "./images/compress_"+img_path_local.split("/")[-1] # 若压缩前图片大小已经大小阈值img_size_thresh则跳过压缩 if(img_src_size<img_size_thresh): print("图片大小小于"+str(img_size_thresh)+"KB,跳过压缩"); shutil.copyfile(img_path_local,img_path_compress) else: print("压缩前图片大小:"+str(int(img_src_size))+"KB") # 调用tinyPNG进行图片压缩 tinify.key = "V02hTQyPz4WRXPyCChGv6nJJTZYVtzcd" source = tinify.from_file(img_path_local) source.to_file(img_path_compress) # 压缩后图片大小 img_compress_size = os.path.getsize(img_path_compress)/1024 print("压缩后图片大小:"+str(int(img_compress_size))+"KB") return img_path_compress img_path_local = "./images/1684153992017.jpg" img_path_compress = img_compress_by_tinify(img_path_local) print(img_path_compress)调用结果压缩前图片大小:693KB 压缩后图片大小:148KB ./images/compress_1684153992017.jpg
2023年05月15日
516 阅读
0 评论
0 点赞
2023-05-15
python上传文件到阿里云oss
安装依赖包pip install oss2核心代码import oss2 access_key_id = 'LTA*******************' access_key_secret = 'ZAx*******************************' bucket_name = 'caucshop' endpoint = 'oss-cn-beijing.aliyuncs.com' # 创建bucket对象 bucket = oss2.Bucket(oss2.Auth(access_key_id, access_key_secret), endpoint, bucket_name) # 待上传的文件路径 file_path_local = "./Snipaste_2023-05-13_18-54-02.jpg" # 上传到oss后保保存的路径 file_path_oss = "goodImgsCompresss/"+file_path_local.split("/")[-1] # 读取文件 with open(file_path_local, "rb") as f: data = f.read() # 上传文件 bucket.put_object(file_path_oss, data) # 获取文件的url file_url_oss = "https://"+bucket_name+"."+endpoint+"/"+file_path_oss; print(file_url_oss)执行结果,得到文件在oss中的存储地址,我这里采用的是公共读的权限https://caucshop.oss-cn-beijing.aliyuncs.com/goodImgsCompresss/Snipaste_2023-05-13_18-54-02.jpg参考资料【python】 文件/图片上传 阿里云OSS ,获取外网链接 实例_oss图片外链_维玉的博客-CSDN博客
2023年05月15日
365 阅读
0 评论
0 点赞
1
...
4
5
6
...
24