网站建设规划设计任务书/win7系统优化工具

网站建设规划设计任务书,win7系统优化工具,美国建网站的价格,跨境电子商务网站建设提示: 所有体系课见专栏:Go 项目开发极速入门实战课;欢迎加入 云原生 AI 实战 星球,12 高质量体系课、20 高质量实战项目助你在 AI 时代建立技术竞争力(聚焦于 Go、云原生、AI Infra);本节课最终…

提示:

  • 所有体系课见专栏:Go 项目开发极速入门实战课;
  • 欢迎加入 云原生 AI 实战 星球,12+ 高质量体系课、20+ 高质量实战项目助你在 AI 时代建立技术竞争力(聚焦于 Go、云原生、AI Infra);
  • 本节课最终源码位于 fastgo 项目的 feature/s13 分支;
    更详细的课程版本见:Go 项目开发中级实战课:26 | 业务实现(3):实现 Biz 层代码

Biz 层依赖 Store 层,所以实现了 Store 层代码之后,便可以实现 Biz 层代码。Biz 层代码,主要用来实现系统中 REST 资源的各类业务操作,例如用户资源的增删改查等。

整个 fastgo 项目的设计较为规范,规范化的项目设计带来的优点之一是开发方式的一致性和开发效率的提升。fastgo 项目 Biz 层的开发方式与 Store 层的开发方式保持一致。

API 接口定义

在开发 Biz 层代码之前,需要先定义好 API 接口的请求入参和返回参数。为此,新建了 pkg/api/apiserver/v1/post.go 文件和 pkg/api/apiserver/v1/user.go 文件,分别保存了用户接口和博客接口的请求入参和返回参数。

因为请求入参和返回参数(例如 CreateUserRequestCreateUserResponse)会提供给接口调用方(客户端),所以需要将接口定义保存在 pkg/api 目录下。另外,考虑到未来 fastgo 可能会加入多个服务,每个服务都有自己的 API 定义,fastgo 项目选择了将每个服务的 API 定义保存在独立的服务目录下,例如 pkg/api/apiserver。

考虑到未来 API 接口的版本升级,fastgo 项目将接口进行了版本化处理,v1 版本的接口保存在 pkg/api/apiserver/v1 目录下,v2 版本的接口保存在 pkg/api/apiserver/v2 目录下。

IBiz 接口定义及实现

Biz 层代码保存 internal/apiserver/biz/biz.go 文件中,接口名为 IBiz,定义如下:

// IBiz 定义了业务层需要实现的方法.
type IBiz interface {// 获取用户业务接口.UserV1() userv1.UserBiz// 获取帖子业务接口.PostV1() postv1.PostBiz// 获取帖子业务接口(V2版本).// PostV2() post.PostBiz
}

IBiz 接口包含了 User 资源和 Post 资源 v1 版本的接口,通过抽象工厂设计模式返回对应资源的接口。在 Go 项目开发中,业务层代码的代码量通常最大、变动最频繁,并且随着项目的迭代,可能会出现不兼容的变更。

这时需要对外暴露 v2 版本的 API 接口。因此,为了提高代码的可维护性并保留未来的扩展能力,Biz 层代码的存放结构如下:

internal/apiserver/biz/
├── biz.go
├── v1/ # v1 版本代码实现
│   ├── post/ # 提高代码可维护性,不同资源的代码实现分别存放在不同的目录中
│   │   └── post.go
│   └── user/
│       └── user.go
└── v2/ # 保留扩展能力:v2 代码保存目录

上述代码,将不同版本的代码保存在不同的版本化目录中,不同 REST 资源的业务逻辑实现保存在跟资源对应的目录中。不同资源的业务逻辑代码均在其对应的目录中实现,可以在目录级别隔离不同资源的代码实现,有利于提高代码的稳定性,并降低维护的复杂度。

Biz 层依赖于 Store 层的实现,所以在创建 IBiz 实例时,需要传入 IStore 类型的实例,IBiz 实例由 NewBiz 函数创建:

