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

news2024/11/17 1:35:29

工程维度(摘自官网)

.
├── 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

version: '3'
services:
  mysql:
    container_name: mysql8
    image: mysql:${MYSQL_VERSION}
    restart: always
    ports:
      - ${MYSQL_PORT}:3306
    environment:
      TZ: Asia/Shanghai
      MYSQL_ROOT_PASSWORD: 123456
      MYSQL_DATABASE: zero_demo
    volumes:
      - ${MYSQL_DIR}/data:/var/lib/mysql
      - ${MYSQL_DIR}/conf:/etc/mysql/conf.d/
      - ${MYSQL_DIR}/logs:/logs
    command:
      --default-authentication-plugin=mysql_native_password
      --character-set-server=utf8mb4
      --collation-server=utf8mb4_general_ci
      --explicit_defaults_for_timestamp=true
      --lower_case_table_names=1

  Redis:
    container_name: redis6
    image: redis:${REDIS_VERSION}
    restart: always
    volumes:
      - ${REDIS_DIR}/data:/data
      - ${REDIS_DIR}/conf:/etc/redis/redis.conf
    ports:
      - ${REDIS_PORT}:6379
    command: redis-server /etc/redis/redis.conf

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

Name: demo   # 由api中的service名决定
Host: 0.0.0.0
Port: 8080

Mysql:
  DataSource: root:111111@tcp(127.0.0.1:3306)/demo?charset=utf8mb4&parseTime=true&loc=Local

#jwtAuth   go-zero 中内置了 JWT 的解密和验证功能,只需开启jwt使用即可
JwtAuth:
  AccessSecret: demo-aslfhsafsfsflaskfasf
  AccessExpire: 7200

#Redis:
#  Address: 127.0.0.1:6379
#  Pass: 123456

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

package config

import "github.com/zeromicro/go-zero/rest"

//yaml文件中的配置参数经过解析后会解析到此文件中,所以此文件中的参数要与yaml中的参数相对应
type Config struct {
	rest.RestConf
	Mysql struct {
		DataSource string
	}
	JwtAuth struct {
		AccessSecret string
		AccessExpire int64
	}
	//Redis struct {
	//	Address string
	//	Pass    string
	//}
}

1.4、svc下servicecontext.go文件配置

package svc

import (
	"demo/common/database"
	"demo/internal/config"
)

type ServiceContext struct {
	Config      config.Config
	UserRepo    repo.UserRepo
	//Redis  *redis.Redis
}

func NewServiceContext(c config.Config) *ServiceContext {
	dbConn := database.NewDB(c.Mysql.DataSource) //引入数据库得到数据库链接
	//newRedis := redis.New(c.Redis.Address, redisConfig(c))
	return &ServiceContext{
		Config:      c,
		UserRepo:    repo.NewUserRepo(dbConn), //调用数据库(数据库初始化,因为NewServiceContext()函数在main函数中已经调用初始化了)
		//Redis:  newRedis,
	}
}

//func redisConfig(c config.Config) redis.Option {
//	return func(r *redis.Redis) {
//		r.Type = redis.NodeType
//		r.Pass = c.Redis.Pass
//	}
//}

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

package database

import (
	"gorm.io/driver/mysql"
	"gorm.io/gorm"
	"gorm.io/gorm/schema"
)

type DBConn struct {
	ConnGorm *gorm.DB
}

// NewDB  连接并初始化数据库
func NewDB(dataSource string) *DBConn {
	db, err := gorm.Open(mysql.Open(dataSource), &gorm.Config{
		DisableForeignKeyConstraintWhenMigrating: true,
		SkipDefaultTransaction:                   false,
		NamingStrategy: schema.NamingStrategy{
			SingularTable: true, // use singular table name, table for `User` would be `user` with this option enabled
		},
	})
	if err != nil {
		panic("连接数据库失败")
	}

	d := &DBConn{
		ConnGorm: db,
	}
	InitDB(db)
	return d
}
func InitDB(db *gorm.DB) {
	if err := db.AutoMigrate(
		&User{},
	); err != nil {
		panic(err)
	}
}

1.6、数据库操作业务代码

package repo

import (
	"demo/common/database"
	"demo/internal/types"
)

type user struct {
	db *database.DBConn
}

type UserRepo interface {
}

func NewUserRepo(conn *database.DBConn) UserRepo {
	return &user{conn}
}

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

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

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

2.1、自定义返回错误 

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

2.1.1、官方的:

package main

import (
	"demo/internal/config"
	"demo/internal/handler"
	"demo/internal/svc"
	"flag"
	"fmt"
	"github.com/zeromicro/go-zero/core/conf"
	"github.com/zeromicro/go-zero/core/logc"
	"github.com/zeromicro/go-zero/rest"
)

