首页 > 其他分享 >为了让Go开发变得更简单我把传统多层结构改为准单层(也可以认为两个实则一层,以为有一层框架自己可生成)

为了让Go开发变得更简单我把传统多层结构改为准单层(也可以认为两个实则一层,以为有一层框架自己可生成)

时间:2024-07-19 18:56:04浏览次数:8  
标签:一层 接口 gf 模块 Go home douyinapp 路由 单层

前言

自从使用上Go语言我们把开发简单贯彻到底,一个语言是否用得到舒服吗,我们一方面是看语言本身,另一方面还得有个好用框架,我们开发项目一般是不会从零开始编写代码,都是找个框架,在框架基础上搭建自己业务。所以我们一直想有一个满足开发简单、维护简单、学习简单、性能优秀、安全保障的框架,全网搜索没有找到合意框架,经过7年积累,自己戳一个,目前使用已经满足快速开发外包项目要求了,新老程序员交接成本也很低。本文我们一起分享一下我们这赖人搭建的框架。

框架设计思路

我们包传统常见的表现层(Controller),业务逻辑层(Service),和数据访问层(DAO),压缩为仅1层即业务逻辑层,简称接口实现层。但我们框架是存在Controller层的,但开发时我们不会去写Controller层,Controller框架作为约束规则会自己生产,我们仅编写当前请求操作接口代码即可。

结构如下:

├── app                       # 应用目录
│   ├── douyinapp             # 抖音应用模块
│   │   ├── home              # 应用首页数据
│   │   ├── user              #抖音用户相关业务接口
│   │   └── controller.go    # 模块控制器-仅针对douyinapp控制
│   └── controller.go        # 总应用控制器

 其中controller.go是控制,它控制使用模块,及模块控制它控制模块下的业务类使用。

控制层

1.主控控制代码如下,它是负责控制模块引入,也就是那个模块使用就在import引入,不用就去掉。

package controller

/**
* app路由引入口《引入模块控制器》
*
* 请把您使用包用 _ "gofly/app/xx"导入您编写的包 自动生成路由
* 不需要使用的模块则注释掉 例如home模块暂时用不到就注释掉,这样不占用资源,使用是取消注释即可。
* 路由规则:包路径“business/article” + 包中结构体“Cate”转小写+方法名(首字母转小写_ "gofly/app/business"
* 有控制的模块请在RouterHandler添加模块的路由钩子
 */
import (
	"gofly/app/douyinapp"
	"gofly/utils/gf"
)

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

2.模块控制器代码如下,它是负责控制业务类引入,也就是那个业务类使用就在import引入,不用就去掉。

package douyinapp

/**
* 引入控制器
* 请把您使用包用 _ "gofly/app/home/XX"导入您编写的包 自动生成路由
* 不是使用则注释掉
* 路由规则:包路径“home/article” + 包中结构体“Cate”转小写+方法名
 */
import (
	_ "gofly/app/douyinapp/home"
	_ "gofly/app/douyinapp/user"
	"gofly/utils/gf"
)

// 路由中间件/路由钩子,可以从c获取请求各种参数
func RouterHandler(c *gf.GinCtx, IsCtr bool) {
	if IsCtr {
		c.Next()
	}
}

接口实现层(业务逻辑层)代码实现

我们在接口实现层中编写,业务代码,在开发时我们只关心接口层,其他框架帮大家生成或自动引入无需人为编写,我们仅仅编写接口实现层代码,下面演示接口实现层代码编写步骤:

如下图,是home接口实现层代码,我们开发时就在douyinapp模块目录下添加业务类目录,然后在douyinapp目录的controller.go控制器import业务类,代码生成会自动引入。手动添加要自己用途一下。

 1.添加业务类目录

如上图我们在douyinapp模块创建首页home类,我们直接创建名称为home文件夹即可

2.创建接口文件

创建接口有两种一种是接口忽略文件层路由则命名为index.go,生成路由/douyinapp/接口名。另一个是用文件名作为一层路由名称则命名:文件(字母或者字母+数字).go,这样生成路由为 /douyinapp/文件名/接口名。

以一种为例,我们创建index.go文件,添加一个获取首页轮播图数据,代码如下:

package home

import "gofly/utils/gf"

/**
* 首页功能接口
 */
type Index struct{}

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

// 获取Swipe轮播数据
func (api *Index) GetSwipe(c *gf.GinCtx) {
	list := gf.List{gf.Map{"name": "第一页", "image": "https://weui.shanliwawa.top/weui/images/1.jpg"}, gf.Map{"name": "第2页", "image": "https://weui.shanliwawa.top/weui/images/2.jpg"}}
	gf.Success().SetMsg("获取Swipe轮播数据").SetData(list).Regin(c)
}

