V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
• 请不要在回答技术问题时复制粘贴 AI 生成的内容
wangbenjun5
V2EX  ›  程序员

介绍自己搭的一个 Go Web 脚手架项目

  •  
  •   wangbenjun5 · 2021-06-24 00:42:25 +08:00 · 2712 次点击
    这是一个创建于 1283 天前的主题,其中的信息可能已经有所发展或是发生改变。

    Gen Web - 基于 Gin 框架封装的脚手架结构,便于快速开发 API

    https://github.com/wangbjun/gen

    介绍

    主要使用以下开源组件:

    项目目录结构清晰明了,简单易用,快速上手,包含了一个用户注册、登录、文章增删改查等功能的 Restful API 应用,仅供参考!

    主要包含以下 API:

    METHOD URI DESCRIPTION
    GET / 默认首页
    POST /api/v1/user/register 用户注册
    POST /api/v1/user/login 用户登录
    POST /api/v1/user/logout 用户登出
    GET /api/v1/articles 文章列表
    POST /api/v1/articles 发布文章
    GET /api/v1/articles/:id 文章详情
    PUT /api/v1/articles/:id 修改文章
    DELETE /api/v1/articles/:id 删除文章
    POST /api/v1/articles/:id/comments 添加文章评论

    架构

    项目采用了依赖注入的方式贯穿全局,我们可以把 DB 、缓存、HTTP API 等功能看作是项目的一个服务,通过 facebook 开源的 inject 库,我们在启动项目把这些Service注入进去,解决各自之间的依赖关系。

    type ArticleService struct {
        SQLStore *SQLService         `inject:""`
        Cache    *cache.CacheService `inject:""`
    }
    
    func init() {
        registry.RegisterService(&ArticleService{})
    }
    
    func (r ArticleService) Init() error {
        return nil
    }
    

    既灵活,也不影响性能,因为虽然依赖注入使用了反射,但是我们只在程序启动之前做这件事,而且只需要进行一次。

    启动流程

    main文件是程序的入口,主要功能是解析命令行参数,只有一个参数,那就是配置文件,默认配置文件是当前目录下的app.ini

    紧接着,创建一个Server实例:

    // Server is responsible for managing the lifecycle of services.
    type Server struct {
        context          context.Context
        shutdownFn       context.CancelFunc
        childRoutines    *errgroup.Group
        log              *zap.Logger
        cfg              *config.Cfg    // 项目配置
        shutdownOnce     sync.Once
        shutdownFinished chan struct{}
        isInitialized    bool
        mtx              sync.Mutex
        serviceRegistry  serviceRegistry // 注册的服务
    }
    

    这个 Server 实例是管理所有服务的中心,其主要工作就是加载配置文件,然后根据配置文件初始化日志配置,日志库采用 zap log,主要文件在zap/zap_logger.go里面

    然后还有一个最重要是就是初始化所有注册过服务,执行其Init方法做一些初始化工作,最后执行后台服务。

    如果一个服务实现了Run方法,就是一个后台服务,会在项目启动时候运行,结束时候优雅关闭,其中最好的例子就是HTTPServer,我们可以把 API 服务认为是一个后台服务,在整个项目启动的时候就会运行。

    type HTTPServer struct {
        log     *zap.Logger
        gin     *gin.Engine
        context context.Context
    
        Cfg            *config.Cfg             `inject:""`
        ArticleService *article.ArticleService `inject:""`
        UserService    *user.UserService       `inject:""`
    }
    

    HTTPServer 的代码在api/http_server.go文件里面,其主要作用就是初始化一些服务配置,然后启动 HTTP 服务,使用了 Gin 框架。

    代码介绍

    services文件夹下包含了一些服务的代码文件。

    项目整体是一个 3 层架构,即控制器层、Service 层、模型层。

    个人理解,控制器层主要做一些接口参数校验等工作,模型层主要是数据操作,Service 层才是主要的业务逻辑。

    数据库相关配置在models/db.go里面,也是一个服务,主要作用是根据配置,初始化数据库连接,支持多数据库配置。

    type SQLService struct {
        Cfg *config.Cfg `inject:""`
    
        conns map[string]*gorm.DB
        log   *zap.Logger
    }
    
    func DB(dbName ...string) *gorm.DB {
        if len(dbName) > 0 {
            if conn, ok := sqlStore.conns[dbName[0]]; ok {
                return conn
            }
        }
        return db
    }
    

    项目使用了 Gorm ( 2.0 版本),具体详细用法可以参考官方文档。

    路由文件位于api/api.go,可以多层嵌套,中间件在middleware文件夹。

    config/config.go是配置文件的一些加载逻辑,可以根据自己需求适当的修改优化。

    关于接口参数,建议 POST 、PUT 统一使用 JSON 形式,在模型层里面定义好相应的结构体,参数的校验采用了go-playground/validator/v10库,直接在结构体 Tag 里面标记即可,详细用法请参考其官方文档。

    type CreateArticleCommand struct {
        Id      int
        UserId  int
        Title   string `form:"title" json:"title" binding:"gt=1,lt=100"`
        Content string `form:"content" json:"content" binding:"gt=1,lt=2000"`
    }
    
    type UpdateArticleCommand struct {
        Id      int
        UserId  int
        Title   string `form:"title" json:"title" binding:"gt=1,lt=100"`
        Content string `form:"content" json:"content" binding:"gt=1,lt=2000"`
    }
    

    。。。 。。。 。。。

    7 条回复    2021-06-24 20:05:37 +08:00
    wandehul
        1
    wandehul  
       2021-06-24 00:51:39 +08:00   ❤️ 1
    先 mark,刚好最近有这方面的需求,等这一阵手里的活忙完了,再看
    quzard
        2
    quzard  
       2021-06-24 08:52:29 +08:00 via Android
    学习了。自己也写一个
    JustSong
        3
    JustSong  
       2021-06-24 12:13:50 +08:00 via Android
    建议设成 template
    honkki
        4
    honkki  
       2021-06-24 13:16:18 +08:00
    log 能打印 sql 语句吗
    wangbenjun5
        5
    wangbenjun5  
    OP
       2021-06-24 13:58:34 +08:00 via Android
    @honkki 可以
    abccccabc
        6
    abccccabc  
       2021-06-24 16:56:39 +08:00
    @wangbenjun5 你是怎么学 go 的?? 好厉害呀, 给新手一个学习提纲如何?
    WhereverYouGo
        7
    WhereverYouGo  
       2021-06-24 20:05:37 +08:00
    @abccccabc #6 自己做个小项目。换了家公司,从 Java 转 Go,进来先自己做个小项目,你做着做着就都会了[都是泪]
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   2796 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 26ms · UTC 09:23 · PVG 17:23 · LAX 01:23 · JFK 04:23
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.