• 首页 首页 icon
  • 工具库 工具库 icon
    • IP查询 IP查询 icon
  • 内容库 内容库 icon
    • 快讯库 快讯库 icon
    • 精品库 精品库 icon
    • 问答库 问答库 icon
  • 更多 更多 icon
    • 服务条款 服务条款 icon

go-zero的配置和gorm、自定义返回等的引入以和扩展

武飞扬头像
fbbqt
帮助1

工程维度(摘自官网)

.
├── consumer
├── go.mod
├── internal
│   └── model
├── job
├── pkg
├── restful
├── script
└── service

  • consumer: 队列消费服务
  • internal: 工程内部可访问的公共模块
  • job: cron job 服务
  • pkg: 工程外部可访问的公共模块
  • restful:HTTP 服务目录,下存放以服务为维度的微服务
  • script:脚本服务目录,下存放以脚本为维度的服务
  • service:gRPC 服务目录,下存放以服务为维度的微服务

服务维度(项目目录)(摘自官网)

example
├── etc
│   └── example.yaml
├── main.go
└── internal
    ├── config
    │   └── config.go
    ├── handler
    │   ├── xxxhandler.go
    │   └── xxxhandler.go
    ├── logic
    │   └── xxxlogic.go
    ├── svc
    │   └── servicecontext.go
    └── types
        └── types.go

  • example:单个服务目录,一般是某微服务名称
  • etc:静态配置文件目录
  • main.go:程序启动入口文件
  • internal:单个服务内部文件,其可见范围仅限当前服务
  • config:静态配置文件对应的结构体声明目录
  • handler:handler 目录,可选,一般 http 服务会有这一层做路由管理,handler 为固定后缀
  • logic:业务目录,所有业务编码文件都存放在这个目录下面,logic 为固定后缀
  • svc:依赖注入目录,所有 logic 层需要用到的依赖都要在这里进行显式注入
  • types:结构体存放目录

一、基本配置

1、数据库

1.1、docker-compose.yaml

  1.  
    version: '3'
  2.  
    services:
  3.  
    mysql:
  4.  
    container_name: mysql8
  5.  
    image: mysql:${MYSQL_VERSION}
  6.  
    restart: always
  7.  
    ports:
  8.  
    - ${MYSQL_PORT}:3306
  9.  
    environment:
  10.  
    TZ: Asia/Shanghai
  11.  
    MYSQL_ROOT_PASSWORD: 123456
  12.  
    MYSQL_DATABASE: zero_demo
  13.  
    volumes:
  14.  
    - ${MYSQL_DIR}/data:/var/lib/mysql
  15.  
    - ${MYSQL_DIR}/conf:/etc/mysql/conf.d/
  16.  
    - ${MYSQL_DIR}/logs:/logs
  17.  
    command:
  18.  
    --default-authentication-plugin=mysql_native_password
  19.  
    --character-set-server=utf8mb4
  20.  
    --collation-server=utf8mb4_general_ci
  21.  
    --explicit_defaults_for_timestamp=true
  22.  
    --lower_case_table_names=1
  23.  
     
  24.  
    Redis:
  25.  
    container_name: redis6
  26.  
    image: redis:${REDIS_VERSION}
  27.  
    restart: always
  28.  
    volumes:
  29.  
    - ${REDIS_DIR}/data:/data
  30.  
    - ${REDIS_DIR}/conf:/etc/redis/redis.conf
  31.  
    ports:
  32.  
    - ${REDIS_PORT}:6379
  33.  
    command: redis-server /etc/redis/redis.conf
学新通

1.2、etc目录下的yaml文件配置

  1.  
    Name: demo # 由api中的service名决定
  2.  
    Host: 0.0.0.0
  3.  
    Port: 8080
  4.  
     
  5.  
    Mysql:
  6.  
    DataSource: root:111111@tcp(127.0.0.1:3306)/demo?charset=utf8mb4&parseTime=true&loc=Local
  7.  
     
  8.  
    #jwtAuth go-zero 中内置了 JWT 的解密和验证功能,只需开启jwt使用即可
  9.  
    JwtAuth:
  10.  
    AccessSecret: demo-aslfhsafsfsflaskfasf
  11.  
    AccessExpire: 7200
  12.  
     
  13.  
    #Redis:
  14.  
    # Address: 127.0.0.1:6379
  15.  
    # Pass: 123456
