紫色飞猪的研发之旅–06go自定义状态码

在实际开发中,需要前后端需要协商状态码,状态码用于后端返前端时使用。在一个团队中,定义的状态码讲道理应该是一致的,项目开始的起始阶段状态码应该是定义了个七七八八的,随着功能的叠加而不断增加。此系列将围绕我的研发之旅进行。

状态码推荐的项目目录为 pkg/globalcode目录

后端返前端的json 格式为:

{
    "code": 状态码,
    "data": [
        功能逻辑后返前字段
    ],
    "message": 状态码对应的message
}

本片将以 成功参数校验两个常见的状态码为案例进行

.
├── [  96]  cmd
│   └── [1.3K]  root.go
├── [ 128]  config
│   ├── [2.2K]  cfg.go
│   └── [ 129]  config.yaml
├── [ 160]  controller
│   ├── [ 267]  base.go
│   ├── [ 452]  name.go
│   └── [  96]  validation   # 校验层
│       └── [ 151]  name.go
├── [ 242]  go.mod
├── [ 66K]  go.sum
├── [ 200]  main.go
├── [  96]  pkg
│   └── [ 128]  globalcode
│       ├── [  79]  code.go
│       └── [ 148]  message.go
├── [  96]  router
│   └── [ 343]  routes.go
└── [  96]  service
          └──[  80]  name.go

8 directories, 13 files

逻辑:项目初始化 –> 前端调接口–> 后端routes层 –> 后端controller层(判断前端传参是否有无(如果没有前端传参跳过此步骤) )–> 后端service层处理功能逻辑(有可能需要model层) –> 后端controller层处理返回结果(这里需要状态码处理)

main.go

/**
 * @Author: zisefeizhu
 * @Description: code
 * @File:  main.go
 * @Version: 1.0.0
 * @Date: 2021/9/4 10:13
 */

package main

import (
    "codedemo/cmd"
)

func main() {
    //入口
    cmd.Execute()
}

cmd/root.go

package cmd

import (
    "codedemo/config"
    "codedemo/routes"
    "fmt"
    "os"

    "github.com/gin-gonic/gin"
    "github.com/sirupsen/logrus"
    "github.com/spf13/cobra"
    "github.com/spf13/viper"
)

var (
    cfgFile string
    serverPort int
)

var rootCmd = &cobra.Command{
    Use:   "server",
    Short: "about the code",
    Long:  "summary of status codes from zisefeizhu",
    Run: func(cmd *cobra.Command, args []string) {
        fmt.Println("启动参数: ", args)
        httpServer()
    },
}

func init() {
    logrus.Infoln("init root.go...")
    cobra.OnInitialize(initConifg)
    rootCmd.PersistentFlags().StringVar(&cfgFile, "config", "", "config file (default is $CURRENT_DIR/config/config.yaml)")
    rootCmd.Flags().IntVarP(&serverPort, "port", "p", 9001, "port on which the server will listen")
}

// 初始化配置
func initConifg() {
    config.Loader(cfgFile)
    config.InitLog()
}

func httpServer() {
    logrus.Infoln("server start...")
    defer func() {
        logrus.Infoln("server exit..")
    }()
    //设置模式,设置模式要放在调用Default()函数之前
    gin.SetMode(viper.GetString("runmode"))
    logrus.Infoln("runmode: ", viper.GetString("runmode"))

    // 路由设置
    g := gin.Default()
    routes.Init(g)
    g.Run(fmt.Sprintf(":%d", serverPort))

}

// Execute rootCmd
func Execute() {
    if err := rootCmd.Execute(); err != nil {
        logrus.Fatalln(err)
        os.Exit(1)
    }
}

config/cfg.go

package config

import (
    "fmt"
    "github.com/gin-gonic/gin"
    "github.com/sirupsen/logrus"
    "github.com/spf13/viper"
    "io"
    "os"
    "path/filepath"
    "strings"
)

// Loader 加载配置文件
func Loader(cfgFile string) {
    if cfgFile == "" {
        path, _ := os.Getwd()
        cfgFile = path + "/config/config.yaml"
        fmt.Println(cfgFile)
    }

    viper.SetConfigFile(cfgFile)              //用来指定配置文件的名称
    viper.SetEnvPrefix("ENV")                 //SetEnvPrefix会设置一个环境变量的前缀名
    viper.AutomaticEnv()                      //会获取所有的环境变量,同时如果设置过了前缀则会自动补全前缀名
    replacer := strings.NewReplacer(".", "_") //NewReplacer() 使用提供的多组old、new字符串对创建并返回一个*Replacer
    viper.SetEnvKeyReplacer(replacer)

    if err := viper.ReadInConfig(); err != nil {
        fmt.Printf("config file error: %s\n", err)
        os.Exit(1)
    }
}

