最近在用Go 的gin框架重构之前PHP开发的老项目,由于基础不扎实,打算从零开始进行开发,在写Model和Service时感觉效率比较低,并且大量代码重复,所以就自己用template模板来实现代码的生成。
其中遇到一些问题,记录一下。
一:在使用模板时不能使用模板定义标签如
{{define "index/index.html"}}
{{end}}
上述标签如果存在则获取不到模板数据
代码生成模板的正确写法如下:
//model.tmpl
package model
import (
"fmt"
"gin-icqqg/config"
"github.com/gin-gonic/gin"
)
//{{.Model}} {{.Name}}表
type {{.Model}} struct {
ID int64 `gorm:"column:id;primaryKey;autoIncrement;type:int(11);" json:"id,omitempty"`
{{- range $i,$v:=.Filed}}
{{$v.Name}} {{$v.Type}} `gorm:"column:{{$v.Column}};type:{{$v.SqlType}}({{$v.Size}});" json:"{{$v.Column}},omitempty"` //{{$v.comment}}
{{- end}}
CreatedAt *LocalTime `gorm:"column:created_at" json:"created_at,omitempty"`
UpdatedAt *LocalTime `gorm:"column:updated_at" json:"updated_at,omitempty"`
DeletedAt *LocalTime `gorm:"column:deleted_at" json:"-,omitempty"`
}
type Add{{.Model}} struct {
{{- range $i,$v:=.Filed }}
{{$v.Name}} {{$v.Type}} `form:"{{$v.Column}}" json:"{{$v.Column}},omitempty"`//{{$v.Comment}}
{{- end}}
}
func New{{.Model}}() *{{.Model}} {
//自动迁移
db.AutoMigrate(&{{.Model}}{})
if !db.Migrator().HasTable(&{{.Model}}{}) {
//创建表
db.Set("gorm:ENGINE", "InnoDB").Migrator().CreateTable(&{{.Model}}{})
}
return &{{.Model}}{}
}
func (m *{{.Model}}) TableName() string {
return "{{.TableName}}"
}
//List 获取{{.Name}}列表展示的
//get
func (m *{{.Model}}) List(c *gin.Context) {
var {{.Model}}List []{{.Model}}
err := db.Model(&{{.Model}}{}).Find(&{{.Model}}List).Error
if err != nil {
config.ErrorLog(fmt.Sprintf("%v", err))
c.JSON(200, gin.H{"code": 500, "msg": "发送错误"})
} else {
c.JSON(200, gin.H{"code": 200, "data": {{.Model}}List})
}
c.Abort()
}
//Add{{.Model}} 新增{{.Name}}
//post
func (m *{{.Model}}) Add{{.Model}}( c *gin.Context) {
var add Add{{.Model}}
err := c.ShouldBind(&add)
{{- range $i,$v:=.Filed }}
m.{{$v.Name}} = add.{{$v.Name}}
{{- end}}
err = db.Model(&{{.Model}}{}).Create(&m).Error
if err != nil {
config.ErrorLog(fmt.Sprintf("%v", err))
c.JSON(200, gin.H{"code": 500, "msg": "failed"})
} else {
c.JSON(200, gin.H{"code": 200, "msg": "success"})
}
c.Abort()
}
//Delete{{.Model}} 通过ID删除{{.Name}}
//delete
func (m *{{.Model}}) Delete{{.Model}}(id string, c *gin.Context) {
err := db.Model(&{{.Model}}{}).Where("id = ?", id).Delete(m).Error
if err != nil {
config.ErrorLog(fmt.Sprintf("%v", err))
c.JSON(200, gin.H{"code": 500, "msg": "failed"})
} else {
c.JSON(200, gin.H{"code": 200, "msg": "success"})
}
c.Abort()
}
//Update{{.Model}} 修改{{.Name}}
//put
func (m *{{.Model}}) Update{{.Model}}(id string,c *gin.Context) {
var add Add{{.Model}}
err := c.ShouldBind(&add)
{{- range $i,$v:=.Filed }}
m.{{$v.Name}} = add.{{$v.Name}}
{{- end}}
if err != nil {
config.ErrorLog(fmt.Sprintf("%v", err))
c.JSON(200, gin.H{"code": 500, "msg": "failed"})
}else{
err := db.Model(&{{.Model}}{}).Where("id = ?", id).Updates(m).Error
if err != nil {
config.ErrorLog(fmt.Sprintf("%v", err))
c.JSON(200, gin.H{"code": 500, "msg": "failed"})
} else {
c.JSON(200, gin.H{"code": 200, "msg": "success"})
}
}
c.Abort()
}
//GetOne 通过ID获取信息
//get
func (m *{{.Model}}) GetOne(id string, c *gin.Context) {
err := db.Model(&{{.Model}}{}).Where("id = ?", id).First(m).Error
if err != nil {
config.ErrorLog(fmt.Sprintf("%v", err))
c.JSON(200, gin.H{"code": 500, "msg": "failed"})
} else {
c.JSON(200, gin.H{"code": 200, "data": m})
}
c.Abort()
}
接下来的是生成Service代码
//service.tmpl 代码
package web
import (
"gin-icqqg/model"
"github.com/gin-gonic/gin"
)
type {{.Model}} struct {
{{- range $i,$v:=.Filed}}
{{$v.Name}} {{$v.Type}} `form:"{{$v.Column}}" json:"{{$v.Column}},omitempty"` //{{$v.Comment}}
{{- end}}
}
func New{{.Model}}() *{{.Model}} {
return &{{.Model}}{}
}
//List 数据列表
//@Tags {{.Title}}模块
//@Summary {{.Name}}列表
//@Param token header string true "token"
//@Produce json
// @Success 200 {object} []model.{{.Model}} "{"code":200,"data":[]model.{{.Model}}}"
// @Failure 400 {object} response.Code "请求错误"
// @Failure 500 {object} response.Code "内部错误"
//@Router /api/web/{{.Path}}List [get]
func (a *{{.Model}}) List(c *gin.Context) {
service := model.New{{.Model}}()
service.List(c)
return
}
//Get 通过ID获取角色信息
//@Tags {{.Title}}模块
//@Summary 获取{{.Name}}信息
//@Param token header string true "token"
//@Param id path int true "ID"
//@Produce json
// @Success 200 {object} model.{{.Model}} "{"code":200,"data":model.{{.Model}}}"
// @Failure 400 {object} response.Code "请求错误"
// @Failure 500 {object} response.Code "内部错误"
//@Router /api/web/{{.Path}}/{id} [get]
func (a *{{.Model}}) Get(c *gin.Context) {
id := c.Param("id")
if id == "" {
c.JSON(400, gin.H{"code": 400, "msg": "参数有误"})
} else {
service := model.New{{.Model}}()
service.GetOne(id, c)
}
return
}
//Add 新增{{.Name}}信息
//@Tags {{.Title}}模块
//@Summary 添加{{.Name}}信息
//@Param token header string true "token"
{{- range $i,$v:=.Filed}}
//@Param {{$v.Column}} formData {{$v.Type}} true "{{$v.Comment}}"
{{- end}}
//@Produce json
// @Success 200 {object} response.Code "{"code":200,"msg":"success"}"
// @Failure 400 {object} response.Code "请求错误"
// @Failure 500 {object} response.Code "内部错误"
//@Router /api/web/{{.Path}} [post]
func (a *{{.Model}}) Add(c *gin.Context) {
service := model.New{{.Model}}()
service.Add{{.Model}}(c)
return
}
//Edit 修改{{.Name}}信息
//@Tags {{.Title}}模块
//@Summary 修改{{.Name}}信息
//@Param token header string true "token"
{{- range $i,$v:=.Filed}}
//@Param {{$v.Column}} formData {{$v.Type}} true "{{$v.Comment}}"
{{- end}}
//@Produce json
// @Success 200 {object} response.Code "{"code":200,"msg":"success"}"
// @Failure 400 {object} response.Code "请求错误"
// @Failure 500 {object} response.Code "内部错误"
//@Router /api/web/{{.Path}}/{id}/edit [put]
func (a *{{.Model}}) Edit(c *gin.Context) {
id := c.Param("id")
if id == "" {
c.JSON(400, gin.H{"code": 400, "msg": "参数有误"})
c.Abort()
return
}
service := model.New{{.Model}}()
service.Update{{.Model}}(id,c)
return
}
//Delete 删除{{.Name}}信息
//@Tags {{.Title}}模块
//@Summary 删除{{.Name}}信息
//@Param token header string true "token"
//@Param id path int true "ID"
//@Produce json
// @Success 200 {object} response.Code "{"code":200,"msg":"success"}"
// @Failure 400 {object} response.Code "请求错误"
// @Failure 500 {object} response.Code "内部错误"
//@Router /api/web/{{.Path}}/{id} [delete]
func (a *{{.Model}}) Delete(c *gin.Context) {
id := c.Param("id")
if id == "" {
c.JSON(400, gin.H{"code": 400, "msg": "参数有误"})
c.Abort()
return
}
service := model.New{{.Model}}()
service.Delete{{.Model}}(id, c)
return
}
接下来解析模板并且将文件保存到指定文件夹中:
func Index(c *gin.Context) {
Model := "Product"
var Filed []map[string]interface{}
list1 := map[string]interface{}{"Name": "Name", "Type": "string", "Column": "name", "SqlType": "varchar", "Size": "50", "Comment": "名称"}
list2 := map[string]interface{}{"Name": "Title", "Type": "string", "Column": "title", "SqlType": "varchar", "Size": "50", "Comment": "标题"}
list3 := map[string]interface{}{"Name": "Version", "Type": "string", "Column": "version", "SqlType": "varchar", "Size": "50", "Comment": "型号"}
Filed = append(Filed, list1, list2, list3)
Data := map[string]interface{}{
"Model": Model,
"Filed": Filed,
"TableName": "table_product",
"Name": "产品",
"Title": "后台产品",
"Path": "product",
}
tempModel, _ := template.New("model.tmpl").ParseFiles("resource/view/admin/model.tmpl")
tempService, _ := template.New("service.tmpl").ParseFiles("resource/view/admin/service.tmpl")
var ModelBytes bytes.Buffer
var ServiceBytes bytes.Buffer
if err := tempModel.Execute(&ModelBytes, Data); err != nil {
c.String(http.StatusInternalServerError, fmt.Sprintf("Error executing template: %v", err))
return
}
if err := tempService.Execute(&ServiceBytes, Data); err != nil {
c.String(http.StatusInternalServerError, fmt.Sprintf("Error executing template: %v", err))
return
}
err := ioutil.WriteFile("model/"+strings.ToLower(Model)+".go", ModelBytes.Bytes(), 0777)
err = ioutil.WriteFile("api/web/"+strings.ToLower(Model)+".go", ServiceBytes.Bytes(), 0777)
if err != nil {
config.ErrorLog(fmt.Sprintf("%v", err))
}
c.JSON(http.StatusOK, gin.H{"code": 200, "msg": "模板输出成功"})
}
上述模板文件集成了swagger Api文档注解,控制台swag init 即可生成对应的接口文档。
经过上述三个操作,代码已经生成了,访问时直接在路由文件中添加对应的路由地址即可。