param=$2
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 ' ')
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 docker users 1.0.0
EOF
exit 0
}
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 . .
RUN CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -ldflags="-s -w" -toolexec="/build/doc/tool/skywalking-go-agent" -a -o app ./service/${struct_name}Service/${param}.go
FROM alpine
COPY --from=builder /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/ca-certificates.crt
WORKDIR /app
COPY --from=builder /build/app .
COPY --from=builder /build/i18n /app/i18n
COPY --from=builder /build/key/google_play_service_account_key.json /etc/ssl/certs/google_play_service_account_key.json
COPY --from=builder /build/key/SubscriptionKey_23HSTRGFC3.p8 /etc/ssl/certs/SubscriptionKey_23HSTRGFC3.p8
ENV SW_AGENT_NAME=go-${param}
ENV SW_AGENT_REPORTER_GRPC_BACKEND_SERVICE=skywalking-oap.skywalking.svc.cluster.local:11800
ENV SW_AGENT_REPORTER_GRPC_CDS_FETCH_INTERVAL=-1
ENTRYPOINT ["./app"]
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
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
mv -f ${path}${param}.go ./proto/client
rm -r ${path}
echo "Done."
elif [ "$1" == "api" ]; then
goctl api go -api ./proto/source/api/gateway.api -dir ./service/gatewayService -style go_zero
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
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
goctl model mysql ddl --src ./dao/mysql/source/${param}.sql --dir ./dao/mysql/model -i '' --strict
gen
echo "Done."
elif [ "$1" == "docker" ]; then
version=$3
tagName="harbor.pokerup.io/pokerup-stag/go-microservices/${param}:${version}"
dockerfile
docker build --no-cache -t "${param}" .
docker tag "${param}" "${tagName}"
docker push "${tagName}"
docker rmi "${param}"
docker rmi "${tagName}"
rm -f Dockerfile
echo "Done."
else
echo "参数无效"
help
fi
项目目录结构
-
- com【业务公共代码】
- dao【model层】
- mysql
- model【生成curd和model的目录】
- source【表结构】
- redis
- doc【文档】
- swagger【接口文档】
- tool 【执行工具】
- skywalking-go-agent 【链路追踪程序】
- 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【脚本文件】