学新通

1.3、internal中的config目录下的config.go文件配置

  1.  
    package config
  2.  
     
  3.  
    import "github.com/zeromicro/go-zero/rest"
  4.  
     
  5.  
    //yaml文件中的配置参数经过解析后会解析到此文件中,所以此文件中的参数要与yaml中的参数相对应
  6.  
    type Config struct {
  7.  
    rest.RestConf
  8.  
    Mysql struct {
  9.  
    DataSource string
  10.  
    }
  11.  
    JwtAuth struct {
  12.  
    AccessSecret string
  13.  
    AccessExpire int64
  14.  
    }
  15.  
    //Redis struct {
  16.  
    // Address string
  17.  
    // Pass string
  18.  
    //}
  19.  
    }
学新通

1.4、svc下servicecontext.go文件配置

  1.  
    package svc
  2.  
     
  3.  
    import (
  4.  
    "demo/common/database"
  5.  
    "demo/internal/config"
  6.  
    )
  7.  
     
  8.  
    type ServiceContext struct {
  9.  
    Config config.Config
  10.  
    UserRepo repo.UserRepo
  11.  
    //Redis *redis.Redis
  12.  
    }
  13.  
     
  14.  
    func NewServiceContext(c config.Config) *ServiceContext {
  15.  
    dbConn := database.NewDB(c.Mysql.DataSource) //引入数据库得到数据库链接
  16.  
    //newRedis := redis.New(c.Redis.Address, redisConfig(c))
  17.  
    return &ServiceContext{
  18.  
    Config: c,
  19.  
    UserRepo: repo.NewUserRepo(dbConn), //调用数据库(数据库初始化,因为NewServiceContext()函数在main函数中已经调用初始化了)
  20.  
    //Redis: newRedis,
  21.  
    }
  22.  
    }
  23.  
     
  24.  
    //func redisConfig(c config.Config) redis.Option {
  25.  
    // return func(r *redis.Redis) {
  26.  
    // r.Type = redis.NodeType
  27.  
    // r.Pass = c.Redis.Pass
  28.  
    // }
  29.  
    //}
学新通

1.5、引入gorm 链接数据库实现

  1.  
    package database
  2.  
     
  3.  
    import (
  4.  
    "gorm.io/driver/mysql"
  5.  
    "gorm.io/gorm"
  6.  
    "gorm.io/gorm/schema"
  7.  
    )
  8.  
     
  9.  
    type DBConn struct {
  10.  
    ConnGorm *gorm.DB
  11.  
    }
  12.  
     
  13.  
    // NewDB 连接并初始化数据库
  14.  
    func NewDB(dataSource string) *DBConn {
  15.  
    db, err := gorm.Open(mysql.Open(dataSource), &gorm.Config{
  16.  
    DisableForeignKeyConstraintWhenMigrating: true,
  17.  
    SkipDefaultTransaction: false,
  18.  
    NamingStrategy: schema.NamingStrategy{
  19.  
    SingularTable: true, // use singular table name, table for `User` would be `user` with this option enabled
  20.  
    },
  21.  
    })
  22.  
    if err != nil {
  23.  
    panic("连接数据库失败")
  24.  
    }
  25.  
     
  26.  
    d := &DBConn{
  27.  
    ConnGorm: db,
  28.  
    }
  29.  
    InitDB(db)
  30.  
    return d
  31.  
    }
  32.  
    func InitDB(db *gorm.DB) {
  33.  
    if err := db.AutoMigrate(
  34.  
    &User{},
  35.  
    ); err != nil {
  36.  
    panic(err)
  37.  
    }
  38.  
    }
学新通

