这两天在网上研究了很多开源的自动cms生成工具,这里对这两天的收获做一下总结。本质上,自己做一个简单的也不费事儿,但是闭门造车容易,拥抱世界却很难。所以先看看有什么巨人的肩膀可以用是好的。
在低代码和零代码领域的应用,一般有四种类型:
- bootstrap studio,自动拖拽生成页面样式模版,套一套数据就是页面
- 自动生成小程序或者app,例如谷歌收购的apigee
- 自动生成cms,包含crud操作和界面的增删查改搜等5项操作
- 调用代码生成,也就是一般的sdk,帮助快速接入api和功能
这两天调研的功能主要属于第三种类型。下面我就每一种都简单介绍一下
- go-admin,4.4k☆
- goweb,385☆
- qor,4.6k★
- CCMS,19☆
- pinecms,35☆
- go-blog,154☆
- GoAdmin,118☆
7.1 第一步:建表
7.2 第二步:点击生成
7.3 第三步:整合生成的代码
7.4 第四步:添加菜单入口
7.5 第五步:刷新goadmin后台,完成:
7.6 后记
下载并运行:https://github.com/GoAdminGroup/go-admin
也有一个demo:https://github.com/GoAdminGroup/example.git
打开体验地址:http://localhost:9033/admin
文档地址:http://doc.go-admin.cn/zh/
评价
可以说,这个项目做得挺认真的,特别是当我们发现这是一个中山大学的大三学生的项目时,感觉更为不容易。为小兄弟点赞。
- 整体利用后台golang代码控制前端显示和功能布局,对于后台能力强于前端的团队来说还可以考虑一下。
- 该项目支持go.mod。
- 文档写的不错。
- 基于gin框架。
地址:https://github.com/iissy/goweb
如果遇到端口冲突,无法启动,则把
iris.Addr(":80"),
改为:
iris.Addr(":8083"),
评价
- 安装后打开主页空空如也,即使是导入了hrefs.cn.sql(看不到效果,就不好感受是否好用了)。
- 项目只能使用consul来做注册发现,如果要关掉consul,需要改一些代码,不明确的变更工作量。
地址:https://github.com/qor/qor-example
文档地址;https://getqor.com/cn
https://doc.getqor.com/
这个项目看起来比较专业,但是无法运行起来。
报错信息:
Failed to find configuration config/smtp.yml, using example file config/smtp.example.yml
WARNING: AssetFS is used before overwrite it!
看起来依赖的AssetFS和smtp没有搞定。
评价
- 这个只有英文文档网站。
- example无法打开,无法体验效果。
- 虽然建设看起来专业的,但是已经有2年没有维护了。
- go mod vendor无法通过。
地址:https://gitee.com/omyscode/CCMS.git
http://127.0.0.1:8081/ccms 普通用户;账号密码:453453453453/453453453453
http://127.0.0.1:8081/ccms/c_login 管理员;admin/admin;
评价
- 这个网站就是一个定制的cms管理后台,功能只跟考生有关系,要想修改为自己所用有点费劲。本身不具有开放性。
- 样式太老气了。
地址:https://github.com/xiusin/pinecms.git
这个网站报错解决不了。无法编译通过。
# github.com/shirou/gopsutil/disk
../../go-miniapp/pkg/mod/github.com/shirou/gopsutil@v3.20.11+incompatible/disk/disk_darwin.go:64:52: cannot use stat.Mntfromname[:] (type []int8) as type []byte in argument to common.ByteToString
../../go-miniapp/pkg/mod/github.com/shirou/gopsutil@v3.20.11+incompatible/disk/disk_darwin.go:65:50: cannot use stat.Mntonname[:] (type []int8) as type []byte in argument to common.ByteToString
../../go-miniapp/pkg/mod/github.com/shirou/gopsutil@v3.20.11+incompatible/disk/disk_darwin.go:66:51: cannot use stat.Fstypename[:] (type []int8) as type []byte in argument to common.ByteToString
../../go-miniapp/pkg/mod/github.com/shirou/gopsutil@v3.20.11+incompatible/disk/disk_darwin.go:77:44: cannot use stat.Fstypename[:] (type []int8) as type []byte in argument to common.ByteToString
评价
- 无法编译通过,应该是很长时间没有维护了。虽然只过了8个月。
代码地址:https://github.com/1920853199/go-blog.git
体验地址:http://127.0.0.1:8088/
评价
- 网站太粗糙了,感觉是自己做了个网站,顺便改了一下开源出来,并非一个扩展性很强的网站。
代码地址:
https://github.com/CrazyRocks/autocreate.git 90☆
https://gitee.com/crazyrocks/goadmin.git 118☆
体验地址:
http://127.0.0.1:8081/ 在这里生成代码;GF代码生成器;
http://localhost:8192/ 在这里体验网站;goadmin后台;
注意啊,作者没有很详尽的readme,我看了源代码很久才折腾好了。
第一步:建表
注意:
- project:用来做require代码包的,你想引用到哪里去,你就用啥project名,比如我想放到goadmin项目去,就填goadmin;
- module:这个是模块名,在goadmin后台的module目录下,已经用了home、public、sys三个模块了,所以新生成的module也要放这里。比如site。
- menu:这个没有看懂是用来干啥的,暂时其实也用不到,看起来是指用来生成了一个sql文件,导入到某个地方去支撑页面入口添加。无妨。
- 表名:用处很大。看了源码里面,解析成路径path了。一般设置为两级目录,下划线分隔,例如module_path,module就是上面的module;path就是这个数据库表功能的名字,比如订单、用户、成绩、分数等都可以。
这一步,需要在goadmin的数据库中建表。例如:
先修改配置文件,支持链接数据库:
// 在config/config.toml 文件中,修改数据库配置,指定数据库名字;
host = "localhost"
port = "3306"
user = "root"
pass = "123456"
name = "goadmin"
type = "mysql"
role = "master"
charset = "utf8"
priority = "1"
debug = true
然后自己在终端下面访问数据库,创建表,这里我一次性创建两个:
第二步:点击生成
表建好之后,运行GF代码生成器。
https://github.com/CrazyRocks/autocreate.git里面运行:
go run .
命令行提示,端口启动在8081,则访问:http://localhost:8081/#generator.html 即可访问GF代码生成器。
填写:
- project为goadmin
- module为site
- menu为wxmenu
- 选中site_weixin和site_wxuser
点击生成代码按钮,提示成功。查看代码路径,发现增加了一个result目录:
result
├── html
│ └── site
│ ├── weixin.html
│ └── wxuser.html
├── js
│ └── site
│ ├── weixin.js
│ └── wxuser.js
├── site
│ ├── config
│ │ └── router.go
│ ├── controller
│ │ ├── site_weixin_controller.go
│ │ └── site_wxuser_controller.go
│ ├── model
│ │ ├── site_weixin_model.go
│ │ └── site_wxuser_model.go
│ └── module.go
├── sql
│ ├── site_weixin_menu.sql
│ └── site_wxuser_menu.sql
└── vue
└── site
├── siteweixin-add-or-update.vue
├── siteweixin.vue
├── sitewxuser-add-or-update.vue
└── sitewxuser.vue
第三步:整合生成的代码
作者只是说result就可以拿去用了,但是怎么用呢?这里我研究了一下,可以这样和goadmin进行整合:
- result/html/site放到goadmin/template/site目录下;
- result/js/site放到goadmin/public/modules/site目录下;
- result/site放到goadmin/module目录下,和home、public、sys放一起;
第四步:添加菜单入口
为了能在goadmin左侧显示菜单入口,需要修改goadmin/template/layout/nav.html,在右侧导航加入菜单项:
<li class="nav-item">
<a href="/sys/oss/index" class="nav-link "><i class="fas fa-cloud-upload-alt"></i>
<span>文件管理</span></a>
</li>
<li class="nav-item">
<a href="/site/weixin" class="nav-link "><i class="fas fa-cloud-upload-alt"></i>
<span>微信绑定</span></a>
</li>
<li class="nav-item">
<a href="/site/wxuser" class="nav-link "><i class="fas fa-cloud-upload-alt"></i>
<span>微信用户</span></a>
</li>
第五步:刷新goadmin后台,完成:
后记
通过
egrep -r "weixin|site" result/* | grep -v vue | grep -v wxuser > /tmp/one.txt
查看改动,为了省略篇幅,去掉vue和wxuser,只看site_weixin的结果。可以看到autocreate工程修改的范围,体会模版做的工作有哪些,感觉还是比较清晰的:
result/html/site/weixin.html: <div class="breadcrumb-item"><a href="/site/weixin">绑定微信</a></div>
result/html/site/weixin.html: <div class="breadcrumb-item"><a href="/site/weixin">列表</a></div>
result/html/site/weixin.html: v-model="siteweixin.Name"
result/html/site/weixin.html: v-model="siteweixin.ShortId"
result/html/site/weixin.html: v-model="siteweixin.Qrcode"
result/html/site/weixin.html: v-model="siteweixin.CreateTime"
result/html/site/weixin.html: v-model="siteweixin.UpdateTime"
result/html/site/weixin.html: v-model="siteweixin.Status"
result/html/site/weixin.html:<script src="/modules/site/weixin.js?_1608464436"></script>
result/js/site/weixin.js: url: baseURL + 'site/weixin/page',
result/js/site/weixin.js: siteweixin:{
result/js/site/weixin.js: vm.siteweixin= {};
result/js/site/weixin.js: var url = vm.siteweixin.Id ==null ? "site/weixin/save" : "site/weixin/update";
result/js/site/weixin.js: data: vm.siteweixin,
result/js/site/weixin.js: url: baseURL + "site/weixin/delete",
result/js/site/weixin.js: url: baseURL + "site/weixin/delete",
result/js/site/weixin.js: $.get(baseURL + "site/weixin/get/" +Id, function (r) {
result/js/site/weixin.js: vm.siteweixin= r.data;
result/site/config/router.go: "goadmin/module/site/controller"
result/site/config/router.go: s.Group(urlPath+"/site", func(g *ghttp.RouterGroup) {
result/site/config/router.go: siteWxuserController := new(controller.SiteWxuserController)
result/site/config/router.go: siteWeixinController := new(controller.SiteWeixinController)
result/site/config/router.go: g.ALL("/weixin", siteWeixinController)
result/site/config/router.go: g.POST("/weixin/page", siteWeixinController.Page)
result/site/config/router.go: g.GET("/weixin/get/{id}", siteWeixinController.Get)
result/site/config/router.go: g.POST("/weixin/save", siteWeixinController.Save)
result/site/config/router.go: g.POST("/weixin/update", siteWeixinController.Update)
result/site/config/router.go: g.POST("/weixin/delete", siteWeixinController.Delete)
result/site/controller/site_weixin_controller.go:* @File: site_weixin_controller
result/site/controller/site_weixin_controller.go: "goadmin/module/site/model"
result/site/controller/site_weixin_controller.go: base.WriteTpl(r, "site/weixin.html", g.Map{})
result/site/model/site_weixin_model.go:* @File: site_weixin_model
result/site/model/site_weixin_model.go: return "site_weixin"
result/site/module.go:package site
result/site/module.go:import "goadmin/module/site/config"
result/sql/site_weixin_menu.sql: VALUES ('1', 'wxmenu', 'site/siteweixin', NULL, '1', 'config', '6');
result/sql/site_weixin_menu.sql: SELECT @parentId, '查看', null, 'site:siteweixin:list,site:siteweixin:info', '2', null, '6';
result/sql/site_weixin_menu.sql: SELECT @parentId, '新增', null, 'site:siteweixin:save', '2', null, '6';
result/sql/site_weixin_menu.sql: SELECT @parentId, '修改', null, 'site:siteweixin:update', '2', null, '6';
result/sql/site_weixin_menu.sql: SELECT @parentId, '删除', null, 'site:siteweixin:delete', '2', null, '6';
总体来说比较清爽,但是要注意,在阅读源代码时,发现搜索功能有个bug:
点击查询的时候,向后台传递的参数是search,
但是,代码中匹配时有问题:
这里却是按name取的字段,修改为:
if form.Params != nil && form.Params["search"] != "" {
where += " and name like ? "
params = append(params, "%"+form.Params["search"]+"%")
}
之后就好了:
评价
- 支持go.mod;
- 基于gof框架;
- 作者在readme.md中的介绍实在是太简略了,导致填写和看代码才能看懂最后生成代码的填写方法;
- 作为cms,增删查改都有,比较方便;可以作为初级使用,符合我自己简单搭建后台的需要。
-
image.png
作者也够粗心的,连项目名字都会写错(这里应该是GoAdmin,哎,作者大概是着急赚钱去了吧,难怪还存在一个bug);
- 关于vue的部分,不知道是不是个半成品;
感谢大家阅读到这里,后续如果还有星比较多的项目,我再体验一下,发给大家。