// InitLog 初始化日志
func InitLog() {
    // log.logrus_json
    if viper.GetBool("log.logrus_json") {
        logrus.SetFormatter(&logrus.JSONFormatter{})
    }

    // log.logrus_level
    switch viper.GetString("log.logrus_level") {
    case "trace":
        logrus.SetLevel(logrus.TraceLevel)
    case "debug":
        logrus.SetLevel(logrus.DebugLevel)
    case "info":
        logrus.SetLevel(logrus.InfoLevel)
    case "warn":
        logrus.SetLevel(logrus.WarnLevel)
    case "error":
        logrus.SetLevel(logrus.ErrorLevel)
    }

    // log.logrus_file
    if viper.GetBool("log.file") {
        logrusFile := viper.GetString("log.logrus_file")
        os.MkdirAll(filepath.Dir(logrusFile), os.ModePerm)

        file, err := os.OpenFile(logrusFile, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0666)
        if err == nil {
            if viper.GetBool("log.logrus_console") {
                logrus.SetOutput(io.MultiWriter(file, os.Stdout))
            } else {
                logrus.SetOutput(file)
            }
        }

        // log.gin_file & log.gin_console
        ginFile := viper.GetString("log.gin_file")
        os.MkdirAll(filepath.Dir(ginFile), os.ModePerm)

        file, err = os.OpenFile(ginFile, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0666)
        if err == nil {
            if viper.GetBool("log.gin_console") {
                gin.DefaultWriter = io.MultiWriter(file, os.Stdout)
            } else {
                gin.DefaultWriter = io.MultiWriter(file)
            }
        }
    }

    // default
    logrus.SetReportCaller(true)
}

config/config.yaml

prefix_path: /zisefeizhu/api/v1 #api路径
gormlog: true # gorm 的日志模式, true 是详细日志, false 不记录日志

routes.go

package routes

import (
    "codedemo/controller"
    "github.com/gin-contrib/cors"
    "github.com/gin-gonic/gin"
    "github.com/spf13/viper"
)

func Init(g *gin.Engine) {
    prefixPath := viper.GetString("prefix_path")
    g.Use(cors.Default())
    // 集群
    codedemo := g.Group(prefixPath + "/code")
    {
        codedemo.GET("/codedemo",controller.GetName)
    }
}

name.go

package controller

import (
    "codedemo/controller/validation"
    "codedemo/pkg/globalcode"
    "codedemo/service"
    "github.com/gin-gonic/gin"
    "strings"
)

func GetName(c *gin.Context)()  {
    var param  validation.GetNameRepos
    if err := c.ShouldBind(¶m); err != nil {
        ErrResponse(c, globalcode.PARAMETER_ERR, err.Error())
        return
    }
    param.Name = strings.TrimSpace(param.Name)
    if param.Name == "zise" {
        name := service.CodeDemo(param.Name)
        SuccessResponse(c ,name)
    } else {
        data := "name 必须是zise"
        ErrResponse(c, globalcode.PARAMETER_MUST_ZISE, data)
    }
}

validation/name.go

package validation

// GetNameRepos 前端param
type GetNameRepos struct {
    Name string json:"name" form:"name" binding:"required"        // 姓名不能为空
}

base.go

package controller

import (
    "codedemo/pkg/globalcode"
    "github.com/gin-gonic/gin"
    "net/http"
)

func ErrResponse(c *gin.Context, code int, data interface{}) {
    response(c, code, data)
}

func SuccessResponse(c *gin.Context, data interface{}) {
    response(c, globalcode.SUCCESS, data)
}

// SuccessPaginateResponse 成功返回带分页
func SuccessPaginateResponse(c *gin.Context, data interface{}, total int, curPage int, curPageSize int) {
    pageResponse := gin.H{
        "cur_page":      curPage,
        "cur_page_size": curPageSize,
        "total":         total,
        "total_page":    total / curPageSize,
        "data":          data,
    }
    response(c, globalcode.SUCCESS, pageResponse)
}

func response(c *gin.Context, code int, data interface{}) {
    c.JSON(http.StatusOK, gin.H{
        "code":    code,
        "message": globalcode.Msg[code],
        "data":    data,
    })
}

name.go

  • 状态码处理,本篇的重心

code.go

  • 定义状态码
package globalcode

var (
    SUCCESS                 = 200
    PARAMETER_ERR           = 10000
    PARAMETER_MUST_ZISE     = 10001
)

message.go

  • 状态码对应的信息
package globalcode

// Msg 全局状态码
var Msg = map[int]string{
    SUCCESS:                "请求成功",
    PARAMETER_ERR:          "请求参数错误",
    PARAMETER_MUST_ZISE:    "参数必须是zise",
}

*
1. 请求参数错误

紫色飞猪的研发之旅--06go自定义状态码
*
1. 参数传入正确但非zise
紫色飞猪的研发之旅--06go自定义状态码
*
1. 正确code
紫色飞猪的研发之旅--06go自定义状态码

Original: https://www.cnblogs.com/zisefeizhu/p/15226993.html
Author: 紫色飞猪
Title: 紫色飞猪的研发之旅–06go自定义状态码

原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/516618/

转载文章受原作者版权保护。转载请注明原作者出处!

(0)

大家都在看

亲爱的 Coder【最近整理,可免费获取】👉 最新必读书单  | 👏 面试题下载  | 🌎 免费的AI知识星球