衔接上文,继续开发。这一章主要是优化应用结构。
上一篇文章我们优化了配置结构,实现了配置项的统一管理。
这一章主要实现项目的优化,主要是下面几点:
- 错误提前返回、统一返回方法
- 从routers中抽离service,减少routers/api的逻辑。
- 增加GORM错误判断,增加内部错误码,让错误提示更明确。
这一章内容比较长…
编写错误返回方法
错误提前返回,则必然会入侵 c.JSON。
1. 在pkg目录下,新建app文件夹,新建request.go文件,内容如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
package app import ( "ginBlog/pkg/logging" "github.com/astaxie/beego/validation" ) //MarkErros 输出错误日志 func MarkErros(errors []*validation.Error) { for _, err := range errors { logging.Info(err.Key, err.Message) } return } |
2. 在app文件夹下新建 response.go 文件,内容如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 |
package app import ( "ginBlog/pkg/e" "github.com/gin-gonic/gin" ) //Gin 封装gin.Context上下文 type Gin struct { C *gin.Context } //Response 结构体 type Response struct { Code int `json:"code"` Msg string `json:"msg"` Data interface{} `json:"data"` } //Response 设置gin.JSON func (g *Gin) Response( httpCode int, errCode int, data interface{}, ) { g.C.JSON(httpCode, Response{ Code: errCode, Msg: e.GetMsg(errCode), Data: data, }) } |
抽离service,优化routers
接下来的主要任务是针对Tag和Article都实现下面三个步骤。
- 修改models下的数据库操作,让GORM的操作有错误码返回
- 实现service,数据库操作都在这一层完成(包括后面接入Redis)。
- 优化routers
我们应该先实现Tag相关的修改,然后再实现Article相关修改。因为Article里面依赖了Tag。
Tag相关
1. 修改models目录下,tag.go文件,
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 |
package models //Tag 标签 type Tag struct { Model Name string `json:"name"` CreatedBy string `json:"created_by"` ModifiedBy string `json:"modified_by"` State int `json:"state"` } //GetTag 获取标签 // id tag.ID int 标签ID func GetTag(id int) (tag *Tag, err error) { err = db.Select("id").Where("id = ? AND deleted_on = ?", id, 0).First(tag).Error return } //GetTags 获取多个标签 func GetTags( pageNum int, pageSize int, maps interface{}, ) (tags []*Tag, err error) { err = db.Where(maps).Where("deleted_on = ?", 0).Offset(pageNum).Limit(pageSize).Find(&tags).Error return } //GetTagTotal 获取标签总数 func GetTagTotal( maps interface{}, ) (count int64, err error) { err = db.Model(&Tag{}).Where(maps).Where("deleted_on = ?", 0).Count(&count).Error return } //IsExistTagByName 判断标签是否存在 // name tag.Name string 标签名称 // ret: bool 如果标签存在返回true, 否则返回false func IsExistTagByName(name string) (bool, error) { var tag Tag err := db.Select("id").Where("name = ? AND deleted_on = ?", name, 0).First(&tag).Error return tag.ID > 0, err } //IsExistTagByID 判断标签是否存在 // id tag.ID int 标签ID // ret: bool 如果标签存在返回true,否则返回false func IsExistTagByID(id int) (bool, error) { var tag Tag err := db.Select("id").Where("id = ? AND deleted_on = ?", id, 0).First(&tag).Error return tag.ID > 0, err } //AddTag 新增标签 func AddTag( data map[string]interface{}, ) error { return db.Create(&Tag{ Name: data["name"].(string), State: data["state"].(int), CreatedBy: data["created_by"].(string), }).Error } //EditTag 修改标签 // 不做deleted_on判断,可以通过接口将deleted_on设置为0(恢复数据) func EditTag( data map[string]interface{}, ) error { return db.Model(&Tag{}).Where("id = ?", data["id"]).Updates(data).Error } //DeleteTag 删除标签 // 实现软删除 func DeleteTag(id int) error { return db.Where("id = ?", id).Delete(&Tag{}).Error } //CleanAllTag 清理标签 // 函数会清理所有已经被软删除的标签 func CleanAllTag() error { return db.Unscoped().Where("deleted_on != ?", 0).Delete(&Tag{}).Error } |
2. 项目根目录新建service文件夹,文件夹内新建tagservice文件夹,新建tag.go文件,内容如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 |
package tagservice import ( "context" "encoding/json" "ginBlog/models" "ginBlog/pkg/gredis" "ginBlog/pkg/logging" "ginBlog/service/cacheservice" ) //Tag 缓存数据结构体 // 最重要的是支持和models交互 type Tag struct { ID int Name string CreatedBy string ModifiedBy string State int PageNum int PageSize int } //ExistByName 根据名称判断标签是否存在 func (t *Tag) ExistByName() (bool, error) { return models.IsExistTagByName(t.Name) } //ExistByID 根据ID判断标签是否存在 func (t *Tag) ExistByID() (bool, error) { return models.IsExistTagByID(t.ID) } //Add 新增标签 func (t *Tag) Add() error { err := models.AddTag(map[string]interface{}{ "name": t.Name, "created_by": t.CreatedBy, "state": t.State, }) return err } //Edit 修改标签 func (t *Tag) Edit() error { err := models.EditTag(map[string]interface{}{ "id": t.ID, "name": t.Name, "modified_by": t.ModifiedBy, "state": t.State, }) return err } //Delete 删除标签 func (t *Tag) Delete() error { err := models.DeleteTag(t.ID) return err } //Get 根据ID获取标签 func (t *Tag) Get() (*models.Tag, error) { //查找数据库 tag, err := models.GetTag(t.ID) if err != nil { return nil, err } return tag, nil } //GetAll 根据筛选条件获取Tag func (t *Tag) GetAll() ([]*models.Tag, error) { //查找数据库 tags, err := models.GetTags(t.PageNum, t.PageSize, t.getMaps()) if err != nil { return nil, err } return tags, nil } //Count 返回符合条件的Tag数量 func (t *Tag) Count() (count int64, err error) { count, err = models.GetTagTotal(t.getMaps()) return } func (t *Tag) getMaps() map[string]interface{} { maps := make(map[string]interface{}) maps["deleted_on"] = 0 if t.Name != "" { maps["name"] = t.Name } if t.State != -1 { maps["state"] = t.State } return maps } |
3. 同时修改routers/api/v1/tag.go 文件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 |
package v1 import ( "ginBlog/pkg/app" "ginBlog/pkg/e" "ginBlog/pkg/setting" "ginBlog/pkg/util" "ginBlog/service/tagservice" "net/http" "github.com/astaxie/beego/validation" "github.com/gin-gonic/gin" "github.com/unknwon/com" ) //GetTags 获取多个标签 func GetTags(c *gin.Context) { appG := app.Gin{C: c} valid := validation.Validation{} name := c.Query("name") var state int = -1 if arg := c.Query("state"); arg != "" { state = com.StrTo(arg).MustInt() valid.Range(state, 0, 1, "state").Message("状态只允许0或1") } if valid.HasErrors() { app.MarkErros(valid.Errors) appG.Response(http.StatusBadRequest, e.InvalidParams, nil) return } tag := tagservice.Tag{ Name: name, State: state, PageNum: util.GetPage(c), PageSize: setting.App.PageSize, } //获取标签数量 tagsCount, err := tag.Count() if err != nil { appG.Response(http.StatusInternalServerError, e.ErrorCountArticleFailed, nil) return } //获取标签信息 tagsData, err := tag.GetAll() if err != nil { appG.Response(http.StatusInternalServerError, e.ErrorGetTagsFailed, nil) return } //返回数据 data := make(map[string]interface{}) data["lists"] = tagsData data["total"] = tagsCount appG.Response(http.StatusOK, e.Success, data) } // AddTag 新增标签 // @Summary 新增标签 // @Produce json // @Param name query string true "Name" // @Param state query int false "State" // @Param created_by query int false "CreatedBy" // @Success 200 {string} json "{"code":200,"data":{},"msg":"ok"}" // @Router /api/v1/tags [post] func AddTag(c *gin.Context) { appG := app.Gin{C: c} name := c.Query("name") state := com.StrTo(c.DefaultQuery("state", "0")).MustInt() createdBy := c.Query("created_by") valid := validation.Validation{} valid.Required(name, "name").Message("名字不能为空") valid.MaxSize(name, 100, "name").Message("名称最长为100字符") //这个长度跟随数据库字段长度 valid.Required(createdBy, "created_by").Message("创建人不能为空") valid.MaxSize(createdBy, 100, "created_by").Message("创建人最长为100字符") valid.Range(state, 0, 1, "state").Message("状态只允许0或者1") if valid.HasErrors() { app.MarkErros(valid.Errors) appG.Response(http.StatusBadRequest, e.InvalidParams, nil) return } tag := tagservice.Tag{ Name: name, CreatedBy: createdBy, State: state, } exist, err := tag.ExistByName() if err != nil { appG.Response(http.StatusInternalServerError, e.ErrorCheckTagExistFailed, nil) return } if exist { appG.Response(http.StatusOK, e.ErrorTagExist, nil) return } err = tag.Add() if err != nil { appG.Response(http.StatusInternalServerError, e.ErrorAddTagFailed, nil) return } appG.Response(http.StatusOK, e.Success, nil) } //EditTag 修改标签 func EditTag(c *gin.Context) { appG := app.Gin{C: c} id := com.StrTo(c.Param("id")).MustInt() name := c.Query("name") modifiedBy := c.Query("modified_by") valid := validation.Validation{} valid.Required(name, "name").Message("名字不能为空") valid.MaxSize(name, 100, "name").Message("名称最长为100字符") //这个长度跟随数据库字段长度 valid.Required(modifiedBy, "modified_by").Message("修改人不能为空") valid.MaxSize(modifiedBy, 100, "modified_by").Message("修改人最长为100字符") //state 这个字段可有可无,如果不存在则默认-1,存在则需要校验 var state int = -1 if arg := c.Query("state"); arg != "" { state = com.StrTo(arg).MustInt() valid.Range(state, 0, 1, "state").Message("状态只允许0或者1") } if valid.HasErrors() { app.MarkErros(valid.Errors) appG.Response(http.StatusBadRequest, e.InvalidParams, nil) return } tag := tagservice.Tag{ ID: id, Name: name, ModifiedBy: modifiedBy, State: state, } //判断标签存在 exist, err := tag.ExistByID() if err != nil { appG.Response(http.StatusInternalServerError, e.ErrorCheckTagExistFailed, nil) return } if !exist { appG.Response(http.StatusInternalServerError, e.ErrorTagNotExist, nil) return } //修改标签 err = tag.Edit() if err != nil { appG.Response(http.StatusInternalServerError, e.ErrorEditTagFailed, nil) return } appG.Response(http.StatusOK, e.Success, nil) } //DeleteTag 删除标签 func DeleteTag(c *gin.Context) { appG := app.Gin{C: c} id := com.StrTo(c.Param("id")).MustInt() valid := validation.Validation{} valid.Min(id, 1, "id").Message("ID必须大于0") if valid.HasErrors() { app.MarkErros(valid.Errors) appG.Response(http.StatusBadRequest, e.InvalidParams, nil) return } tag := tagservice.Tag{ ID: id, } //判断标签存在 exist, err := tag.ExistByID() if err != nil { appG.Response(http.StatusInternalServerError, e.ErrorCheckTagExistFailed, nil) return } if !exist { appG.Response(http.StatusInternalServerError, e.ErrorTagNotExist, nil) return } //删除标签 err = tag.Delete() if err != nil { appG.Response(http.StatusInternalServerError, e.ErrorDeleteTagFailed, nil) return } appG.Response(http.StatusOK, e.Success, nil) } |
Article相关
1. 修改models目录下的article.go文件,保证所有的数据库操作都会返回错误码。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 |
package models //Article 文章 type Article struct { Model TagID int `json:"tag_id" gorm:"index"` Tag Tag `json:"tag"` Title string `json:"title"` Desc string `json:"desc"` Content string `json:"content"` CreatedBy string `json:"created_by"` ModifiedBy string `json:"Modified_by"` State int `json:"state"` } //IsExistArticleByID 判断文章是否存在 // id article.ID int 文章ID // ret: bool 如果文章存在返回true,否则返回false func IsExistArticleByID(id int) (bool, error) { var article Article err := db.Select("id").Where("id = ?", id).Where("deleted_on = ?", 0).First(&article).Error return article.ID > 0, err } //GetArticleTotal 获取文章总数 func GetArticleTotal( maps interface{}, ) (count int64, err error) { err = db.Model(&Article{}). Where(maps). Where("deleted_on = ?", 0). Count(&count). Error return } //GetArticels 获取文章 func GetArticels( pageNum int, pageSize int, maps interface{}, ) (articles []*Article, err error) { err = db.Preload("Tag"). Where(maps). Where("deleted_on = ?", 0). Offset(pageNum). Limit(pageSize). Find(&articles). Error return articles, err } //GetArticle 获取文章 func GetArticle( id int, ) (article *Article, err error) { err = db.Preload("Tag"). Where("id = ?", id). Where("deleted_on = ?", 0). First(&article). Error return article, err } //EditArticle 更新文章 // 更新接口不判断deleted_on字段 func EditArticle( id int, data interface{}, ) error { return db.Model(&Article{}).Where("id = ?", id).Updates(data).Error } //AddArticle 新增文章 func AddArticle( data map[string]interface{}, ) error { return db.Create(&Article{ TagID: data["tag_id"].(int), Title: data["title"].(string), Desc: data["desc"].(string), Content: data["content"].(string), CreatedBy: data["created_by"].(string), State: data["state"].(int), }).Error } //DeleteArticle 删除文章 // 实现软删除 func DeleteArticle(id int) error { return db.Where("id = ?", id).Delete(Article{}).Error } //CleanAllArticle 清理文章 func CleanAllArticle() error { return db.Unscoped().Where("deleted_on != ?", 0).Delete(Article{}).Error } |
2. 项目根目录下service文件夹内新建articleservice文件夹,新建article.go文件:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 |
package articleservice import ( "context" "encoding/json" "ginBlog/models" "ginBlog/pkg/gredis" "ginBlog/pkg/logging" "ginBlog/service/cacheservice" ) //Article 结构体用于数据库交互 type Article struct { ID int TagID int Title string Desc string Content string State int CreatedBy string ModifiedBy string PageNum int PageSize int } //Add 新增文章 func (a *Article) Add() error { err := models.AddArticle(map[string]interface{}{ "tag_id": a.TagID, "title": a.Title, "desc": a.Desc, "content": a.Content, "created_by": a.CreatedBy, "state": a.State, }) return err } //Edit 修改文章 func (a *Article) Edit() error { //修改数据库内容 err := models.EditArticle(a.ID, map[string]interface{}{ "id": a.ID, //加个ID是因为之前hook用到了 "tag_id": a.TagID, "title": a.Title, "desc": a.Desc, "content": a.Content, "created_by": a.CreatedBy, "state": a.State, "modified_by": a.ModifiedBy, }) return err } //Get 根据ID获取文章 func (a *Article) Get() (*models.Article, error) { //查找数据库 article, err := models.GetArticle(a.ID) if err != nil { return nil, err } return article, nil } //GetAll 根据筛选条件获取文章 func (a *Article) GetAll() ([]*models.Article, error) { articles, err := models.GetArticels(a.PageNum, a.PageSize, a.getMaps()) return articles, err } func (a *Article) getMaps() map[string]interface{} { maps := make(map[string]interface{}) maps["deleted_on"] = 0 if a.State != -1 { maps["state"] = a.State } if a.TagID != -1 { maps["tag_id"] = a.TagID } return maps } //Delete 删除文章 func (a *Article) Delete() error { //从数据库内删除,如果删除成功,再删除缓存数据 err := models.DeleteArticle(a.ID) return err } //ExistByID 根据ID判断文章是否存在 func (a *Article) ExistByID() (bool, error) { return models.IsExistArticleByID(a.ID) } //Count 返回符合条件文章数量 func (a *Article) Count() (int64, error) { return models.GetArticleTotal(a.getMaps()) } |
这里主要实现文章数据操作相关方法,
3. 修改routers/api/v1/article.go 文件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 |
package v1 import ( "ginBlog/pkg/app" "ginBlog/pkg/e" "ginBlog/pkg/setting" "ginBlog/pkg/util" "ginBlog/service/articleservice" "ginBlog/service/tagservice" "net/http" "github.com/astaxie/beego/validation" "github.com/gin-gonic/gin" "github.com/unknwon/com" ) //GetArticle 获取单个文章 func GetArticle(c *gin.Context) { appG := app.Gin{c} id := com.StrTo(c.Param("id")).MustInt() //Valid valid := validation.Validation{} valid.Min(id, 1, "id").Message("ID必须大于0") if valid.HasErrors() { app.MarkErros(valid.Errors) appG.Response(http.StatusBadRequest, e.InvalidParams, nil) } //从数据库中获取数据 article := articleservice.Article{ID: id} exist, err := article.ExistByID() if err != nil { appG.Response(http.StatusInternalServerError, e.ErrorCheckArticleExistFailed, nil) return } if !exist { appG.Response(http.StatusOK, e.ErrorArticleNotExist, nil) return } articleData, err := article.Get() if err != nil { appG.Response(http.StatusInternalServerError, e.ErrorGetArticleFailed, nil) return } appG.Response(http.StatusOK, e.Success, articleData) } //GetArticles 获取多个文章 func GetArticles(c *gin.Context) { appG := app.Gin{c} valid := validation.Validation{} var state int = -1 if arg := c.Query("state"); arg != "" { state = com.StrTo(arg).MustInt() valid.Range(state, 0, 1, "state").Message("状态只允许0或1") } var tagID = -1 if arg := c.Query("tag_id"); arg != "" { tagID = com.StrTo(arg).MustInt() valid.Min(tagID, 1, "tag_id").Message("标签ID必须大于0") } if valid.HasErrors() { app.MarkErros(valid.Errors) appG.Response(http.StatusBadRequest, e.InvalidParams, nil) return } article := articleservice.Article{ TagID: tagID, State: state, PageNum: util.GetPage(c), PageSize: setting.App.PageSize, } //获取文章数量 atriclesCount, err := article.Count() if err != nil { appG.Response(http.StatusInternalServerError, e.ErrorCountArticleFailed, nil) return } //获取文章信息 articlesData, err := article.GetAll() if err != nil { appG.Response(http.StatusInternalServerError, e.ErrorGetArticlesFailed, nil) return } data := make(map[string]interface{}) data["lists"] = articlesData data["total"] = atriclesCount appG.Response(http.StatusOK, e.Success, data) } //AddArticle 新增文章 func AddArticle(c *gin.Context) { appG := app.Gin{c} tagID := com.StrTo(c.Query("tag_id")).MustInt() title := c.Query("title") desc := c.Query("desc") content := c.Query("content") createdBy := c.Query("created_by") state := com.StrTo(c.DefaultQuery("state", "0")).MustInt() //检查参数 valid := validation.Validation{} valid.Min(tagID, 1, "tag_id").Message("标签ID必须大于0") valid.Required(title, "title").Message("标题不能为空") valid.Required(desc, "desc").Message("简述不能为空") valid.Required(content, "content").Message("内容不能为空") valid.Required(createdBy, "created_by").Message("创建人不能为空") valid.Range(state, 0, 1, "state").Message("状态只允许0或1") if valid.HasErrors() { app.MarkErros(valid.Errors) appG.Response(http.StatusBadRequest, e.InvalidParams, nil) return } //判断Tag存在 tag := tagservice.Tag{ID: tagID} tagExist, err := tag.ExistByID() if err != nil { appG.Response(http.StatusInternalServerError, e.ErrorCheckTagExistFailed, nil) return } if !tagExist { appG.Response(http.StatusOK, e.ErrorTagNotExist, nil) return } article := articleservice.Article{ TagID: tagID, Title: title, Desc: desc, Content: content, State: state, CreatedBy: createdBy, } if err := article.Add(); err != nil { appG.Response(http.StatusInternalServerError, e.ErrorCreateArticleFailed, nil) return } appG.Response(http.StatusOK, e.Success, nil) } //EditArticle 修改文章 func EditArticle(c *gin.Context) { appG := app.Gin{c} id := com.StrTo(c.Param("id")).MustInt() tagID := com.StrTo(c.Query("tag_id")).MustInt() title := c.Query("title") desc := c.Query("desc") content := c.Query("content") modifiedBy := c.Query("modified_by") valid := validation.Validation{} var state int = -1 if arg := c.Query("state"); arg != "" { state = com.StrTo(arg).MustInt() valid.Range(state, 0, 1, "state").Message("状态只允许0和1") } valid.Min(id, 1, "id").Message("ID必须大于0") valid.MaxSize(title, 100, "title").Message("标题最长为100字符") valid.MaxSize(desc, 255, "desc").Message("简述最长255字符") valid.MaxSize(content, 65535, "content").Message("内容最长为65535字符") valid.Required(modifiedBy, "modified_by").Message("修改人不能为空") valid.MaxSize(modifiedBy, 100, "modified_by").Message("修改人最长为100字符") if valid.HasErrors() { app.MarkErros(valid.Errors) appG.Response(http.StatusBadRequest, e.InvalidParams, nil) return } //判断文章存在 article := articleservice.Article{ID: id} articleExist, err := article.ExistByID() if err != nil { appG.Response(http.StatusInternalServerError, e.ErrorCheckArticleExistFailed, nil) } if !articleExist { appG.Response(http.StatusOK, e.ErrorArticleNotExist, nil) return } //判断Tag存在 tag := tagservice.Tag{ID: tagID} tagExist, err := tag.ExistByID() if err != nil { appG.Response(http.StatusInternalServerError, e.ErrorCheckTagExistFailed, nil) return } if !tagExist { appG.Response(http.StatusOK, e.ErrorTagNotExist, nil) return } //修改文章 if tagID > 0 { article.TagID = tagID } if title != "" { article.Title = title } if desc != "" { article.Desc = desc } if content != "" { article.Content = content } if state != -1 { article.State = state } article.ModifiedBy = modifiedBy if err := article.Edit(); err != nil { appG.Response(http.StatusInternalServerError, e.ErrorCreateArticleFailed, nil) return } appG.Response(http.StatusOK, e.Success, nil) } //DeleteArticle 删除文章 func DeleteArticle(c *gin.Context) { appG := app.Gin{c} id := com.StrTo(c.Param("id")).MustInt() valid := validation.Validation{} valid.Min(id, 1, "id").Message("ID必须大于0") if valid.HasErrors() { app.MarkErros(valid.Errors) appG.Response(http.StatusBadRequest, e.InvalidParams, nil) return } //判断文章存在 article := articleservice.Article{ID: id} articleExist, err := article.ExistByID() if err != nil { appG.Response(http.StatusInternalServerError, e.ErrorCheckArticleExistFailed, nil) } if !articleExist { appG.Response(http.StatusOK, e.ErrorArticleNotExist, nil) return } if err := article.Delete(); err != nil { appG.Response(http.StatusInternalServerError, e.ErrorDeleteArticleFailed, nil) return } appG.Response(http.StatusOK, e.Success, nil) } |
因为没有使用Form表单,所以代码量会稍微多一些。
验证修改
最后我们需要验证我们的修改,进行测试。
启动服务,然后使用Postman。
获取Auth Token
GET 192.168.1.101:8000/api/auth?username=root&password=root
返回:
1 2 3 4 5 6 7 |
{ "code": 200, "msg": "ok", "data": { "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6InJvb3QiLCJwYXNzd29yZCI6InJvb3QiLCJleHAiOjE2MDA4NjYyNDksImlzcyI6ImdpbkJsb2cifQ.GpZLV6_GPpS4xG-ALXGuDvlu3-17zrfePaQLQNfBj_E" } } |
测试Tag
新增Tag:POST 192.168.1.101:8000/api/v1/tags?name=17&state=1&created_by=root&token=eyJhbG……
查找Tag:GET 192.168.1.101:8000/api/v1/tags?name=17&state=1&token=eyJh…
我这里返回的Id是36,下面的修改会用到:
修改Tag:PUT 192.168.1.101:8000/api/v1/tags/36?name=17-Edit&state=0&modified_by=root&token=eyJhb…
再查找Tag:GET 192.168.1.101:8000/api/v1/tags?state=0&token=eyJhbG…
删除Tag:DELETE 192.168.1.101:8000/api/v1/tags/36?token=eyJhbG…
然后再次查找:GET 192.168.1.101:8000/api/v1/tags?state=0&token=eyJhbG…
最后通过MySQL语句查看软删除效果:
1 2 3 4 5 6 7 |
mysql> SELECT * FROM blog_tag WHERE state=0; +----+---------+------------+------------+-------------+-------------+------------+-------+ | id | name | created_on | created_by | modified_on | modified_by | deleted_on | state | +----+---------+------------+------------+-------------+-------------+------------+-------+ | 36 | 17-Edit | 1600856452 | root | 1600857059 | root | 1600857212 | 0 | +----+---------+------------+------------+-------------+-------------+------------+-------+ 1 row in set (0.00 sec) |
测试Article
新增Article: POST 192.168.1.101:8000/api/v1/articles?tag_id=8&title=ArticleTest&desc=ArticleTest-Desc&content=ArticleTest-Content&created_by=root&state=1&token=eyJhbG…
这里发现一个问题,新增文章之后,我居然不知道文章的ID,先查找所有文章:
GET 192.168.1.101:8000/api/v1/articles?token=eyJhbG…
这里找到我之前的文章ID是3,再查找指定文章:
GET 192.168.1.101:8000/api/v1/articles/3?token=eyJhbG…
然后修改文章:
PUT 192.168.1.101:8000/api/v1/articles/3?content=ArticleTest-Content-Edit&modified_by=root&state=1&token=eyJhbG…
这里注意,如果title、desc等字段不赋值,就会被置空。
为什么这么设计是因为:如果我就删掉文章所有内容,那我就需要给它一个空值。
最后删除文章:
DELETE 192.168.1.101:8000/api/v1/articles/3?token=eyJhbG…
这些方法测试通过,且没有bug。则视为OK。