1.6、数据库操作业务代码

  1.  
    package repo
  2.  
     
  3.  
    import (
  4.  
    "demo/common/database"
  5.  
    "demo/internal/types"
  6.  
    )
  7.  
     
  8.  
    type user struct {
  9.  
    db *database.DBConn
  10.  
    }
  11.  
     
  12.  
    type UserRepo interface {
  13.  
    }
  14.  
     
  15.  
    func NewUserRepo(conn *database.DBConn) UserRepo {
  16.  
    return &user{conn}
  17.  
    }
学新通

2、自定义返回错误--返回数据

格式:code、msg、data标准错误

 推荐使用 code-data 统一响应格式用法(官方文档HTTP扩展),此法最简单只需替换即可

2.1、自定义返回错误 

在main函数中下面两种引入方式选择其一就行,好处是只需引入一次即可

2.1.1、官方的:

  1.  
    package main
  2.  
     
  3.  
    import (
  4.  
    "demo/internal/config"
  5.  
    "demo/internal/handler"
  6.  
    "demo/internal/svc"
  7.  
    "flag"
  8.  
    "fmt"
  9.  
    "github.com/zeromicro/go-zero/core/conf"
  10.  
    "github.com/zeromicro/go-zero/core/logc"
  11.  
    "github.com/zeromicro/go-zero/rest"
  12.  
    )
  13.  
     
  14.  
    var configFile = flag.String("f", "etc/demo.yaml", "the config file")
  15.  
     
  16.  
    func main() {
  17.  
    flag.Parse()
  18.  
     
  19.  
    //调试用,调试时使错误以plain(比较直观)的方式打印在终端
  20.  
    var x logc.LogConf
  21.  
    x.Encoding = "plain"
  22.  
    logc.MustSetup(x)
  23.  
     
  24.  
     
  25.  
    引入自定义返回错误,也可以引入自己构造的
  26.  
    /* httpx.SetErrorHandlerCtx(func(ctx context.Context, err error) (int, any) {
  27.  
    switch e := err.(type) {
  28.  
    case *errors.CodeMsg:
  29.  
    return http.StatusOK, xhttp.BaseResponse[types.Nil]{
  30.  
    Code: e.Code,
  31.  
    Msg: e.Msg,
  32.  
    }
  33.  
    default:
  34.  
    return http.StatusInternalServerError, nil
  35.  
    }
  36.  
    })*/
  37.  
     
  38.  
    var c config.Config
  39.  
    conf.MustLoad(*configFile, &c)
  40.  
     
  41.  
    server := rest.MustNewServer(c.RestConf)
  42.  
    defer server.Stop()
  43.  
     
  44.  
    ctx := svc.NewServiceContext(c)
  45.  
    handler.RegisterHandlers(server, ctx)
  46.  
     
  47.  
    fmt.Printf("Starting server at %s:%d...\n", c.Host, c.Port)
  48.  
    server.Start()
  49.  
    }
学新通

2.1.2:自定义的

引入代码(写法一):

  1.  
    package errorz
  2.  
     
  3.  
    import (
  4.  
    "fmt"
  5.  
    )
  6.  
     
  7.  
    //**********************************
  8.  
    //按go-zero官方例子进行,用 /* */ 标注这段需要配置在main函数中。
  9.  
     
  10.  
    /*
  11.  
    httpx.SetErrorHandlerCtx(func(ctx context.Context, err error) (int, any) {
  12.  
    switch e := err.(type) {
  13.  
    case *errorz.CodeMsg:
  14.  
    return http.StatusOK, errorz.CodeMsg[errorz.Nil]{
  15.  
    Code: e.Code,
  16.  
    Msg: e.Msg,
  17.  
    }
  18.  
    default:
  19.  
    return http.StatusInternalServerError, nil
  20.  
    }
  21.  
    })*/
  22.  
     
  23.  
    // 用来在main函数中赋值
  24.  
    type CodeMsg[T any] struct {
  25.  
    Code int `json:"code"`
  26.  
    Msg string `json:"msg"`
  27.  
    }
  28.  
     
  29.  
    //*****************************************************
  30.  
     
  31.  
    type StdCodeMsg struct {
  32.  
    Code int `json:"code"`
  33.  
    Msg string `json:"msg"`
  34.  
    }
  35.  
     
  36.  
    func (c *StdCodeMsg) Error() string {
  37.  
    return fmt.Sprintf("code: %d, msg: %s", c.Code, c.Msg)
  38.  
    }
  39.  
     
  40.  
    // New creates a new StdCodeMsg.
  41.  
    func NewStdCodeMsg(code int, msg string) error {
  42.  
    return &StdCodeMsg{Code: code, Msg: msg}
  43.  
    }
  44.  
     
  45.  
    func (c *StdCodeMsg) StdCodeMsg() any {
  46.  
    return &StdCodeMsg{
  47.  
    Code: c.Code,
  48.  
    Msg: c.Msg,
  49.  
    }
  50.  
    }
  51.  
     
  52.  
    // Nil represents the predeclared value nil.
  53.  
    type Nil struct{}
