Golang:微服务常用代码分层结构

news2024/12/26 17:22:43

1.代码结构

代码分层结构是一个老生常谈的话题,好的代码结构能够使得系统易于理解、开发及维护,如果代码结构很混乱就会使得不同层级的代码块耦合,导致难以维护和拓展。
比较经典的代码结构(宏观)有Web的MVC模式分层结构,将代码分为Controller路由层、Model模型层、View视图层。
在这里插入图片描述

更加具体地来看,对于微服务来说(不考虑前后端一体化情况),后端只有Controller及Model层, 可以细化为:

  • controller层:路由层,定义接口的路由
  • service层:逻辑层,定义服务的逻辑
  • dao层:数据层,定义数据库间的交互
  • entity层:实体层,定义数据PO、DTO、VO等结构
  • utils层:工具层,定义各类工具
    在这里插入图片描述

2.Golang:微服务代码分层结构

这里分享一下工作中常用到的Golang微服务代码分层结构,以及每一层结构的定义及能做的事情、不能做的事情。
在这里插入图片描述

由于Golang是不支持包之间循环依赖的,所以从hanlders到pkgs,均为单向依赖。下面介绍各个层级的含义,以及要做的事情。

2.1.pkg

pkg包存放与业务逻辑无关的工具包,如格式化工具、结构体转换工具等。

pkg/
 |- formatter/
  |- formatter.go
 |- converter/
  |- converter.go
  • converter.go
func obj2String(obj interface{}) (string, error) {
    bytes, err := json.Marshal(&obj)
    if err != nil {
        return "", err
    }
    return string(bytes), nil
}

2.2.entity

entity包存放领域实体及其相关方法及枚举。

  • entity包只能提供最基本的和实体相关的方法,如定义了User结构体,提供IsValidUser方法判断该User是否有效等。
  • entity包不依赖于其他任何包(基础类库、pkgs包)除外,只提供最基础的领域模型定义。
entity/
 |- user.go
 |- item.go
  • user.go
type UserType string

const (
    UserTypeAdmin  UserType = "admin"
    UserTypeNormal UserType = "normal"
)

type User struct {
    UserType UserType
    UserID   int64
    UserName string
}

func (u *User) IsAdmin() bool {
    return u.UserType == UserTypeAdmin
}

2.3.dao

dao包存放于数据库交互的所有代码,即数据的增、删、改、查。

  • dao包包含领域模型的所有数据CRUD操作
  • dao包不包含业务逻辑相关的操作
dao/
 |- dao.go
 |- user_dao.go
  • dao.go
var UserDao UserDaoIF

func InitDAO() {
    UserDao = new(userDao)
}
  • user_dao.go
type UserDaoIF interface {
    GetUser(userID int64) (*entity.User, error)
    CreateUser(user *entity.User) error
}

type userDao struct{}

// CreateUser implements UserDaoIF
func (*userDao) CreateUser(user *entity.User) error {
    panic("unimplemented")
}

// GetUser implements UserDaoIF
func (*userDao) GetUser(userID int64) (*entity.User, error) {
    panic("unimplemented")
}

2.4.policies

policies包存放和业务逻辑校验、实体验证相关的代码。

policies/
 |- policy.go
 |- user_policy.go
  • policy.go
var UserPolicy UserPolicyIF

func Init() {
    UserPolicy = new(userPolicy)
}
- user_policy.go
type UserPolicyIF interface {
    CanLogin(userID int64) bool
    CanRegister(userID int64) bool
}

type userPolicy struct{}

// CanLogin implements UserPolicyIF
func (*userPolicy) CanLogin(userID int64) bool {
    panic("unimplemented")
}

// CanRegister implements UserPolicyIF
func (*userPolicy) CanRegister(userID int64) bool {
    panic("unimplemented")
}

2.5.services

services存放业务逻辑相关代码,是整个项目中逻辑最复杂的部分。

