游戏电视苹果数码历史美丽
投稿投诉
美丽时装
彩妆资讯
历史明星
乐活安卓
数码常识
驾车健康
苹果问答
网络发型
电视车载
室内电影
游戏科学
音乐整形

Gin框架中处理请求参数的零值问题

  Gin框架处理前端请求的时候,使用ShouldBindXXX绑定参数数据到结构体上是一种比较常用的取数据手段,但在一些情况下,可能会出现问题
  例如,现在有一个userupdate接口,用于更新用户的年龄和昵称,即接收两个字段:age(int)、nickname(string),并且这两个字段并不要求必须同时传递,可以两个都传,也可以只传其中一个,后端从请求中解析这两个参数,取到哪个字段就对哪个字段进行更新typeUserstruct{Ageintjson:ageNickNamestringjson:nickname}复制代码
  两个字段都传递那还好说,但如果只传其中一个字段,并且后端用ShouldBindXXX来绑定数据到结构体,就可能会出现问题了funcHandlerUpdate(cgin。Context){varuserUseriferr:c。ShouldBind(user);err!nil{。。。}}复制代码
  如果前端只传了一个nickname字段,没传age字段,那么user。Age的值就是零值,即0,ShouldBindXXX并不判断这个0到底是零值还是前端真的传了0
  这个问题解决起来倒也简单,两个方法
  一是将结构体内的字段改成指针类型typeUserstruct{Ageintjson:ageNickNamestringjson:nickname}复制代码
  指针的零值nil,ShouldBindXXX之后,字段值为nil的自然就是没传值的
  但将结构体所有的字段都定义为指针类型未免有些不符合习惯,并且操作指针也不方便,也更容易出错(例如空指针问题)
  第二个是办法是借助map
  ShouldBindXXX有问题的话那我大不了不用了,直接将参数(GET)数据(POST)映射到map就行
  但这样的话就会引出另外一个问题,ShouldBindXXX方法一个显著的好处是可以根据结构体里定义的tag规则来对字段进行校验,如果你直接读到map中就要自己实现字段校验逻辑了,字段少点还好,要是多了得写一大串的if。。。else或者是干脆要实现一个通用校验方法了,未免繁琐
  所以想到用ShouldBindXXX来做校验,再借助map用于区分零值,即对请求传递的数据读了两次
  以GET请求为例:funcHandlerUpdate(cgin。Context){varuserUser用ShouldBind作校验iferr:c。ShouldBind(user);err!nil{fmt。Printf(genGetMapShouldBinderror:v,err)return}请求真正传递的参数映射到map中allMap:map〔string〕interface{}{}urlvalues:c。Request。URL。Query()fork,urls:rangeurlvalues{fmt。Printf(genGetMapk,urls,v,v,k,urls)重复值则取最后一个allMap〔k〕urls〔len(urls)1〕}}复制代码
  截至目前,只是校验并获取到了请求的数据,下一步还要进行更新数据库的操作,这里以gorm为例
  因为user只是用于校验请求的数据是否合法,无法判断零值,所以不能直接以user为基础操作数据库可能因零值问题导致出现不符合预期的结果db。Save(user)复制代码
  allMap可以分辨出请求到底携带了哪些参数数据,但可能存在一些额外不需要的数据,例如当希望更新用户的age和nickname属性的时候,操作的数据表是dbuser,而这个数据表中除了age、nickname两列外,还存在用于标识用户是否注销了的isdel列,那么按照如下更新方式也是会出问题的:db。Model(user)。Updates(allMap)复制代码
  如果allMap中存在isdel属性,那么也会更新数据表中的isdel字段,并不是预期的结果,所以需要将allMap中不需要的属性去掉,可以复制出一份只包含所需更新属性的map,也可以直接删除掉allMap上额外的属性只保留所需的,这里以前一种为例allMap:make(map〔string〕interface{})realMap:make(map〔string〕interface{})ifv,ok:allMap〔age〕;ok{realMap〔age〕v}ifv,ok:allMap〔nickname〕;ok{realMap〔nickname〕v}db。Model(user)。Updates(realMap)复制代码
  这里只有age、nickname两个字段所以还好,但如果所需更新的字段最多在5个以上就要写最多5个条件语句了,未免繁琐,可以借助reflect处理,无论存在多少个需要更新的字段,代码量都是一样的realMap:make(map〔string〕interface{})typ:reflect。TypeOf(user)。Elem()fori:0;ityp。NumField();i{tagName:typ。Field(i)。Tag。Get(json)ifv,isOK:allMap〔tagName〕;isOK{realMap〔tagName〕v}}db。Model(user)。Updates(realMap)复制代码
  完整代码:将请求的参数映射到m中,如果是GET,返回query参数组成的map;如果是POST,返回请求体里的数据instance:指向具体结构体实例的指针,作用是获取结构体中每个字段名为json的tag,以映射mapfuncGenMapByStruct(cgin。Context,instanceinterface{},mmap〔string〕interface{})error{ifc。ContentType()!gin。MIMEJSON{returnerrors。New(contenttypemustbegin。MIMEJSON)}ifc。Request。Method!http。MethodGetc。Request。Method!http。MethodPost{returnerrors。New(methodmustbeGETorPOST)}allMap:map〔string〕interface{}{}ifc。Request。Methodhttp。MethodGet{iferr:genGetMap(c,instance,allMap);err!nil{returnerr}}else{iferr:genPostMap(c,instance,allMap);err!nil{returnerr}}typ:reflect。TypeOf(instance)。Elem()fori:0;ityp。NumField();i{tagName:typ。Field(i)。Tag。Get(json)ifv,isOK:allMap〔tagName〕;isOK{(m)〔tagName〕v}}returnnil}从get请求中获取query,并将query处理成map映射到allMap中funcgenGetMap(cgin。Context,instanceinterface{},allMapmap〔string〕interface{})error{iferr:c。ShouldBind(instance);err!nil{fmt。Printf(genGetMapShouldBinderror:v,err)returnerr}urlvalues:c。Request。URL。Query()fork,urls:rangeurlvalues{fmt。Printf(genGetMapk,urls,v,v,k,urls)重复值则取最后一个(allMap)〔k〕urls〔len(urls)1〕}returnnil}从post请求中获取body,并将body反序列化到allMap中funcgenPostMap(cgin。Context,instanceinterface{},allMapmap〔string〕interface{})error{shouldBind会导致body无法再次读取,方便起见这里使用了ShouldBindBodyWithiferr:c。ShouldBindBodyWith(instance,binding。JSON);err!nil{fmt。Printf(genPostMapShouldBinderror:v,err)returnerr}body,:c。Get(gin。BodyBytesKey)varbodyByte〔〕bytevarokboolifbodyByte,okbody。(〔〕byte);!ok{returnerrors。New(bodyisinvalid)}iflen(bodyByte)0{returnnil}iferr:json。Unmarshal(bodyByte,allMap);err!nil{returnerr}returnnil}复制代码
  使用示例:typeUserstruct{Ageintjson:ageNickNamestringjson:nickname}r。Any(update,func(cgin。Context){m:map〔string〕interface{}{}varuserUseriferr:GenMapByStruct(c,s,m);err!nil{c。JSON(http。StatusOK,gin。H{code:1,message:err。Error()})return}c。JSON(http。StatusOK,gin。H{code:0,data:m})})复制代码
  可以看到,因为存在更多的计算过程,所以处理请求零值的情况,会带来更高的资源消耗,所以应该尽可能避免这种情况的出现,相比于在后端额外处理,让客户端携带完整的所需参数才是更优解
  作者:清夜
  链接:https:juejin。cnpost7016514018487566343
  来源:稀土掘金
  著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

