从golang-gin-realworld-example-app项目学写httpapi (二)
https://github.com/gothinkster/golang-gin-realworld-example-app/blob/master/users/models.go
模型定义
users/models.go
package users
import (
"errors"
"github.com/jinzhu/gorm"
"github.com/wangzitian0/golang-gin-starter-kit/common"
"golang.org/x/crypto/bcrypt"
)
// UserModel对象,对应用户表
// gorm结构体标记,常用的column, type, size, primary_key, unique, index, unique_index, not null, -(忽略此字段)
type UserModel struct {
ID uint `gorm:"primary_key"`
Username string `gorm:"column:username"`
Email string `gorm:"column:email;unique_index"`
Bio string `gorm:"column:bio;size:1024"`
Image *string `gorm:"column:image"`
PasswordHash string `gorm:"column:password;not null"`
}
// FollowModel对象,对应关注表
// gorm.Model 是一个包含了基本字段的结构(struct), 其中包括字段: ID、CreatedAt、UpdatedAt、DeletedAt(逻辑删除字段)
type FollowModel struct {
gorm.Model
Following UserModel
FollowingID uint
FollowedBy UserModel
FollowedByID uint
}
// 函数 用于创建表结构
// 如果不特别指定表名,以对象名大写单词拆分,用下划线连接,未尾加s 指定表名,如UserModel -> user_models
func AutoMigrate() {
// 获取数据库连接
db := common.GetDB()
// 整合表结构,会创建新增的字段,不会改变原有字段内容,可以选择db.CreateTable代替
db.AutoMigrate(&UserModel{})
db.AutoMigrate(&FollowModel{})
//db.CreateTable(&UserModel{})
//db.CreateTable(&FollowModel{})
}
// UserModel对象的内置方法 用于设置密码, 使用 if err := user.setPassword("password0"); err !=nil { ... }
func (u *UserModel) setPassword(password string) error {
if len(password) == 0 {
return errors.New("password should not be empty!")
}
bytePassword := []byte(password)
// `bcrypt generator cost` 取值 [4, 32] 间
passwordHash, _ := bcrypt.GenerateFromPassword(bytePassword, bcrypt.DefaultCost)
u.PasswordHash = string(passwordHash)
return nil
}
// UserModel对象的内置方法 用于校验密码,使用 if err := user.checkPassword("password0"); err != nil { ... }
func (u *UserModel) checkPassword(password string) error {
bytePassword := []byte(password)
byteHashedPassword := []byte(u.PasswordHash)
return bcrypt.CompareHashAndPassword(byteHashedPassword, bytePassword)
}
// UserModel对象相关的函数 用于查找符合条件的第一条记录,使用 user, err := FindOneUser(&UserModel{Username: "username0"})
func FindOneUser(condition interface{}) (UserModel, error) {
db := common.GetDB()
var model UserModel
// condition使用Struct 或者 Map
err := db.Where(condition).First(&model).Error
return model, err
}
// UserModel对象相关的函数 用于插入记录,使用 if err := SaveOne(&userModel); err != nil { ... }
func SaveOne(data interface{}) error {
db := common.GetDB()
err := db.Save(data).Error
//err := db.Create(data).Error
return err
}
// UserModel对象的内置方法 用于更新记录,使用 if err := user.Update(UserModel{Username: "wangzitian0"}); err !=nil { ... }
func (model *UserModel) Update(data interface{}) error {
db := common.GetDB()
err := db.Model(model).Update(data).Error
return err
}
// UserModel对象的内置方法 建立用户间关注(user1 -> user2),使用 if err := user1.following(user2); err != nil { ... }
func (u UserModel) following(v UserModel) error {
db := common.GetDB()
var follow FollowModel
// 查询是否建立关注,如果没有则建立
err := db.FirstOrCreate(&follow, &FollowModel{
FollowingID: v.ID,
FollowedByID: u.ID,
}).Error
return err
}
// UserModel对象的内置方法 查询用户间是否关注(user1 -> user2),使用 if ok := user1.isFollowing(user2); if ok { ... }
func (u UserModel) isFollowing(v UserModel) bool {
db := common.GetDB()
var follow FollowModel
db.Where(FollowModel{
FollowingID: v.ID,
FollowedByID: u.ID,
}).First(&follow)
// 查询是否关注,如果有关注,返回True(用户ID非0值),没有关注(用户ID为0值)
return follow.ID != 0
}
// UserModel对象的内置方法 取消用户间关注,使用 if err := user1.unFollowing(user2); err != nil { ... }
func (u UserModel) unFollowing(v UserModel) error {
db := common.GetDB()
err := db.Where(FollowModel{
FollowingID: v.ID,
FollowedByID: u.ID,
}).Delete(FollowModel{}).Error
//因为FollowModel包含DeletedAt字段,此处为逻辑删除,实际执行的是 UPDATE follow_models SET deleted_at="2013-10-29 10:23" WHERE ...;
return err
}
// UserModel对象的内置方法 查询指定用户的所有关注,使用 followings := user1.GetFollowings()
func (u UserModel) GetFollowings() []UserModel {
db := common.GetDB()
// 事务处理开始
tx := db.Begin()
var follows []FollowModel
var followings []UserModel
// 获取关注表里所有相关的关联记录
tx.Where(FollowModel{
FollowedByID: u.ID,
}).Find(&follows)
// 循环每条关联记录
for _, follow := range follows {
var userModel UserModel
// 第2参数Following为外键名
tx.Model(&follow).Related(&userModel, "Following")
followings = append(followings, userModel)
}
// 事务处理结束
tx.Commit()
return followings
}
从golang-gin-realworld-example-app项目学写httpapi (二)的更多相关文章
- 从golang-gin-realworld-example-app项目学写httpapi (八)
https://github.com/gothinkster/golang-gin-realworld-example-app/blob/master/common/unit_test.go 单元测试 ...
- 从golang-gin-realworld-example-app项目学写httpapi (七)
https://github.com/gothinkster/golang-gin-realworld-example-app/blob/master/hello.go main调用 package ...
- 从golang-gin-realworld-example-app项目学写httpapi (六)
https://github.com/gothinkster/golang-gin-realworld-example-app/blob/master/users/validators.go 验证器 ...
- 从golang-gin-realworld-example-app项目学写httpapi (五)
https://github.com/gothinkster/golang-gin-realworld-example-app/blob/master/users/middlewares.go 中间件 ...
- 从golang-gin-realworld-example-app项目学写httpapi (四)
https://github.com/gothinkster/golang-gin-realworld-example-app/blob/master/users/routers.go 路由定义 pa ...
- 从golang-gin-realworld-example-app项目学写httpapi (三)
https://github.com/gothinkster/golang-gin-realworld-example-app/blob/master/users/serializers.go 序列化 ...
- 从golang-gin-realworld-example-app项目学写httpapi (一)
https://wangzitian0.github.io/2013/06/29/zero-to-one-1/ https://github.com/gothinkster/golang-gin-re ...
- 【饿了么】—— Vue2.0高仿饿了么核心模块&移动端Web App项目爬坑(三)
前言:接着上一篇项目总结,这一篇是学习过程记录的最后一篇,这里会梳理:评论组件.商家组件.优化.打包.相关资料链接.项目github地址:https://github.com/66Web/ljq_el ...
- Golang Gin 项目包依赖管理 godep 使用
Golang Gin 项目包依赖管理 godep 使用 标签(空格分隔): Go 在按照github.com/tools/godep文档go get完包以后,调整项目结构为$GOPATH/src/$P ...
随机推荐
- (转)深入剖析Redis主从复制
一.主从概述 Redis 支持 Master-Slave(主从)模式,Redis Server 可以设置为另一个 Redis Server 的主机(从机),从机定期从主机拿数据.特殊的,一个从机同样可 ...
- Installing Vim 8.0 on Ubuntu 16.04 and Linux Mint 18
sudo add-apt-repository ppa:jonathonf/vim sudo apt update sudo apt install vim uninstall sudo apt re ...
- VMware虚拟机配置
VMware虚拟机配置 背景 在做学习Linux时经常会在win环境下安装虚拟机,这其中涉及到一些细节操作,需要对虚拟机工作模式加以理解. 本文在学习hadoop分布式环境搭建时写作. 1.虚拟交换机 ...
- java的finally简单理解
1. 大家都知道, 普通的try, catch, finally格式: try{ //有可能会抛出异常的代码 }catch{ //抛出异常时处理的代码 }finally{ //无条件执行的代码,就不管 ...
- 学生信息管理系统(C语言版本)
这是我个人写的一个学生管理系统,这是我仅仅用来练手的代码,要知道链表可是你在面试过程中最大机率会考到的,我是陆续从单向链表入门,然后采用双向链表写的代码!如有BUG,请指正,让我们共同进步! 1 #i ...
- 如何创建一个基于Node的HTTP服务器
首先创建一个HTTP服务器. var http = require('http'); function serve(request,response) { console.log(request.me ...
- ContextMenustrip 控件
ContextMenustrip 控件是由 System.Windows.Forms.ContextMenustrip类提供,也是ToolstripMenu对象的容器,用来创建窗体的右键显示的菜单,主 ...
- 如鹏网学习笔记(九)JavaScript
JavaScript笔记 一.JavaScript简介 1,JavaScript是一种计算机编程语言,可以像等其他编程语言那样定义变量,执行循环等. 2,JavaScript代码主要执行在浏览器上,为 ...
- vscode下eslint代码规范
直接上规范吧: // 将设置放入此文件中以覆盖默认设置 { "editor.fontSize": 17, "editor.tabSize": 2, " ...
- 六:SpringCloud-Config
十:SpringCloudConfig分布式配置中心 1. 概述 1.1 分布式系统面临的 配置问题 微服务意味着要将单体应用中的业务拆分成一个个子服务,每个服务的粒度相对较小,因此系统中会出现大量的 ...