学新通

引入代码(写法二):

  1.  
    package errorz
  2.  
     
  3.  
    //**********************************
  4.  
    //按go-zero官方例子进行,用 /* */ 标注这段需要配置在main函数中用来返回错误。
  5.  
     
  6.  
    /*httpx.SetErrorHandlerCtx(func(ctx context.Context, err error) (int, interface{}) {
  7.  
    switch e := err.(type) {
  8.  
    case *errorx.BizError:
  9.  
    return http.StatusOK, e.Data()
  10.  
    default:
  11.  
    return http.StatusInternalServerError, nil
  12.  
    }
  13.  
    })
  14.  
    */
  15.  
     
  16.  
    type CoMsg struct {
  17.  
    Code int `json:"code"`
  18.  
    Msg string `json:"msg"`
  19.  
    }
  20.  
     
  21.  
    type ErrorResponse struct {
  22.  
    Code int `json:"code"`
  23.  
    Msg string `json:"msg"`
  24.  
    }
  25.  
     
  26.  
    func NewCoMsg(code int, msg string) *CoMsg {
  27.  
    return &CoMsg{
  28.  
    Code: code,
  29.  
    Msg: msg,
  30.  
    }
  31.  
    }
  32.  
     
  33.  
    func (e *CoMsg) Error() string {
  34.  
    return e.Msg
  35.  
    }
  36.  
     
  37.  
    func (e *CoMsg) Data() any {
  38.  
    return &ErrorResponse{
  39.  
    e.Code,
  40.  
    e.Msg,
  41.  
    }
  42.  
    }
学新通

2.2、自定义返回数据 (最简单的是方式二)

方式一:需要在业务代码的返回函数中调用以下函数

  1.  
    // 返回数据---方式一
  2.  
    type RespCoMsgSuccess struct {
  3.  
    Code int `json:"code"`
  4.  
    Message string `json:"message"`
  5.  
    Data any `json:"data"`
  6.  
    }
  7.  
     
  8.  
    func CoMsgSuccess(data interface{}) *RespCoMsgSuccess {
  9.  
    return &RespCoMsgSuccess{200, "OK", data}
  10.  
    }
  11.  
     
  12.  
    // 返回数据---方式二
  13.  
    type StdResponse[T any] struct {
  14.  
    // Code represents the business code, not the http status code.
  15.  
    Code int `json:"code" xml:"code"`
  16.  
    // Msg represents the business message, if Code = BusinessCodeOK,
  17.  
    // and Msg is empty, then the Msg will be set to BusinessMsgOk.
  18.  
    Msg string `json:"msg" xml:"msg"`
  19.  
    // Data represents the business data.
  20.  
    Data T `json:"data,omitempty" xml:"data,omitempty"`
  21.  
    }
  22.  
     
  23.  
    func StdSuccess(v any) StdResponse[any] {
  24.  
    var resp StdResponse[any]
  25.  
    resp.Code = 200
  26.  
    resp.Msg = "OK"
  27.  
    resp.Data = v
  28.  
    return resp
  29.  
    }
学新通

