zoukankan      html  css  js  c++  java
  • 紫色飞猪的研发之旅--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
    ", 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 不记录日志
    

    router层

    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)
    	}
    }
    

    controller 层

    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(&param); 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,
    	})
    }
    

    service 层

    name.go

    package service
    
    func CodeDemo(name string)  string {
    	return name + "feizhu"
    }
    

    pkg/globalcode 层

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

    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. 请求参数错误
        参数校验错误
      1. 参数传入正确但非zise
        参数传入正确但非zise
      1. 正确code
        正确code
    过手如登山,一步一重天
  • 相关阅读:
    SQL 多列合并一列
    jQuery Ajax post多个值传参
    jquery获取select选中的值
    js 事件对象
    有关cookie
    事件冒泡和事件捕获
    js事件监听
    阻止浏览器的默认行为
    鼠标拖拽效果
    自定义右键菜单
  • 原文地址:https://www.cnblogs.com/zisefeizhu/p/15226993.html
Copyright © 2011-2022 走看看