Actual library system management case

  • config : Sensitive configurations are generally configured in the configuration center, such as consul or Apollo
  • controller : Write some handlers, and get the parameters to call the logic of the service layer. ( Only responsible for accepting parameters, how to bind parameters, which service to call, an entry of handler )
  • service: The service layer is the real business processing layer . Call the addition, deletion, modification, and query operations of the dao layer
  • dao: only care about one operation of the database , in fact, you have the database and es in the dao layer
  • db: responsible for the initialization of the database and middleware layer
  • middleware: store the middleware of gin, and introduce the middleware when registering the route

Go common project structure 


The dao layer only cares about the operation of the database, and the db layer only does the initialization of the Mysql layer. model to define the table structure, define the intermediate table, many-to-many structure. 

The middleware has a token verification.

In the controller layer, first look for routing, how many interfaces (router.go) this project has, and which corresponding handlers each interface goes to.

After the controller layer receives the parameters, it looks at which service is called, and what additions, deletions, changes, and queries are performed by the service.

For database additions, deletions, changes and queries, go to the dao layer to check.

This layer is very distinct. The above can be understood as the best practice of directory structure for daily development.

create database


mysql> create database books charset utf8;

Library Management Services 


User Service: Login, Register
Book service: the operation of adding, deleting, modifying and checking books
There are two main dimensions, one is the book dimension and the other is the user dimension. The user dimension needs to write two functions, one is login and the other is registration.
Registration is to insert a piece of data into the database. Login is a verification. Cooperate with the token middleware to do a verification.
When adding a book, you need to associate users. Who does this book belong to? Addition, deletion, modification and query of books need to be associated with this user. This involves a 1-to-many relationship.
When developing, start from the bottom and work upwards. The first one is to define the model layer of the database.

  

The model layer defines the database structure


The binding tag indicates that it is a required item, and the token can be empty , because the token is empty at the beginning of registration. The token is only available when you log in.

user.go

package model

type 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 model

type 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"
}

The many-to-many relationship can be defined at the user level, or at the book level. This mainly depends on one of your actual use scenarios. Here, you can define it in the book model.

It is also necessary to define an intermediate table model user_m2m_book.go

package model

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

There is no need to customize the table name here, it only has a primary key and no other attributes. It also preserves foreign keys and uses the primary keys of those two models.


DB layer


After the model is defined, do the initialization of the database, which needs to be reserved here, because it may not only be the initialization of MySQL.

In this way, assign it to a global variable, and then use mysql.DB to use it anywhere. 

package mysql

import (
	"book/model"
	"fmt"
	"gorm.io/driver/mysql"
	"gorm.io/gorm"
)

// DB 要将DB实例放到全局变量,这样就可以使用mysql.DB在任何地方去使用了.
var DB *gorm.DB

func 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 = db
	
	err = DB.AutoMigrate(model.Book{}, model.User{}, model.BookUser{})
	if err != nil {
		fmt.Println(err)
	}
}

DAO layer


After initialization, start writing in the dao layer. The operation of the dao layer is to add, delete, modify and check the database

package dao

import (
	"book/db/mysql"
	"book/model"
	"errors"
	"fmt"
	"github.com/wonderivan/logger"
	"gorm.io/gorm"
)

//定义user结构体,以及User变量,能够直接跨包调用user下面的方法
//只需要一次初始化即可,不用每次调用的都是先初始化

var User user

type 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.ErrRecordNotFound
	if errors.Is(tx.Error, gorm.ErrRecordNotFound) {
		return nil, false, nil
	}
	//等会去调用的时候,不会先去判断有没有,要先去判断error,有error就是真正的错误,没有判断是不是false
	if 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.ErrRecordNotFound
	if 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 layer


Like the dao layer, the same structure is defined, and different packages use the same structure variable, but the methods of pointing out are different.

Guess you like

Origin blog.csdn.net/qq_34556414/article/details/132078695
Recommended