感觉写得有点偏题了,不过这是疫情期间,无聊,关在家里边学习边写的,错误比较多,我当作笔记一样写,大家就别浪费时间看了.
昨天,所有的c.JSON的输出,错误代码都是手工写的,不好,所以在utils下新建目录e,增加code.go和msg.go这两个文件.
code.go的内容如下:
package e
const (
SUCCESS = 200
ERROR = 500
INVALID_PARAMS = 400
)
msg.go的内容如下:
package e
var MsgFlags = map[int]string{
SUCCESS: "ok",
ERROR: "fail",
INVALID_PARAMS: "请求参数错误",
}
// GetMsg get error information based on Code
func GetMsg(code int) string {
msg, ok := MsgFlags[code]
if ok {
return msg
}
return MsgFlags[ERROR]
}
以后的错误代码和信息,只要统一维护这里即可.
昨天所有的Controller都是空接口,今天把userController.go写上内容:
package controller
import (
"demo/models"
"demo/utils"
"demo/utils/e"
"log"
"net/http"
"strconv"
"strings"
"github.com/astaxie/beego/validation"
"github.com/gin-gonic/gin"
)
type UserInfo struct{}
// @Summary 新用户
// @Description 新用户
// @Accept json
// @Produce json
// @Param mobile query string true "mobile"
// @Param password query string true "password"
// @Param realname query string false "realname"
// @Param gender query string false "gender"
// @Success 200 {string} string "OK"
// @Failure 400 {string} string "We need mobile or password!!"
// @Router /api/v1/users/ [post]
func (u *UserInfo) Add(c *gin.Context) {
data := make(map[string]interface{})
mobile := c.Query("mobile")
password := c.Query("password")
realname := strings.TrimSpace(c.Query("realname"))
gender := c.DefaultQuery("gender", "1")
valid := validation.Validation{}
valid.Required(mobile, "mobile").Message("请输入手机号码")
valid.Mobile(mobile, "mobile").Message("不是有效的手机号码")
valid.Required(password, "password").Message("请输入密码")
valid.MinSize(password, 6, "password").Message("密码至少为6位")
valid.MaxSize(realname, 20, "realname").Message("姓名最多不能超过20个字")
code := e.INVALID_PARAMS
if !valid.HasErrors() {
user, err := new(models.Users).GetByMobile(mobile)
if err != nil {
log.Printf("手机查找用户错误: %v", err)
code = e.ERROR
} else if user.Id < 1 {
user.Mobile = mobile
user.RealName = realname
user.Gender, _ = strconv.Atoi(gender)
user.Status = 10
// 获取salt 和 加密密码
user.Salt = utils.RandomString(23)
// 两次加密
user.Password = utils.SHA256(utils.Md5(password) + user.Salt)
if err := user.Add(); err != nil {
log.Printf("添加用户失败: %v", err)
code = e.ERROR
} else {
data["user"] = user
code = e.SUCCESS
}
}
} else {
for _, err := range valid.Errors {
log.Printf("err.key: %s, err.message: %s", err.Key, err.Message)
}
}
c.JSON(http.StatusOK, gin.H{
"code": code,
"msg": e.GetMsg(code),
"data": data,
})
}
// @Summary 修改用户信息
// @Description 修改用户信息
// @Accept json
// @Produce json
// @Param Id query int64 true "Id"
// @Param realname query string false "realname"
// @Param gender query string false "gender"
// @Success 200 {string} string "OK"
// @Failure 400 {string} string "We need Id!!"
// @Failure 404 {string} string "Can not find Id"
// @Router /api/v1/users/:id [patch]
func (u *UserInfo) Edit(c *gin.Context) {
data := make(map[string]interface{})
strId := c.Param("id")
id, _ := strconv.Atoi(strId)
realname := strings.TrimSpace(c.Query("realname"))
gender, _ := strconv.Atoi(c.Query("gender"))
valid := validation.Validation{}
valid.Required(strId, "id").Message("id不能为空")
valid.Min(id, 1, "id").Message("id必须大于0")
valid.MaxSize(realname, 20, "realname").Message("姓名最多不能超过20个字")
valid.Range(gender, 0, 1, "gender").Message("性别只能是0或者1")
code := e.INVALID_PARAMS
if !valid.HasErrors() {
user, err := new(models.Users).GetById(int64(id))
if err != nil {
log.Printf("编辑用户错误1: %v", err)
code = e.ERROR
}
if user.Id > 0 {
user.RealName = realname
user.Gender = gender
if err := user.Update("realname", "gender"); err != nil {
log.Printf("编辑用户错误2: %v", err)
code = e.ERROR
} else {
data["user"] = user
code = e.SUCCESS
}
}
} else {
for _, err := range valid.Errors {
log.Printf("err.key: %s. err.message: %s", err.Key, err.Message)
}
}
c.JSON(http.StatusOK, gin.H{
"code": code,
"msg": e.GetMsg(code),
"data": data,
})
}
// @Summary 删除用户
// @Description 删除用户
// @Accept json
// @Produce json
// @Param Id query int64 true "Id"
// @Success 200 {string} string "OK"
// @Failure 400 {string} string "We need Id!!"
// @Failure 404 {string} string "Can not find Id"
//@Router /api/v1/users/:id [delete]
func (u *UserInfo) Delete(c *gin.Context) {
strId := c.Param("id")
id, _ := strconv.Atoi(strId)
valid := validation.Validation{}
valid.Required(strId, "id").Message("id不能为空")
valid.Min(id, 1, "id").Message("id必须大于0")
code := e.INVALID_PARAMS
if !valid.HasErrors() {
user, err := new(models.Users).GetById(int64(id))
if err != nil {
log.Printf("删除用户错误1: %v", err)
code = e.ERROR
}
if user.Id > 0 {
if err := user.Delete(); err != nil {
log.Printf("删除用户错误2: %v", err)
code = e.ERROR
} else {
code = e.SUCCESS
}
}
} else {
for _, err := range valid.Errors {
log.Printf("err.key: %s, err.message: %s", err.Key, err.Message)
}
}
c.JSON(http.StatusOK, gin.H{
"code": code,
"msg": e.GetMsg(code),
"data": make(map[string]interface{}),
})
}
// @Summary 查看用户信息
// @Description 查看用户信息
// @Accept json
// @Produce json
// @Param Id query int64 true "Id"
// @Success 200 {string} string "OK"
// @Failure 400 {string} string "We need Id!!"
// @Failure 404 {string} string "Can not find Id"
//@Router /api/v1/users/:id [get]
func (u *UserInfo) GetUser(c *gin.Context) {
data := make(map[string]interface{})
code := e.INVALID_PARAMS
strId := c.Param("id")
id, _ := strconv.Atoi(strId)
valid := validation.Validation{}
valid.Required(strId, "id").Message("id不能为空")
valid.Min(id, 1, "id").Message("id必须大于0")
if !valid.HasErrors() {
user, err := new(models.Users).GetById(int64(id))
if err != nil {
log.Printf("获取用户信息错误: %v", err)
code = e.ERROR
} else {
data["user"] = user
code = e.SUCCESS
}
} else {
for _, err := range valid.Errors {
log.Printf("err.key: %s, err.message: %s", err.Key, err.Message)
}
}
c.JSON(http.StatusOK, gin.H{
"code": code,
"msg": e.GetMsg(code),
"data": data,
})
}
// @Summary 获取用户列表
// @Description 获取用户列表
// @Accept json
// @Produce json
// @Success 200 {string} string "OK"
// @Router /api/v1/users/ [get]
func (u *UserInfo) GetUsers(c *gin.Context) {
data := make(map[string]interface{})
code := e.SUCCESS
userList, err := new(models.Users).FindAll()
if err != nil {
log.Printf("获取用户列表错误: %v", err)
code = e.ERROR
}
data["user_list"] = userList
c.JSON(http.StatusOK, gin.H{
"code": code,
"msg": e.GetMsg(code),
"data": data,
})
}
由于加密用户密码的需要,在utils/utils.go里加上:
// 返回SHA256加密
func SHA256(s string) string {
h := sha256.New()
h.Write([]byte(s))
rs := hex.EncodeToString(h.Sum(nil))
return rs
}
//生成随机字符串(大写字母)
func RandomString(len int) string {
var result bytes.Buffer
var temp string
for i := 0; i < len; {
if string(RandomInt(65, 90)) != temp {
temp = string(RandomInt(65, 90))
result.WriteString(temp)
i++
}
}
return result.String()
}
//生成随机数字
func RandomInt(min int, max int) int {
rand.Seed(time.Now().UTC().UnixNano())
return min + rand.Intn(max-min)
}
roleController.go:
package controller
import (
"demo/models"
"demo/utils"
"demo/utils/e"
"log"
"net/http"
"strconv"
"strings"
"github.com/astaxie/beego/validation"
"github.com/gin-gonic/gin"
)
type Roles struct{}
// @Summary 新角色
// @Description 新角色
// @Accept json
// @Produce json
// @Param name query string true "name"
// @Success 200 {string} string "OK"
// @Failure 400 {string} string "We need name!!"
// @Router /api/v1/roles/ [post]
func (r *Roles) Add(c *gin.Context) {
name := strings.TrimSpace(c.Query("name"))
valid := validation.Validation{}
valid.Required(name, "name").Message("角色名字不能为空")
valid.MinSize(name, 2, "name").Message("角色名字不能少于2个字符")
code := e.INVALID_PARAMS
if !valid.HasErrors() {
role := models.Roles{Name: name}
if err := role.Add(); err != nil {
log.Printf("新增角色错误: %v", err)
code = e.ERROR
} else {
code = e.SUCCESS
}
} else {
for _, err := range valid.Errors {
log.Printf("err.key: %s, err.message: %s", err.Key, err.Message)
}
}
c.JSON(http.StatusOK, gin.H{
"code": code,
"msg": e.GetMsg(code),
"data": make(map[string]interface{}),
})
}
// @Summary 修改角色信息
// @Description 修改角色信息
// @Accept json
// @Produce json
// @Param Id query int64 true "Id"
// @Param name query string true "name"
// @Success 200 {string} string "OK"
// @Failure 400 {string} string "We need Id!!"
// @Failure 404 {string} string "Can not find Id"
// @Router /api/v1/roles/:id [patch]
func (r *Roles) Edit(c *gin.Context) {
data := make(map[string]interface{})
code := e.INVALID_PARAMS
strId := c.Param("id")
id, _ := strconv.Atoi(strId)
name := strings.TrimSpace(c.Query("name"))
valid := validation.Validation{}
valid.Required(strId, "id").Message("id不能为空")
valid.Min(id, 1, "id").Message("id不能小于0")
valid.Required(name, "name").Message("角色名称不能为空")
if !valid.HasErrors() {
role, err := new(models.Roles).GetById(int64(id))
if err != nil {
log.Printf("编辑角色错误1: %v", err)
code = e.ERROR
}
if role.RoleId > 0 {
role.Name = name
if err := role.Update("name"); err != nil {
log.Printf("编辑角色错误2: %v", err)
code = e.ERROR
} else {
data["role"] = role
code = e.SUCCESS
}
}
} else {
for _, err := range valid.Errors {
log.Printf("err.key: %s, err.message: %s", err.Key, err.Message)
}
}
c.JSON(http.StatusOK, gin.H{
"code": code,
"msg": e.GetMsg(code),
"data": data,
})
}
// @Summary 删除角色
// @Description 删除角色
// @Accept json
// @Produce json
// @Param Id query int64 true "Id"
// @Success 200 {string} string "OK"
// @Failure 400 {string} string "We need Id!!"
// @Failure 404 {string} string "Can not find Id"
//@Router /api/v1/roles/:id [delete]
func (r *Roles) Delete(c *gin.Context) {
strId := c.Param("id")
id, _ := strconv.Atoi(strId)
valid := validation.Validation{}
valid.Required(strId, "id").Message("id不能为空")
valid.Min(id, 1, "id").Message("id不能小于0")
code := e.INVALID_PARAMS
if !valid.HasErrors() {
role, err := new(models.Roles).GetById(int64(id))
if err != nil {
log.Printf("删除角色错误1: %v", err)
code = e.ERROR
}
if role.RoleId > 0 {
if err := role.Delete(); err != nil {
log.Printf("删除角色错误2: %v", err)
code = e.ERROR
} else {
code = e.SUCCESS
}
}
} else {
for _, err := range valid.Errors {
log.Printf("err.key: %s, err.message: %s", err.Key, err.Message)
}
}
c.JSON(http.StatusOK, gin.H{
"code": code,
"msg": e.GetMsg(code),
"data": make(map[string]interface{}),
})
}
// @Summary 查看角色信息
// @Description 查看角色信息
// @Accept json
// @Produce json
// @Param Id query int64 true "Id"
// @Success 200 {string} string "OK"
// @Failure 400 {string} string "We need Id!!"
// @Failure 404 {string} string "Can not find Id"
//@Router /api/v1/roles/:id [get]
func (r *Roles) GetRole(c *gin.Context) {
h := utils.Gin{C: c}
data := make(map[string]interface{})
strId := c.Param("id")
id, _ := strconv.Atoi(strId)
valid := validation.Validation{}
valid.Required(strId, "id").Message("id不能为空")
valid.Min(id, 1, "id").Message("id不能小于0")
code := e.INVALID_PARAMS
if valid.HasErrors() {
utils.MarkErrors(valid.Errors)
h.Response(http.StatusOK, e.INVALID_PARAMS, data)
return
}
role, err := new(models.Roles).GetById(int64(id))
if err != nil {
log.Printf("查看角色信息错误1: %v", err)
code = e.ERROR
}
if role.RoleId > 0 {
data["role"] = role
code = e.SUCCESS
}
h.Response(http.StatusOK, code, data)
}
// @Summary 获取角色列表
// @Description 获取角色列表
// @Accept json
// @Produce json
// @Success 200 {string} string "OK"
// @Router /api/v1/roles/ [get]
func (r *Roles) GetRoles(c *gin.Context) {
h := utils.Gin{C: c}
data := make(map[string]interface{})
code := e.SUCCESS
roleList, err := new(models.Roles).FindAll()
if err != nil {
log.Printf("获取角色列表错误: %v", err)
code = e.ERROR
}
data["list"] = roleList
h.Response(http.StatusOK, code, data)
}
写到后面,发现c.JSON每次都重复很多,新引入的校验,也是重复的写,参考"煎鱼"的做法,新增utlis/http.go:
package utils
import (
"demo/utils/e"
"log"
"github.com/astaxie/beego/validation"
"github.com/gin-gonic/gin"
)
// 简化response代码
type Gin struct {
C *gin.Context
}
func (g *Gin) Response(httpCode, errCode int, data interface{}) {
g.C.JSON(httpCode, gin.H{
"code": errCode,
"msg": e.GetMsg(errCode),
"data": data,
})
return
}
// 输入验证的错误处理
func MarkErrors(errors []*validation.Error) {
for _, err := range errors {
log.Println(err.Key, err.Message)
}
return
}
使用postman验证的时候,老是提示权限问题,到casbin的在线权限编辑验证去测试了一把,最后router.go改成如下:
package routers
import (
"demo/controller"
"demo/middleware"
"github.com/gin-gonic/gin"
)
func InitRouter() *gin.Engine {
//获取router路由对象
r := gin.New()
apiv1 := r.Group("/api/v1")
//使用自定义拦截器中间件
apiv1.Use(middleware.Authorize())
{
//hello测试
apiv1.GET("/hello", controller.Hello)
userRoutes := apiv1.Group("/users")
{
userController := new(controller.UserInfo)
// 用户列表
userRoutes.GET("/", userController.GetUsers)
// 单个用户信息
userRoutes.GET("/:id", userController.GetUser)
// 新增用户
userRoutes.POST("/", userController.Add)
// 修改用户信息
userRoutes.PATCH("/:id", userController.Edit)
// 删除用户
userRoutes.DELETE("/:id", userController.Delete)
}
roleRoutes := apiv1.Group("/roles")
{
roleController := new(controller.Roles)
// 角色列表
roleRoutes.GET("/", roleController.GetRoles)
// 单个角色信息
roleRoutes.GET("/:id", roleController.GetRole)
// 新增角色
roleRoutes.POST("/", roleController.Add)
// 修改角色信息
roleRoutes.PATCH("/:id", roleController.Edit)
// 删除角色
roleRoutes.DELETE("/:id", roleController.Delete)
}
}
return r
}
而数据库的casbin_rule表中,也做相应的修改:
再用postman验证,权限就没有问题了.