1,简介:go-admin是go和vue配合开发的。
2,如何五分钟搭建一个后台管理系统。
# 代码拉取 并且 创建 Project
cd Project
git clone https://github.com/go-admin-team/go-admin.git # 服务端
git clone https://github.com/go-admin-team/go-admin-ui.git # 前端 vue-element-admin 魔改的
# 假设目前在Project目录
# 服务端项目部署:
cd go-admin
go build . # 编译
./go-admin migrate -c config/settings.yml # settings.yml 配置数据库信息,执行数据库迁移
./go-admin server -c config/settings.yml # 服务启动
# 前端项目部署
cd go-admin-ui
yarn install # 安装依赖包
npm run dev # 开发模式
npm run build:prod # 生产环境 build
# 执行完就能访问了
3,重点:如何增加自己的功能
# 这是五分钟以外的事情了,我就做个城市管理的demo
# 服务端方向:教你一个小技巧,做业务需求以路由为起点
# 1,新增路由: 路由路径go-admin/app/admin/router
cd app/admin/router
vim province.go # 我是把城市的东西都扔这了,其实可以分开,复制其他的路由文件
# 这是导入的东西,可以自己在做定义
import (
"github.com/gin-gonic/gin"
jwt "github.com/go-admin-team/go-admin-core/sdk/pkg/jwtauth"
"go-admin/app/admin/apis"
"go-admin/common/middleware"
)
# 需认证的路由代码 还有一种可以不需要认证的,routerCheckRole和noCheck都在router.go里
func init() {
routerCheckRole = append(routerCheckRole, registerProvinceRouter)
}
func registerProvinceRouter(v1 *gin.RouterGroup, authMiddleware *jwt.GinJWTMiddleware) {
api := apis.Province{}
r := v1.Group("/city").Use(authMiddleware.MiddlewareFunc()).Use(middleware.AuthCheckRole())
{
r.GET("", api.GetPage)
r.GET("/:id", api.GetCity)
r.POST("", api.InsertCity)
r.PUT("", api.UpdateCity)
r.DELETE("", api.DeleteCity)
}
r1 := v1.Group("/province").Use(authMiddleware.MiddlewareFunc()).Use(middleware.AuthCheckRole())
{
r1.GET("/:id", api.Get) // ok
r1.POST("", api.Insert) // ok
r1.PUT("", api.Update) // ok
r1.DELETE("", api.Delete)
}
}
#2,定义接口:这是我看的最惊艳的地方,抽象出整个RunTime,然后在Http请求中将整个抽象的实现进行整合。api接口路径:go-admin/app/admin/apis
vim province.go # 可以和路由文件同名,识别度高
import (
"github.com/gin-gonic/gin"
"github.com/gin-gonic/gin/binding" # gin框架http参数的抽象定义
"go-admin/app/admin/models" # 数据模型,这里定义的是你写的 gorm 的东西
"go-admin/app/admin/service" # 模型查询方法
"go-admin/app/admin/service/dto" # dto 放的基本是请求参数定义
"github.com/go-admin-team/go-admin-core/sdk/api" # 这个api放的就是RunTime到了Http的核心,关注头部结构体
"github.com/go-admin-team/go-admin-core/sdk/pkg/jwtauth/user" # jwt 鉴权
)
# 获取城市城市列表
func (p Province) GetPage(c *gin.Context) {
s := service.City{} # service 的 City 我会在下面写,作用是绑定模型查询
req := dto.CityGetPageReq{} # 请求参数模型 在service/dto下面
err := p.MakeContext(c). // 绑定上下文,数据库日志权限都在这,必须加
MakeOrm(). // 初始化Gorm 这里需要改造,现在只能是单库,作者估计也没想好怎么加,我给配置文件加了两个数据库配置,然后在handler里面将上下文的key他这里是用*改成read和write也能做读写分离,但不是最优解,这个等待好思路
Bind(&req, binding.Form). # 参数解析,binding 有多种抽象,各个实现都不同,具体看实现了
MakeService(&s.Service). # 绑定模型查询服务
Errors # error
if err != nil {
p.Logger.Error(err) # 日志信息
p.Error(500, err, err.Error()) # 这里就是Response了,作者将response做了封装
return
}
//数据权限检查
list := make([]models.Province, 0) # 这里就是返回的数据结构了,并不是一定要使用models的东西,你可以自己封装一个dto同级的response,正好对应request和response
var count int64 # 分页用的 total
err = s.GetPage(&req, &list, &count) # 查询实体逻辑
if err != nil {
p.Error(500, err, "查询失败")
return
}
# 跟上面的Error一样的
p.PageOK(list, int(count), req.GetPageIndex(), req.GetPageSize(), "查询成功")
}
# 3,接下来就是service,也就是上面的City的定义,路径:go-admin/app/admin/service
vim city.go
import (
"github.com/go-admin-team/go-admin-core/sdk/service" # 这里面也是一个接口,封装数据库实例,多库就是要改这里,还有日志,错误信息之类,都可以加,看自己使用
"go-admin/app/admin/models" # 模型
"go-admin/app/admin/service/dto" # 查询参数
cDto "go-admin/common/dto" # 通用查询结构,分页各种条件封装,这块对应的是dto里面的请求参数,参数里面加了各种条件然后再去cDto里面用反射组装了sql
"errors"
"gorm.io/gorm"
)
type City struct {
service.Service
}
// GetPage 获取city列表
func (e *City) GetPage(c *dto.CityGetPageReq, list *[]models.Province, count *int64) error {
var err error
var data models.Province # 这模型是专门做绑定的
err = e.Orm.Debug().Model(&data).Preload("City")./*Preload("City.CityArea").*/
Scopes(
cDto.MakeCondition(c.GetNeedSearch()),
cDto.Paginate(c.GetPageSize(), c.GetPageIndex()),
).
Find(list).Limit(-1).Offset(-1).
Count(count).Error # gorm 的用法我就不多介绍了
if err != nil {
e.Log.Errorf("Service GetCityPage error:%s", err)
return err
}
return nil
}
# 4,接下来看一下dto的定义,路径go-admin/app/admin/service/dto
vim city.go
import (
"go-admin/app/admin/models" # 模型
"go-admin/common/dto" # common 的 dto 放了一些通用查询排序,分页参数之类的,用的着就加
common "go-admin/common/models" # 模型通用字段 id create_by之类
)
// CityGetPageReq 功能列表请求参数
type CityGetPageReq struct {
dto.Pagination `search:"-"` # search 就是 上文提到的将会被反射使用的tag
Name string `form:"name" search:"type:contains;column:name;table:province" comment:"名称"` # form 就是表单参数
Pinyin string `form:"pinyin" search:"type:contains;column:pinyin;table:province" comment:"拼音"` # type,column,table,除了type会分多钟,column,table跟随语义
// CityOrder # 排序参数 ,看需求
}
type CityOrder struct {
TitleOrder string `search:"type:order;column:title;table:sys_api" form:"titleOrder"`
PathOrder string `search:"type:order;column:path;table:sys_api" form:"pathOrder"`
CreatedAtOrder string `search:"type:order;column:created_at;table:sys_api" form:"createdAtOrder"`
}
# 5,顺序好像有点问题,其实路由过后就应该做models定义,路径go-admin/app/admin/models
vim city.go
import (
"go-admin/common/models" # 下面用的呢
)
type City struct {
models.Model
Name string `json:"name" gorm:"size:128;comment:name"`
Fullname string `json:"fullname" gorm:"size:128;comment:标题"`
ProvinceId int `json:"provinceId" gorm:"column:provinceId;size:128;comment:地址"`
DistrictId int `json:"districtId" gorm:"column:districtId;size:16;comment:区域ID"`
CityPy string `json:"cityPy" gorm:"column:cityPy;size:16;comment:城市拼音"`
Py string `json:"py" gorm:"column:py;size:16;comment:短拼"`
Pinyin string `json:"pinyin" gorm:"column:pinyin;size:16;comment:全拼"`
Longitude string `json:"longitude" gorm:"column:longitude;size:16;comment:经度"`
Latitude string `json:"latitude" gorm:"column:latitude;size:16;comment:纬度"`
IsHot int `json:"isHot" gorm:"column:isHot;size:16;comment:是否热门"`
CityArea []CityArea `json:"city_area"`
models.ModelTime # 时间,逻辑删除也在这
models.ControlBy # 创建更新账号
}
func (City) TableName() string {
return "city"
}
# 增加更新这里用的着,可以直接把request绑定到models上
func (e *City) Generate() models.ActiveRecord {
o := *e
return &o
}
# 取更新后的id,增加不会返回,还没找到原因,但是到这肯定是够用了
func (e *City) GetId() interface{} {
return e.Id
}
# 6,我把整个城市管理的模型给大家发一下,上面有城市的了,代码就不发了太多了,逻辑写法基本没有区别,复制粘贴就可以快速实现你的后台功能
# 城区
type CityArea struct {
Id int `json:"id" gorm:"primaryKey;autoIncrement;comment:主键编码"`
Code string `json:"code" gorm:"size:128;comment:code"`
Fullname string `json:"fullname" gorm:"size:128;comment:全名称"`
Pinyin string `json:"pinyin" gorm:"size:128;comment:完整拼音"`
Py string `json:"py" gorm:"size:16;comment:短拼音"`
CityId string `json:"cityId" gorm:"column:cityId;size:16;comment:城市id"`
Longitude string `json:"longitude" gorm:"size:16;comment:经度"`
Latitude string `json:"latitude" gorm:"size:16;comment:纬度"`
Rank string `json:"rank" gorm:"size:16;comment:排序"`
models.ModelTime
models.ControlBy
}
# 省份
type Province struct {
models.Model
Name string `json:"name" gorm:"size:128;comment:name"`
Pinyin string `json:"pinyin" gorm:"size:128;comment:拼音"`
Pyshort string `json:"pyshort" gorm:"size:128;comment:短拼音"`
DistrictId int `json:"districtId" gorm:"column:districtId;size:16;comment:地区ID"`
Sort string `json:"sort" gorm:"size:16;comment:排序"`
City []City `json:"city"`
models.ModelTime
models.ControlBy
}
# 7,此止:后台的基本功能就可以了,重新编译启动后,用postman访问一下你的新接口
# 前端方向:也是以路由为起点,千万记得路由起点。
# 1,定义路由
cd go-admin-ui
npm run dev
# 接口路径:go-admin-ui/src/api复制粘贴一个
vim city.js
import request from '@/utils/request'
// 查询provinnce-city列表
export function listCityApi(query) {
return request({
url: '/api/v1/city',
method: 'get',
params: query
})
} # 我这都是打样,都一样的写法
# 2,定义页面:这个页面需要和后台的菜单管理做对应,这样才能完整的使用到权限管理。假如说我是二级目录,那么创建跟系统管理的菜单:内容管理<目录类型,路由路径 /cms(这个cms就是你将来在iviews下面要加的顶级目录)组件路径:顶级的都是Layout,要用左边和上边的公共组件> -- 城市管理<菜单类型,路由路径 /cms/city(这个cms就是你将来在iviews下面要加的顶级目录)组件路径:/cms/city/index>,再去index里面去制作你的页面和接口的逻辑
# 3,到这就可以测试了。下面看下最后的实现效果。
4,结束语:不加班是提高生产力的唯一动力。