var configFile = flag.String("f", "etc/demo.yaml", "the config file")

func main() {
	flag.Parse()

	//调试用,调试时使错误以plain(比较直观)的方式打印在终端
	var x logc.LogConf
	x.Encoding = "plain"
	logc.MustSetup(x)


	引入自定义返回错误,也可以引入自己构造的
	/*	httpx.SetErrorHandlerCtx(func(ctx context.Context, err error) (int, any) {
		switch e := err.(type) {
		case *errors.CodeMsg:
			return http.StatusOK, xhttp.BaseResponse[types.Nil]{
				Code: e.Code,
				Msg:  e.Msg,
			}
		default:
			return http.StatusInternalServerError, nil
		}
	})*/

	var c config.Config
	conf.MustLoad(*configFile, &c)

	server := rest.MustNewServer(c.RestConf)
	defer server.Stop()

	ctx := svc.NewServiceContext(c)
	handler.RegisterHandlers(server, ctx)

	fmt.Printf("Starting server at %s:%d...\n", c.Host, c.Port)
	server.Start()
}

2.1.2:自定义的

引入代码(写法一):

package errorz

import (
	"fmt"
)

//**********************************
//按go-zero官方例子进行,用 /*  */ 标注这段需要配置在main函数中。

/*
httpx.SetErrorHandlerCtx(func(ctx context.Context, err error) (int, any) {
	switch e := err.(type) {
	case *errorz.CodeMsg:
		return http.StatusOK, errorz.CodeMsg[errorz.Nil]{
			Code: e.Code,
			Msg:  e.Msg,
		}
	default:
		return http.StatusInternalServerError, nil
	}
})*/

// 用来在main函数中赋值
type CodeMsg[T any] struct {
	Code int    `json:"code"`
	Msg  string `json:"msg"`
}

//*****************************************************

type StdCodeMsg struct {
	Code int    `json:"code"`
	Msg  string `json:"msg"`
}

func (c *StdCodeMsg) Error() string {
	return fmt.Sprintf("code: %d, msg: %s", c.Code, c.Msg)
}

// New creates a new StdCodeMsg.
func NewStdCodeMsg(code int, msg string) error {
	return &StdCodeMsg{Code: code, Msg: msg}
}

func (c *StdCodeMsg) StdCodeMsg() any {
	return &StdCodeMsg{
		Code: c.Code,
		Msg:  c.Msg,
	}
}

// Nil represents the predeclared value nil.
type Nil struct{}

引入代码(写法二):

package errorz

//**********************************
//按go-zero官方例子进行,用 /*  */ 标注这段需要配置在main函数中用来返回错误。

/*httpx.SetErrorHandlerCtx(func(ctx context.Context, err error) (int, interface{}) {
	switch e := err.(type) {
	case *errorx.BizError:
	return http.StatusOK, e.Data()
	default:
	return http.StatusInternalServerError, nil
	}
})
*/

type CoMsg struct {
	Code int    `json:"code"`
	Msg  string `json:"msg"`
}

type ErrorResponse struct {
	Code int    `json:"code"`
	Msg  string `json:"msg"`
}

func NewCoMsg(code int, msg string) *CoMsg {
	return &CoMsg{
		Code: code,
		Msg:  msg,
	}
}

func (e *CoMsg) Error() string {
	return e.Msg
}

func (e *CoMsg) Data() any {
	return &ErrorResponse{
		e.Code,
		e.Msg,
	}
}

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

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

// 返回数据---方式一
type RespCoMsgSuccess struct {
	Code    int    `json:"code"`
	Message string `json:"message"`
	Data    any    `json:"data"`
}

func CoMsgSuccess(data interface{}) *RespCoMsgSuccess {
	return &RespCoMsgSuccess{200, "OK", data}
}

// 返回数据---方式二
type StdResponse[T any] struct {
	// Code represents the business code, not the http status code.
	Code int `json:"code" xml:"code"`
	// Msg represents the business message, if Code = BusinessCodeOK,
	// and Msg is empty, then the Msg will be set to BusinessMsgOk.
	Msg string `json:"msg" xml:"msg"`
	// Data represents the business data.
	Data T `json:"data,omitempty" xml:"data,omitempty"`
}

func StdSuccess(v any) StdResponse[any] {
	var resp StdResponse[any]
	resp.Code = 200
	resp.Msg = "OK"
	resp.Data = v
	return resp
}

方式二: 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

package handler

import (
    "net/http"

    "demo/internal/logic"
    "demo/internal/svc"
    "demo/internal/types"
    "github.com/zeromicro/go-zero/rest/httpx"
    xhttp "github.com/zeromicro/x/http"
)

func loginHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
    return func(w http.ResponseWriter, r *http.Request) {
        var req types.LoginRequest
        if err := httpx.Parse(r, &req); err != nil {
            // httpx.ErrorCtx(r.Context(), w, err)
             // code-data 响应格式
            xhttp.JsonBaseResponseCtx(r.Context(), w, err)
            return
        }

        l := logic.NewLoginLogic(r.Context(), svcCtx)
        resp, err := l.Login(&req)
        if err != nil {
            // code-data 响应格式
            xhttp.JsonBaseResponseCtx(r.Context(), w, err)
        } else {
            // code-data 响应格式
            xhttp.JsonBaseResponseCtx(r.Context(), w, resp)
        }
    }
}

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

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

//Handler中
func GreetHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
    return func(w http.ResponseWriter, r *http.Request) {
        var req types.Request
        if err := httpx.Parse(r, &req); err != nil {
            httpx.Error(w, err)
            return
        }

        l := logic.NewGreetLogic(r.Context(), svcCtx)
        resp, err := l.Greet(&req)
        response.Response(w, resp, err)
    }
}

package response

import (
    "net/http"

    "github.com/zeromicro/go-zero/rest/httpx"
)

type Body struct {
    Code int         `json:"code"`
    Msg  string      `json:"msg"`
    Data interface{} `json:"data,omitempty"`
}

