前言
一个语言是否好友除了语言语法及内置包以外,还需要有一个设计不错框架,我们认为好的框架目录是一定是简洁的,目录结构都不能合理设计,那我们也不敢相信他能把框架设计的好。一个简洁的框架是可以让框架易学,让新人的快速上手。不论您公司人员流动如何,一定有新人加入,当一个新人拿到框架,如果能让他快速上手,肯定是能给您公司减少成本的。说了这么希望我们能达成框架目录结构的简洁理念,接下来我们一起看看我们设计简洁目录的框架咯。
框架目录
先看看框架目录:
├── 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下面的应该控制器代码如下:
Go
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展开说明:
Go
├── developer # 开发者工具
├── datacenter # 数据中心-数据字典-配置
├── user # 用户登录等操作
├── system # 后台系统管理(展开举例)
│ ├── account.go # 用户管理
│ ├── dept.go # 部门管理
│ ├── log.go # 系统日志
│ ├── role.go # 角色管理
│ └── rule.go # 系统菜单
│
├── createcode # 代码生成示例代码
│ ├── product.go # 演示产品
│ └── productcate.go # 演示产品分类
│
└── controller.go # 模块控制器-也就是business这个模块的控制
模块控制器
模块下的控制器代码如下:
Go
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,然后创建增删改查的接口,示例代码如下:
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全栈开发社区 这里处理资料还可以交流学习的。