BlueBell注册功能逻辑及其实现

注册路由

r.POST("/signup", controller.SignupHandler)

控制层实现

第一步,获取参数和参数校验

在models包中定义一个注册请求参数的结构体(ParamSignUp),用于将JSON参数绑定至结构体中。

json 的tag用于绑定参数,binding参数是gin内置validator校验的tag,required代表此字段是传入参数中必须要有的,eqfield=xxx,代表此字段与结构体中的xxx字段值需要相等,否则会校验失败,返回错误

package models

// 定义请求的参数结构体

// ParamSignUp 注册请求参数
type ParamSignUp struct {
	Username   string `json:"username" binding:"required"` // 代表校验此字段是必须在的
	Password   string `json:"password" binding:"required"`
	RePassword string `json:"re_password" binding:"required,eqfield=Password"`
}

得到一个注册请求参数结构体指针

p := new(models.ParamSignUp) // 得到一个注册请求参数结构体指针

ps:new返回类型的指针。

gin自带ShouldBindJSON方法将传入参数序列化到p结构体中

	if err := c.ShouldBindJSON(p); err != nil {
		// 请求参数有误,直接返回响应
		zap.L().Error("SignUp with invalid param", zap.Error(err))
		// 判断err类型是不是validator.ValidationErrors类型
		errs, ok := err.(validator.ValidationErrors)
		// 如果不是就返回正常错误
		if !ok {
			c.JSON(http.StatusOK, gin.H{
				"msg": "请求参数错误",
			})
			return
		}
		// 如果是就返回翻译过后的内容
		c.JSON(http.StatusOK, gin.H{
			"msg": errs.Translate(trans),
		})
		return
	}
Validator翻译器完整代码

由于validator校验返回的错误信息是英文,为方便用户读取,做一个翻译器,将错误类型为validator.ValidationErrors的内容翻译成中文。

package controller

/*
用于翻译validator.ValidationErrors错误的内容
*/
import (
	"bluebell/models"
	"fmt"
	"github.com/gin-gonic/gin/binding"
	"github.com/go-playground/locales/en"
	"github.com/go-playground/locales/zh"
	ut "github.com/go-playground/universal-translator"
	"github.com/go-playground/validator/v10"
	enTranslations "github.com/go-playground/validator/v10/translations/en"
	zhTranslations "github.com/go-playground/validator/v10/translations/zh"
	"reflect"
	"strings"
)

// 定义一个全局翻译器T
var trans ut.Translator

// InitTrans 初始化翻译器
func InitTrans(locale string) (err error) {
	// 修改gin框架中的Validator引擎属性,实现自定制
	if v, ok := binding.Validator.Engine().(*validator.Validate); ok {

		// 注册一个获取json tag的自定义方法
		v.RegisterTagNameFunc(func(fld reflect.StructField) string {
			name := strings.SplitN(fld.Tag.Get("json"), ",", 2)[0]
			if name == "-" {
				return ""
			}
			return name
		})

		// 为SignUpParam注册自定义校验方法
		v.RegisterStructValidation(SignUpParamStructLevelValidation, models.ParamSignUp{})

		zhT := zh.New() // 中文翻译器
		enT := en.New() // 英文翻译器

		// 第一个参数是备用(fallback)的语言环境
		// 后面的参数是应该支持的语言环境(支持多个)
		// uni := ut.New(zhT, zhT) 也是可以的
		uni := ut.New(enT, zhT, enT)

		// locale 通常取决于 http 请求头的 'Accept-Language'
		var ok bool
		// 也可以使用 uni.FindTranslator(...) 传入多个locale进行查找
		trans, ok = uni.GetTranslator(locale)
		if !ok {
			return fmt.Errorf("uni.GetTranslator(%s) failed", locale)
		}

		// 注册翻译器
		switch locale {
		case "en":
			err = enTranslations.RegisterDefaultTranslations(v, trans)
		case "zh":
			err = zhTranslations.RegisterDefaultTranslations(v, trans)
		default:
			err = enTranslations.RegisterDefaultTranslations(v, trans)
		}
		return
	}
	return
}

// removeTopStruct 去除提示信息中的结构体名称
func removeTopStruct(fields map[string]string) map[string]string {
	res := map[string]string{}
	for field, err := range fields {
		res[field[strings.Index(field, ".")+1:]] = err
	}
	return res
}

// SignUpParamStructLevelValidation 自定义SignUpParam结构体校验函数
func SignUpParamStructLevelValidation(sl validator.StructLevel) {
	su := sl.Current().Interface().(models.ParamSignUp)

	if su.Password != su.RePassword {
		// 输出错误提示信息,最后一个参数就是传递的param
		sl.ReportError(su.RePassword, "re_password", "RePassword", "eqfield", "password")
	}
}

