好久没有水博客了,我们来水篇博客吧。(逃
就聊一聊最近写的玩具wx-pusher
吧(其实就是为了说这个!)
这个wx-pusher
还是受到server酱
的启发,但是我显然写不出server酱
那木牛逼的东西
只能写一个十分简陋的版本了。
前言
想必大家都有自己的微信,想必大家或多或少,自愿或被迫都关注了一些微信公众号。
虽然,非常不喜欢某一些微信号推送一些乱起八糟的东西。
但是,我们不能以偏概全,有些微信号确实很不错的。
比如说,当你看见大佬写的文章后,感觉非常符合自己,值得学习。
我一般都会采取一些方法来关注这些文章,包括但不限于使用,RSS,注册平台号然后关注,收藏博客地址等。
不过,大部分的情况是在许多文章的后面都会有一个微信公众号关注的二维码,只需用扫码即可轻松关注。
不过,我对微信确实存在偏见,比如说微信安卓没有夜间模式,界面一如既往的丑陋,功能一如既往的残缺。
这导致,我十分得不情愿使用微信相关的功能。但是,没有办法,当你身边的人都在使用的时候,这个时候你还不用,呵呵呵。
所以,最后我觉得为何自己不弄一个公众号呢?(这算是某种从众了吧?)
写了一个库
搞公众号需要很繁琐的申请步骤,不过好在个人无法认证的公众号申请很简单。
后台功能是很简单容易上手的,看起来管理应该不是很难,不过难在内容的输出。
不过单纯靠这个后台管理,只能做一些推送相关的东西,无法提供一些实用的功能。
这个时候就得需要自己进行后台相关的开发了,正好自己是学这个的,所以想来尝试一波。
于是,我开始人生第一次的造轮子,不过这恐怕连个玩具也算不上吧。
仅仅提供了一些基础功能的支持,只适合像我这种没有认证的公众号。
学习使用gin
框架开发
选gin
的理由非常简单,gin
框架简单,易上手,灵活。
这里不得不提到我的一个失败的项目,elibrary。我发现如果要做好,前后端分离实现起来比较舒服。苦于自己对前端一窍不通,看看以后能不能把坑填上吧。orz
这里,不去搞花俏的外观,不去弄没有意义的功能。仅仅有一个核心,差不多就行了。
目录结构
关于这一点,我以为会有一个比较通用的模板结构,不过去搜索一圈下来并没有。
我在这里纠结很久,想找一个可以参照的框架结构。浪费了很多的时间。
所谓的框架结构,我个人的理解是为了帮助开发者更好得进行开发,容易拓展,减少代码冗余等。
此外,我还对时候使用不同的文件夹感到困惑,因为一个文件夹往往对于了一个包,许多个文件夹就意味着有许多个包。
这又意味着,需要同时管理许多包,还要避免需要互相调用照成循环引用的尴尬。
最后,放开了自我,参考一些别人的做法,最后结构如下。
wx-pusher
├─app //主程序,协调下面的包,完成相关的初始化,服务的入口
├─assets //资源文件存放
├─config //加载配置,被许多包依赖
├─model //数据库模型,依赖db
├─route //路由的注册以及实现
│ ├─api //api路由,负责提供api调用,依赖model
│ └─page //page路由,负责提供页面展示,依赖redis
├─service //存放封装好的服务
│ ├─db //提供db支持,依赖config
│ ├─log //提供log支持,依赖config
│ ├─redis //提供缓存支持,依赖config
│ └─wechat //提供微信推送的接口,依赖config
├─template //gohtml文件存放,渲染页面
└─util //公共库,不依赖上面的库
这里面就没有所谓严格的MVC
模型,全是怎样舒服怎样来。
聊一聊代码
关于全局变量的使用
不知道我是受到什么影响,觉得如果如果在代码里面出现了全局变量是一件很糟糕的事情。
为此,我尽量的避开或者少用全局变量。当然,这不能说是错的。
就如同,goto
语句会导致程序的结构不清晰,全局变量可能导致程序的耦合上升。
但是,这绝对不是我们不去用它的理由,如同goto
有其适用场地,全局变量也有其存在的地方。
全局变量在包内有存在的必要,当然也要看包提供了什么功能。
比如说,http
包就提供了一个defaultServeMux
变量,再通过这个变量导出这个类型的各种方法,这样我们使用http
这个包的时候,会觉得很舒服。
回到我们的wx-pusher
,对于redis
,db
,log
这样的包就有必要提供过去实列Instance
的接口。又由于,一般应用只需用一个db
,所以我们完全可以声明一个全局变量来提供一个唯一的实列,避免导出传递指针的尴尬。
应该在main
函数完成什么操作
main
函数,抽象意义上的程序的入口。
现在,问题是那些操作应该写在main
函数里面
我觉得main
函数里面应该给出一个程序的核心流程,可以让别人快速的抓住程序的重点。
package main
import (
"wxServ/app"
)
func main() {
app.Run()
}
这里的main
只做了一件事情,就是启动app
。至于如何启动的,我们再看app
里面代码。
package app
import (
"wxServ/config"
"wxServ/model"
"wxServ/route"
"wxServ/service/db"
"wxServ/service/log"
"wxServ/service/redis"
"wxServ/service/wechat"
"github.com/gin-gonic/gin"
)
var g *gin.Engine
func Init() {
g = gin.New()
g.Use(gin.Logger(), gin.Recovery())
config.Init()
log.Init()
db.Init()
redis.Init()
model.Init()
wechat.Init(g)
route.Init(g)
}
func Run() {
Init()
log.Instance().Info("starting wx server")
panic(g.Run(":80"))
}
app
里面是完成相关的初始化任务,和运行一个gin
框架。这样我们的app
启动过程就算是结束了。
最后
其实还有很多地方需要改善,这个坑以后慢慢填吧。