A must-read for GoWeb developers: Master the skills of GORM to achieve efficient database operations (complete code attached)

1 Introduction

What is a web application? The simple process of a web application is as shown in the figure below

Insert image description here
From the picture above, we find that our GoWeb practical project still lacks the last key link, the database. So how to use the GO language to operate the database and complete operations such as additions, deletions, modifications, and queries is our goal of learning today.

Implementing a GoWeb MVC framework from scratch: giving you a deeper understanding of MVC architecture design

2. What is ORM

Object Relational Mapping (ORM for short) automatically persists objects in a program to a relational database by using metadata that describes the mapping between objects and databases.

We are object-oriented. When the object's information changes, we need to save the object's information in the relational database. Programmers will mix many SQL statements into their business logic code to add, read, modify, and delete related data, and these codes are usually repeated.

The emergence of ORM serves as a bridge between the object and database levels.

3、MySQL

3.1. What is MySQL

MySQL is a relational database management system developed by the Swedish MySQL AB company and is a product of Oracle. MySQL is one of the most popular relational database management systems. In terms of WEB applications, MySQL is one of the best RDBMS (Relational Database Management System) application software.

MySQL is a relational database management system. A relational database stores data in different tables instead of placing all data in one large warehouse, which increases speed and flexibility.

The SQL language used by MySQL is the most commonly used standardized language for accessing databases. MySQL software adopts a dual licensing policy and is divided into community version and commercial version. Due to its small size, fast speed, low total cost of ownership, and especially the characteristics of open source, MySQL is generally chosen as the website for the development of small, medium and large websites. database.

3.2. MySQL installation

3.2.1 Docker environment

Docker environment MySQL8 master-slave configuration

3.2.2 Newbie Tutorial

MySQL Newbie Tutorial

3.3. Create database

Quickly create a database through Navicat Premium. Database name example: go_gorm, character set selection: utf8mb4, collation selection: utf8mb4_general_ci. Finally click Confirm

Insert image description here

3.4. Create data table

Create a system user table, and the user completes our subsequent CRUD and other operations. The table creation statement is as follows:

