go-zero自动生成repository文件和测试用例
文章目录
- repository的作用
- 自动生成repository文件
- repo模板文件
- repo_test模板文件
- 生成结果
- 运行测试用例
repository的作用
在软件开发中,尤其是在采用分层架构或者领域驱动设计(DDD)的项目里,repository(仓库)是一个关键概念,它起到数据访问层和业务逻辑层之间的桥梁作用,负责处理数据的持久化与检索,让业务逻辑层无需直接与数据库或其他数据存储交互。例如下面代码中的 UserRepo
中的几个方法示例,展示了它是如何进行数据操作的:
// 获取用户信息
func (r *UserRepo) GetUserInfo(id int64) (*model.User, error) {m := r.svcCtx.Model.Userres, err := m.WithContext(r.ctx).Debug().Where(m.ID.Eq(id)).Where(m.IsDeleted.Eq(0)).First()if err != nil {logx.WithContext(r.ctx).Errorf("Failed to get data by id: %v", err)return nil, err}return res, nil
}// 创建用户
func (r *UserRepo) CreateUser(models *model.User) (*model.User, error) {m := r.svcCtx.Model.Usererr := m.WithContext(r.ctx).Debug().Create(models)if err != nil {logx.WithContext(r.ctx).Errorf("Failed to insert data: %v", err)return nil, err}return models, nil
}
以上代码中, UserRepo
就是一个典型的仓库(repository)示例。它具备以下几个方面的作用:
- 数据访问封装:UserRepo 把对 User 模型的数据库操作封装起来,像查询、插入、更新和删除等操作。这样,业务逻辑层就能通过调用 UserRepo 的方法来完成数据操作,而无需关心具体的数据库交互细节。
- 数据持久化与检索:UserRepo 提供了一系列方法,用于从数据库中获取用户信息、统计用户数量、创建新用户、更新用户信息以及删除用户等操作。这些方法负责将业务逻辑层的请求转化为数据库查询或更新操作。
- 上下文管理:UserRepo 借助 context.Context 来管理请求的上下文,保证数据库操作能在请求的生命周期内完成,并且可以处理超时和取消操作。
简单来说,repository 是一种设计模式,它把数据访问逻辑封装起来,让业务逻辑层和数据访问层解耦,从而提高代码的可维护性和可测试性。UserRepo 就是一个实现了该模式的具体类,它提供了对 User 模型的各种数据操作方法。
自动生成repository文件
在之前的这篇文章《go-zero框架基本配置和错误码封装》中,可以使用GEN 自动生成 GORM 模型结构体文件和查询方法。接下来,在此基础上,我们来通过一个脚本可以自动生成所需数据表的repository文件。
新增一个 generate_repo_files.go
文件,写入如下脚本:
package mainconst repoDir = "./internal/repo/mysql"// toCamelCase 将下划线分隔的字符串转换为驼峰命名
func toCamelCase(s string) string {parts := strings.Split(s, "_")var result strings.Builderfor _, part := range parts {if len(part) > 0 {result.WriteString(strings.ToUpper(part[:1]) + part[1:])}}return result.String()
}func generateRepoFile(baseName string) error {// 生成文件名fileName := strings.ToLower(baseName) + "_repo.go"filePath := filepath.Join(repoDir, fileName)// 检查文件是否存在if _, err := os.Stat(filePath); err == nil {fmt.Printf("File %s already exists, skipping generation.\n", filePath)return nil}// 创建文件file, err := os.Create(filePath)if err != nil {return fmt.Errorf("failed to create file %s: %v", filePath, err)}defer func(file *os.File) {err := file.Close()if err != nil {fmt.Printf("Failed to close file %s: %v\n", filePath, err)}}(file)// 生成 repo 名称, 将数据表的下划线转为驼峰写法repoName := toCamelCase(baseName)// 使用模板生成文件内容// 读取模板文件内容templateFilePath := "template_files/repo_template.txt"_, fileDir, _, _ := runtime.Caller(0)templateData, err := os.ReadFile(filepath.Join(fileDir, "../", templateFilePath))if err != nil {log.Fatalf("repo模板文件读取失败: %s", err)}// 将字节切片转换为字符串并打印repoTemplate := string(templateData)tmpl, err := template.New("repo").Parse(repoTemplate)if err != nil {return fmt.Errorf("failed to parse template: %v", err)}data := struct {RepoName string}{RepoName: repoName,}if err := tmpl.Execute(file, data); err != nil {return fmt.Errorf("failed to execute template: %v", err)}fmt.Printf("Successfully generated file %s\n", filePath)return nil
}func main() {// 初始化go-zero的配置var c config.ConfigconfigFile := config.GetConfigFile("") //调用自定义的GetConfigFile方法,读取当前配置的env信息conf.MustLoad(configFile, &c)tablePrefix := "" // 表名前缀// 连接数据库db, _ := gorm.Open(mysql.Open(c.Mysql.DataSource), &gorm.Config{NamingStrategy: schema.NamingStrategy{TablePrefix: tablePrefix, // 表名前缀SingularTable: true, // 使用单数表名,启用该选项,会区分 user 和 users 表为两个不同的数据表},})//获取全部表名var tableNames []stringdb.Raw("SHOW TABLES").Scan(&tableNames)for _, tableName := range tableNames {// 生成 repo 文件baseName := strings.TrimPrefix(tableName, tablePrefix)if err := generateRepoFile(baseName); err != nil {fmt.Printf("Error generating repo file for table %s: %v\n", tableName, err)}if err := generateRepoTestFile(baseName); err != nil {fmt.Printf("Error generating repo test file for table %s: %v\n", tableName, err)}}
}
以上代码是通过读取模板文件template_files/repo_template.txt
将相关的变量替换为指定的数据表名,然后生成统一的增删改查方法。
repo模板文件
接下来定义这个模板文件template_files/repo_template.txt
:
package mysqltype {{.RepoName}}Repo struct {logx.Loggerctx context.ContextsvcCtx *svc.ServiceContext
}func New{{.RepoName}}Repo(ctx context.Context, sCtx *svc.ServiceContext) *{{.RepoName}}Repo {return &{{.RepoName}}Repo{Logger: logx.WithContext(ctx),ctx: ctx,svcCtx: sCtx,}
}// 查询数据详情
func (r *{{.RepoName}}Repo) Get{{.RepoName}}Info(id int64) (*model.{{.RepoName}}, error) {m := r.svcCtx.Model.{{.RepoName}}res, err := m.WithContext(r.ctx).Debug().Where(m.ID.Eq(id)).Where(m.IsDeleted.Eq(0)).First()if err != nil {logx.WithContext(r.ctx).Errorf("Failed to get data by id: %v", err)return nil, err}return res, nil
}// 查询数据总数
func (r *{{.RepoName}}Repo) Get{{.RepoName}}Count(queryEqualConditions map[string]interface{}, queryMoreConditions map[string]interface{}) (int64, error) {m := r.svcCtx.Model.{{.RepoName}}queryEqualConditions["is_deleted"] = 0querys := m.WithContext(r.ctx).Debug()//基础查询条件querys = querys.Where(field.Attrs(queryEqualConditions))//更多查询条件if len(queryMoreConditions) > 0 {//todo your logic}return querys.Count()
}// 查询数据列表
func (r *{{.RepoName}}Repo) Get{{.RepoName}}ListByConditions(queryEqualConditions map[string]interface{}, queryMoreConditions map[string]interface{}, page, pageSize int) ([]*model.{{.RepoName}}, int64, error) {offset := (page - 1) * pageSizelimit := pageSizem := r.svcCtx.Model.{{.RepoName}}queryEqualConditions["is_deleted"] = 0querys := m.WithContext(r.ctx).Debug()//基础查询条件querys = querys.Where(field.Attrs(queryEqualConditions))//更多查询条件if len(queryMoreConditions) > 0 {//todo your logic}return querys.Order(m.ID.Desc()).FindByPage(offset, limit)
}// 查询一批id和创建时间的map
func (r *{{.RepoName}}Repo) Get{{.RepoName}}CreateTimeMapByIds(Ids []int64) (map[int64]string, error) {if len(Ids) == 0 {return nil, nil}Ids = utils.RemoveDuplicatesInt64Slice(Ids)m := r.svcCtx.Model.{{.RepoName}}res, err := m.WithContext(r.ctx).Debug().Where(m.ID.In(Ids...),m.IsDeleted.Eq(0),).Find()if err != nil {logx.WithContext(r.ctx).Errorf("Failed to get create_time by ids: %v", err)return nil, err}mapData := make(map[int64]string, len(res))for _, v := range res {mapData[v.ID] = (v.CreateTime).Format("2006-01-02 15:04:05")}return mapData, nil
}// 创建数据
func (r *{{.RepoName}}Repo) Create{{.RepoName}}(models *model.{{.RepoName}}) (*model.{{.RepoName}}, error) {m := r.svcCtx.Model.{{.RepoName}}err := m.WithContext(r.ctx).Debug().Create(models)if err != nil {logx.WithContext(r.ctx).Errorf("Failed to insert data: %v", err)return nil, err}return models, nil
}// 更新数据
func (r *{{.RepoName}}Repo) Update{{.RepoName}}(models *model.{{.RepoName}}, id int64) (gen.ResultInfo, error) {m := r.svcCtx.Model.{{.RepoName}}res, err := m.WithContext(r.ctx).Debug().Where(m.ID.Eq(id)).Updates(models)if err != nil {logx.WithContext(r.ctx).Errorf("Failed to update data: %v", err)return res, err}return res, nil
}// (软)删除数据
func (r *{{.RepoName}}Repo) Delete{{.RepoName}}(id int64) (gen.ResultInfo, error) {m := r.svcCtx.Model.{{.RepoName}}res, err := m.WithContext(r.ctx).Debug().Where(m.ID.Eq(id)).Updates(&model.{{.RepoName}}{IsDeleted: 1,})if err != nil {logx.WithContext(r.ctx).Errorf("Failed to soft delete data: %v", err)return res, err}return res, nil
}/*
// (硬)删除数据
func (r *{{.RepoName}}Repo) ForeverDelete{{.RepoName}}(id int64) (gen.ResultInfo, error) {m := r.svcCtx.Model.{{.RepoName}}res, err := m.WithContext(r.ctx).Debug().Where(m.ID.Eq(id)).Delete()if err != nil {logx.WithContext(r.ctx).Errorf("Failed to hard delete data: %v", err)return res, err}return res, nil
}
*/
这个模板文件可以通过提前手动写好一个示例的go文件的常用的方法,然后保存为一个txt文件,把示例的数据表名改为{{.RepoName}}
用来替换其他的表名。
repo_test模板文件
同样的,可以提前写好一份针对以上repository各个方法的测试用例,然后替换为变量标识符,可以写出如下的测试用例的模板文件:template_files/repo_test_template.txt
package mysql_testfunc TestGet{{.RepoName}}Info(t *testing.T) {ts := utils.NewTestCtx()repo := mysql.New{{.RepoName}}Repo(ts.Ctx, ts.SvcCtx)info, err := repo.Get{{.RepoName}}Info(1)t.Log("info: ", utils.EchoJson(info))t.Log("error: ", err)assert.NoError(t, err)
}func TestGet{{.RepoName}}Count(t *testing.T) {ts := utils.NewTestCtx()repo := mysql.New{{.RepoName}}Repo(ts.Ctx, ts.SvcCtx)condsEq := make(map[string]interface{})condsMore := make(map[string]interface{})count, err := repo.Get{{.RepoName}}Count(condsEq, condsMore)t.Log("count: ", count)t.Log("error: ", err)assert.NoError(t, err)
}func TestGet{{.RepoName}}ListByConditions(t *testing.T) {ts := utils.NewTestCtx()repo := mysql.New{{.RepoName}}Repo(ts.Ctx, ts.SvcCtx)condsEq := make(map[string]interface{})condsMore := make(map[string]interface{})list, count, err := repo.Get{{.RepoName}}ListByConditions(condsEq, condsMore, 1, 1)t.Log("list: ", utils.EchoJson(list))t.Log("count: ", count)t.Log("error: ", err)assert.NoError(t, err)
}func TestGet{{.RepoName}}CreateTimeMapByIds(t *testing.T) {ts := utils.NewTestCtx()repo := mysql.New{{.RepoName}}Repo(ts.Ctx, ts.SvcCtx)ids := []int64{1, 2, 3}createTimeMap, err := repo.Get{{.RepoName}}CreateTimeMapByIds(ids)t.Log("createTimeMap: ", utils.EchoJson(createTimeMap))t.Log("error: ", err)assert.NoError(t, err)
}func TestCreate{{.RepoName}}(t *testing.T) {ts := utils.NewTestCtx()repo := mysql.New{{.RepoName}}Repo(ts.Ctx, ts.SvcCtx)resp, err := repo.Create{{.RepoName}}(&model.{{.RepoName}}{//todo 补充需要添加的字段})t.Log("resp: ", utils.EchoJson(resp))t.Log("error: ", err)assert.NoError(t, err)
}func TestUpdate{{.RepoName}}(t *testing.T) {ts := utils.NewTestCtx()repo := mysql.New{{.RepoName}}Repo(ts.Ctx, ts.SvcCtx)resp, err := repo.Update{{.RepoName}}(&model.{{.RepoName}}{//todo 补充需要添加的字段}, 1)t.Log("resp: ", utils.EchoJson(resp))t.Log("error: ", err)assert.NoError(t, err)
}func TestDelete{{.RepoName}}(t *testing.T) {ts := utils.NewTestCtx()repo := mysql.New{{.RepoName}}Repo(ts.Ctx, ts.SvcCtx)resp, err := repo.Delete{{.RepoName}}(0)t.Log("resp: ", utils.EchoJson(resp))t.Log("error: ", err)assert.NoError(t, err)
}
以上只是我根据自己的业务习惯整理出来的几个常用的查询数据库的方法,你也可以适当的调整增加更多的方法,然后封装到模板文件中。
生成结果
运行generate_repo_files.go
这个脚本,就可以生成设置的所有数据表的repository文件和测试用例。运行试试:
运行测试用例
上面生成的测试用例,可以根据需要直接调试对应的repo文件。例如需要调试user_repo_test.go
里面的方法,可以分别使用如下两种方式运行:
// 测试全部方法: go test user_repo_test.go -v
// 测试指定方法: go test user_repo_test.go -v -run TestGetUserInfo
相关文章:
go-zero自动生成repository文件和测试用例
文章目录 repository的作用自动生成repository文件repo模板文件repo_test模板文件生成结果运行测试用例 repository的作用 在软件开发中,尤其是在采用分层架构或者领域驱动设计(DDD)的项目里,repository(仓库…...
红宝书第三十六讲:持续集成(CI)配置入门指南
红宝书第三十六讲:持续集成(CI)配置入门指南 资料取自《JavaScript高级程序设计(第5版)》。 查看总目录:红宝书学习大纲 一、什么是持续集成? 持续集成(CI)就像咖啡厅的…...
【Java学习】如何利用AI学习Java语言开发(二)
利用AI辅助学习Java语言开发可以显著提高学习效率、解决实际问题和优化代码质量。以下是结合AI工具和方法的系统化学习路径: 一、AI辅助学习基础阶段 智能交互式学习平台 使用Codecademy(AI驱动版)或JetBrains Academy的Java课程,AI会根据你的代码实时提供修正建议 尝试Ch…...
【C++算法】53.链表_重排链表
文章目录 题目链接:题目描述:解法C 算法代码: 题目链接: 143. 重排链表 题目描述: 解法 模拟 找到链表的中间节点 快慢双指针 把后面的部分逆序 双指针,三指针,头插法 合并两个链表 合并两个有…...
Ubuntu安装Docker引擎
安装Docker引擎 一、注意事项 防火墙兼容性 若使用 ufw 或 firewalld,Docker 容器端口会绕过防火墙规则。建议通过 iptables 或 ip6tables 配置防火墙,并将规则添加到 DOCKER-USER 链。仅支持 iptables-nft 和 iptables-legacy࿰…...
[目标检测]2023ICCV:DiffusionDet: Diffusion Model for Object Detection
作者:Shoufa Chen, Peize Sun, Yibing Song, Ping Luo 论文:https://arxiv.org/pdf/2211.09788v2 代码:https://github.com/ShoufaChen/DiffusionDet 摘要 我们提出了一个新的框架DiffusionDet, 将目标检测构建为从噪声框到目标…...
CExercise_09_结构体和枚举_2VS的Debug模式查看它的内存布局,采用结构体数组的方式存储信息,调用函数打印结构体数组.
题目: 下面结构体类型的变量的内存布局是怎样的?请使用VS的Debug模式查看它的内存布局 typedef struct stundent_s {int number;char name[25];char gender;int chinese;int math;int english; } Student;// 结构体对象的声明和初始化 Student s1 { 1, …...
LeetCode 热题 100_零钱兑换(85_322_中等_C++)(动态规划)
LeetCode 热题 100_零钱兑换(85_322) 题目描述:输入输出样例:题解:解题思路:思路一(动态规划): 代码实现代码实现(思路一(动态规划)&a…...
Java——抽象方法抽象类 接口 详解及综合案例
1.抽象方法抽象类 介绍 抽象方法: 将共性的行为(方法)抽取到父类之后, 由于每一个子类执行的内容是不一样, 所以,在父类中不能确定具体的方法体。 该方法就可以定义为抽象方法。 抽象类: 如果一个类中存在抽象方法,那么该类就必须…...
国产芯片解析:LDR6501 Type-C接口OTG充电PD芯片详解
LDR6501 是一款专为 USB Type-C 设备设计的单C口DPR接口PD通信芯片,封装形式为 SOT23-6。此款芯片具有多项实用功能,在耳机转接器、领夹麦克风以及 OTG 转接头等应用中表现出色。 应用领域 耳机转接器:许多新型耳机采用 Type-C 接口&am…...
Payoneer(P卡)会关联吗?如何有效防止P卡关联?
随着跨境电商和全球支付需求的增加,Payoneer(简称P卡)成为了许多商家和个人进行国际支付和收款的重要工具。Payoneer是一种全球支付平台,支持用户跨国收款、汇款,并提供多种货币的账户支持。 许多从事跨境电商的商家和…...
前端基础之《Vue(3)—计算属性》
一、computed选项 1、计算属性 语法:在computed选项中,定义计算属性方法,在方法体使用声明式变量进行若干计算。 2、计算属性一定是个函数。一定有返回值。 3、计算属性的作用 (1)用于优化指令的表达式,…...
【Linux】Linux 权限:数字背后的神秘 “门禁卡” 系统
目录 权限的基本概念Linux上用户的分类超级用户和普通用户用户之间的切换文件访问者的分类 文件属性与访问权限Linux下的文件类型文件后缀在Linux中的作用文件自身的属性【⭐】文件访问者的三种权限【rwx】文件权限值的表示方法 文件访问权限的相关设置方法chmod——设置文件的…...
Java中List方法的使用详解
目录 一、List接口概述二、List常用方法(一)创建List对象(二)添加元素(三)删除元素(四)查找元素(五)遍历列表(六)列表的大小ÿ…...
多模态大语言模型arxiv论文略读(十一)
Can We Edit Multimodal Large Language Models? ➡️ 论文标题:Can We Edit Multimodal Large Language Models? ➡️ 论文作者:Siyuan Cheng, Bozhong Tian, Qingbin Liu, Xi Chen, Yongheng Wang, Huajun Chen, Ningyu Zhang ➡️ 研究机构: 浙江大…...
JS—防抖和节流:1分钟掌握防抖和节流
个人博客:haichenyi.com。感谢关注 一. 目录 一–目录二–防抖三–节流四–进阶应用五–总结 二. 防抖(Debounce) 防抖(Debebounce)和节流(Throttle)都是前端开发中用于优化高频事件性能的两…...
MCP基础学习二:MCP服务搭建与配置
文章目录 MCP服务搭建与配置一,学习目标:二,学习内容:1. 如何搭建MCP服务端服务端初始化与配置MCP服务架构与数据流交互图核心实现注册服务功能服务器启动与API暴露 2. 本地应用与MCP服务的集成客户端SDK实现客户端应用实现功能演…...
MyBatis 操作数据库
目录 什么是MyBatis? 注释 Mapper注释的介绍和使用 Select注释的介绍和使用 SpringBootTest注释的介绍和使用 Test注释的介绍的使用 MyBatis入门 1)准备工作 <1>创建工程 <2>数据准备 2)配置数据库连接字符串 3ÿ…...
蓉光:科技与自然的千年交响
故事背景 故事发生在中国四川成都,这座千年古城在近未来完成蜕变,青城山的云雾与锦江的碧波间,智能建筑如雨后春笋般生长。全城建筑采用太阳能皮肤,街道流淌着数字化的都江堰水系,杜甫草堂的飞檐与机械芙蓉树共舞&…...
[C语言]gets和fgets函数区别及详解
一、gets 每当讨论 gets 函数时,大家不由自主地就会想起 1988 年的“互联网蠕虫”,它在 UNIX 操作系统的 finger 后台程序中使用一个 gets 调用作为它的攻击方式之一。很显然,对蠕虫病毒的实现来说, gets 函数的功劳不可小视。不…...
【场景应用3】audio_classification:音频分类的微调
1 引言 本笔记展示了如何对多语种预训练的语音模型进行微调,以实现自动语音识别(Automatic Speech Recognition)。 本笔记旨在使用SUPERB数据集中的关键词检测子集,并且可以使用任何来自模型库(Model Hub)的语音模型检查点,只要该模型有一个包含序列分类头(Sequence …...
【前端】【难点】前端富文本开发的核心难点总结与思路优化
前端富文本开发的核心难点总结 富文本编辑器在前端开发中广泛应用于内容管理系统、文章发布、评论区等场景。其开发与集成存在较多复杂性,涵盖内容结构管理、交互体验、跨平台兼容性等方面,以下逐项分析。 二、富文本开发的具体难点分析 (一…...
如何优雅使用 ReentrantLock 进行加解锁:避免常见坑点,提高代码可维护性
引言:锁的基本概念和问题 在多线程编程中,为了确保多个线程在访问共享资源时不会发生冲突,我们通常需要使用 锁 来同步对资源的访问。Java 提供了不同的锁机制,其中 ReentrantLock 是一种最常用且功能强大的锁,它属于…...
帕金森患者行动迟缓,日常生活怎么破局?
帕金森病,是一种常见于中老年人的神经退行性疾病,正悄然改变着无数患者的生活轨迹。它初期症状隐匿,常以手抖为信号,起初可能只是在安静状态下,手部出现轻微且有节律的震颤,随着时间推移,震颤逐…...
7-openwrt-one通过web页面配置访客网络、无线中继等功能
前几个章节一直在介绍编译、分区之类的,都还没正常开始使用这个路由器的wifi。默认wifi是没有启动的,前面还是通过手动修改uci配置启动的,这个章节介绍下官方web页面的使用。特别是访客网络、无线中继 1、开启wifi,配置wifi基本信息 我们使用有线连接路由器,通过192.168.…...
塑造现代互联网的力量:Berkeley在网络领域的影响与贡献
引言 “Berkeley” 这个名字在计算机网络和互联网领域中具有举足轻重的地位,许多关键的技术、协议和工具都与其紧密相关。它与 加利福尼亚大学伯克利分校(UC Berkeley) 密切相关,该校在计算机科学与网络研究中做出了许多开创性的…...
大数据学习(105)-Hbase
🍋🍋大数据学习🍋🍋 🔥系列专栏: 👑哲学语录: 用力所能及,改变世界。 💖如果觉得博主的文章还不错的话,请点赞👍收藏⭐️留言📝支持一…...
c# 系列pdf转图片 各种处理3--net3.1到net8 PDFtoImage
最近一直在做pdf渲染图片的问题,nuget PDFtoImage 支持3.1到net8 ,直接上代码 private static void DownloadFileAsync(string url, string localPath){using (HttpClient client new HttpClient()){client.DefaultRequestHeaders.Add("User-Agen…...
宁德时代25年春招笔试演绎数字推理SHL测评题库
宁德时代校招测评包含演绎推理数字推理两部分,请单击以下链接进行测评,详细操作指引请参见如下指引,请在测试前了解,大约用时60分钟。正式测评有两个部分:数字推理18分钟演绎推理18分钟,数字推理共10题,演绎…...
C# 看门狗策略实现
using System; using System.Threading;public class Watchdog {private Timer _timer;private volatile bool _isTaskAlive;private readonly object _lock new object();private const int CheckInterval 5000; // 5秒检测一次private const int TimeoutThreshold 10000; …...
聊透多线程编程-线程池-5.C# 线程池(ThreadPool)详解
1. 线程池的基本概念 线程池的作用 由于每创建一个线程都需要该线程分配一定的内存空间,因此创建大量线程会导致内存使用量迅速增加,并可能导致性能问题。线程池的主要目的是减少线程创建和销毁的开销,从而提高程序性能。线程池维护了…...
清华DeepSeek教程又双叒叕更新了!(共7份PDF下载)
清华团队的DeepSeek教程又双叒叕更新了,目前共计有7份DeepSeek的教程,分别是《DeepSeek从入门到精通》、《DeepSeek赋能职场》、《普通人如何抓住DeepSeek红利》、《DeepSeekDeepResearch:让科研像聊天一样简单》、《DeepSeek与AI幻觉》、《A…...
免费在线文档工具,在线PDF添加空白页,免费在任意位置插入空白页,多样化的文件处理
小白工具(https://www.xiaobaitool.net/files/pdf-add-page/ )是一款免费的在线文档工具,专注于为用户提供便捷的 PDF 空白页添加服务。 功能特点:该工具支持在 PDF 文件的任意位置插入单页或多页空白页,能满足用户不同…...
MATLAB在哪些特定领域比Python更有优势?
文章目录 前言科学研究与工程计算数值计算信号处理控制系统设计 教育领域易于学习和上手教学资源丰富 快速原型开发集成开发环境便捷 前言 MATLAB 在以下特定领域比 Python 更具优势: 科学研究与工程计算 数值计算 高效矩阵运算:MATLAB 以矩阵为基本数…...
CAN协议
CAN简介 TJA1050(高速CAN收发器) 5V供电 界定符用来隔开各个数据 这个时候就要用到采样了 谁先谁后??仲裁机制 发送邮箱用来放帧的 正常模式:正常收发 静默模式:只收不发 环回模式:不读,自己收 环回静…...
MFC案例:用鼠标移动窗口图像的实验
当使用基于对话框的MFC项目窗口显示图像时,如窗口的尺寸小于图像的尺寸,在不做缩放的情况下按照原图尺寸在窗口显示,那么只能看到图像的局部,这时我们希望可以通过鼠标移动图像进而显示其它部分。今天就进行这个实验,编…...
Linux基础IO(五)之用户缓冲区
文章目录 缓冲区FILE初步实现缓冲区 缓冲区 FILE 因为IO相关函数与系统调用接口对应,并且库函数封装系统调用, 所以本质上,访问文件都是通过fd访问的。 所以C库当中的FILE结构体内部,必定封装了fd。 编写代码and查看现象&…...
【Scrapy】Scrapy教程12——中间件
中间件这部分算是一个高阶的Scrapy内容,即便不了解这部分也可以使用Scrapy,但是一些特殊情况使用中间件就比较方便处理了,比如修改请求和响应等。 通过之前的工作原理图中,我们了解到Scrapy中有两个中间件,分别是下载器中间件和爬虫中间件,本节将一一讲解如何激活、编写自…...
C++学习之ORACLE①
目录 1.ORACLE数据库简介 2..ORACLE数据库安装 3..ORACLE体系结构 4..ORACLE基本概念 5..ORACLE基本元素 6..ORACLE数据库启动和关闭 7.SQLPLUS登录ORACLE数据库相关操作 8.SQLPLUS的基本操作 9.oracle中上课使用的方案 10.SQL语言分类 11.SQL中的select语句语法和注…...
vue---按钮防抖和节流----项目问题
一般来说前端都需要做按钮防抖避免一个时间被重复触发,首先可能会出现bug,消耗服务器性能,用户体验也不是很好。 1.防抖 解决方法:main.js文件自定义指令 Vue.directive("preventReClick", {inserted(el, binding) {…...
【LunarVim】解决which-key 自定义键位注册不成功问题
问题描述 LunarVim将which-key设置放在一个keymaps.lua中,然后config.lua调用reload “user.keymaps”,键位没用注册成功,而直接写在config.lua中,就注册成功 这暴露了LunarVim 插件和配置加载顺序的一些细节坑,下面解…...
湖北趣豆智能科技有限公司浅析XR技术对传统游戏的影响
在科技飞速发展的当下,XR(扩展现实)技术正以前所未有的态势重塑游戏行业格局。湖北趣豆智能科技有限公司凭借在XR技术与游乐设备融合领域的创新实践,对XR技术给传统游戏带来的影响有着深刻见解。 沉浸体验升级,重塑游戏…...
[操作系统] 进程间通信:system V共享内存
文章目录 内存共享示意图共享内存的管理代码shmget 函数原理先创建共享内存如何保证两个不同的进程拿到的是一块共享内存 shmctl 函数IPC_RMID参数 shmat函数无同步机制同步机制是什么模拟演示非同步效果如何提供保护机制 shmdt再谈描述共享内存的数据结构struct shmid_dsstruc…...
科技快讯 | 阿里云百炼MCP服务上线;英伟达官宣:CUDA 工具链将全面原生支持 Python
李飞飞团队最新AI报告:中美模型性能差距近乎持平 4月8日,斯坦福大学以人为本人工智能研究所发布《2025年人工智能指数报告》。报告显示,2023年AI性能显著提升,AI应用加速,投资增长,中美AI模型差距缩小。报告…...
踩雷,前端一直卡在获取token中
问题:一直卡在var token SecureStorage.Default.GetAsync("auth_token").Result; public VideoService(){_httpClient new HttpClient();var token SecureStorage.Default.GetAsync("auth_token");} 这是一个典型的同步等待异步操作导致的死…...
MATLAB双目标定
前言: 现在有许多双目摄像头在出厂时以及标定好,用户拿到手后可以直接使用,但也有些双目摄像头在出厂时并没有标定。因而这个时候就需要自己进行标定。本文主要介绍基于matlab工具箱的自动标定方式来对双目相机进行标定。 1、MATLAB工具箱标…...
4.10学习总结
完成两道算法题(感觉对贪心的思路很难去想到如何解) 完成stream流的学习,开始学习方法引用...
QML自定义组件
自定义组件是 QML 开发中的核心概念,它允许您创建可重用的 UI 元素和逻辑单元。以下是创建和使用自定义组件的完整方法。 1. 基本自定义组件创建 创建单独组件文件 (推荐方式) qml // MyButton.qml(单独一个qml文件)import QtQuick 2.15R…...
多模态大语言模型arxiv论文略读(十)
Towards End-to-End Embodied Decision Making via Multi-modal Large Language Model: Explorations with GPT4-Vision and Beyond ➡️ 论文标题:Towards End-to-End Embodied Decision Making via Multi-modal Large Language Model: Explorations with GPT4-Vi…...
关于 Spring Boot + Vue 前后端开发的打包、测试、监控、预先编译和容器部署 的详细说明,涵盖从开发到生产部署的全流程
以下是关于 Spring Boot Vue 前后端开发的打包、测试、监控、预先编译和容器部署 的详细说明,涵盖从开发到生产部署的全流程: 1. 打包 1.1 后端(Spring Boot) 打包方式 使用 Maven 或 Gradle 打包成可执行的 JAR/WAR 文件&…...