Go语言简洁框架目录和高效的快发框架设计

news2025/1/18 12:57:19

前言

一个语言是否好友除了语言语法及内置包以外,还需要有一个设计不错框架,我们认为好的框架目录是一定是简洁的,目录结构都不能合理设计,那我们也不敢相信他能把框架设计的好。一个简洁的框架是可以让框架易学,让新人的快速上手。不论您公司人员流动如何,一定有新人加入,当一个新人拿到框架,如果能让他快速上手,肯定是能给您公司减少成本的。说了这么希望我们能达成框架目录结构的简洁理念,接下来我们一起看看我们设计简洁目录的框架咯。

框架目录

先看看框架目录:

├── app                      # 应用目录
│   ├── admin                # 后台管理应用模块(安装saas时存在、不安装则删除)
│   ├── business             # 业务端应用模块
│   ├── common               # 公共应用模块
│   └── controller.go        # 应用控制器
├── devsource                # 开发静态资源(安装界面、代码生成模板)
├── resource                 # 静态资源及配置文件(发布应用带上)
├── utils                    # 框架核心代码及工具包
├── go.mod                   # 依赖包管理工具
├── go.sum         
├── main.go                  # main函数       
├── runner.conf              # fresh热编译配置文件
└── README.md                # 项目介绍

 从目录总我们看到这个目录很简洁,这里的简洁不是为了简单而简单,而是在实用基础上进行精简。

框架设计中我们把框架的核心代码放在utils中,在项目开发中在非必要情况下不要去改动utils目录下的代码,业务代码放在app目录下,静态资源分别放在devsource和resource中(为什么分两个目录呢,这是因为方便部署直接拷贝resource目录带部署环境中,devsource是开始时用到资源到在生产环境中用不到,所以分开可以减少部署时上传资源)。目录结构中我们只要3个类型目录:一个框架核心代码目录、一个开发业务目录、一个静态资源目录。大道至简,开发时技术员只需在app目录下编写代码即可,不会把框架代码和业务代码混合在一起。

 接下来在看看app业务开发目录,这是开发时核心目录,也需要简洁。首先app目录下有个controller.go控制器文件,他是用来引入同目录文件目录,这是框架设计自动生成请求路径用到的。也就是说这个框架不需开发者开发一个接口手动添加一个请求路由,框架会会根据目录层级生成路由。

应用控制器

app下面的应该控制器代码如下:

package controller

/**
* app路由引入口《引入模块控制器》
*/
import (
	"gofly/app/admin"
	"gofly/app/business"
	_ "gofly/app/common"
	"gofly/utils/gf"
)

// 路由中间件/路由钩子
func RouterHandler(c *gf.GinCtx) {
	business.RouterHandler(c, "business")
	admin.RouterHandler(c, "admin")
}

再看app下的admin和business 这两个是框架的两个后台的后端,如果开发时业务不需有多租户我们就删除admin,这样app目录下就只剩下business和common了。所以说这个框架很简洁,也容易扩展多个端再加个目录即可。

模块目录

在继续看模块(即app下面目录)目录下的目录结构,这里就直接用business模块举例子了,选是system展开说明:

├── developer          # 开发者工具
├── datacenter         # 数据中心-数据字典-配置
├── user               # 用户登录等操作
├── system             # 后台系统管理(展开举例)
│   ├── account.go     # 用户管理
│   ├── dept.go        # 部门管理
│   ├── log.go         # 系统日志
│   ├── role.go        # 角色管理
│   └── rule.go        # 系统菜单
│
├── createcode         # 代码生成示例代码 
│   ├── product.go     # 演示产品
│   └── productcate.go # 演示产品分类
│
└── controller.go      # 模块控制器-也就是business这个模块的控制   

模块控制器

模块下的控制器代码如下:

package business

/**
* 引入控制器-文件夹名称的路径
*/
import (
	_ "gofly/app/business/datacenter"
	_ "gofly/app/business/developer"
	_ "gofly/app/business/system"
	_ "gofly/app/business/user"
	"gofly/utils/gf"
)

// 路由中间件/路由钩子,noAuths无需路由验证接口,可以从c获取请求各种参数
func RouterHandler(c *gf.GinCtx, modelname string) {
	if gf.IsModelPath(c.FullPath(), modelname) { //在这里面处理拦截操作,如果需要拦截终止执行则:c.Abort()
		// 判断请求接口是否需要验证权限(RBAC的权限)
		if gf.NeedAuthMatch(c) {
			haseauth := gf.CheckAuth(c, modelname)
			if haseauth {
				c.Next()
			} else {
				gf.Failed().SetMsg(gf.LocaleMsg().SetLanguage(c.Request.Header.Get("locale")).Message("sys_auth_permission")).SetData(haseauth).Regin(c)
				c.Abort()
			}
		} else {
			c.Next()
		}
	}
}