func Response(w http.ResponseWriter, resp interface{}, err error) {
    var body Body
    if err != nil {
        body.Code = -1
        body.Msg = err.Error()
    } else {
        body.Msg = "OK"
        body.Data = resp
    }
    httpx.OkJson(w, body)
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/707495.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

MMYOLO框架标注、训练、测试全流程(补充篇)

前言 MMYOLO框架是一个基于PyTorch和MMDetection的YOLO系列算法开源工具箱。MMYOLO定位为YOLO系列热门开源库以及工业应用核心库,MMYOLO框架Github项目地址支持的任务:目标检测、旋转目标检测支持的算法:YOLOv5、YOLOX、RTMDet、RTMDet-Rota…

使用 okhttp3库发送 get、post(json参数传递,form表单提交) java代码实现

OkHttp是一个开源的HTTP客户端,由Square公司开发。OkHttp3是OkHttp库的最新版本。它提供了一个简单而强大的API来处理网络通信。以下是OkHttp3库的一些主要特点: 与Android平台完全兼容:OkHttp3可以与标准的Java库一起使用,也可以…

【前端】导航栏html(ul+li)/css/js(jq)

引入jq <script src"https://cdn.staticfile.org/jquery/1.10.2/jquery.min.js"></script> css代码 <style>ul {list-style: none;margin: 0;padding: 0;}li {cursor: pointer;}.color-white {color: #FFFFFF !important;background-color: rgb…

git 报错 fatal: Authentication failed的解决

git提交代码的时候&#xff0c;报错 remote: Support for password authentication was removed on August 13, 2021. remote: Please see https://docs.github.com/en/get-started/getting-started-with-git/about-remote-repositories#cloning-with-https-urls for informa…

三个好基友Cookie、Session和Token

原创声明&#xff0c;转载请注明文章链接来源、作者信息 >三个好基友Cookie、Session和Token hello&#xff0c;我是索奇~ 精心写了一篇Cookie、Session和Token的 vivid 文章&#xff0c;并分享给大家 我们可以把Cookie、Token和Session看作是三个好基友&#xff0c;它们…

Linux中创建sftp用户并限制目录权限

注意两点&#xff1a; 一是禁止该用户通过ssh登录&#xff0c;二是不需要创建家目录。家目录简单来说&#xff0c;就是在/home下的用户命令&#xff0c;默认每个用户在/home中都是有与用户名一样的文件夹。 1.创建组 groupadd sftp 2. 创建用户 useradd -g sftp -s /sbin/…

Vue3 JSX 插槽、v-model 的用法以及 React JSX 的区别

前言 写这篇文章的初衷是&#xff0c;Vue3 JSX 部分与 React JSX 容易混淆&#xff0c;比如如本文所说的 slot & v-model&#xff0c; 如果你是第一次接触 JSX&#xff0c;可先阅读前面写过的 React & JSX 日常用法与基本原则 来对 JSX 有一个整体的认知以及比较两者间…

如何了解(海外抖音TiKToK)与国内抖音的区别以及介绍

一、海外抖音TK平台的优势 自从抖音在中国大受欢迎后&#xff0c;海外也推出了海外版抖音TK平台。尽管两者都是视频分享平台&#xff0c;但它们在一些方面具有明显的区别和独特的优势。下面将详细介绍海外抖音TK平台的优势以及与国内抖音的区别性。 优势&#xff1a; 1. 多元…

9-2 小波滤波器、去噪、增强、变换(matlab程序)

1.简述 小波去噪滤波算法是一种基于小波变换的滤波方法&#xff0c;它通过对信号进行小波变换来分解信号的频率分量&#xff0c;并根据信号的特点选择合适的阈值处理方法来去除噪声。该算法的主要思想是将信号分解成多个频率分量&#xff0c;根据信号的特点选择合适的阈值处理…

【IMX6ULL驱动开发学习】13.Pinctrl子系统与GPIO子系统

上一篇博客中&#xff0c;已经实现了设备树的添加 【IMX6ULL驱动开发学习】12.Linux驱动之设备树 这篇博客介绍Pinctrl子系统与GPIO子系统的使用 Pinctrl子系统参考文档&#xff1a; 内核文档链接&#xff1a;https://www.kernel.org/doc/Documentation/ 内核源码doc&#xff…

AD23 原理图选中元件在PCB中高亮显示

概述 项目需要&#xff0c;再次使用AD&#xff0c;在此做个笔录。 1、原理图界面 2、在原理图界面选中电容后&#xff0c;对应的PCB界面该电容高亮显示 3、总结 希望能帮助到有需要的攻城狮。

Linux查看日志常用操作整理

项目出现异常&#xff0c;要定位问题&#xff0c;查看日志是最常用的方法&#xff0c;在Linux系统查看一些日志文件&#xff0c;我们一般会使用tail、cat等命令&#xff0c;下面总结归纳一下这些常用的命令。 1、查看日志的方法 tail&#xff1a;tail命令应该是使用最多的&am…

探讨绿色照明与智能照明节能控制系统应用

张心志 安科瑞电气股份有限公司 上海嘉定 201801 【摘 要】随着社会经济的不断发展&#xff0c;人们对生活质量、环境品质越发重视。积极推广绿色智能照明&#xff0c;提高城市照明质量&#xff0c;对于改善人们居住环境意义重大。文章简要介绍了绿色照 明的基本要求、室内智…

互联网编程之简单邮箱发送程序

需求是使用Java写一个简单的邮箱发送程序。 注意需要到QQ邮箱的设置-账户中开启服务。 package org.example;import org.apache.commons.mail.Email; import org.apache.commons.mail.EmailException; import org.apache.commons.mail.SimpleEmail;public class Main {public …

ospf-interface-fsm-and-neighbor-fsm

/* Interface State Machine */ struct {int (*func) (struct ospf_interface *);int next_state; } ISM [OSPF_ISM_STATE_MAX][OSPF_ISM_EVEN

网络安全技术入门(1):简介

文章目录 1.前言2.什么是网络安全技术&#xff1f;3.列举一些常见的网络安全技术3.1 防火墙3.2 加密技术3.3 身份认证和访问控制3.4 恶意软件防护3.5 网络监控和日志管理3.6 威胁情报和漏洞管理3.7 安全培训和意识教育 4.网络安全研究的关键技术5.网络安全防护技术有哪些&#…

计算机网络 - 应用层http协议 - http报文格式介绍(1)

前言 本篇认识和理解应用层中的http协议&#xff0c;了解抓包工具并进行使用&#xff0c;认识请求报文与响应报文&#xff0c;了解报文中基本键值对意思例如&#xff1a;Set-Cookie, 状态码等&#xff0c;如有错误&#xff0c;请在评论区指正&#xff0c;让我们一起交流&#…

segement and remove-SAM一键清除物体(代码安装实战项目)

结果展示 去除图片中前景物体的步骤: 1.框选 2.分割 3.分离 4.去除 项目介绍 一键帮你剔除视频内的物体,现在只需要一句话。使用Meta的SAM技术,你现在可以让视频内任意物体消失! 特点 按照提示进行分割:只需输入“黑色狗”,您就可以将您的黑色狗分割出来; 修复图…

JAVA 初识序列化与反序列化

JAVA 初识序列化与反序列化 目录 JAVA 初识序列化与反序列化初识序列化与反序列化1 概述2 特点/应用场景3 涉及到的流对象4 代码实现序列化与反序列化4.1 步骤1&#xff1a;创建学生类Student4.2 步骤2&#xff1a;创建序列化测试类 5 测试报错NotSerializableException:6 测试…

yarn与npm的区别(yarn的安装报错问题)

一、yarn 是什么&#xff0c;yarn 与 npm 的区别是什么&#xff1f; yarn 是一个软件包管理系统&#xff0c;Yarn 和 npm 都是包管理工具&#xff0c;用于管理用 JavaScript 编写的软件包&#xff0c;yarn的出现是为了弥补 npm的一些缺陷。yarn 与 npm 的区别 &#xff1a; 性能…