感覺寫得有點偏題了,不過這是疫情期間,無聊,關在家裡邊學習邊寫的,錯誤比較多,我當作筆記一樣寫,大家就别浪費時間看了.
昨天,所有的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驗證,權限就沒有問題了.