接口代码实现

在看看如下编写接口代码,我们用createcode这个代码示例类举例,首先创建一个product.go,然后创建增删改查的接口,示例代码如下:

package createcode

import (
	"gofly/utils/gf"
	"gofly/utils/tools/gmap"
)

// 演示代码-产品管理
type Product struct{}

func init() {
	fpath := Product{}
	gf.Register(&fpath, fpath)
}

// 获取列表
func (api *Product) GetList(c *gf.GinCtx) {
	pageNo := gf.Int(c.DefaultQuery("page", "1"))
	pageSize := gf.Int(c.DefaultQuery("pageSize", "10"))
	//搜索添条件
	param, _ := gf.RequestParam(c)
	whereMap := gmap.New()
	whereMap.Set("business_id", c.GetInt64("businessID"))
	if cid, ok := param["cid"]; ok && gf.Int(cid) != 0 {
		cids := gf.CateAllChilId("createcode_product_cate", cid)
		whereMap.Set("cid In(?)", cids)
	}
	if title, ok := param["title"]; ok && title != "" {
		whereMap.Set("title like ?", "%"+gf.String(title)+"%")
	}
	if status, ok := param["status"]; ok && status != "" {
		whereMap.Set("status", status)
	}
	if createtime, ok := param["createtime"]; ok && createtime != "" {
		datetime_arr := gf.SplitAndStr(gf.String(createtime), ",")
		whereMap.Set("createtime between ? and ?", gf.Slice{datetime_arr[0] + " 00:00", datetime_arr[1] + " 23:59"})
	}

	if userType, ok := param["userType"]; ok && userType != "" {
		whereMap.Set("userType", userType)
	}
	MDB := gf.Model("createcode_product").Where(whereMap)
	totalCount, _ := MDB.Clone().Count()
	list, err := MDB.Fields("id,title,image,cid,userType,images,likeColor,record_audio,price,des,sex,workerway,status,updatetime").Page(pageNo, pageSize).Order("id desc").Select()
	if err != nil {
		gf.Failed().SetMsg(err.Error()).Regin(c)
	} else {

		for _, val := range list {
			val["cidName"] = gf.GetTalbeFieldVal("createcode_product_cate", "name", val["cid"])
			val["userType"] = gf.GetDicFieldVal("2", val["userType"])
			if val["workerway"].String() != "" {
				val["workerway"] = gf.VarNew(gf.SplitAndStr(val["workerway"].String(), ","))
			}
		}
		gf.Success().SetMsg("获取全部列表").SetData(gf.Map{
			"page":     pageNo,
			"pageSize": pageSize,
			"total":    totalCount,
			"items":    list}).Regin(c)
	}
}

// 保存
func (api *Product) Save(c *gf.GinCtx) {
	param, _ := gf.RequestParam(c)
	var f_id = gf.GetEditId(param["id"])
	param["workerway"] = gf.ArrayToStr(param["workerway"], ",")
	if f_id == 0 {
		param["business_id"] = c.GetInt64("businessID") //当前用户商户ID
		addId, err := gf.Model("createcode_product").Data(param).InsertAndGetId()
		if err != nil {
			gf.Failed().SetMsg("添加失败").SetData(err).Regin(c)
		} else {
			if addId != 0 {
				gf.Model("createcode_product").Where("id", addId).Update(gf.Map{"weigh": addId})
			}
			gf.Success().SetMsg("添加成功!").SetData(addId).Regin(c)
		}
	} else {
		res, err := gf.Model("createcode_product").Where("business_id", c.GetInt64("businessID")).Where("id", f_id).Update(param)
		if err != nil {
			gf.Failed().SetMsg("更新失败").SetData(err).Regin(c)
		} else {
			gf.Success().SetMsg("更新成功!").SetData(res).Regin(c)
		}
	}
}

// 更新状态
func (api *Product) UpStatus(c *gf.GinCtx) {
	param, _ := gf.RequestParam(c)
	res, err := gf.Model("createcode_product").Where("business_id", c.GetInt64("businessID")).Where("id", param["id"]).Update(param)
	if err != nil {
		gf.Failed().SetMsg("更新失败!").SetData(err).Regin(c)
	} else {
		msg := "更新成功!"
		if res == nil {
			msg = "暂无数据更新"
		}
		gf.Success().SetMsg(msg).SetData(res).Regin(c)
	}
}

