eddycjy / go-programming-tour-book-comments

go-programming-tour-book-comments
1 stars 1 forks source link

模块开发:标签管理 | Go 语言编程之旅 #3

Open utterances-bot opened 3 years ago

utterances-bot commented 3 years ago

模块开发:标签管理 | Go 语言编程之旅

2.6 模块开发:标签管理 在初步完成了业务接口的入参校验的逻辑处理后,接下来我们正式的进入业务模块的业务逻辑开发,在本章节将完成标签模块的接口代码编写,涉及的接口如下: 功能 HTTP 方法 路径 新增标签 POST /tags 删除指定标签 DELETE /tags/:id 更新指定标签 PUT /tags/:id 获取标签列表 GET /tags 2.6.1 新建 model 方法 首先我们

https://golang2.eddycjy.com/posts/ch2/06-api-tag-module/

RanchoCooper commented 3 years ago
db = db.Where("state = ?", t.State)
if err := db.Model(&t).Where("is_del = ?", 0).Count(&count).Error; err != nil {
    return 0, err
}

这里 err的赋值写法看着好奇怪啊

eddycjy commented 3 years ago
db = db.Where("state = ?", t.State)
if err := db.Model(&t).Where("is_del = ?", 0).Count(&count).Error; err != nil {
  return 0, err
}

这里 err的赋值写法看着好奇怪啊

@RanchoCooper 不奇怪,现实企业项目中很多开发者爱这么写。一般如果对变量 err 需要有其他处理,才会单独处理。

RanchoCooper commented 3 years ago

2.6.2 处理 model 回调部分

新版的gorm找不到gorm.Scope

eddycjy commented 3 years ago

2.6.2 处理 model 回调部分

新版的gorm找不到gorm.Scope

@RanchoCooper 由于本文,在拉取 gorm 时已经限定了 v1 的版本(当时 v2 还在 beta)。因此是不支持 gorm v2 的。等后续如果第四次印刷的话,才会考虑正式支持 gorm v2。

如果是按自己个人意愿拉取了 v2,那就自行适配就好了。适配好了可以把所属代码在评论区上留下言,让更多小伙伴学习,谢谢。

GarfieldZhan commented 3 years ago

我跟着博客写到这里 发现创建的钩子函数未生效,而更新和删除的钩子函数生效了,请问下这有可能是什么原因 。。。 db.Callback().Create().Replace("gorm:update_timestamp", updateTimeStampForCreateCallback) 。。。 func updateTimeStampForCreateCallback(scope *gorm.Scope) { if !scope.HasError() { fmt.Printf("scope has no error") nowTime := time.Now().Unix() if createTimeField, ok := scope.FieldByName("CreatedOn"); ok { if createTimeField.IsBlank { = createTimeField.Set(nowTime) } }

    if modifyTimeField, ok := scope.FieldByName("ModifiedOn"); ok {
        if modifyTimeField.IsBlank {
            _ = modifyTimeField.Set(nowTime)
        }
    }
}

}

fjjreal commented 3 years ago