第二步,业务处理,logic层进行业务处理

调用logic包中的Signup方法,实现用户插入数据库的操作,完成注册的功能。

// 2.业务处理 logic层进行业务处理
	if err := logic.Signup(p); err != nil {
		c.JSON(http.StatusOK, gin.H{
			"msg": err.Error(),
		})
		return
	}
Signup方法实现

第一步,校验用户是否存在

// 1.校验用户是否存在
	if err := mysql.CheckUserExist(p); err != nil {
		return err
	}

调用mysql中的CheckUserExist方法,判断该用户是否已存在,如果存在,说明该用户已经注册过了。

mysql包中CheckUserExist方法实现
// CheckUserExist 判断用户是否存在
func CheckUserExist(user *models.ParamSignUp) error {
	sqlStr := "select count(user_id) from user where username = ?"
	var count int
	if err := db.Get(&count, sqlStr, user.Username); err != nil {
		return err
	}
	if count > 0 {
		return errors.New("用户已存在")
	}
	return nil
}

搜索相关用户名,统计个数,判断是否大于0,大于0即是存在。

第二步,雪花算法生成UID,生成一个用户实例

调用snowflake包中的GenID获取UID

// 2.生成UID
	UID := snowflake.GenID()

在models表中创建一个用户User结构体,对应数据库中的user表,相互绑定。

package models

/*
构造user结构体与数据库中user表相对应,相互绑定
*/

type User struct {
	UserID   int64  `db:"user_id"`
	UserName string `db:"username"`
	PassWord string `db:"password"`
}

生成一个用户实例

// 生成一个用户实例
	user := &models.User{
		UserID:   UID,
		UserName: p.Username,
		PassWord: p.Password,
	}

第三步,保存到数据库

调用mysql包中的InsertUser方法,传入用户实例

// 3.保存到数据库
	if err := mysql.InsertUser(user); err != nil {
		return err
	}
mysql包中InsertUser方法实现
// InsertUser 向数据库中插入一条用户数据
func InsertUser(user *models.User) error {
	sqlStr := "insert into user(user_id,username,password) values(?,?,?)"
	user.PassWord = encryptPassword(user.PassWord)
	if _, err := db.Exec(sqlStr, user.UserID, user.UserName, user.PassWord); err != nil {
		return err
	}
	return nil
}

创建相关sql语句,执行写入数据库。

mysql包中encryptPassword方法实现

数据库中不能存储明文密码,所以要对密码进行加密。

// 对密码进行加密
func encryptPassword(oPassword string) string {
	h := md5.New()
	h.Write([]byte(secret))
	return hex.EncodeToString(h.Sum([]byte(oPassword)))
}
 logic/Signup完整代码
package logic

import (
	"bluebell/dao/mysql"
	"bluebell/models"
	"bluebell/pkg/snowflake"
)

func Signup(p *models.ParamSignUp) error {
	// 1.校验用户是否存在
	if err := mysql.CheckUserExist(p); err != nil {
		return err
	}
	// 2.生成UID
	UID := snowflake.GenID()
	// 生成一个用户实例
	user := &models.User{
		UserID:   UID,
		UserName: p.Username,
		PassWord: p.Password,
	}
	// 3.保存到数据库
	if err := mysql.InsertUser(user); err != nil {
		return err
	}
	return nil
}

第三步,返回响应

如果没有任何报错,则返回success

// 3.返回响应
	c.JSON(http.StatusOK, gin.H{
		"msg": "success",
	})

控制层完整代码

package controller

import (
	"bluebell/logic"
	"bluebell/models"
	"github.com/gin-gonic/gin"
	"github.com/go-playground/validator/v10"
	"go.uber.org/zap"
	"net/http"
)

func SignupHandler(c *gin.Context) {
	// 1.获取参数和参数校验
	p := new(models.ParamSignUp) // 得到一个注册请求参数结构体指针
	if err := c.ShouldBindJSON(p); err != nil {
		// 请求参数有误,直接返回响应
		zap.L().Error("SignUp with invalid param", zap.Error(err))
		// 判断err类型是不是validator.ValidationErrors类型
		errs, ok := err.(validator.ValidationErrors)
		// 如果不是就返回正常错误
		if !ok {
			c.JSON(http.StatusOK, gin.H{
				"msg": "请求参数错误",
			})
			return
		}
		// 如果是就返回翻译过后的内容
		c.JSON(http.StatusOK, gin.H{
			"msg": errs.Translate(trans),
		})
		return
	}
	// 2.业务处理 logic层进行业务处理
	if err := logic.Signup(p); err != nil {
		c.JSON(http.StatusOK, gin.H{
			"msg": err.Error(),
		})
		return
	}
	// 3.返回响应
	c.JSON(http.StatusOK, gin.H{
		"msg": "success",
	})
	return
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值