紫色飞猪的研发之旅–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)

大家都在看

  • Go Micro Dashboard – 简介

    前言 使用Go Micro开发微服务系统很久了,但是一直没有很好的可视化工具用于开发和监控微服务系统。 所以基于go-micro和ng-alain开发了Go Micro Dashb…

    Go语言 2023年5月25日
    045
  • Go语言实现线程安全访问队列

    这个例子用Go语言的包”container/list”实现一个线程安全访问的队列。其中不少细节耐人寻味,做出它则是花费了不少精力,找不到样例啊! Go语言的…

    Go语言 2023年5月29日
    043
  • go语言 函数return值的几种情况

    分三种情况 (以下 “指定返回值”这句话, 仅指return后面直接跟着的返回值) 退出执行,不指定返回值 *(1) 函数没有返回值 package mai…

    Go语言 2023年5月29日
    056
  • go语言四 channel和gorotime

    goroutine go中使用Goroutine来实现并发concurrently。 Goroutine是Go语言特有的名词。区别于进程Process,线程Thread,协程Cor…

    Go语言 2023年5月29日
    042
  • GO语言程序查询数据库字段为空遇到的几个问题总结

    如果字段值可能为空,那么从表里面读取数据的时候程序使用的变量类型应该使用 sql.NullXXX 类型,比如下面的日期类型: 开始的时候,deleteAt 使用的也是 time.T…

    Go语言 2023年5月25日
    067
  • 对不起,我错了,这代码不好写

    hello,大家好呀,我是小楼。 前几天不是写了这篇文章《发现一个开源项目优化点,点进来就是你的了》嘛。 文章介绍了Sentinl的自适应缓存时间戳算法,从原理到实现都手把手解读了…

    Go语言 2023年5月25日
    057
  • 基于Go语言的xmind读写库,我主要用来把有道云笔记思维导图转为xmind

    xmind 基于go语言的xmind接口 本库主要加载xmind文件为json结构,保存文件时也用的json结构而不是xml结构 本库只做了最基本的主题添加功能,类似 &#…

    Go语言 2023年5月25日
    062
  • Go语言程序的命令行参数

    获取命令行参数是程序功能多样化的必要前提。 这个例子展示Go语言如何获得程序的命令行参数。 Go语言程序: // echoarg project main.go package m…

    Go语言 2023年5月29日
    044
  • golang 应用自升级

    概要 最近遇到一个需求,golang应用部署在远程机器,远程机器在内网,部署之后不方便再次登录此远程机器去升级。 因此,需要golang应用自动检查是否需要升级,如果需要升级,则下…

    Go语言 2023年5月25日
    065
  • 使用Go http重试请求

    原文连接:https://www.zhoubotong.site/post/78.html开发中对于http请求是经常遇到,一般可能网络延迟或接口返回超时,对于发起客户端的请求, …

    Go语言 2023年5月25日
    047
  • Go语言基础之并发

    并发是编程里面一个非常重要的概念,Go语言在语言层面天生支持并发,这也是Go语言流行的一个很重要的原因。 Go语言中的并发编程 并发与并行 并发:同一时间段内执行多个任务(你在用微…

    Go语言 2023年5月29日
    045
  • go学习笔记(一)

    零值的 slice等于 nil。 nil值的 slice没有底层数组 nil值的 slice的长度和容量都是 0。但是也有非 nil值的 slice的长度和容量为 0的,如 []i…

    Go语言 2023年5月25日
    029
  • Go 简单入门

    GO的环境配置? GOPATH GOROOT 都是干嘛用的? 配置环境跟java对比有点奇怪 https://blog.csdn.net/weixin_40563757/artic…

    Go语言 2023年5月25日
    068
  • Go基础知识梳理(二)

    Go基础知识梳理(二) 简单函数的定义 //有参数有返&#x5…

    Go语言 2023年5月25日
    044
  • Go 的 golang.org/x/ 系列包和标准库包有什么区别?

    在开发过程中可能会遇到这样的情况,有一些包是引入自不同地方的,比如: golang.org/x/net/html 和 net/html, golang.org/x/crypto 和…

    Go语言 2023年5月25日
    060
  • go微服务框架Kratos笔记(二)引入zap日志库

    zap日志库是一款高性能的开源日志库,提供了结构化日志记录和printf风格的日志记录 go get -u go.uber.org/zap 参考官方文档中描述,为了方便业务自适配不…

    Go语言 2023年5月25日
    044
亲爱的 Coder【最近整理,可免费获取】👉 最新必读书单  | 👏 面试题下载  | 🌎 免费的AI知识星球