services/
 |- service.go
 |- user/
  |- user_service.go    
 |- item/
  |- item_service.go
  • service.go
var UserService UserServiceIF

func Init() {
    UserService = new(userService)
}
- user_service.go
type UserServiceIF interface {
    UserLogin(u *entity.User) error
}

type userService struct{}

// UserLogin implements UserServiceIF
func (*userService) UserLogin(u *entity.User) error {
    panic("unimplemented")
}

2.6.handlers

handlers定义了各类对外处理器入口,如http、rpc、eventbus等处理器。

  • handlers中的处理器只做三件事情:接受请求解析入参、调用services完成业务逻辑、构造响应参数
  • handlers不包含业务代码逻辑,应该简单地作路由使用
handlers/
 |- handler.go
 |- rpc/
  |- user_rpc.go    
 |- http/
  |- item_http.go

2.7.其他包

  • conf包:存放相关的配置文件,如config_prod.yaml等
  • script包:存放系统相关的脚本,如编译脚本build.sh等
  • cmd包:存放相关的可直接运行的go脚本,如刷数脚本reflush.go等

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

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

相关文章

SpringBoot整合websockt实现消息对话

文章目录 前言websockt什么是websockt?websockt和Socket区别代码部分实战应用 前言 websockt 什么是websockt? WebSocket是一种在Web应用程序中实现实时双向通信的技术。Web应用程序通常是基于HTTP协议的,HTTP是一种请求/响应式的协议&…

【服务器使用基础】---华为云云耀云服务器实例使用实践

🦖我是Sam9029,一个前端 Sam9029的CSDN博客主页:Sam9029的博客_CSDN博客-JS学习,CSS学习,Vue-2领域博主 **🐱‍🐉🐱‍🐉恭喜你,若此文你认为写的不错,不要吝啬你的赞扬,求…

肖sir__linux详解__003(vim命令)

linux 文本编辑命令 作用:用于编辑一个文件 用法:vim 文件名称 或者vi (1)编辑一个存在的文档 例子:编辑一个file1文件 vim aa (2)编辑一个文件不存在,会先创建文件,再…

Python-图像拼接神器-stitching

多幅图像的拼接 采用这个包,图像拼接结果很好~ 代码只需要三四行 import stitching import cv2imgs ["data/test02/1Hill.jpg","data/test02/2Hill.jpg","data/test02/3Hill.jpg",] stitcher stitching.Stitcher() panorma stit…

postgresql-多表连接

postgresql-多表连接 内连接查询左外连接查询右外连接查询全外连接查询交叉连接查询简写 总结 内连接查询 内连接用于返回两个表中匹配的数据行,使用关键字INNER JOIN表示,也可以简写成JOIN; selecte.first_name ,d.department_id fromcps…

无涯教程-JavaScript - POISSON函数

POISSON函数取代了Excel 2010中的POISSON.DIST函数。 描述 该函数返回泊松分布。泊松分布的常见应用是预测特定时间的事件数。 语法 POISSON(x,mean,cumulative)争论 Argument描述Required/OptionalXThe number of events.RequiredMeanThe expected numeric value.Require…

leecode学习(1)

一、题目 给定一个数组nums和一个目标值target,请你再该数组中找出和为目标值的那两个数,并返回数组的下标,你可以假设输入只会对应一个答案,但是数组的同一个元素不能使用两次。 二、解题思路 目的就是要求出两数之和等于目标值嘛。 就是…

探索树堆Treap和红黑树的优势和劣势

探索树堆Treap和红黑树的优势和劣势 一、背景知识二、树堆(Treap)的介绍三、红黑树(RB-Tree)的介绍四、树堆(Treap)与红黑树(RB-Tree)的比较总结 博主简介 💡一个热爱分享…

王道考研数据结构