艺术活动太阳花手工制作活动教学反思我所执教的艺术活动《太阳花》是一个手工制作活动,其目标是运用画、剪、折等方法将纸杯变成自己喜欢的太阳花,锻炼幼儿的动手操作能力;体验变废为宝的快乐,培养幼儿废物利用意识。《纲要……关于逐臭之夫的造句1、这个气味人人掩鼻,只有老王这个逐臭之夫,喜欢得不得了。2、人人有嗜好的自由,我们对逐臭之夫应该一视同仁,予以尊重。3、每个人的癖好不同,到处都有逐臭之夫,你何必……Unitampnbsp3ampnbspHoobies第二课时unit3hoobies第二课时教材类型:所属学科:英语gt;gt;5b(五下)教案内容:一、教学目标1、能正确地听、说、读、写单词acoin和词组ta……幸福的歌教案一、教学内容:演唱:《彝家娃娃真幸福》聆听:《快乐的罗嗦》动用打击乐器为歌曲伴奏二、教学目标:1、学生能够用轻巧、富有弹性的声音演唱歌曲《彝家娃娃真幸福……Unit7Howmucharethesepants教学反思今天我执教了一节校内公开课。我的教学内容是人教版《新目标英语》七年级上册第七单元Howmucharethesepants?的SectionA部分。本节课围绕Howmuchare……幼儿园中班家长会教师发言稿尊敬的各位家长:大家早上好!首先,感谢大家在百忙中来参加我们的这次家长会,在此,也可看出家长对幼儿的重视以及对我们的信任。我是中班的杨老师,在我们班,目前有25位小……时而时而造句好句句子是语言运用的基本单位,它由词或词组构成,能表达一个完整的意思,下面为大家分享了时而时而的造句大全,欢迎借鉴!时而时而造句11、你看动物园的猴子,时而跳到假山上,时而爬……蚂蚁和蝈蝈第一课时的教学设计教学目标:1、能正确连贯地朗读课文。2、认识绿线格和田字格中的15个生字,写好田字格中的5个左右结构的字。3、初步感受概括主要内容的方法。4、初步理解课……中国的地理差异人教版地理八年级下册教案第五章第五章中国的地理差异(第2课时)教学目标知识目标:1、知道地理区域划分的不同依据及相应的区域类型。2、知道四大地理区域划分的自然、人文原因。3、初……我的雨量器的教学反思在本课的教学的时候,我首先进行介绍雨量器组成和历史,我想这是给学生更多的时间进行制作,因此我进行了快速的介绍。我想如果给予学生时间,组织学生进行搜集材料进行介绍,效果应该也不错……认识图形拼组图形教学设计教学目标1通过操作,加深对图形的认识,初步认识图形之间的关系2通过操作,发展学生的想像力和创造性3培养学生的想象力和创新能力4通过操作,显示对美的追求,……口算除法的说课稿一、教学内容《口算除法》(人教版第六册第二单元第一课时)二、知识背景《口算除法》是在学生掌握了表内乘、除法,一位数乘多位数的基础上进行教学的,为后面学生掌握除……
音乐火车波尔卡教学反思《火车波尔卡》采用写实的手法,对蒸汽机车启动、加速、到站、做了细致的描绘。它是降B大调24拍,快板,复三部曲式。前把小节是引子。由短笛、长笛吹奏出短促的倚音和休止符构成的汽笛声……假一赔三!直播带货时销售山寨手机被诉,主播一审被判欺诈IT之家9月21日消息据北京互联网法院官方微信公众号消息,因认为主播许某某在快手直播间销售的某品牌手机(以下简称涉案手机)为仿冒机,构成欺诈,王某某将主播许某某及快手APP运营……赞扬的近义词同义词有哪些赞扬是表示对一个人进行称赞,表扬。那么与赞扬意思相近的词语大家知道有哪些呢?接下来就由小编为大家带来关于赞扬的近义词及其相关知识,希望对大家有所帮助,一起来看看吧!赞扬的……寒武纪7月20日将在上海证券交易所科创板上市IT之家7月16日消息今天,寒武纪发布公告称,该公司股票将于2020年7月20日在上海证券交易所科创板上市。IT之家了解到,寒武纪本次发行后公司总股本为40,010。00……B站测试短视频播放界面视频时长多为5分钟以下IT之家12月25日消息据Tech星球报道,据用户反映,近期在哔哩哔哩App内观看视频时,并不是像以前那样横屏播放,而是可以竖着播放,并且能够上下切换视频,像抖音一样。在……扎克伯格成为美国科技巨头中的最后一位创始人CEO2月4日早间消息,随着杰夫贝佐斯(JeffBezos)将在今年晚些时候卸任亚马逊CEO,马克扎克伯格(MarkZuckerberg)将成为美国科技巨头中最后一位创始人CEO,即……收到快递起火短信?菜鸟驿站假的,每年这个时候都要辟谣IT之家11月13日消息双11狂欢夜过去了,现在快递小哥开始变得异常繁忙。不少网友表示自己收到了快递起火的短信,就连数码大V都表示自己收到了快递起火的短信,一时间让许多不明真相……特斯拉关于上海车辆事故的说明系电池模组故障所致IT之家6月28日消息4月21日晚,上海市徐汇区某小区地下车库内,一白色特斯拉轿车忽然冒起白烟,进而发生自燃。特斯拉周围两辆轿车被燃烧波及,所幸并无人员伤亡。报道称,涉事……水滴筹辟谣从未收取过服务费及手续费IT之家5月8日消息近日,德云社吴鹤臣脑出血,家人通过水滴筹发起百万众筹却被曝家中有车有房一事,引起广泛关注;随后有消息称,水滴筹募捐是要收取手续费的,并爆料称50元的捐款,水……我的母亲阅读理解及答案我的母亲(17分)母亲生在农家,勤俭诚实。为我们的衣食,母亲要给大家洗衣服,缝补衣裳。在我的记忆中,她的手终年是鲜红微肿的。白天,她洗衣服,洗一两大盆。她料理家务永远丝毫……认识分数教学反思认识分数是学生关于数的认识的又一次扩展。而分数概念是学生初步接触的基础知识。在本单元,分数被作为整体的一个部分来认识,这种认识又与平均分的经验分不开。其实,学生正式学习分数以前……央行针对部分老年人不会使用移动支付,将提升支付产品的便利性IT之家11月26日消息在今天的《关于切实解决老年人运用智能技术困难实施方案》国务院政策例行吹风会上,中国人民银行科技司司长李伟表示高度重视解决老年人运用智能技术困难的问题,准……
友情链接:易事利快生活快传网聚热点七猫云快好知快百科中准网快好找文好找中准网快软网