-- ----------------------------
-- 系统用户
-- ----------------------------
DROP TABLE IF EXISTS `sys_user`;
CREATE TABLE `sys_user`
(
    `id`             bigint unsigned NOT NULL AUTO_INCREMENT COMMENT '主键 ID',
    `name`           varchar(10)  NOT NULL DEFAULT '' COMMENT '用户名',
    `account`        varchar(20)  NOT NULL DEFAULT '' COMMENT '账号',
    `password`       varchar(64)  NOT NULL DEFAULT '' COMMENT '密码',
    `password_salt`  varchar(64)  NOT NULL DEFAULT '' COMMENT '密码盐值',
    `mail_address`   varchar(64)  NOT NULL DEFAULT '' COMMENT '邮箱地址',
    `phone_number`   varchar(20)  NOT NULL DEFAULT '' COMMENT '手机号码',
    `age`            tinyint unsigned NOT NULL DEFAULT '0' COMMENT '用户年龄',
    `is_using`       tinyint unsigned NOT NULL DEFAULT '0' COMMENT '是否启用  10(默认0)',
    `is_delete`      tinyint unsigned NOT NULL DEFAULT '0' COMMENT '是否删除  10(默认0)',
    `create_time`    datetime     NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
    `update_time`    datetime     NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '修改时间',
    `remark`         varchar(100) NOT NULL DEFAULT '' COMMENT '描述',
    PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb3 COMMENT='系统用户';

3.5. New data

Add a new piece of super administrator data. Note: There are security risks in storing the current user password in plain text.

INSERT INTO `sys_user` ( `name`, `account`, `password` ) VALUES ('超级管理员', 'admin', '123456')

4. Write code

This project is based on the source code of " GoWeb Project Practice: Using the Iris Framework to Build a Safe and Reliable API Service (With JWT Authentication Implementation) ". If you only want to know about CRUD, you can ignore it.

4.1. Install software package

# gorm 安装
go get -u gorm.io/gorm

# mysql 驱动
go get -u gorm.io/driver/mysql

4.2. Write code

4.2.1. Load MySQL database

Create a new file mysql.go in the utils/db directory. The complete code is as follows:

package db

import (
	"fmt"
	"log"
	"os"
	"time"

	"gorm.io/driver/mysql"
	"gorm.io/gorm"
	"gorm.io/gorm/logger"
)

// 全局变量
var GormDb *gorm.DB

func init() {
    
    
	fmt.Println("开始加载 MySQL 数据库")
	GormDb = InitMysql()
}

/*
* <h2>初始化 MySQL 数据库</h2>
**/
func InitMysql() *gorm.DB {
    
    
	// GORM 定义了这些日志级别:Silent、Error、Warn、Info
	newLogger := logger.New(
		log.New(os.Stdout, "\r\n", log.LstdFlags), // io writer(日志输出的目标,前缀和日志包含的内容——译者注)
		logger.Config{
    
    
			SlowThreshold:             time.Second, // 慢 SQL 阈值
			LogLevel:                  logger.Info, // 日志级别
			IgnoreRecordNotFoundError: false,       // 忽略ErrRecordNotFound(记录未找到)错误
			Colorful:                  false,       // 禁用彩色打印
		},
	)

	// MySQL 数据库地址和用户信息
	dsn := "替换自己数据库用户名:替换自己数据库密码@tcp(数据库IP地址:数据库端口)/go_gorm?charset=utf8mb4&parseTime=True&loc=Local"

	db, err := gorm.Open(mysql.New(mysql.Config{
    
    
		DSN:                       dsn,   // DSN data source name
		DefaultStringSize:         256,   // string 类型字段的默认长度
		DisableDatetimePrecision:  true,  // 禁用 datetime 精度,MySQL 5.6 之前的数据库不支持
		DontSupportRenameIndex:    true,  // 重命名索引时采用删除并新建的方式,MySQL 5.7 之前的数据库和 MariaDB 不支持重命名索引
		DontSupportRenameColumn:   true,  // 用 `change` 重命名列,MySQL 8 之前的数据库和 MariaDB 不支持重命名列
		SkipInitializeWithVersion: false, // 根据当前 MySQL 版本自动配置
	}), &gorm.Config{
    
    Logger: newLogger})

	if err != nil {
    
    
		fmt.Println("加载数据库异常信息:", err)
		return nil
	}

	// 获取通用数据库对象 sql.DB,然后使用其提供的功能
	mysqlDB, err := db.DB()
	if err != nil {
    
    
		fmt.Println("获取通用数据库对象异常信息:", err)
		return nil
	}

	// Ping
	err = mysqlDB.Ping()
	if err != nil {
    
    
		fmt.Println("数据库连接异常信息:", err.Error())
		return nil
	}

	fmt.Println("数据库连接成功", mysqlDB)

	// SetMaxIdleConns 用于设置连接池中空闲连接的最大数量。
	mysqlDB.SetMaxIdleConns(10)

	// SetMaxOpenConns 设置打开数据库连接的最大数量。
	mysqlDB.SetMaxOpenConns(100)

	// SetConnMaxLifetime 设置了连接可复用的最大时间。
	mysqlDB.SetConnMaxLifetime(time.Hour)

	return db
}

4.2.2. Business exception customization

Modify the file errors.go in the utils/constant directory. The complete code is as follows:

package constant

import "errors"

/**
 * <h1>业务异常自定义</h1>
 * Created by woniu
 */

var (
	ResErrAuthorizationIsNilErr = errors.New("1001_token 为空")
	ResErrSysUserPasswordErr    = errors.New("2001_密码错误")
	ResErrIdIsNil               = errors.New("2002_主键 ID 不能为空")
	ResErrSysUserRepeat         = errors.New("2003_用户已存在")
	ResErrSysUserIsNil          = errors.New("2004_用户不存在")
)

4.2.3. System user model

Create a new file sys_user.go in the app/model directory. The complete code is as follows:

package model

import "time"

// 系统用户信息
type SysUser struct {
    
    
	Id           int64     `gorm:"primaryKey"`           // 用户 ID
	Name         string    `gorm:"column:name"`          // 用户姓名
	Account      string    `gorm:"column:account"`       // 用户账号
	Password     string    `gorm:"column:password"`      // 用户密码
	PasswordSalt string    `gorm:"column:password_salt"` // 密码盐值
	MailAddress  string    `gorm:"column:mail_address"`  // 邮箱地址
	PhoneNumber  string    `gorm:"column:phone_number"`  // 手机号码
	Age          int       `gorm:"column:age"`           // 用户年龄
	IsUsing      int       `gorm:"column:is_using"`      // 是否启用  1是 0否(默认0)
	IsDelete     int       `gorm:"column:is_delete"`     // 是否删除  1是 0否(默认0)
	CreateTime   time.Time `gorm:"column:create_time"`   // 创建时间
	UpdateTime   time.Time `gorm:"column:update_time"`   // 修改时间
	Remark       string    `gorm:"column:remark"`        // 描述
}

// TableName 指定表名
func (SysUser) TableName() string {
    
    
	return "sys_user"
}

4.2.4. System user response structure

Modify the file sys_user_vo.go in the app/vo directory. The complete code is as follows:

package vo

// 系统用户信息
type SysUserVo struct {
    
    
	Id          int64  `json:"id"`          // 用户 ID
	Name        string `json:"name"`        // 用户姓名
	Account     string `json:"account"`     // 用户账号
	MailAddress string `json:"mailAddress"` // 邮箱地址
	PhoneNumber string `json:"phoneNumber"` // 手机号码
	Age         int    `json:"age"`         // 用户年龄
	IsUsing     int    `json:"isUsing"`     // 是否启用  1是 0否(默认0)
	IsDelete    int    `json:"isDelete"`    // 是否删除  1是 0否(默认0)
	CreateTime  string `json:"createTime"`  // 创建时间
	UpdateTime  string `json:"updateTime"`  // 修改时间
	Remark      string `json:"remark"`      // 描述
	Token       string `json:"token"`       // token
}


4.2.5. Paging data response structure

Note: This structure is the core of paging.
Create a new file page.go in the app/vo directory. The complete code is as follows:

package vo

// 分页数据结构
type Page struct {
    
    
	Current int64       `json:"current"` // 当前页码
	Size    int64       `json:"size"`    // 每页条数
	Total   int64       `json:"total"`   // 总数据量
	Pages   int64       `json:"pages"`   // 总分页数
	Records interface{
    
    } `json:"records"` // 分页数据
}

/**
 * <h2>提供了一个构造方法</h2>
 * 需要传入当前页码和每页条数
 */
func NewPage(current, size int64) *Page {
    
    
	return &Page{
    
    Current: current, Size: size}
}

/**
 * <h2>设置总数据量</h2>
 */
func (p *Page) SetTotal(t int64) {
    
    
	p.Total = t

	// 总分页数 = 总数据量 / 每页条数
	s := p.GetTotal() / p.GetSize()

	// 如果总数据量 / 每页条数有余数,则总分页数 + 1
	if p.GetTotal()%p.GetSize() != 0 {
    
    
		s = s + 1
	}

	p.Pages = s
}

/**
 * <h2>设置分页数据</h2>
 */
func (page *Page) SetRecords(records interface{
    
    }) {
    
    
	page.Records = records
}

/**
 * <h2>获取当前页码</h2>
 * 默认当前页码 1
 */
func (p *Page) GetCurrent() int64 {
    
    
	if p.Current < 1 {
    
    
		p.Current = 1
	}
	return p.Current
}

/**
 * <h2>获取数据偏移量</h2>
 */
func (p *Page) GetOffset() int64 {
    
    
	if p.GetCurrent() > 0 {
    
    
		return (p.GetCurrent() - 1) * p.GetSize()
	}
	return 0
}

/**
 * <h2>获取每页条数</h2>
 * 默认每页 10 条数据
 */
func (p *Page) GetSize() int64 {
    
    
	if p.Size < 1 {
    
    
		p.Size = 10
	}
	return p.Size
}

/**
 * <h2>获取总数据量</h2>
 */
func (p *Page) GetTotal() int64 {
    
    
	return p.Total
}

/**
 * <h2>获取总分页数</h2>
 */
func (p *Page) GetPages() int64 {
    
    
	return p.Pages
}

/**
 * <h2>获取分页数据</h2>
 */
func (page *Page) GetRecords() interface{
    
    } {
    
    
	return page.Records
}

4.2.6. System user business processing

Note: This business processing class is the advanced core code of this project

  • User login verification is changed from fixed password to database dynamic verification
  • System user adds data
  • System user modifies data
  • System user deletes data
  • System user query data
  • System user query data list

Modify the file sys_user_service.go in the app/service directory. The complete code is as follows:

package service

import (
	"fmt"
	"go-iris/app/dto"
	"go-iris/app/model"
	"go-iris/app/vo"
	"go-iris/utils/constant"
	"go-iris/utils/db"
	"go-iris/utils/tool"
)

/**
 * <h1>系统用户业务处理</h1>
 * Created by woniu
 */
var SysUser = new(sysUserService)

type sysUserService struct{
    
    }

/**
 * <h2>用户账号 + 用户密码登录</h2>
 */
func (service *sysUserService) PasswordLogin(account string, password string) (*vo.SysUserVo, error) {
    
    
	// 用户账号为空
	if tool.IsEmpty(account) {
    
    
		return nil, constant.ResErrSysUserIsNil
	}

	// 用户密码为空
	if tool.IsEmpty(password) {
    
    
		return nil, constant.ResErrSysUserPasswordErr
	}

	// 根据用户账号查询用户信息
	sysUser := service.GetSysUserByAccount(account)

	if sysUser == nil {
    
    
		return nil, constant.ResErrSysUserIsNil
	}

	// 密码不匹配(暂时使用明文密码比对)
	if password != sysUser.Password {
    
    
		return nil, constant.ResErrSysUserPasswordErr
	}

	// 用户名 + 密码 校验正确,返回用户信息
	return service.GetSysUserVo(sysUser), nil
}

/**
 * <h2>根据用户账号查询用户信息</h2>
 */
func (service *sysUserService) GetSysUserByAccount(account string) *model.SysUser {
    
    
	var sysUser = &model.SysUser{
    
    }
	// 根据用户账号查询一条数据,主键 ID 排序
	result := db.GormDb.Table(sysUser.TableName()).Where("account = ?", account).First(sysUser)
	// 查询不到记录报错
	if result.Error != nil {
    
    
		fmt.Println("数据查询异常:", result.Error)
		return nil
	}
	return sysUser
}

/**
 * <h2>新增系统用户</h2>
 */
func (service *sysUserService) Save(sysUser model.SysUser) (*vo.SysUserVo, error) {
    
    

	// 根据用户账号查询用户信息
	sysUserOld := service.GetSysUserByAccount(sysUser.Account)
	if sysUserOld != nil {
    
    
		return nil, constant.ResErrSysUserRepeat
	}

	// 主键采用数据库自增
	sysUser.Id = 0
	// 创建时间
	sysUser.CreateTime = tool.DataTimeNow()
	// 修改时间
	sysUser.UpdateTime = sysUser.CreateTime

	// 创建记录
	result := db.GormDb.Table(sysUser.TableName()).Create(&sysUser)
	// 返回 error
	if result.Error != nil {
    
    
		fmt.Println("数据新增异常:", result.Error)
		return nil, result.Error
	}
	fmt.Println("数据新增成功,主键ID:", sysUser.Id)
	return service.GetSysUserVo(&sysUser), nil
}

/**
 * <h2>根据主键 ID 修改用户</h2>
 */
func (service *sysUserService) UpdateById(sysUser model.SysUser) (*model.SysUser, error) {
    
    
	if sysUser.Id < 1 {
    
    
		return nil, constant.ResErrIdIsNil
	}

	// 如果修改用户账号,则需要判断账号是否重复
	if tool.IsNotEmpty(sysUser.Account) {
    
    
		// 根据用户账号查询用户信息
		sysUserOld := service.GetSysUserByAccount(sysUser.Account)
		// 如果用户账号存在并且ID不相等
		if sysUserOld != nil && sysUserOld.Id != sysUser.Id {
    
    
			return nil, constant.ResErrSysUserRepeat
		}
	}

	// 修改时间
	sysUser.UpdateTime = tool.DataTimeNow()

	// Updates 方法支持 struct 和 map[string]interface{} 参数。
	// 当使用 struct 更新时,默认情况下,GORM 只会更新非零值的字段
	result := db.GormDb.Table(sysUser.TableName()).Model(&sysUser).Updates(&sysUser)
	// 返回 error
	if result.Error != nil {
    
    
		fmt.Println("数据修改异常:", result.Error)
		return nil, result.Error
	}
	return service.GetById(sysUser)
}

/**
 * <h2>根据主键 ID 查询用户</h2>
 */
func (service *sysUserService) GetById(sysUser model.SysUser) (*model.SysUser, error) {
    
    
	if sysUser.Id < 1 {
    
    
		return nil, constant.ResErrIdIsNil
	}
	// 当目标对象有一个主要值时,将使用主键构建条件
	result := db.GormDb.Table(sysUser.TableName()).First(&sysUser)
	// 返回 error
	if result.Error != nil {
    
    
		fmt.Println("数据修改异常:", result.Error)
		return nil, result.Error
	}
	return &sysUser, nil
}

/**
 * <h2>根据主键 ID 删除用户</h2>
 */
func (service *sysUserService) RemoveById(sysUser model.SysUser) error {
    
    
	if sysUser.Id < 1 {
    
    
		return constant.ResErrIdIsNil
	}
	// 删除一条记录时,删除对象需要指定主键,否则会触发 批量 Delete
	result := db.GormDb.Table(sysUser.TableName()).Delete(&sysUser)
	// 返回 error
	if result.Error != nil {
    
    
		fmt.Println("数据删除异常:", result.Error)
		return result.Error
	}
	return nil
}

/**
 * <h2>检索全部对象</h2>
 */
func (service *sysUserService) List(sysUser model.SysUser) ([]*vo.SysUserVo, error) {
    
    
	var sysUserList []model.SysUser
	// 检索全部对象
	result := db.GormDb.Table(sysUser.TableName()).Find(&sysUserList)
	// 返回 error
	if result.Error != nil {
    
    
		fmt.Println("数据列表查询异常:", result.Error)
		return nil, result.Error
	}
	return service.GetSysUserVoList(sysUserList), nil
}

/**
 * <h2>检索全部对象 - 分页查询</h2>
 */
func (service *sysUserService) Page(current int64, size int64, sysUserDto dto.SysUserDto) (*vo.Page, error) {
    
    
	page := vo.NewPage(current, size)

	var sysUserList []model.SysUser

	var sysUser model.SysUser
	query := db.GormDb.Table(sysUser.TableName())
	var count int64 // 统计总的记录数
	query.Count(&count)

	if count > 0 {
    
    
		result := query.Limit(int(page.GetSize())).Offset(int(page.GetOffset())).Find(&sysUserList)
		// 返回 error
		if result.Error != nil {
    
    
			fmt.Println("数据分页查询异常:", result.Error)
			return nil, result.Error
		}
	}

	page.SetTotal(count)
	page.SetRecords(sysUserList)

	fmt.Println(page.GetRecords())

	return page, nil
}

/**
 * <h2>将 SysUser 集合 转换为 SysUserVo 集合</h2>
 */
func (service *sysUserService) GetSysUserVoList(sysUserList []model.SysUser) []*vo.SysUserVo {
    
    
	var sysUserVoList []*vo.SysUserVo

	for i := range sysUserList {
    
    
		// 将 SysUser 转换为 SysUserVo
		vo := service.GetSysUserVo(&sysUserList[i])
		sysUserVoList = append(sysUserVoList, vo)
	}

	return sysUserVoList
}

/**
 * <h2>将 SysUser 转换为 SysUserVo</h2>
 */
func (service *sysUserService) GetSysUserVo(sysUser *model.SysUser) *vo.SysUserVo {
    
    
	var sysUserVo = vo.SysUserVo{
    
    
		Id:          sysUser.Id,
		Name:        sysUser.Name,
		Account:     sysUser.Account,
		MailAddress: sysUser.MailAddress,
		PhoneNumber: sysUser.PhoneNumber,
		Age:         sysUser.Age,
		IsUsing:     sysUser.IsUsing,
		IsDelete:    sysUser.IsDelete,
		CreateTime:  tool.DataTimeFormat(sysUser.CreateTime),
		UpdateTime:  tool.DataTimeFormat(sysUser.UpdateTime),
		Remark:      sysUser.Remark,
	}

	return &sysUserVo
}

4.2.7, System User Controller

Modify the file sys_user_controller.go in the app/controller directory. The complete code is as follows:

package controller

import (
	"fmt"
	"go-iris/app/dto"
	"go-iris/app/model"
	"go-iris/app/service"
	"go-iris/utils/common"
	"go-iris/utils/tool"

	"github.com/kataras/iris/v12"
)

/**
 * <h1>系统用户控制器</h1>
 * Created by woniu
 */
var SysUser = new(SysUserController)

type SysUserController struct{
    
    }

/**
 * <h2>用户名密码登录</h2>
 */
func (sc *SysUserController) PasswordLogin(ctx iris.Context) {
    
    

	// 登录参数
	var requestModel dto.LoginDto

	// 参数绑定
	if err := ctx.ReadForm(&requestModel); err != nil {
    
    
		ctx.JSON(common.ResponseError(-1, "传参异常"))
		return
	}

	// 用户登录,用户账号 + 用户密码登录
	sysUser, err := service.SysUser.PasswordLogin(requestModel.Account, requestModel.Password)

	if err != nil {
    
    
		// 响应失败
		ctx.JSON(common.ResponseErrorMessage(err.Error()))
		return
	}

	// 生成 JWT 的 Token
	sysUser.Token = tool.SignedJwtTokenBySysUser(sysUser)

	// 响应成功
	ctx.JSON(common.ResponseSuccess(sysUser))
}

/**
 * <h2>新增用户</h2>
 */
func (sc *SysUserController) Save(ctx iris.Context) {
    
    
	// 参数
	var requestModel model.SysUser

	// 参数绑定
	if err := ctx.ReadForm(&requestModel); err != nil {
    
    
		ctx.JSON(common.ResponseError(-1, "传参异常"))
		return
	}

	// 新增系统用户
	_, err := service.SysUser.Save(requestModel)

	if err != nil {
    
    
		// 响应失败
		ctx.JSON(common.ResponseErrorMessage(err.Error()))
		return
	}

	// 响应成功
	ctx.JSON(common.ResponseSuccess(nil))
}

/**
 * <h2>根据主键 ID 修改用户</h2>
 */
func (sc *SysUserController) UpdateById(ctx iris.Context) {
    
    
	// 参数
	var requestModel model.SysUser

	// 参数绑定
	if err := ctx.ReadForm(&requestModel); err != nil {
    
    
		ctx.JSON(common.ResponseError(-1, "传参异常"))
		return
	}

	// 根据主键 ID 修改用户
	_, err := service.SysUser.UpdateById(requestModel)

	if err != nil {
    
    
		// 响应失败
		ctx.JSON(common.ResponseErrorMessage(err.Error()))
		return
	}

	// 响应成功
	ctx.JSON(common.ResponseSuccess(nil))
}

/**
 * <h2>根据主键 ID 查询用户</h2>
 */
func (sc *SysUserController) GetById(ctx iris.Context) {
    
    
	// 参数
	var requestModel model.SysUser

	// 参数绑定
	if err := ctx.ReadForm(&requestModel); err != nil {
    
    
		ctx.JSON(common.ResponseError(-1, "传参异常"))
		return
	}

	// 根据主键 ID 查询用户
	sysUser, err := service.SysUser.GetById(requestModel)

	if err != nil {
    
    
		// 响应失败
		ctx.JSON(common.ResponseErrorMessage(err.Error()))
		return
	}

	// 响应成功
	ctx.JSON(common.ResponseSuccess(sysUser))
}

/**
 * <h2>根据主键 ID 删除用户</h2>
 */
func (sc *SysUserController) RemoveById(ctx iris.Context) {
    
    
	// 参数
	var requestModel model.SysUser

	// 参数绑定
	if err := ctx.ReadForm(&requestModel); err != nil {
    
    
		ctx.JSON(common.ResponseError(-1, "传参异常"))
		return
	}

	// 根据主键 ID 删除用户
	err := service.SysUser.RemoveById(requestModel)

	if err != nil {
    
    
		// 响应失败
		ctx.JSON(common.ResponseErrorMessage(err.Error()))
		return
	}

	// 响应成功
	ctx.JSON(common.ResponseSuccess(nil))
}

/**
 * <h2>条件查询系统用户列表</h2>
 */
func (sc *SysUserController) List(ctx iris.Context) {
    
    
	// 参数
	var requestModel model.SysUser

	// 参数绑定
	if err := ctx.ReadForm(&requestModel); err != nil {
    
    
		ctx.JSON(common.ResponseError(-1, "传参异常"))
		return
	}

	// 检索全部对象
	sysUser, err := service.SysUser.List(requestModel)

	if err != nil {
    
    
		// 响应失败
		ctx.JSON(common.ResponseErrorMessage(err.Error()))
		return
	}

	// 响应成功
	ctx.JSON(common.ResponseSuccess(sysUser))
}

/**
 * <h2>条件查询系统用户列表</h2>
 */
func (sc *SysUserController) Page(ctx iris.Context) {
    
    
	// 参数
	var requestModel dto.SysUserDto

	// 参数绑定
	if err := ctx.ReadForm(&requestModel); err != nil {
    
    
		ctx.JSON(common.ResponseError(-1, "传参异常"))
		return
	}

	fmt.Println("requestModel = ", requestModel)

	// 检索全部对象 - 分页查询
	page, err := service.SysUser.Page(requestModel.Current, requestModel.Size, requestModel)

	if err != nil {
    
    
		// 响应失败
		ctx.JSON(common.ResponseErrorMessage(err.Error()))
		return
	}

	// 响应成功
	ctx.JSON(common.ResponseSuccess(page))
}

4.2.8. Request routing

Create a new file router.go in the router directory. The complete code is as follows:

package router

import (

	// 自己业务 controller 路径
	"fmt"
	"go-iris/app/controller"
	"go-iris/utils/common"
	"go-iris/utils/constant"
	"go-iris/utils/tool"

	"github.com/kataras/iris/v12"
)

/**
 * <h2>注册路由</h2>
 */
func RegisterRouter(app *iris.Application) {
    
    

	// 跨域解决方案
	app.Use(Cors)
	// 登录验证中间件
	app.Use(CheckAuthorization)

	// 系统用户
	login := app.Party("/sysUser")
	{
    
    
		// 用户名 + 密码登录
		login.Post("/passwordLogin", controller.SysUser.PasswordLogin)
		// 新增用户
		login.Post("/save", controller.SysUser.Save)
		// 根据主键 ID 修改用户
		login.Post("/updateById", controller.SysUser.UpdateById)
		// 根据主键 ID 查询用户
		login.Post("/getById", controller.SysUser.GetById)
		// 根据主键 ID 删除用户
		login.Post("/removeById", controller.SysUser.RemoveById)
		// 条件查询系统用户列表
		login.Post("/list", controller.SysUser.List)
		// 条件查询系统用户列表 - 分页
		login.Post("/page", controller.SysUser.Page)
	}

	// 通用异常
	err := app.Party("/error")
	{
    
    
		err.Get("/responseError", controller.Error.ResponseError)
		err.Get("/responseErrorCode", controller.Error.ResponseErrorCode)
		err.Get("/responseErrorMessage", controller.Error.ResponseErrorMessage)
	}
}

/**
 * <h2>跨域解决方案</h2>
 */
func Cors(ctx iris.Context) {
    
    
	ctx.Header("Access-Control-Allow-Origin", "*")
	if ctx.Request().Method == "OPTIONS" {
    
    
		ctx.Header("Access-Control-Allow-Methods", "GET,POST,PUT,DELETE,PATCH,OPTIONS")
		ctx.Header("Access-Control-Allow-Headers", "Content-Type, Accept, Authorization")
		ctx.StatusCode(204)
		return
	}
	ctx.Next()
}

/**
 * <h2>登录验证中间件</h2>
 */
func CheckAuthorization(ctx iris.Context) {
    
    
	fmt.Println("登录验证中间件", ctx.Path())
	// 放行设置
	urlItem := []string{
    
    "/sysUser/passwordLogin", "/sysUser/login"}
	if !tool.IsStringInArray(ctx.Path(), urlItem) {
    
    
		// 从请求头中获取Token
		token := ctx.GetHeader("Authorization")

		// 请求头 Authorization 为空
		if tool.IsEmpty(token) {
    
    
			ctx.JSON(common.ResponseErrorMessage(constant.ResErrAuthorizationIsNilErr.Error()))
			return
		}

		claims, err := tool.ParseWithClaims(token)
		if err != nil {
    
    
			fmt.Println("token 解析异常信息:", err)
			ctx.JSON(common.ResponseErrorMessage(err.Error()))
			return
		}

		// 打印消息
		claims.ToString()
	}
	// 前置中间件
	ctx.Application().Logger().Infof("Runs before %s", ctx.Path())
	ctx.Next()
}

The relevant code has been written, and the final project structure and files are as shown below

Insert image description here

5. Start and test

5.1. Start the project

Enter the following command in the VS Code terminal and execute it

# 启动项目
go run main.go

The following information indicates successful startup

Iris Version: 12.2.0-beta6

Now listening on: http://localhost:8080
Application started. Press CTRL+C to shut down.

5.2. Test interface

5.2.1. User login

Note: You need to ensure that there is an initialization data in the system user table. If there is no data, it will prompt that the user does not exist.

Insert image description here

account = admin and password = 123456, response successful

Insert image description here

5.2.2. New data

Note: Add Authorization to the request header

Insert image description here

5.2.3. Modification of primary key ID

Note: Add Authorization to the request header

Insert image description here

5.2.4. Primary key ID query

Note: Add Authorization to the request header

Insert image description here

5.2.5. Query data list

Note: Add Authorization to the request header

Insert image description here

Examples of response result data are as follows:

{
    
    
    "code": 0,
    "message": "操作成功",
    "data": [
        {
    
    
            "id": 1,
            "name": "超级管理员",
            "account": "admin",
            "mailAddress": "",
            "phoneNumber": "",
            "age": 0,
            "isUsing": 0,
            "isDelete": 0,
            "createTime": "2022-12-12 17:54:39",
            "updateTime": "2022-12-12 17:54:39",
            "remark": "",
            "token": ""
        },
        {
    
    
            "id": 2,
            "name": "测试用户名称-修改后",
            "account": "test",
            "mailAddress": "[email protected]",
            "phoneNumber": "158XXXXXXXX",
            "age": 18,
            "isUsing": 0,
            "isDelete": 0,
            "createTime": "2022-12-12 17:59:59",
            "updateTime": "2022-12-12 18:15:35",
            "remark": "我是通过接口创建的-修改后",
            "token": ""
        }
    ]
}

5.2.6. Paging query

Note: Add Authorization to the request header

Insert image description here

Examples of response result data are as follows:

{
    
    
    "code": 0,
    "message": "操作成功",
    "data": {
    
    
        "current": 1,
        "size": 1,
        "total": 2,
        "pages": 2,
        "records": [
            {
    
    
                "Id": 1,
                "Name": "超级管理员",
                "Account": "admin",
                "Password": "123456",
                "PasswordSalt": "",
                "MailAddress": "",
                "PhoneNumber": "",
                "Age": 0,
                "IsUsing": 0,
                "IsDelete": 0,
                "CreateTime": "2022-12-12T17:54:39+08:00",
                "UpdateTime": "2022-12-12T17:54:39+08:00",
                "Remark": ""
            }
        ]
    }
}

5.2.7. Delete primary key ID

Note: Add Authorization to the request header

Insert image description here

Through the above test verification, the project has achieved the expected goals. Friends, please try it yourself.

6. One note per day

What are the ORM frameworks of GO? Which is the most elegant Go ORM framework?

6.1、BLUE

Golang's excellent ORM library is designed to be developer-friendly.

6.1.1、Github

Github

6.1.2. Documentation

Chinese documentation

6.1.3. Installation

# gorm 安装
go get -u gorm.io/gorm

# mysql 驱动
go get -u gorm.io/driver/mysql

6.2

xorm is a simple and powerful Go language ORM library. It can make database operations very simple.

6.2.1、Github

Github

6.2.2. Documentation

Chinese documentation

6.2.3. Installation

# xorm 安装
go get -u github.com/go-xorm/xorm

# mysql 驱动
go get -u github.com/go-sql-driver/mysql

6.3、Ent

ent is a simple yet powerful Go language entity framework. Ent is easy to build and maintain applications and big data models.

6.3.1、Github

Github

6.3.2. Documentation

Chinese documentation

6.2.3. Installation

# ent 安装
go get -u entgo.io/ent/cmd/ent@latest

6.4. Others

There are other ORM frameworks, such as gorose, upper/db, etc.

6.5. How to choose?

There is no best one, only the more suitable ones. You can choose according to your actual needs.

This tutorial ends here. If you have any questions, please feel free to discuss.

Practice is the only criterion for testing truth. One click to send three consecutive attentions to avoid getting lost.

Guess you like

Origin blog.csdn.net/u011374856/article/details/128286993