这样我们就编写好一个getSwipe接口,请求路由为:/douyinapp/home/getSwipe,如下图是框架自动生成路由,在终端打印日志。

 总结

 从上面我们可以看出编写一个接口很简单,代码很少,开发是我们也只关心业务接口,不用去几个文件编写代码,需要多个文件跳来跳去的。

如果你需要数据库操作,参考如下代码,直接在接口层编写,不用再写model层。


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

// 删除
func (api *Product) Del(c *gf.GinCtx) {
	param, _ := gf.RequestParam(c)
	res2, err := gf.Model("createcode_product").WhereIn("id", param["ids"]).Delete()
	if err != nil {
		gf.Failed().SetMsg("删除失败").SetData(err).Regin(c)
	} else {
		gf.Success().SetMsg("删除成功!").SetData(res2).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("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)
		}
	}
}

标签:一层,接口,gf,模块,Go,home,douyinapp,路由,单层
From: https://blog.csdn.net/qq_23731311/article/details/140556980

相关文章

  • 推荐一款m3u8视频下载工具:MediaGo
    MediaGo是一款功能强大的M3U8视频下载工具,专为流媒体视频下载而设计。它不仅支持m3u8视频的在线提取,还能通过软件自带的浏览器轻松嗅探网页中的视频资源,从资源列表中选择并下载所需视频,操作简便快捷。软件特点无需抓包:使用软件自带的浏览器,用户可以轻松嗅探网页中的视频资源......
  • Go Context的使用详解
    GoContext的使用在Gohttp包的Server中,每一个请求在都有一个对应的goroutine去处理。请求处理函数通常会启动额外的goroutine用来访问后端服务,比如数据库和RPC服务。用来处理一个请求的goroutine通常需要访问一些与请求特定的数据,比如终端用户的身份认证信息、验证......
  • Google 常用语法说明
    Google常用语法说明背景GoogleHacking,作为一种利用谷歌搜索引擎的强大能力来挖掘互联网中敏感或未公开信息的技巧,已成为安全研究、漏洞挖掘及信息搜集领域的重要工具。通过精心构造的搜索查询,用户可以轻松地发现从轻微的安全疏忽(如遗留的后门、未加密的后台入口)到严重的信息......
  • 计算机毕业设计PySpark+Django高考志愿填报推荐系统 高考预测 高考大数据分析 Hadoop
    摘要本文旨在设计与实现一个基于Spark的高考志愿填报推荐系统,旨在帮助高考生根据自身成绩和兴趣,精准推荐合适的大学和专业。系统采用大数据处理框架Spark,结合机器学习算法,实现了对高考数据的深度挖掘和分析,为考生提供科学、有效的志愿填报建议。系统捕捉考生个人特征、......
  • 学习Go的第二天
    加完班回到家,继续第二天的学习,先尝试了解下常量,常量使用关键字const定义,用于存储不会改变的数据。故意尝试修改下常量:IDE提示:cannotassigntoPi(neitheraddressablenoramapindexexpression),即:无法分配给pi(既不是可寻址的,也不是映射索引表达式)iota特殊常量可以用......
  • mongo事务
    事务内的读取操作可能会返回旧数据,这称为 陈旧读取。事务内的读取操作不能保证看到其他已提交事务或非事务性写入执行的写入。将文档插入到employees集合中db.getSiblingDB("hr").employees.insertOne({_id:1,status:"Active"})开始会话session=db.getMongo()......
  • Go踩坑:interface{}判断nil
    问题背景在实习的一次真实程序开发中,我编写了一个函数,其处理一个接口类型(interface{})的参数,根据其类型返回一个字符串。在传入的参数为nil时,我希望通过判断,返回空字符串。看看我的大致代码:funcmain(){ varp*int64 fmt.Println(defaultValueFn(p))//p未赋值,我希望返回......
  • 管理索引mongo
    列出数据库的所有索引db.getCollectionNames().forEach(function(collection){indexes=db[collection].getIndexes();print("Indexesfor"+collection+":");printjson(indexes);});列出特定类型的索引//Thefollowingfindsallhashedindex......
  • mongo索引类型
    要创建单字段索引,请使用以下原型:db.<collection>.createIndex({<field>:<sortOrder>})复合索引要创建复合索引,请使用下列 db.collection.createIndex()方法: db.<collection>.createIndex({<field1>:<sortOrder>,<field2>:<sortOrder&......
  • ChaosMeta for AI:混沌工程让AI稳定性更上一层楼
    作者:刘凇杉在今天的AI时代,AI系统的架构愈发复杂,其稳定性、资源利用率以及故障自愈能力也显得尤为重要。如果我们在实际运行中遇到问题再去修复,不仅成本高,还会对用户体验造成影响。混沌工程则是通过主动暴露和解决系统脆弱性,极大提升系统的韧性。而ChaosMeta,作为蚂蚁集团开源的混......