实战 图书馆系统管理案例

  • config :敏感的配置一般都是在配置中心配置,比如consul或者阿波罗上面
  • controller :写一些handler的,拿到参数要去调用service层的逻辑。(只负责接受参数,怎么绑定参数,要去调用哪个service的,handler的一个入口
  • service:service层才是正真的业务处理层。调用dao层的增删改查操作
  • dao:只关心数据库的一个操作,其实你有数据库和es都在dao层
  • db:负责数据库,中间件层的初始化
  • middleware:存放gin的中间件,在注册路由的时候将中间件引入进来

go常用项目结构 


dao层只关心数据库的操作,db层只做Mysql层的初始化。model去定义表结构,定义中间表,多对多的结构体。 

中间件有个token的验证。

controller层,先去找路由,这个项目有多少的接口(router.go),每个接口到哪些对应的handler。

controller层接收完参数之后,再看调用到哪个service,service再去干了什么增删改查操作。

数据库增删改查就去dao层查看。

这一层一层非常的分明。上面可以理解为日常开发的目录结构最佳实践。

创建数据库


mysql> create database books charset utf8;

图书管理服务 


用户服务:登录,注册
书籍服务:对书籍的增删改查的操作
主要有两个维度,一个是书籍维度,一个是用户维度。用户维度要去写两个功能,一个功能是登入,一个功能是注册。
注册就是数据库插入一条数据。登入就是一个校验。配合token中间件去做一个校验。
在新增书籍的时候要去关联用户,这本书属于谁?书籍的增删改查都需要关联这个用户。这里就涉及到1对多的关系。
开发的时候是从最底层开始,往上开发。第一个先去定义数据库的model层。

  

model层 定义数据库结构


binding标签表示是必填项,token是可以为空的,因为一开始注册的时候token的为空。只有登入的时候才有token。

user.go

package modeltype User struct {ID       int64  `gorm:"primaryKey" json:"id"`UserName string `gorm:"not null" json:"username" binding:"required"`PassWord string `gorm:"not null" json:"password" binding:"required"`Token    string `json:"token"`
}func (*User) TableName() string {return "user"
}

book.go

package modeltype Book struct {ID    int64  `gorm:"primaryKey" json:"id"`Name  string `gorm:"not null" json:"name" binding:"required"`Desc  string `json:"desc"`Users []User `gorm:"many2many:book_users"`
}func (*Book) TableName() string {return "book"
}

多对多关系可以在user这层定义也行,在book这一层定义也可以。这个主要看你的一个实际使用的场景,这里在book模型里面去定义就行了。

还需要去定义一个中间表的模型user_m2m_book.go

package modeltype BookUser struct {UserID int64 `gorm:"primaryKey"`BookID int64 `gorm:"primaryKey"`
}

这里不需要自定义表名,它只有一个主键,也没有其他属性了。它也是永了外键,也是使用了那两个模型的主键。


DB层


模型定义好之后去做数据库的初始化,这里需要预留,因为可能不仅仅只有MySQL的初始化。

这样赋值到一个全局变量,之后使用mysql.DB就可以在任何地方去使用了。 

package mysqlimport ("book/model""fmt""gorm.io/driver/mysql""gorm.io/gorm"
)// DB 要将DB实例放到全局变量,这样就可以使用mysql.DB在任何地方去使用了.
var DB *gorm.DBfunc InitMysql() {dsn := "root:7PXjAkY!&nlR@tcp(192.168.11.128:3306)/books?charset=utf8mb4&parseTime=True&loc=Local"db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{})//这个地方Log和panic都是可以的if err != nil {fmt.Println(err)}DB = dberr = DB.AutoMigrate(model.Book{}, model.User{}, model.BookUser{})if err != nil {fmt.Println(err)}
}

DAO层


初始化好之后在dao层开始写,dao层的操作就是数据库的增删改查