方式二: code-data 统一响应格式用法(官方文档HTTP扩展

在 zeromicro 下有一个 x 仓库专门用于对 go-zero 的扩展,其中 HTTP 的扩展支持了:

  1. code-data 响应格式支持
  2. xml 响应支持
  3. code-msg error 类型支持

详情可参考 GitHub - zeromicro/x: This repository is part of the go-zero project but outside the main tree. It's developed under looser compatibility requirements than the go-zero project.This repository is part of the go-zero project but outside the main tree. It's developed under looser compatibility requirements than the go-zero project. - GitHub - zeromicro/x: This repository is part of the go-zero project but outside the main tree. It's developed under looser compatibility requirements than the go-zero project.学新通https://github.com/zeromicro/x

  1.  
    package handler
  2.  
     
  3.  
    import (
  4.  
    "net/http"
  5.  
     
  6.  
    "demo/internal/logic"
  7.  
    "demo/internal/svc"
  8.  
    "demo/internal/types"
  9.  
    "github.com/zeromicro/go-zero/rest/httpx"
  10.  
    xhttp "github.com/zeromicro/x/http"
  11.  
    )
  12.  
     
  13.  
    func loginHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
  14.  
    return func(w http.ResponseWriter, r *http.Request) {
  15.  
    var req types.LoginRequest
  16.  
    if err := httpx.Parse(r, &req); err != nil {
  17.  
    // httpx.ErrorCtx(r.Context(), w, err)
  18.  
    // code-data 响应格式
  19.  
    xhttp.JsonBaseResponseCtx(r.Context(), w, err)
  20.  
    return
  21.  
    }
  22.  
     
  23.  
    l := logic.NewLoginLogic(r.Context(), svcCtx)
  24.  
    resp, err := l.Login(&req)
  25.  
    if err != nil {
  26.  
    // code-data 响应格式
  27.  
    xhttp.JsonBaseResponseCtx(r.Context(), w, err)
  28.  
    } else {
  29.  
    // code-data 响应格式
  30.  
    xhttp.JsonBaseResponseCtx(r.Context(), w, resp)
  31.  
    }
  32.  
    }
  33.  
    }
学新通

 方式三:官方的定制模板法

可以通过官方的定制模板调用以下方法进行模板生成,也可在自己的返回包中实现,在handler中进行调用

  1.  
    //Handler中
  2.  
    func GreetHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
  3.  
    return func(w http.ResponseWriter, r *http.Request) {
  4.  
    var req types.Request
  5.  
    if err := httpx.Parse(r, &req); err != nil {
  6.  
    httpx.Error(w, err)
  7.  
    return
  8.  
    }
  9.  
     
  10.  
    l := logic.NewGreetLogic(r.Context(), svcCtx)
  11.  
    resp, err := l.Greet(&req)
  12.  
    response.Response(w, resp, err)
  13.  
    }
  14.  
    }
  1.  
    package response
  2.  
     
  3.  
    import (
  4.  
    "net/http"
  5.  
     
  6.  
    "github.com/zeromicro/go-zero/rest/httpx"
  7.  
    )
  8.  
     
  9.  
    type Body struct {
  10.  
    Code int `json:"code"`
  11.  
    Msg string `json:"msg"`
  12.  
    Data interface{} `json:"data,omitempty"`
  13.  
    }
  14.  
     
  15.  
    func Response(w http.ResponseWriter, resp interface{}, err error) {
  16.  
    var body Body
  17.  
    if err != nil {
  18.  
    body.Code = -1
  19.  
    body.Msg = err.Error()
  20.  
    } else {
  21.  
    body.Msg = "OK"
  22.  
    body.Data = resp
  23.  
    }
  24.  
    httpx.OkJson(w, body)
  25.  
    }
学新通

这篇好文章是转载于:学新通技术网

  • 版权申明: 本站部分内容来自互联网,仅供学习及演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,请提供相关证据及您的身份证明,我们将在收到邮件后48小时内删除。
  • 本站站名: 学新通技术网
  • 本文地址: /boutique/detail/tanhgbiaba
系列文章
更多 icon
同类精品
更多 icon
继续加载