// 删除
func (api *Product) Del(c *gf.GinCtx) {
	param, _ := gf.RequestParam(c)
	res, err := gf.Model("createcode_product").Where("business_id", c.GetInt64("businessID")).WhereIn("id", param["ids"]).Delete()
	if err != nil {
		gf.Failed().SetMsg("删除失败").SetData(err).Regin(c)
	} else {
		gf.Success().SetMsg("删除成功!").SetData(res).Regin(c)
	}
}

// 获取内容
func (api *Product) GetContent(c *gf.GinCtx) {
	id := c.DefaultQuery("id", "")
	if id == "" {
		gf.Failed().SetMsg("请传参数id").Regin(c)
	} else {
		data, err := gf.Model("createcode_product").Where("business_id", c.GetInt64("businessID")).Where("id", id).Find()
		if err != nil {
			gf.Failed().SetMsg("获取内容失败").SetData(err).Regin(c)
		} else {
			if data != nil && data["workerway"].String() != "" {
				data["workerway"] = gf.VarNew(gf.SplitAndStr(data["workerway"].String(), ","))
			}
			gf.Success().SetMsg("获取内容成功!").SetData(data).Regin(c)
		}
	}
}

好了这就是框架设计结构与其编写业务代码流程,这里看看可以还是有点复杂,但在IED编辑器中就一目了然。

GoFly不仅是软件开发追求简单,嵌入式开发也最求简单,想学习Go语言嵌入式的可以去:嵌入式视频教程了解一下。

更多资料在:GoFly全栈开发社区 这里处理资料还可以交流学习的。

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

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

相关文章

2025边缘计算新年沙龙成功举办,共话边缘AI未来

1月11日下午,北京市海淀区中关村创业大街热闹非凡,以“云边腾跃,蛇启新航”为主题的 2025边缘计算新年沙龙 盛大举行。本次活动汇聚了边缘计算、人工智能以及云边协同领域的顶尖专家、学者和从业者,共同探讨技术前沿与实际应用场景…

使用redis-cli命令实现redis crud操作

项目场景: 线上环境上redis中的key影响数据展示,需要删除。但环境特殊没办法通过 redis客户端工具直连。只能使用redis-cli命令来实现。 操作步骤: 1、确定redis安装的服务器; 2、找到redis的安装目录下 ##找到redis安装目…

CentOS 下载软件时报Error: Failed to synchronize cache for repo ‘AppStream‘解决方法

下载软件时出现以下问题 直接把CentOS-AppStream.repo改个名字就行 cd /etc/yum.repos.d/ mv CentOS-AppStream.repo CentOS-AppStream.repo.bak就可以了 解决思路 把AI问遍,无人会,解决法 想要下载软件通通失败了,解决方法当然是问AI&am…

【深度学习】神经网络之Softmax

Softmax 函数是神经网络中常用的一种激活函数,尤其在分类问题中广泛应用。它将一个实数向量转换为概率分布,使得每个输出值都位于 [0, 1] 之间,并且所有输出值的和为 1。这样,Softmax 可以用来表示各类别的预测概率。 Softmax 函…

python管理工具:conda部署+使用

python管理工具:conda部署使用 一、安装部署 1、 下载 - 官网下载: https://repo.anaconda.com/archive/index.html - wget方式: wget -c https://repo.anaconda.com/archive/Anaconda3-2023.03-1-Linux-x86_64.sh2、 安装 在conda文件的…

当PHP遇上区块链:一场奇妙的技术之旅

PHP 与区块链的邂逅 在技术的广袤宇宙中,区块链技术如同一颗耀眼的新星,以其去中心化、不可篡改、透明等特性,掀起了一场席卷全球的变革浪潮。众多开发者怀揣着对新技术的热忱与探索精神,纷纷投身于区块链开发的领域,试…

unity——Preject3——开始界面拼面板

目录 1.创建panel,去掉panel自带的image,自己加一个image,使用锚点分配好 2.锚点(快捷键点击后 ALTShift) 锚点是什么? 锚点的实际例子 例子1:固定在父容器的中心 例子2:对齐到…

PyTorch使用教程(6)一文讲清楚torch.nn和torch.nn.functional的区别