package daoimport ("book/db/mysql""book/model""errors""fmt""github.com/wonderivan/logger""gorm.io/gorm"
)//定义user结构体,以及User变量,能够直接跨包调用user下面的方法
//只需要一次初始化即可,不用每次调用的都是先初始化var User usertype user struct {
}// Add 新增 用于注册
func (*user) Add(user *model.User) error {if tx := mysql.DB.Create(user); tx.Error != nil {//打印错误提示logger.Error(fmt.Sprintf("添加User失败,错误信息:%s", tx.Error))return errors.New(fmt.Sprintf("添加User失败,错误信息:%s", tx.Error))}return nil
}// Has 查询 基于name 用于新增
func (*user) Has(name string) (*model.User, bool, error) {//初始化要申请内存,不然会报错data := &model.User{}tx := mysql.DB.Where("username = ?", name).Find(data)//如果记录没有查询到,报错是从tx.error里面拿到的,相当于tx.Error = gorm.ErrRecordNotFoundif errors.Is(tx.Error, gorm.ErrRecordNotFound) {return nil, false, nil}//等会去调用的时候,不会先去判断有没有,要先去判断error,有error就是真正的错误,没有判断是不是falseif tx.Error != nil {logger.Error(fmt.Sprintf("查询用户失败,错误信息:%s", tx.Error))return nil, false, errors.New(fmt.Sprintf("查询用户失败,错误信息:%s", tx.Error))}return data, true, nil
}// GetByToken 基于token查询,用于中间件token校验
func (*user) GetByToken(token string) (*model.User, bool, error) {//初始化要申请内存,不然会报错data := &model.User{}tx := mysql.DB.Where("token = ?", token).Find(data)//如果记录没有查询到,报错是从tx.error里面拿到的,相当于tx.Error = gorm.ErrRecordNotFoundif errors.Is(tx.Error, gorm.ErrRecordNotFound) {return nil, false, nil}if tx.Error != nil {logger.Error(fmt.Sprintf("查询用户失败%s", tx.Error))return nil, false, errors.New(fmt.Sprintf("查询用户失败%v/n", tx.Error))}return data, true, nil
}// UPDateToken 更新token,这里其实就是找到user的条件去更新就行了
// 第一个参数可以是id也可以是用户名,如果用户名唯一,只要保证找到指定用户即可
// 除了查询的操作以外,增删改只需要返回一个error即可,判断操作有没有成功
func (*user) UPDateToken(user *model.User, token string) error {tx := mysql.DB.Model(user).Where("username= ? and password = ?", user.UserName, user.PassWord).Update("token", token)if tx.Error != nil {logger.Error(fmt.Sprintf("更新user token失败,错误信息:%s", tx.Error))return errors.New(fmt.Sprintf("更新user token失败,错误信息:%s", tx.Error))}return nil
}

service层


和dao层一样,都定义了相同的结构体,不同的包使用相同的结构体变量,但是点出来的方法都是不同的。

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

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

相关文章

CSS中如何实现元素之间的间距(Margin)合并效果?

聚沙成塔每天进步一点点 ⭐ 专栏简介⭐ 外边距合并的示例:⭐ 如何控制外边距合并:⭐ 写在最后 ⭐ 专栏简介 前端入门之旅:探索Web开发的奇妙世界 记得点击上方或者右侧链接订阅本专栏哦 几何带你启航前端之旅 欢迎来到前端入门之旅&#xff…

深入Golang之Mutex

深入Golang之Mutex 基本使用方法 可以限制临界区只能同时由一个线程持有。 直接在流程结构中使用 lock、unlock嵌入到结构中,然后通过结构体的 mutex 属性 调用 lock、unlock嵌入到结构体中,但是是直接在需要锁定的资源方法中使用,让外界无…

如何有效进行RLHF的数据标注?

编者按:随着大语言模型在自然语言处理领域的广泛应用,如何从人类反馈进行强化学习(RLHF)已成为一个重要的技术挑战。并且RLHF需要大量高质量的人工数据标注,这是一个非常费力的过程。 本文作者在数据标注领域具有丰富经…

人工智能学习专栏

这个专栏就专门用来记录自己的深度学习的历程吧。从做MCU开始、Soc、Linux系统转行到AI领域,其过程是痛苦的。至少数学这块,那是花了很多时间去从头去学。但是还是有很多不懂的地方。坚持!!!!

分布式集群——jdk配置与zookeeper环境搭建

系列文章目录 分布式集群——jdk配置与zookeeper环境搭建 分布式集群——搭建Hadoop环境以及相关的Hadoop介绍 文章目录 系列文章目录 前言 一 zookeeper介绍与环境配置 1.1 zookeeper的学习 1.2 Zookeeper的主要功能 1.2.1 znode的节点类型 1.2.2 zookeeper的实现 …

[虚幻引擎 UE5] EditableText(可编辑文本) 限制只能输入数字并且设置最小值和最大值

本蓝图函数可以格式化 EditableText 控件输入的数据,让其只能输入一定范围内的整数。 蓝图函数 调用方法 下载蓝图(5.2.1版本)https://dt.cq.cn/archives/618

考生作弊行为分析算法

考生作弊行为分析系统利用pythonyolo系列网络模型算法框架,考生作弊行为分析算法利用图像处理和智能算法对考生的行为进行分析和识别,经过算法服务器的复杂计算和逻辑判断,算法将根据考生行为的特征和规律,判定是否存在作弊行为。…

【已解决】ZooKeeper配置中出现Error contacting service. It is probably not running

ZooKeeper配置中出现Error contacting service. It is probably not running 问题 安装zookeeper,启动报错了 Error contacting service. It is probably not running 思路 tail -100f logs/zookeeper-root-server-node1.itcast.cn.out 查看日志报错 zoo.cfg没…

【UE5】给模型指定面添加自定义材质

实现步骤 1. 首先我们向UE中导入一个简单的模型,可以看到目前该模型的材质插槽只有一个,当我们修改材质时会使得模型整体的材质全部改变,如果我们只想改变模型的某些面的材质就需要继续做后续操作。 2. 选择建模模式 3. 在模式工具栏中点击…

docker desktop安装es 并连接elasticsearch-head:5

首先要保证docker安装成功,打开cmd,输入docker -v,出现如下界面说明安装成功了 下面开始安装es 第一步:拉取es镜像 docker pull elasticsearch:7.6.2第二步:运行容器 docker run -d --namees7 --restartalways -p 9…

win11出现安全中心空白和IT管理员已限制对此应用的某些区域的访问

问题 windows安全中心服务被禁用 winr 输入services.msc 找到windows安全中心服务查看是否被禁用,改为启动,不可以改动看第三条 打开设置,找到应用—windows安全中心–终止–修复–重置 重启如果还是不行看第四条 家庭版系统需要打开gped…

【算法训练-字符串】一 最长无重复子串

废话不多说,喊一句号子鼓励自己:程序员永不失业,程序员走向架构!本篇Blog的主题是最长无重复子串或最长无重复子数组,这类题目出现频率还是很高的。 最长无重复子串【MID】 先来看字符串数据结构的题目 题干 解题思…