这个错误有xd遇到过没 runtime error: invalid memory address or nil pointer dereference ... /go-playground/universal-translator@v0.17.0/translator.go:335 (0x8b619a) (translator).C: b = append(b, trans.text[:trans.indexes[0]]...) **/go-playground/validator/v10@v10.6.1/translations/zh/zh.go:184 (0xc2a315) RegisterDefaultTranslations.func4: c, err = ut.C("min-string-character", f64, digits, ut.FmtNumber(f64, digits)) /go-playground/validator/v10@v10.6.1/errors.go:274 (0x8efe82) (*fieldError).Translate: return fn(ut, fe) /go-playground/validator/v10@v10.6.1/errors.go:76 (0x8ef975) ValidationErrors.Translate: trans[fe.ns] = fe.Translate(ut) /go-programming-tour-book/blog-service/pkg/app/form.go:44 (0xbe8b55) BindAndValid: for key, value := range verrs.Translate(trans) { ***/go-programming-tour-book/blog-service/internal/routers/api/v1/tag.go:104 (0xc33d84) Tag.Update: valid, errs := app.BindAndValid(c, &param) ...

                for key, value := range verrs.Translate(trans) { // 这里报错
            errs = append(errs, &ValidError{
                Key:     key,
                Message: value,
            })
        }
fjjreal commented 3 years ago

修改接口:zh,无参数,就出现(runtime error: invalid memory address or nil pointer dereference)这个情况;en,正常返回。。

eddycjy commented 3 years ago

我跟着博客写到这里 发现创建的钩子函数未生效,而更新和删除的钩子函数生效了,请问下这有可能是什么原因 。。。 db.Callback().Create().Replace("gorm:update_timestamp", updateTimeStampForCreateCallback) 。。。 func updateTimeStampForCreateCallback(scope *gorm.Scope) { if !scope.HasError() { fmt.Printf("scope has no error") nowTime := time.Now().Unix() if createTimeField, ok := scope.FieldByName("CreatedOn"); ok { if createTimeField.IsBlank { = createTimeField.Set(nowTime) } }

  if modifyTimeField, ok := scope.FieldByName("ModifiedOn"); ok {
      if modifyTimeField.IsBlank {
          _ = modifyTimeField.Set(nowTime)
      }
  }
}

}

@GarfieldZhan 有完整代码吗,也有可能是已经走进你的插件逻辑里了,但没有走到具体的实现逻辑里去。如果是没走的话,得 debug 看看,看看是什么地方写错了没有走进去?

eddycjy commented 3 years ago

修改接口:zh,无参数,就出现(runtime error: invalid memory address or nil pointer dereference)这个情况;en,正常返回。。

@fjjreal 能具体描述一下不...只言片语,没法直接定位到你的具体意思。

xiaoshiniudao6 commented 3 years ago

在调用修改标签的接口时,state传0,会报入参错误。传1,就没事,请问是啥原因

zsheng17 commented 3 years ago

type UpdateTagRequest struct { ID uint32 form:"id" binding:"required,gte=1" Name string form:"name" binding:"min=3,max=100" State uint8 form:"state" binding:"required,oneof=0 1" ModifiedBy string form:"modified_by" binding:"required,min=3,max=100" }

楼上的把参数验证,required去掉就行了。@xiaoshiniudao6

shawbs commented 3 years ago

问个可能显得很傻的问题。 为什么对数据库的操作代码是在model层,而不是dao层呀?

shawbs commented 3 years ago
var err error
    if pageOffset >= 0 && pageSize > 0 {
        db = db.Offset(pageOffset).Limit(pageSize)
    }
    if t.Name != "" {
        db = db.Where("name = ?", t.Name)
    }
    db = db.Where("state = ?", t.State)
    if err = db.Where("is_del = ?", 0).Find(&tags).Error; err != nil {
        return nil, err
    }

代码中的db变量会被改变吗?比如我第二次搜索,会不会在上次搜索的结果中搜索?

YingYou commented 2 years ago

调用修改接口state设置0不成功 解决方案:binding:"required"会认为0是空值而不通过校验 把整数字段改成整数指针类型,指针没有默认值0,也就没有这个问题了,注意取值加*,设值加&总之记得他是指针就好了

实测ok

Zrealshadow commented 2 years ago

在修改标签过程中 输入

curl -X PUT http://127.0.0.1:8000/api/v1/tags/{1} -F state=0 -F modified_by=eddycjy

结果

{"code":10000001,"details":["ID is a required field","Name must be at least 1 character in length"],"msg":"Invalid Args"}%

但是在UpdateTagRequest里,我没有限制Name为requreid

type UpdateTagRequest struct {
    ID         uint32 `form:"id" binding:"required,gte=1"`
    Name       string `form:"name" binding:"min=1,max=100"`
    State      uint8  `form:"state" binding:"oneof=0 1"`
    ModifiedBy string `form:"modified_by" binding:"required,min=3,max=100"`
}

如果补上name参数,可以正常修改,例如输入命令

curl -X PUT http://127.0.0.1:8000/api/v1/tags/{1} -F 'name=Go' -F state=0 -F modified_by=eddycjy
Elibool commented 2 years ago
github.com/gin-gonic/gin v1.7.7
github.com/go-playground/validator/v10 v10.9.0

包版本, updateTag, state=0 时会提示 State为必填字段 错误,解决办法按楼上 YingYou 方法使用指针可完美解决。不知道这样会不会有性能问题

type UpdatedTagRequest struct {
    Id         uint32 `form:"id" binding:"required,gte=1"`
    Name       string `form:"name" binding:"min=3,max=100"`
    State      *uint8 `form:"state" binding:"required,oneof=0 1"`
    ModifiedBy string `form:"modified_by" binding:"required,min=3,max=100"`
}
bourne-3 commented 2 years ago

@Zrealshadow 那位老哥 我也是遇到name校验的同样问题 请问不加require为什么还是必须校验啊

TC-Fang commented 2 years ago

$ curl -X POST http://127.0.0.1:8000/api/v1/tags -F 'name=Go' -F created_by=eddycjy 验证新增标签接口这里,name参数不能加引号,否则验证不通过。

nicoxiang commented 2 years ago

@fjjreal 的问题我也遇到了,应该是个 bug

locale := c.GetHeader("locale") trans, _ := uni.GetTranslator(locale)

这一行如果 header 中没有 locale 就拿不到 translator,我改成

if locale == "" { locale = "zh" }

就不会报错了,总之要考虑拿不到 translator 的情况

lcxc-lcxc commented 2 years ago

@Zrealshadow,没写required但是写了min,所以,把min改为min=0就可以了

EricWangZ commented 2 years ago

问个可能显得很傻的问题。 为什么对数据库的操作代码是在model层,而不是dao层呀?

我也想问同样的这个问题,为什么要多个model

EricWangZ commented 2 years ago
github.com/gin-gonic/gin v1.7.7
github.com/go-playground/validator/v10 v10.9.0

包版本, updateTag, state=0 时会提示 State为必填字段 错误,解决办法按楼上 YingYou 方法使用指针可完美解决。不知道这样会不会有性能问题

type UpdatedTagRequest struct {
  Id         uint32 `form:"id" binding:"required,gte=1"`
  Name       string `form:"name" binding:"min=3,max=100"`
  State      *uint8 `form:"state" binding:"required,oneof=0 1"`
  ModifiedBy string `form:"modified_by" binding:"required,min=3,max=100"`
}

我在这里给State指针赋值,有没有其他好方法

func (t Tag) Update(c *gin.Context) {

newstate := convert.StrTo(c.Param("state")).MustUInt8()

param := service.UpdateTagRequest{
    ID: convert.StrTo(c.Param("id")).MustUInt32(),
    State: &newstate,
}
mmmmfy123 commented 2 years ago

gorm v2版本没有gorm解决方案

func (m *Model) BeforeUpdate(tx *gorm.DB) error {
    now := time.Now().Unix()
    tx.Statement.SetColumn("modified_at", now)
    return nil
}
yrzs commented 2 years ago

每次都要 svc := service.New(c.Request.Context()) 很烦啊

MrCJJW commented 2 years ago

修改标签接口 curl -X PUT http://127.0.0.1:8000/api/v1/tags/{id} -F state=0 -F modified_by=eddycjy 提示id为必填字段,name长度必须至少为3个字符,与文章返回结果不符 原因: shouldBind绑定不了路径参数,应该要用ShouldBindUri name有min=3,max=100,没有传name时也会检测

William9912 commented 2 years ago

@EricWangZ 我没有加把传参转换成int的步骤也成功了,不知道是不是gin的ShouldBind有把int智能的转换成int的功能? 求解

William9912 commented 2 years ago

@YingYou 我只改了UpdateTagRequest成功了 没管请求参数,不知道是不是gin的ShouldBind有把int智能的转换成*int的功能? 求解

zzzpppy commented 2 years ago

大家好 我在执行

curl -X GET 'http://127.0.0.1:8000/api/v1/tags?page=2&page_size=2'
{"list[{"id":3,"created_by":"eddycjy","modified_by":"","created_on":1662619240,"modified_on":1662619240,"deleted_on":0,"is_del":0,"name":"Rust","state":1}],"pager":{"page":2,"page_size":2,"total_rows":3}}

这一操作后报错{"code":20010001,"msg":"获取标签列表失败"}zsh: command not found: list:[id:3],pager:page:2 zsh: command not found: list:[id:3],pager:page:2想询问一下大家这个报错出现的原因是什么

wangwei0326 commented 1 year ago

@fjjreal 遇到了同样的问题 你有解决吗?

wangwei0326 commented 1 year ago

有没有同学遇到这个参数校验的问题? curl -X GET 'http://127.0.0.1:8000/api/v1/tags?state=6

runtime error: invalid memory address or nil pointer dereference /usr/local/Cellar/go@1.18/1.18.7/libexec/src/runtime/panic.go:220 (0x1049e86) panicmem: panic(memoryError) /usr/local/Cellar/go@1.18/1.18.7/libexec/src/runtime/signal_unix.go:818 (0x1049e56) sigpanic: panicmem() /Users/admin/project/blog-service/pkg/logger/logger.go:111 (0x13499c6) (Logger).JSONFormat: data["callers"] = l.callers /Users/admin/project/blog-service/pkg/logger/logger.go:126 (0x1349c1c) (Logger).Output: fmt.Print(l.JSONFormat(level, message)) /Users/admin/project/blog-service/pkg/logger/logger.go:167 (0x1349fcb) (Logger).Errorf: l.Output(LevelError, fmt.Sprintf(format, v...)) /Users/admin/project/blog-service/internal/routers/api/v1/tag.go:35 (0x1613dea) Tag.List: global.Logger.Errorf("app.BindAndValid errs: %v", errs) /Users/admin/go/pkg/mod/github.com/gin-gonic/gin@v1.8.1/context.go:173 (0x1546801) (Context).Next: c.handlersc.index /Users/admin/go/pkg/mod/github.com/gin-gonic/gin@v1.8.1/recovery.go:101 (0x15467ec) CustomRecoveryWithWriter.func1: c.Next() /Users/admin/go/pkg/mod/github.com/gin-gonic/gin@v1.8.1/context.go:173 (0x15458e6) (Context).Next: c.handlersc.index /Users/admin/go/pkg/mod/github.com/gin-gonic/gin@v1.8.1/logger.go:240 (0x15458c9) LoggerWithConfig.func1: c.Next() /Users/admin/go/pkg/mod/github.com/gin-gonic/gin@v1.8.1/context.go:173 (0x15449b0) (Context).Next: c.handlersc.index /Users/admin/go/pkg/mod/github.com/gin-gonic/gin@v1.8.1/gin.go:616 (0x1544618) (Engine).handleHTTPRequest: c.Next() /Users/admin/go/pkg/mod/github.com/gin-gonic/gin@v1.8.1/gin.go:572 (0x154415c) (Engine).ServeHTTP: engine.handleHTTPRequest(c) /usr/local/Cellar/go@1.18/1.18.7/libexec/src/net/http/server.go:2916 (0x12a2eda) serverHandler.ServeHTTP: handler.ServeHTTP(rw, req) /usr/local/Cellar/go@1.18/1.18.7/libexec/src/net/http/server.go:1966 (0x129ded6) (*conn).serve: serverHandler{c.server}.ServeHTTP(w, w.req) /usr/local/Cellar/go@1.18/1.18.7/libexec/src/runtime/asm_amd64.s:1571 (0x1064880) goexit: BYTE $0x90 // NOP

joker2009 commented 1 year ago

我发现 curl -X POST http://127.0.0.1:8000/api/v1/tags -F 'name=Go' -F created_by=eddycjy2 请求会报 {"code":10000001,"msg":"入参错误"} 使用 则可以插入新数据成功,不知道为啥 curl --location --request POST 'http://127.0.0.1:8000/api/v1/tags' \ --form 'name="Go"' \ --form 'created_by="eddycjy2233"'

joker2009 commented 1 year ago

上一个问题,是我的问题 CreateTagRequest 结构体中Name string form:"name" binding:"required,min=2,max=100" 最小值我写成了min=3,所以一直校验不通过,name最小字符数改为2就可以通过

bensontung commented 1 year ago

为什么要用"created_on","modified_on", "deleted_on"这些字段?而不用“created_at", "updated_at", "deleted_at"?这样当数据变化时,gorm可以自动更新相关字段

ink-web3 commented 1 year ago

为什么感觉用go开发个项目这么复杂呢, 是因为教程里没有用到现有的包进行简化吗? 如果都是这样手撸代码 开发个正式项目可真的要累坏了 我以为java够重、配置够繁琐了,学完这节课,发现go也没好哪儿去,一层套一层,给人都弄晕了

blueofmoon commented 8 months ago

service/tag.go 为什么写到这里会报错 func (svc Service) CountTag(param CountTagRequest) (int, error) { return svc.dao.CountTag(param.Name, param.State) ----这段提示有问题 }