紫色飞猪的研发之旅--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] routes
│ └── [ 343] routes.go
├── [ 96] routes
│ └── [ 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层
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(¶m); err != nil {
Response(c, globalcode.PARAMETER_ERR, err.Error())
return
}
param.Name = strings.TrimSpace(param.Name)
if param.Name == "zise" {
name := service.CodeDemo(param.Name)
Response(c, globalcode.SUCCESS ,name)
} else {
// 模仿自定义状态码然后返回前端
}
}
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 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
)
message.go
- 状态码对应的信息
package globalcode
// Msg 全局状态码
var Msg = map[int]string{
SUCCESS: "请求成功",
PARAMETER_ERR: "请求参数错误",
验证
- 错误code

- 正确code

紫色飞猪的研发之旅--06go自定义状态码的更多相关文章
- 飞猪基于 Serverless 的云+端实践与思考
作者 | 王恒飞(承荫) 本文整理自飞猪旅行前端技术专家--王恒飞(承荫)在[阿里云 Serverless Developer Meetup 上海站]上的分享.点击查看直播回放:https://dev ...
- 对飞猪H5端API接口sign签名逆向实验
免责声明 本文章所提到的技术仅用于学习用途,禁止使用本文章的任何技术进行发起网络攻击.非法利用等网络犯罪行为,一切信息禁止用于任何非法用途.若读者利用文章所提到的技术实施违法犯罪行为,其责任一概由读者 ...
- 不二之选_iTOP-4418开发板研发之旅_缩短开发时间
迅为iTOP-4418开发板拿到手?用能力印证梦想,培养你的研发路程,能力·思维 一.板载WIFI蓝牙.4G.GPS.千兆以太网接口.串口.重力加速度计等. 二.自选模块支持500W摄像头自动对焦摄像 ...
- 我的Android进阶之旅------>Android自定义View来实现解析lrc歌词并同步滚动、上下拖动、缩放歌词的功能
前言 一LRC歌词文件简介 1什么是LRC歌词文件 2LRC歌词文件的格式 LRC歌词文件的标签类型 1标识标签 2时间标签 二解析LRC歌词 1读取出歌词文件 2解析得到的歌词内容 1表示每行歌词内 ...
- 告别IT,出售多年自己研发的股票分析系统源码
不知已过而立,发狠告别IT,回头看看以前自己的多个作品,耗时最多的就是这个股票分析系统了,留在自己的电脑里也体现不出多大价值了,故打算出售源码给需要的人,联系方式QQ:874724605 注明:股票源 ...
- K/3 Cloud开发之旅 -- 主页自定义篇(一)
如果说我们要进行主页自定义篇,首先涉及到的就是登陆的自定义,那么如何进行登录界面的自定义呢 其实登陆界面自定义主要就是图片的替换 ,那么我们就看下登陆界面的图片的组成 登录页面底图有两部分组成,一个是 ...
- [原创] zabbix学习之旅一:源码安装
zabbix是一个基于WEB界面的提供分布式系统监视以及网络监视功能的企业级的开源解决方案.zabbix能监视各种网络参数,保证服务器系统的安全运营:并提供灵活的通知机制以让系统管理员快速定位/解决存 ...
- 我的Android进阶之旅------>Android自定义View实现带数字的进度条(NumberProgressBar)
今天在Github上面看到一个来自于 daimajia所写的关于Android自定义View实现带数字的进度条(NumberProgressBar)的精彩案例,在这里分享给大家一起来学习学习!同时感谢 ...
- 我的Android进阶之旅------>Android自定义窗口标题实例
该实例的功能比较简单,但是通过该实例的扩展可以在自定义标题中做出菜单导航等实用的功能,为了实现自定义窗口标题,需要做以下几个步骤: 1.给自定义标题提供一个界面 2.将自定义标题应用给Activity ...
随机推荐
- macOS下将可执行文件索引位置增添到PATH中
一.shell中可执行文件的两种执行方式 (1)绝对路径 比如,打开电脑上安装的python3,使用绝对路径方式打开为: /usr/local/bin/python3 (2)使用PATH 将pytho ...
- Hadoop 3.1.1 - 概述 - 总览
Apache Hadoop 3.1.1 和之前发布的 3.0.X 版本线相比,Apache Hadoop 3.1.1 吸收了许多重要的改进. 总览 建议用户阅读完整的版本说明.本文提供了对主要变动的总 ...
- 测试开发【提测平台】分享3-正式开发产品需求&项目初始化
上两个分享主要是介绍和演示基本前后端所要使用的框架,接下来我们将正式进入到[提测平台的开发] 提要先给出依赖和内容点: 提测平台定义和产品原型需求说明 使用github创建代码仓库进行项目管理 Fla ...
- 如何区别php,jsp,asp,aspx随笔
PHP是一种跨平台的服务器端的嵌入式脚本语言.它大量地借用C.Java 和 Perl 语言的语法,并耦合PHP自己的特性,使WEB开发者能够快速地写出动态产生页面.它支持目前绝大多数数据库.还有一点, ...
- Java中解决多线程数据安全问题
同步代码块 基本语句 synchronized (任意对象) { 操作共享代码 } 代码示例 public class SellTicket implements Runnable { private ...
- 一定要弄懂GetMemory
堆栈 栈中分配局部变量空间,是系统自动分配空间.定义一个 char a:系统会自动在栈上为其开辟空间.由于栈上的空间是自动分配自动回收的,所以栈上的数据的生存周期只是在函数的运行过程中,运行后就释放掉 ...
- 如何发送一个http请求—apipost
API界面功能布局 API请求参数 Header 参数 你可以设置或者导入 Header 参数,cookie也在Header进行设置 Query 参数 Query 支持构造URL参数,同时支持 RES ...
- 构建工具之Maven的使用(一)
一.前言 对于开发一个Java项目,上线之前会通过编译,测试,打包,部署这几个构建过程,如果文件较少,我们可以使用java-->javac-->jar这些命令去完成上述的构建流程.但是当工 ...
- Pikachu-XSS模块与3个案例演示
一.概述 XSS是一种发生在前端浏览器端的漏洞,所以其危害的对象也是前端用户. 形成XSS漏洞的主要原因是程序对输入和输出没有做合适的处理,导致"精心构造"的字符输出在前端时被浏览 ...
- Linux部署PgSQL数据库
1.安装: yum install postgresql-server -y postgresql-setup initdb cd /var/lib/pgsql/data 2.进入 /var/lib/ ...