torch.nn 和 torch.nn.functional 在 PyTorch 中都是用于构建神经网络的重要组件,但它们在设计理念、使用方式和功能上存在一些显著的区别。以下是关于这两个模块的详细区别: 1. 继承方式与结构 torch.nn torch.nn 中的模块大多数是通过继承 torch.nn…

传统以太网问题与VLAN技术详解

传统以太网的问题 广播域:在网络中能接收同一广播信息的所有设备(计算机、交换机)等的集合 说明:在一个广播域内,当一个设备发送广播帧时,该域内的所有设备都能接收到这个广播帧。工作原理:在以…

OpenAI Whisper:语音识别技术的革新者—深入架构与参数

当下语音识别技术正以前所未有的速度发展,极大地推动了人机交互的便利性和效率。OpenAI的Whisper系统无疑是这一领域的佼佼者,它凭借其卓越的性能、广泛的适用性和创新的技术架构,正在重新定义语音转文本技术的规则。今天我们一起了解一下Whi…

WPS计算机二级•高效操作技巧

听说这里是目录哦 斜线表头 展示项目名称🍋‍🟩横排转竖排🍐批量删除表格空白行🍈方法一方法二建辅助列找空值 能量站😚 斜线表头 展示项目名称🍋‍🟩 选中单元格,单击右键➡️“设…

RabbitMQ实现延迟消息发送——实战篇

在项目中,我们经常需要使用消息队列来实现延迟任务,本篇文章就向各位介绍使用RabbitMQ如何实现延迟消息发送,由于是实战篇,所以不会讲太多理论的知识,还不太理解的可以先看看MQ的延迟消息的一个实现原理再来看这篇文章…

《Keras 3 在 TPU 上的肺炎分类》

Keras 3 在 TPU 上的肺炎分类 作者:Amy MiHyun Jang创建日期:2020/07/28最后修改时间:2024/02/12描述:TPU 上的医学图像分类。 (i) 此示例使用 Keras 3 在 Colab 中查看 GitHub 源 简介 设置 本教程将介…

1.17组会汇报

STRUC-BENCH: Are Large Language Models Good at Generating Complex Structured Tabular Data? STRUC-BENCH:大型语言模型擅长生成复杂的结构化表格数据吗?23年arXiv.org 1概括 这篇论文旨在评估大型语言模型(LLMs)在生成结构…

PyTorch使用教程(2)-torch包

1、简介 torch包是PyTorch框架最外层的包,主要是包含了张量的创建和基本操作、随机数生成器、序列化、局部梯度操作的上下文管理器等等,内容很多。我们基础学习的时候,只有关注张量的创建、序列化,随机数、张量的数学数学计算等常…

idea gradle compiler error: package xxx does not exist

idea 编译运行task时报项目内的包不存在,如果你试了网上的其它方法还不能解决,应该是你更新了新版idea,项目用的是旧版jdk,请在以下编译器设置中把项目JDK字节码版本设为8(jdk1.8,我这里是17请自行选择&…

Nmap之企业漏洞扫描(Enterprise Vulnerability Scanning for Nmap)

简介 Namp是一个开源的网络连接端扫描软件,主要用于网络发现和安全审核。‌它可以帮助用户识别网络上的设备、分析它们的服务、检测操作系统类型,甚至发现潜在的安全漏洞。Nmap由Fyodor开发,最初是为了满足网络管理员的需求,但随…

RabbitMQ前置概念

文章目录 1.AMQP协议是什么?2.rabbitmq端口介绍3.消息队列的作用和使用场景4.rabbitmq工作原理5.整体架构核心概念6.使用7.消费者消息推送限制(work模型)8.fanout交换机9.Direct交换机10.Topic交换机(推荐)11.声明队列…

RabbitMQ---TTL与死信

(一)TTL 1.TTL概念 TTL又叫过期时间 RabbitMQ可以对队列和消息设置TTL,当消息到达过期时间还没有被消费时就会自动删除 注:这里我们说的对队列设置TTL,是对队列上的消息设置TTL并不是对队列本身,不是说队列过期时间…

MySQL8数据库全攻略:版本特性、下载、安装、卸载与管理工具详解

大家好,我是袁庭新。 MySQL作为企业项目中的主流数据库,其5.x和8.x版本尤为常用。本文将详细介绍MySQL 8.x的特性、下载、安装、服务管理、卸载及管理工具,旨在帮助用户更好地掌握和使用MySQL数据库。 1.MySQL版本及下载 企业项目中使用的…