Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

Open
utterances-bot opened this issue Mar 18, 2021 · 35 comments
Open

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

utterances-bot opened this issue Mar 18, 2021 · 35 comments

Comments

@utterances-bot
Copy link

模块开发:标签管理 | 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/

Copy link

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
Copy link
Owner

eddycjy commented Mar 19, 2021

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 需要有其他处理,才会单独处理。

Copy link

2.6.2 处理 model 回调部分

新版的gorm找不到gorm.Scope

@eddycjy
Copy link
Owner

eddycjy commented Mar 21, 2021

2.6.2 处理 model 回调部分

新版的gorm找不到gorm.Scope

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

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

Copy link

我跟着博客写到这里 发现创建的钩子函数未生效,而更新和删除的钩子函数生效了,请问下这有可能是什么原因
。。。
db.Callback().Create().Replace("gorm:update_time_stamp", 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)
		}
	}
}

}

Copy link

fjjreal commented May 27, 2021

这个错误有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,
			})
		}

Copy link

fjjreal commented May 31, 2021

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

@eddycjy
Copy link
Owner

eddycjy commented Jun 14, 2021

我跟着博客写到这里 发现创建的钩子函数未生效,而更新和删除的钩子函数生效了,请问下这有可能是什么原因
。。。
db.Callback().Create().Replace("gorm:update_time_stamp", 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
Copy link
Owner

eddycjy commented Jun 14, 2021

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

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

Copy link

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

Copy link

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

Copy link

shawbs commented Sep 6, 2021

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

Copy link

shawbs commented Sep 7, 2021

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变量会被改变吗?比如我第二次搜索,会不会在上次搜索的结果中搜索?

Copy link

YingYou commented Sep 27, 2021

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

实测ok

Copy link

在修改标签过程中
输入

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

Copy link

Elibool commented Dec 13, 2021

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"`
}

Copy link

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

Copy link

TC-Fang commented Dec 14, 2021

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

Copy link

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

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

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

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

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

Copy link

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

@EricWangZ
Copy link

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

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

@EricWangZ
Copy link

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,
}

Copy link

gorm v2版本没有gorm解决方案

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

Copy link

yrzs commented Jun 30, 2022

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

Copy link

MrCJJW commented Jul 30, 2022

修改标签接口
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时也会检测

Copy link

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

Copy link

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

Copy link

zzzpppy commented Sep 8, 2022

大家好 我在执行

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想询问一下大家这个报错出现的原因是什么

Copy link

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

Copy link

有没有同学遇到这个参数校验的问题?
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

Copy link

我发现 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"'

Copy link

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

Copy link

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

Copy link

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

Copy link

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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests