基于go-zero二次开发的脚本

powershell 复制代码
param=$2
# 字符串风格格式为:DemoName
model_name=$(echo "${param}" | awk -F '_' '{for(i=1;i<=NF;i++) $i=toupper(substr($i,1,1)) tolower(substr($i,2));}1' | tr -d ' ')
# 字符串风格格式为:demoName
struct_name=$(echo "${model_name}" | awk '{print tolower(substr($0,1,1)) substr($0,2)}')
help()
{
   cat <<- EOF

帮助文档:
  Desc: 基于goctl指令生成代码
  程序选项如下:
    api:生成网关和swagger文档,无参数
    rpc:生成rpc代码和proto文件,参数1:rpc文件名(不带扩展名)
    proto 只生成base目录下的proto文件,注意路径,参数1:base
    mysql:生成model和crud代码,参数1:源文件名(不带扩展名)
    docker:打包docker镜像,参数1:main文件名(不带扩展名),参数2:版本号
  Usage:
    ./generate_code.sh api
    ./generate_code.sh rpc user
    ./generate_code.sh proto base
    ./generate_code.sh mysql user
    ./generate_code.sh mysql user v1.0.0
EOF
   exit 0
}

# 生成CRUD的方法
gen()
{
    # 获取要修改的文件名
    filename=./dao/mysql/model/$(echo "${param}" | tr -d '_')model.go
    # 获取行号,用来判断是否需要修改
    line_number=$(sed -n '$=' ${filename})
    if [ "$line_number" -lt 30 ]; then
      cat > "$filename" <<- EOF
package model

import (
    "context"
    "database/sql"
    "errors"
    "github.com/doug-martin/goqu/v9"
    _ "github.com/doug-martin/goqu/v9/dialect/mysql"
    "github.com/zeromicro/go-zero/core/stores/sqlx"
    "upgames-go-microservices/utils/utils"
)

var _ ${model_name}Model = (*custom${model_name}Model)(nil)

type (
    // ${model_name}Model is an interface to be customized, add more methods here,
    // and implement the added methods in custom${model_name}Model.
    ${model_name}Model interface {
        ${struct_name}Model
        withSession(session sqlx.Session) ${model_name}Model
        // GetTableName 获取表名
        GetTableName() string
        // GetCount 根据条件获取数量
        GetCount(ctx context.Context, ex goqu.Expression) (int64, error)
        // FindList 根据条件获取列表,排序:map[string]int{"字段":0/1(0-升序(ASC);1-降序(DESC))};分页:[]uint{页码,每页条数}
        FindList(ctx context.Context, ex goqu.Expression, optionalParams ...any) (*[]${model_name}, error)
        // FindOnly 根据条件获取单条数据,0-升序(ASC);1-降序(DESC)
        FindOnly(ctx context.Context, ex goqu.Expression, order ...map[string]int) (*${model_name}, error)
        // InsertOnly 插入单条数据
        InsertOnly(ctx context.Context, row *${model_name}, tx ...*sql.Tx) (sql.Result, error)
        // BatchInsert 批量插入
        BatchInsert(ctx context.Context, rows []*${model_name}, tx ...*sql.Tx) (sql.Result, error)
        // UpdateByEx 根据条件更新
        UpdateByEx(ctx context.Context, record goqu.Record, ex goqu.Expression, tx ...*sql.Tx) (sql.Result, error)
        // DeleteByEx 根据条件删除数据
        DeleteByEx(ctx context.Context, ex goqu.Expression, tx ...*sql.Tx) (sql.Result, error)
    }

    custom${model_name}Model struct {
        *default${model_name}Model
    }
)

// New${model_name}Model returns a model for the database table.
func New${model_name}Model(conn sqlx.SqlConn) ${model_name}Model {
    return &custom${model_name}Model{
      default${model_name}Model: new${model_name}Model(conn),
    }
}

func (m *custom${model_name}Model) withSession(session sqlx.Session) ${model_name}Model {
    return New${model_name}Model(sqlx.NewSqlConnFromSession(session))
}

// GetTableName 获取表名
func (m *custom${model_name}Model) GetTableName() string {
    return utils.SetTable(m.table)
}

// GetCount 根据条件获取数量
func (m *custom${model_name}Model) GetCount(ctx context.Context, ex goqu.Expression) (int64, error) {
    query, _, err := goqu.Dialect("mysql").Select(goqu.COUNT(1)).From(utils.SetTable(m.table)).Where(ex).ToSQL()
    if err != nil {
        return 0, err
    }
    var resp int64
    err = m.conn.QueryRowCtx(ctx, &resp, query)
    if err != nil && !errors.Is(err, sqlx.ErrNotFound) {
        return 0, err
    }
    return resp, nil
}

// FindList 根据条件获取列表,排序:map[string]int{"字段":0/1(0-升序(ASC);1-降序(DESC))};分页:[]uint{页码,每页条数}
func (m *custom${model_name}Model) FindList(ctx context.Context, ex goqu.Expression, optionalParams ...any) (*[]${model_name}, error) {
    sql := goqu.Dialect("mysql").Select(&${model_name}{}).From(utils.SetTable(m.table)).Where(ex)
    if len(optionalParams) > 0 {
        for _, param := range optionalParams {
            // 排序
            if v, ok := param.(map[string]int); ok {
                for key, value := range v {
                    if value > 0 {
                        sql = sql.Order(goqu.C(key).Desc())
                    } else {
                        sql = sql.Order(goqu.C(key).Asc())
                    }
                }
            }
            // 分页
            if v, ok := param.([]uint); ok {
                if len(v) == 2 {
                    sql = sql.Offset((v[0] - 1) * v[1]).Limit(v[1])
                }
            }
        }
    }
    query, _, err := sql.ToSQL()
    if err != nil {
        return nil, err
    }
    var resp []${model_name}
    err = m.conn.QueryRowsCtx(ctx, &resp, query)
    if err != nil && !errors.Is(err, sqlx.ErrNotFound) {
        return nil, err
    }
    return &resp, nil
}

// FindOnly 根据条件获取单条数据,0-升序(ASC);1-降序(DESC)
func (m *custom${model_name}Model) FindOnly(ctx context.Context, ex goqu.Expression, order ...map[string]int) (*${model_name}, error) {
    sql := goqu.Dialect("mysql").Select(&${model_name}{}).From(utils.SetTable(m.table)).Where(ex)
    if len(order) > 0 {
        for key, value := range order[0] {
          if value > 0 {
              sql.Order(goqu.C(key).Desc())
          } else {
              sql.Order(goqu.C(key).Asc())
          }
        }
    }
    query, _, err := sql.Limit(1).ToSQL()
    if err != nil {
        return nil, err
    }
    var resp ${model_name}
    err = m.conn.QueryRowCtx(ctx, &resp, query)
    switch err {
    case nil:
        return &resp, nil
    case sqlx.ErrNotFound:
        return nil, ErrNotFound
    default:
        return nil, err
    }
}

// InsertOnly 插入单条数据
func (m *custom${model_name}Model) InsertOnly(ctx context.Context, row *${model_name}, tx ...*sql.Tx) (sql.Result, error) {
    query, _, err := goqu.Dialect("mysql").Insert(utils.SetTable(m.table)).Rows(row).ToSQL()
    if err != nil {
        return nil, err
    }
    var result sql.Result
    if len(tx) > 0 {
        result, err = tx[0].ExecContext(ctx, query)
    } else {
        result, err = m.conn.ExecCtx(ctx, query)
    }
    return result, err
}

// BatchInsert 批量插入
func (m *custom${model_name}Model) BatchInsert(ctx context.Context, rows []*${model_name}, tx ...*sql.Tx) (sql.Result, error) {
    query, _, err := goqu.Dialect("mysql").Insert(utils.SetTable(m.table)).Rows(rows).ToSQL()
    if err != nil {
        return nil, err
    }
    var result sql.Result
    if len(tx) > 0 {
        result, err = tx[0].ExecContext(ctx, query)
    } else {
        result, err = m.conn.ExecCtx(ctx, query)
    }
    return result, err
}

// UpdateByEx 根据条件更新
func (m *custom${model_name}Model) UpdateByEx(ctx context.Context, record goqu.Record, ex goqu.Expression, tx ...*sql.Tx) (sql.Result, error) {
    query, _, err := goqu.Dialect("mysql").Update(utils.SetTable(m.table)).Set(record).Where(ex).ToSQL()
    if err != nil {
        return nil, err
    }
    var result sql.Result
    if len(tx) > 0 {
        result, err = tx[0].ExecContext(ctx, query)
    } else {
        result, err = m.conn.ExecCtx(ctx, query)
    }
    return result, err
}

// DeleteByEx 根据条件删除数据
func (m *custom${model_name}Model) DeleteByEx(ctx context.Context, ex goqu.Expression, tx ...*sql.Tx) (sql.Result, error) {
    query, _, err := goqu.Dialect("mysql").Delete(utils.SetTable(m.table)).Where(ex).ToSQL()
    if err != nil {
        return nil, err
    }
    var result sql.Result
    if len(tx) > 0 {
        result, err = tx[0].ExecContext(ctx, query)
    } else {
        result, err = m.conn.ExecCtx(ctx, query)
    }
    return result, err
}
EOF
    else
      echo "行数不准确,crud代码已生成"
    fi
}

dockerfile()
{
   cat > "Dockerfile" <<- EOF
FROM golang:1.22-alpine AS builder

LABEL stage=gobuilder

ENV GOPROXY https://goproxy.cn,direct
RUN sed -i 's/dl-cdn.alpinelinux.org/mirrors.aliyun.com/g' /etc/apk/repositories

RUN apk update --no-cache && apk add --no-cache tzdata

# 设置工作目录
WORKDIR /build

# 加载依赖
ADD go.mod .
ADD go.sum .
RUN go mod download

# 复制源代码
COPY . .

# 静态编译Go程序
RUN CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -ldflags="-s -w" -o app ./service/${struct_name}Service/${param}.go

# 第二阶段:运行时镜像,使用空镜像
FROM scratch

COPY --from=builder /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/ca-certificates.crt

# 设置工作目录
WORKDIR /app

# 复制编译好的二进制文件到运行时镜像
COPY --from=builder /build/app .

# 运行程序
ENTRYPOINT ["./app"]
# 设置CMD指令来指定参数,默认测试环境的etcd
CMD ["16.162.220.93:2379"]
EOF
}

if [ "$1" == "rpc" ]; then
    goctl rpc protoc ./proto/source/${param}.proto --go_out=./proto/generate --go-grpc_out=./proto/generate --zrpc_out=./service/${struct_name}Service --style go_zero
    # 替换omitempty,避免json序列化忽略字段
    sed -i '' -e '/omitempty/s/,omitempty//g' ./proto/generate/${struct_name}/*.pb.go

    # 修改客户端文件包名
    path="./service/${struct_name}Service/${param}_client/"
    sed -i '' -e "s/package ${param}_client/package client/g" ${path}${param}.go
    # 将客户端文件移到./proto/client下,删除原来目录
    mv -f ${path}${param}.go ./proto/client
    rm -r ${path}
    echo "Done."
elif [ "$1" == "api" ]; then
    # api网关生成
    goctl api go -api ./proto/source/api/gateway.api -dir ./service/gatewayService -style go_zero
    # swagger文档生成
    goctl api plugin -plugin goctl-swagger="swagger -filename gateway.json -host 127.0.0.1:8888" -api ./proto/source/api/gateway.api -dir ./doc/swagger/etc
    echo "Done."
elif [ "$1" == "proto" ]; then
    # proto文件生成,base目录下
    protoc --go_out=.. --go-grpc_out=..  ./proto/source/${param}.proto
    sed -i '' -e '/omitempty/s/,omitempty//g' ./proto/generate/${param}/*.pb.go
    echo "Done."
elif [ "$1" == "mysql" ]; then
    # mysql生成代码
    goctl model mysql ddl --src ./dao/mysql/source/${param}.sql --dir ./dao/mysql/model -i ''
    gen
    echo "Done."
elif [ "$1" == "docker" ]; then
    version=$3
    dockerfile
    docker build -t "${param}":"${version}" .
    rm -f Dockerfile
    echo "Done."
else
    echo "参数无效"
    help
fi

项目目录结构

    • com【业务公共代码】
    • dao【model层】
      • mysql
        • model【生成curd和model的目录】
        • source【表结构】
      • redis
    • doc【文档】
      • swagger【接口文档】
    • proto
      • client【rpc客户端连接】
      • generate【生成rpc目录】
      • source【proto源文件】
    • service【微服务】
      • userService【服务名称】
        • etc【配置文件】
        • internal
          • config【配置结构体】
          • logic【业务逻辑】
          • server【rpc service】
          • svc【初始化依赖】
        • user.go【main入口】
    • utils【公共代码模块】
      • config【配置初始化】
      • consts【常量】
      • gos【协程】
      • kafka【kafka相关】
      • logs【日志相关】
      • mysql【mysql】
      • redis【redis】
      • utils【公共代码】
    • generate_code.sh【脚本文件】
相关推荐
沛沛老爹3 小时前
什么是 DevOps 自动化?
大数据·ci/cd·自动化·自动化运维·devops
永恒,怎么可能3 小时前
关于博客系统的自动化功能测试报告
自动化·测试
AI慧聚堂5 小时前
自动化 + 人工智能:投标行业的未来是什么样的?
运维·人工智能·自动化
普密斯科技6 小时前
手机外观边框缺陷视觉检测智慧方案
人工智能·计算机视觉·智能手机·自动化·视觉检测·集成测试
007php00716 小时前
Go语言zero项目部署后启动失败问题分析与解决
java·服务器·网络·python·golang·php·ai编程
野蛮的大西瓜18 小时前
开源呼叫中心中,如何将ASR与IVR菜单结合,实现动态的IVR交互
人工智能·机器人·自动化·音视频·信息与通信
MClink1 天前
Go怎么做性能优化工具篇之pprof
开发语言·性能优化·golang
m0_748254661 天前
go官方日志库带色彩格式化
android·开发语言·golang
爱学测试的李木子1 天前
从0到1搭建 Android 自动化 python+appium 环境
android·软件测试·python·测试工具·自动化
Algorithm15761 天前
云原生相关的 Go 语言工程师技术路线(含博客网址导航)
开发语言·云原生·golang