// biz 是 IBiz 的一个具体实现.
type biz struct {store store.IStore
}// 确保 biz 实现了 IBiz 接口.
var _ IBiz = (*biz)(nil)// NewBiz 创建一个 IBiz 类型的实例.
func NewBiz(store store.IStore) *biz {return &biz{store: store}
}

IBiz 的实现跟 IStore 的实现是保持一致,其他代码,本节不再详解。

UserBiz 接口定义及实现

User 资源的 Biz 层代码实现位于 internal/apiserver/biz/v1/user/user.go 文件中,其接口定义为 UserBiz,代码如下:

// UserBiz 定义处理用户请求所需的方法.
type UserBiz interface {Create(ctx context.Context, rq *apiv1.CreateUserRequest) (*apiv1.CreateUserResponse, error)Update(ctx context.Context, rq *apiv1.UpdateUserRequest) (*apiv1.UpdateUserResponse, error)Delete(ctx context.Context, rq *apiv1.DeleteUserRequest) (*apiv1.DeleteUserResponse, error)Get(ctx context.Context, rq *apiv1.GetUserRequest) (*apiv1.GetUserResponse, error)List(ctx context.Context, rq *apiv1.ListUserRequest) (*apiv1.ListUserResponse, error)UserExpansion
}// UserExpansion 定义用户操作的扩展方法.
type UserExpansion interface {
}

UserBiz 接口中的方法,同样也分为了两大类:标准资源 CURD 接口和扩展接口,扩展接口中实现了用户登录、Token 刷新、密码修改等方法。实现 UserBiz 接口的 Go 结构体是 *userBiz

创建用户:Create 方法实现

userBiz 结构体的 Create 方法实现如下:

// Create 实现 UserBiz 接口中的 Create 方法.
func (b *userBiz) Create(ctx context.Context, rq *apiv1.CreateUserRequest) (*apiv1.CreateUserResponse, error) {var userM model.User_ = copier.Copy(&userM, rq)if err := b.store.User().Create(ctx, &userM); err != nil {return nil, err}return &apiv1.CreateUserResponse{UserID: userM.UserID}, nil
}

