package main import ( "bytes" "dsBaseWeb/Utils/CommonUtil" "dsBaseWeb/Utils/ConfigUtil" "dsBaseWeb/Utils/DbUtil" "dsBaseWeb/Utils/FileUtil" "encoding/json" "fmt" "github.com/ghodss/yaml" "github.com/iancoleman/orderedmap" "log" "sort" "strings" "text/template" ) var db = DbUtil.Engine type Item struct { Description interface{} `json:"description,omitempty"` Type string `json:"type"` Example interface{} `json:"example,omitempty"` Items interface{} `json:"items,omitempty"` } type Properties struct { Success Item `json:"success"` Count Item `json:"count"` List Item `json:"list"` Message Item `json:"message"` } type RootDefinition struct { Type string `json:"type"` Properties Properties `json:"properties"` } type BigStruct struct { Definitions interface{} `json:"definitions"` Host string `json:"host"` Info interface{} `json:"info"` Paths interface{} `json:"paths"` Swagger string `json:"swagger"` } type SortStruct struct { InterfaceName string `json:"interfacename"` Tags string `json:"tags"` SortId float64 `json:"sort_id"` Body interface{} `json:"body"` } /** 功能:结构体排序通用办法 按标签排序 */ type SortTagsStructSlice []SortStruct func (a SortTagsStructSlice) Len() int { return len(a) } func (a SortTagsStructSlice) Swap(i, j int) { a[i], a[j] = a[j], a[i] } func (a SortTagsStructSlice) Less(i, j int) bool { if a[i].Tags == a[j].Tags { return a[i].SortId < a[j].SortId } return a[i].Tags < a[j].Tags } /** 功能:处理排序字段 作者:黄海 时间:2020-05-28 */ func DoSort(jsonStr string) string { //原始map数据,后期修改的依据 var d0 map[string]interface{} json.Unmarshal([]byte(jsonStr), &d0) var bigStruct BigStruct bigStruct.Swagger = d0["swagger"].(string) bigStruct.Info = d0["info"] bigStruct.Host = d0["host"].(string) bigStruct.Definitions = d0["definitions"] //2、我们关心paths d1 := d0["paths"].(map[string]interface{}) var arr = make([]SortStruct, 0) for k, v := range d1 { //k:接口名称,d2:接口名称后面的内容 d2 := v.(map[string]interface{}) //正确判断方法 _, ok := d2["post"] var httpType map[string]interface{} if ok { //post接口 httpType = d2["post"].(map[string]interface{}) } else { //get接口 httpType = d2["get"].(map[string]interface{}) } //按httpType["Tags"]进行一次排序,然后输出 c1 := httpType["tags"].([]interface{}) var s SortStruct s.InterfaceName = k s.Tags = c1[0].(string) //排序号 if httpType["x-sort"] != nil { s.SortId = httpType["x-sort"].([]interface{})[0].(float64) } else { s.SortId = 9999 } s.Body = d2 //增加到数组中 arr = append(arr, s) } sort.Sort(SortTagsStructSlice(arr)) //有序map集合 o := orderedmap.New() for i := range arr { o.Set(arr[i].InterfaceName, arr[i].Body) } //进行结构体赋值 bigStruct.Paths = o //转为json字符串 jsonBytes, _ := json.Marshal(bigStruct) //美化 var str bytes.Buffer _ = json.Indent(&str, jsonBytes, "", " ") return str.String() } func Xswagger(){ //1、手动执行一次swag init CommonUtil.Exec("swag", "init") //3、解析json文件,找到需要本程序代码扩展的配置接口 jsonBody := CommonUtil.ReadSwaggerJson() //读取doc目录下的swagger.json m := jsonBody.(map[string]interface{}) n := m["paths"].(map[string]interface{}) for k, v := range n { //遍历所有接口 t := v.(map[string]interface{}) httpType := "post" //非空检查器 if t["get"] != nil { httpType = "get" } //接口 r1 := t[httpType].(map[string]interface{}) var extendList []interface{} if r1["x-extendswaggerfield"] != nil { extendList = r1["x-extendswaggerfield"].([]interface{}) } var removeList []interface{} if r1["x-removeswaggerfield"] != nil { removeList = r1["x-removeswaggerfield"].([]interface{}) } //result结构体的名称 k2 := strings.Replace(k[1:], "/", ".", -1) //对应的表 tableName := r1["x-tablename"] if tableName == nil { continue } //准备替换 replaceContent := "#/definitions/" + k2 //找到此接口的schema-->ref c := r1["responses"].(map[string]interface{}) d := c["200"].(map[string]interface{}) d = d["schema"].(map[string]interface{}) d["$ref"] = replaceContent //添加返回结构体 var prop Properties var item Item item.Type = "integer" item.Description = "一共有多少条" item.Example = "1" item.Items = nil prop.Count = item item.Type = "boolean" item.Description = "是否成功" item.Example = "true" item.Items = nil prop.Success = item /***************************************************************************/ table := tableName.([]interface{})[0].(string) //(1)根据数据表表名,获取示例数据 sql := "select * from " + table + " limit 1" sampleDataList, _ := db.SQL(sql).Query().List() if len(sampleDataList)==0{ log.Fatalln("数据表"+table+"中手动添些数据吧,要不没法提供示例数据~~~") } //(2)添加数据库字段描述 sql = "select column_name,column_comment,data_type from information_schema.columns where table_name=? and table_schema=?" commentList, _ := db.SQL(sql, table, ConfigUtil.MysqlDbName).Query().List() item.Type = "array" item.Description = "数据列表" item.Example = nil // 终级[]map mProperties := make(map[string]interface{}, 1) //移除指定的字段 var arr []string for t := 0; t < len(removeList); t++ { arr = append(arr, removeList[t].(string)) } //手工添加 arr = append(arr, "last_updated_time") //组装 for p := 0; p < len(commentList); p++ { columnName := commentList[p]["column_name"].(string) if CommonUtil.IsContain(arr, columnName) { continue } columnComment := commentList[p]["column_comment"].(string) dataType := commentList[p]["data_type"].(string) _m2 := make(map[string]interface{}, 1) _m2["description"] = columnComment if strings.Index(dataType, "char") >= 0 { _m2["type"] = "string" } else if strings.Index(dataType, "int") >= 0 { _m2["type"] = "integer" } else if strings.Index(dataType, "float") >= 0 { _m2["type"] = "number" } else { _m2["type"] = dataType } if len(sampleDataList)==0{ fmt.Println(len(sampleDataList)) } _m2["example"] = sampleDataList[0][columnName] mProperties[columnName] = _m2 } //添加一些扩展的字段类型说明 for i := 0; i < len(extendList); i++ { var b = extendList[i].(map[string]interface{}) columnComment := b["column_comment"].(string) columnName := b["column_name"].(string) sampleData := b["sample_data"].(string) _m2 := make(map[string]interface{}, 1) _m2["description"] = columnComment _m2["example"] = sampleData _m2["type"] = "string" mProperties[columnName] = _m2 } resultProperties := make(map[string]interface{}, 1) resultProperties["properties"] = mProperties //如果是Get,那么实例的对象而不是数组 item.Items = resultProperties item.Example = nil item.Description = nil prop.List = item /***************************************************************************/ //(2)根据手动扩展的列名,获取字段的名称和默认值 for i := 0; i < len(extendList); i++ { var b = extendList[i].(map[string]interface{}) extendField := b["column_name"].(string) extendSample := b["sample_data"].(string) for j := 0; j < len(sampleDataList); j++ { sampleDataList[j][extendField] = extendSample } } item.Type = "string" item.Description = "返回的消息" item.Example = "操作成功" item.Items = nil prop.Message = item var rootDefinition RootDefinition rootDefinition.Properties = prop rootDefinition.Type = "object" m["definitions"].(map[string]interface{})[k2] = rootDefinition } //修改Model.Res为固定值 c := m["definitions"].(map[string]interface{}) d := c["Model.Res"].(map[string]interface{}) j := `{ "success": { "description": "是否成功", "type": "boolean", "example": "true" }, "message": { "description": "返回的消息", "type": "string", "example": "操作成功" } }` var dat map[string]interface{} if err := json.Unmarshal([]byte(j), &dat); err == nil { d["properties"] = dat } byteValue, _ := json.Marshal(m) var str bytes.Buffer _ = json.Indent(&str, byteValue, "", " ") //处理排序字段 afterJson := DoSort(str.String()) //回写json文件 FileUtil.WriteFileContent("./docs/swagger.json", afterJson) //转为yaml y, err := yaml.JSONToYAML([]byte(afterJson)) if err != nil { fmt.Printf("err: %v\n", err) return } //回写swagger.yaml文件 FileUtil.WriteFileContent("./docs/swagger.yaml", string(y)) //生成docs.go //调用模板 filesName := "./docs/docs.go.template" t, err := template.ParseFiles(filesName) if err != nil { log.Fatalln("parse file err:", err) return } buf := new(bytes.Buffer) var p = map[string]interface{}{ "json": afterJson, } if err := t.Execute(buf, p); err != nil { log.Fatal("There was an error:", err.Error()) } var content = buf.String() //写入文件 FileUtil.WriteFileContent("./docs/docs.go", content) fmt.Println("恭喜,所有文件成功生成!") } func main() { Xswagger() }