文章目录 C 环境准备官方文档环境准备在线运行VSCode 环境报错解决 绪论线性表顺序表链表错题 栈、队列和数组栈队列栈的应用之中缀转后缀特殊矩阵用数组压缩存储错题 串模式匹配之暴力和KMP 树与二叉树二叉树树和森林哈夫曼树和哈夫曼编码并查集错题 图图的基本概念图的存储及…

LeetCode494. 目标和

494. 目标和 文章目录 [494. 目标和](https://leetcode.cn/problems/target-sum/)一、题目二、题解方法一:目标和路径计数算法方法二:01背包方法三:01背包一维数组 一、题目 给你一个非负整数数组 nums 和一个整数 target 。 向数组中的每个…

IPC进程间通信及示例代码

一. 什么是进程通信 进程通信( InterProcess Communication,IPC)就是指进程之间的信息交换。实际上,进程的同步与互斥本质上也是一种进程通信(这也就是待会我们会在进程通信机制中看见信号量和 PV 操作的原因了&#x…

Ubuntu18.04使用Systemback制作系统镜像并还原

系列文章目录 文章目录 系列文章目录前言一、下载Systemback工具二、制作系统镜像到U盘三、安装制作系统 前言 在Ubuntu系统中开发项目时,有时会希望将项目移植到另外一台计算机(如工控机等)上进行部署,通常会在新计算机中安装Ub…

Qt +VTK+Cmake 编译和环境配置(第二篇,中级篇, 重新编译)

1.下载VTK和Cmake 这里不介绍了。我的VTK 8.2.0 cmake 3.27.4 就是不服这编译器了。重新来一次 打开Cmake,把VTK源文件路径和目标路径设置一下(目标路径自己设置,随意) 点击Configure:。 点击下一步 选择好 Qt的gcc…

国际版阿里云/腾讯云:弹性高性能计算E-HPC入门概述

入门概述 本文介绍E-HPC的运用流程,帮助您快速上手运用弹性高性能核算。 下文以创立集群,在集群中安装GROMACS软件并运转水分子算例进行高性能核算为例,介绍弹性高性能核算的运用流程,帮助您快速上手运用弹性高性能核算。运用流程…

selenium 自动化测试——环境搭建

安装python,并且使用pip命令安装 selenium pip3 install selenium 然后尝试第一次使用selenium 完成一个简单的测试自动化脚本 from selenium import webdriver from selenium.webdriver.common.by import By import timedriver webdriver.Chrome() driver.get(…

A 股个股资金流排行 API 数据接口

A 股个股资金流排行 API 数据接口 全量股票资金流排名,多时间区间,全量A股数据。 1. 产品功能 支持所有A股资金流数据查询;每日定时更新数据;支持多时间段查询;超高的查询效率,数据秒级返回;数…

【问大家】电商问答数据的采集与深度分析

1. 引言 电商运营多年,功能越来越完善,我们发现当您购买过该商品之后,在消息-互动这里会看到别的网友提问的有关该商品的问题,这个功能叫问大家。 问大家模块可以说填补了宝贝评价部分的短板,评价部分单向传播属性较…

CSS中你不得不知道的css优先级

在我们定义css样式时,经常出现两个或更多规则应用在同一元素上,这时就会出现优先级的问题。其实css为每一种基础选择器都分配了一个权重。 我们简化理解: CSS权重计算: 最顶层:!important 权重值:…

【Django】让SQLite数据库中表名支持重命名的方法

修改了数据库表名之后&#xff0c;更新数据库时跳错&#xff1a; django.db.utils.NotSupportedError: Renaming the japi_api_info table while in a transaction is not supported on SQLite < 3.26 because it would break referential integrity. Try adding atomic F…

无涯教程-JavaScript - PERCENTILE函数

PERCENTILE函数替代Excel 2010中的PERCENTILE.INC函数。 描述 该函数返回范围中值的第k个百分位数。您可以使用此功能建立接受阈值。 语法 PERCENTILE (array,k)争论 Argument描述Required/OptionalArrayThe array or range of data that defines relative standing.Requi…