为了提高开发效率,减少不必要的代码量,Create 方法使用了 [github.com/jinzhu/copier](https://github.com/jinzhu/copier)Copy 函数给目标结构体变量 userM 赋值。

Create 方法中,通过 b.store.User().Create(ctx, &userM) 方法调用,将数据保存在数据库中。

在 Go 项目开发中,数据库禁止保存明文密码。用户密码在入库前需要进行加密处理。为了加密明文密码字符串,fastgo 引入了 github.com/onexstack/onexstack/pkg/auth 包,auth 包中的 Encrypt 函数可以用来加密一个明文密码字符串。

因为在入库前都需要对明文密码进行加密,所以,很自然的想到可以通过实现 GORM 框架的 BeforeCreate 钩子来实现。修改 internal/apiserver/model/hook.go 文件,添加以下代码:

import (..."github.com/onexstack/onexstack/pkg/auth"
)// BeforeCreate 在创建数据库记录之前加密明文密码.
func (m *User) BeforeCreate(tx *gorm.DB) error {// Encrypt the user password.var err errorm.Password, err = auth.Encrypt(m.Password)if err != nil {return err}return nil
}

更新用户:Update 方法实现

userBiz 结构体的 Update 方法实现如下:

// Update 实现 UserBiz 接口中的 Update 方法.
func (b *userBiz) Update(ctx context.Context, rq *apiv1.UpdateUserRequest) (*apiv1.UpdateUserResponse, error) {userM, err := b.store.User().Get(ctx, where.T(ctx))if err != nil {return nil, err}if rq.Username != nil {userM.Username = *rq.Username}if rq.Email != nil {userM.Email = *rq.Email}if rq.Nickname != nil {userM.Nickname = *rq.Nickname}if rq.Phone != nil {userM.Phone = *rq.Phone}if err := b.store.User().Update(ctx, userM); err != nil {return nil, err}return &apiv1.UpdateUserResponse{}, nil
}

在更新用户时,根据是否传入待更新的字段来判断是否更新该字段。这样的设计方式,可以通过一个更新接口实现字段的选择性更新。

查询用户列表:List 方法实现

userBiz 结构体的 List 方法实现如下述代码所示:

// List 实现 UserBiz 接口中的 List 方法.
func (b *userBiz) List(ctx context.Context, rq *apiv1.ListUserRequest) (*apiv1.ListUserResponse, error) {whr := where.P(int(rq.Offset), int(rq.Limit))count, userList, err := b.store.User().List(ctx, whr)if err != nil {return nil, err}var m sync.Mapeg, ctx := errgroup.WithContext(ctx)// 设置最大并发数量为常量 MaxConcurrencyeg.SetLimit(known.MaxErrGroupConcurrency)// 使用 goroutine 提高接口性能for _, user := range userList {eg.Go(func() error {select {case <-ctx.Done():return nildefault:count, _, err := b.store.Post().List(ctx, where.T(ctx))if err != nil {return err}converted := conversion.UserodelToUserV1(user)converted.PostCount = countm.Store(user.ID, converted)return nil}})}if err := eg.Wait(); err != nil {slog.ErrorContext(ctx, "Failed to wait all function calls returned", "err", err)return nil, err}users := make([]*apiv1.User, 0, len(userList))for _, item := range userList {user, _ := m.Load(item.ID)users = append(users, user.(*apiv1.User))}slog.DebugContext(ctx, "Get users from backend storage", "count", len(users))return &apiv1.ListUserResponse{TotalCount: count, Users: users}, nil
}

List 方法会查询所有的用户列表,并统计用户所属的博客数,这种遍历多个列表,并且针对列表中每个元素都有耗时处理逻辑的代码,可能会导致 List 方法执行时间较久。为了提高 List 方法的性能,List 方法中使用了 errgroup 包,并发查询每个用户的博客数。

在上述代码中 eg.SetLimit 方法调用的作用是限制程序中同时运行的 Go 协程数量,以避免过多协程并发任务导致的系统资源过载(如高 CPU 和内存占用或高 I/O 消耗)。通过 eg.Go 启动的 goroutine 会按照 SetLimit 的限制规则执行。当已经有 MaxErrGroupConcurrency 个任务在运行时,新任务会阻塞,直到某个正在运行的任务完成。

因为会并发处理 userList 列表中的每个元素,所以需要一个并发安全的数据类型,保存处理后的数据。Go 标准库提供了 sync.Map 数据类型,该类型是并发安全的,可以直接在 Go 协程中使用 sync.MapStore 方法添加 key-value 对。在上述代码中,使用 m.Store 保存了 *apiv1.User 类型的数据。

Store 层返回的数据类型为 *model.UserM,需要转换为 Biz 层使用的数据类型 *apiv1.User*model.UserM*apiv1.User 数据类型之间的相互转换,在 Biz 层经常会发生,为了提高代码的可维护性,将这类转换实现统一保存在 internal/apiserver/pkg/conversion 目录下的 conversion 包中。

Store 层返回的用户列表是降序排列的,为了保证 List 返回的列表也是降序排列的,上述代码的最后,使用以下代码段重新排列了 sync.Map 类型变量 m 中保存的数据:

for _, item := range userList {user, _ := m.Load(item.ID)users = append(users, user.(*apiv1.User))
}

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

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

相关文章

idea更新git代码报错No Git Roots

idea更新git代码报错&#xff1a; No Git Roots None of configured Git roots are under Git. The configured directory must have ".git directory in it.但是本地项目里是存在.git文件的&#xff0c;就是突然间不能更新代码了 然后尝试重新拉新项目代码提示: Git i…

[Hello-CTF]RCE-Labs超详细WP-Level13Level14(PHP下的0/1构造RCE命令简单的字数限制RCE)

Level 13 源码分析 这题又回到了 PHP重点关注preg_match("/[A-Za-z0-9\"%*,-.\/:;>?[\]^|]/", $cmd)禁用了所有数字, 并且回到了 PHP, 没办法用上一关的方法进行绕过但是比起上一关, 给我们少绕过了 &, ~, _似乎有其他方法 解题分析 利用 $(()) 和 …

Qt 控件概述 QWdiget 1.1

目录 qrc机制 qrc使用 1.在项目中创建一个 qrc 文件 2.将图片导入到qrc文件中 windowOpacity&#xff1a; cursor 光标 cursor类型 自定义Cursor font tooltip focusPolicy styleSheet qrc机制 之前提到使用相对路径的方法来存放资源&#xff0c;还有一种更好的方式…

【eNSP实战】将路由器配置为DHCP服务器

拓图 要求&#xff1a; 为 office100 和 office200 分别配置地址池 AR1接口配置 interface GigabitEthernet0/0/0ip address 192.168.100.1 255.255.255.0 # interface GigabitEthernet0/0/1ip address 192.168.200.1 255.255.255.0 AR1路由器上创建office100地址池 [AR1…

数据结构——顺序表seqlist

前言&#xff1a;大家好&#x1f60d;&#xff0c;本文主要介绍了数据结构——顺序表部分的内容 目录 一、线性表的定义 二、线性表的基本操作 三.顺序表 1.定义 2. 存储结构 3. 特点 四 顺序表操作 4.1初始化 4.2 插入 4.2.1头插 4.2.2 尾插 4.2.3 按位置插 4.3 …

OSPF | LSDB 链路状态数据库 / SPF 算法 / 实验

注&#xff1a;本文为 “OSPF | LSDB / SPF ” 相关文章合辑。 LSDB 和 SPF 算法 潇湘浪子的蹋马骨汤 发布 2019-02-15 23:58:46 1. 链路状态数据库 (LSDB) 链路状态协议除了执行洪泛扩散链路状态通告&#xff08;LSA&#xff09;以及发现邻居等任务外&#xff0c;其第三个任…

前端---CSS(前端三剑客)

1.基本语法规范 选择器 {⼀条/N条声明} • 选择器决定针对谁修改 (找谁) • 声明决定修改啥. (⼲啥) • 声明的属性是键值对. 使⽤ ; 区分键值对, 使⽤ : 区分键和值 比如&#xff1a; <!DOCTYPE html> <html lang"en"> <head><meta…

【C++】 —— 笔试刷题day_6

刷题day_6&#xff0c;继续加油哇&#xff01; 今天这三道题全是高精度算法 一、大数加法 题目链接&#xff1a;大数加法 题目解析与解题思路 OK&#xff0c;这道题题目描述很简单&#xff0c;就是给我们两个字符串形式的数字&#xff0c;让我们计算这两个数字的和 看题目我…

todolist docker 小工具

参考链接 前排提示 没有中文&#xff0c;可使用浏览器 翻译 前提 安装docker安装docker-compose 下载仓库 git clone https://github.com/JordanKnott/taskcafe进行安装 cd taskcafe docker-compose -p taskcafe up -d服务启动后会监听在 3333 端口上&#xff0c;通过浏览器…

Unity--GPT-SoVITS接入、处理GPTAPI的SSE响应流

GPT-SoVITS GPT-SoVITS- v2&#xff08;v3也可以&#xff0c;两者对模型文件具有兼容&#xff09; 点击后 会进入新的游览器网页 ----- 看了一圈&#xff0c;发现主要问题集中在模型的训练很需要CPU&#xff0c;也就是模型的制作上&#xff0c;问题很多&#xff0c;如果有现有…

《TypeScript 快速上手:类型、编译与严格模式的简明教程》

一、TypeScript介绍 在引入编程社区 20 多年后&#xff0c;JavaScript 现在已成为有史以来应用最广泛的跨平台语言之一。JavaScript 最初是一种用于向网页添加微不足道的交互性的小型脚本语言&#xff0c;现已发展成为各种规模的前端和后端应 用程序的首选语言。虽然用 JavaSc…

ROS2 系统架构

1.操作系统层 ros2是基于Linux、Windows、macOS系统建立的&#xff0c;这一层为ros2提供了各种基础的硬件驱动&#xff0c;比如网卡驱动&#xff0c;常用USB驱动和常用摄像头驱动等。 2.DDS实现层 ros2的核心通信是采用第三方的通信组件来实现的&#xff0c;这个第三方就是数…

【HTML】二、列表、表格

文章目录 1、列表1.1 无序列表1.2 有序列表1.3 定义列表 2、表格2.1 定义2.2 表格结构标签2.3 合并单元格 1、列表 列表分为&#xff1a; 无序列表有序列表定义列表&#xff1a;一个标题下有多个小分类 1.1 无序列表 ul嵌套li&#xff0c;ul是无序列表&#xff0c;li是列表…

redis zset基本介绍以及底层实现

ZSet&#xff08;Sorted Set&#xff09;有序集合 介绍 Redis 中的有序集合(Sorted Set)是在集合(Set)的基础上,为每个成员关联了一个分数(score)。这个分数可以用来对集合中的成员进行排序。 有序集合保留了集合不能有重复成员的特性&#xff08;成员不能重复&#xff0c;分值…

政策助力,3C 数码行业数字化起航

政策引领&#xff0c;数字经济浪潮来袭 在当今时代&#xff0c;数字经济已成为全球经济发展的核心驱动力&#xff0c;引领着新一轮科技革命和产业变革的潮流。我国深刻洞察这一发展趋势&#xff0c;大力推进数字化经济发展战略&#xff0c;为经济的高质量发展注入了强大动力。 …

IntelliJ IDEA 快捷键系列:重命名快捷键详解

目录 引言一、默认重命名快捷键1. Windows 系统‌2. Mac 系统‌ 二、操作步骤与技巧1. 精准选择重命名范围‌2. 智能过滤无关内容‌ 三、总结 引言 在代码重构中&#xff0c;‌重命名变量、类、方法‌ 是最常用的操作之一。正确使用快捷键可以极大提升开发效率。本文针对 ‌Ma…

文档搜索引擎

首先获取很多网页(爬虫->一个http客户端,发送http请求获取http响应结果(就是网站))(批量化的获取很多的页面) 再根据用户输入的查询词,在网页中进行查找 用户输入查询词之后,如何让查询词和当前这些网页进行匹配 ->使用倒排索引 倒排索引 1.文档: 每个待搜索的网页(被爬…

开源工具利器:Mermaid助力知识图谱可视化与分享

在现代 web 开发中&#xff0c;可视化工具对于展示流程、结构和数据关系至关重要。Mermaid 是一款强大的 JavaScript 工具&#xff0c;它使用基于 Markdown 的语法来呈现可定制的图表、图表和可视化。对于展示流程、结构和数据关系至关重要。通过简单的文本描述&#xff0c;你可…

【AI News | 20250316】每日AI进展

AI Repos 1、ReActMCP 将网络搜索能力集成到AI助手中的一个MCP服务&#xff1a;ReActMCP Web Search&#xff0c;相当于给AI装了个搜索引擎&#xff0c;可以实时查找最新的内容。它基于Exa API执行基本和高级网络搜索&#xff0c;高级搜索比如限制搜索的网站范围、指定日期范围…

【VUE】day04-组件的生命周期、组件之间的数据共享、ref引用、购物车案例

【VUE】day04-组件的生命周期、组件之间的数据共享、ref引用、购物车案例 1. 组件之间的关系2. 使用组件的三个步骤3. vue.components全局注册组件4. 自动生成右边标签插件5. 组件的props6. 结合v-bind使用自定义属性7. props的默认default值8. type值类型9. 组件之间的样式冲突…