当前位置: 首页 > news >正文

Go-zero框架修改模版进行handler统一响应封装

使用go-zero快速生成接口的时候,发现还是有一些情况不太好处理,比如说,想要自定义响应封装等等。

最开始第一版写api文件的时候,写法是这样的。

type LoginRequest {UserName string `json:"userName"`Password string `json:"password"`
}type Response {Code int    `json:"code"`Data string `json:"data"`Msg  string `json:"msg"`
}type UserInfo {UserName string `json:"userName"`Addr     string `json:"addr"`Id       uint   `json:"id"`
}type UserInfoResponse {Code int      `json:"code"`Data UserInfo `json:"data"`Msg  string   `json:"msg"`
}service users {@handler loginpost /api/users/login (LoginRequest) returns (Response)@handler userInfoget /api/users/info returns (UserInfoResponse)
}// goctl api go -api v1.api -dir .

后面发现可以不把code、data、msg这三个重要信息写在api里边,而是通过统一封装,在统一响应中去加上code、data、msg,使之成为我们一个公共的库供我们使用。

首先我们封装好response文件:

package responseimport ("github.com/zeromicro/go-zero/rest/httpx""net/http"
)type Body struct {Code uint32      `json:"code"`Msg  string      `json:"msg"`Data interface{} `json:"data"`
}// Response http返回
func Response(r *http.Request, w http.ResponseWriter, resp interface{}, err error) {if err == nil {//成功返回r := &Body{Code: 0,Msg:  "成功",Data: resp,}httpx.WriteJson(w, http.StatusOK, r)return}//错误返回errCode := uint32(7)// 可以根据错误码,返回具体错误信息//errMsg := "服务器错误"httpx.WriteJson(w, http.StatusOK, &Body{Code: errCode,Msg:  err.Error(),Data: nil,})}

此时还需要考虑问题,假设我们只是需要这个项目使用统一的封装,不希望后面的go-zero项目受到影响,那么我们可以通过直接在本地生成模版文件去给当前这个项目使用。

然后我看了go-zero的官方文档,发现确实可以这么操作,ok,尝试一波。

首先,通过在本地(项目路径下)生成模版文件:

goctl template init --home template

在这里插入图片描述
然后可以看到提示成功了,并且生成了下面的模版。

在这里插入图片描述
下面是原api中的hanlder.tpl文件的代码:

package {{.PkgName}}import ("net/http""github.com/zeromicro/go-zero/rest/httpx"{{.ImportPackages}}
){{if .HasDoc}}{{.Doc}}{{end}}
func {{.HandlerName}}(svcCtx *svc.ServiceContext) http.HandlerFunc {return func(w http.ResponseWriter, r *http.Request) {{{if .HasRequest}}var req types.{{.RequestType}}if err := httpx.Parse(r, &req); err != nil {httpx.ErrorCtx(r.Context(), w, err)return}{{end}}l := {{.LogicName}}.New{{.LogicType}}(r.Context(), svcCtx){{if .HasResp}}resp, {{end}}err := l.{{.Call}}({{if .HasRequest}}&req{{end}})if err != nil {httpx.ErrorCtx(r.Context(), w, err)} else {{{if .HasResp}}httpx.OkJsonCtx(r.Context(), w, resp){{else}}httpx.Ok(w){{end}}}}
}

修改后的tpl文件如下:

package handlerimport ("net/http""fim/common/response"{{.ImportPackages}}{{if .HasRequest}}"github.com/zeromicro/go-zero/rest/httpx"{{end}}
)func {{.HandlerName}}(svcCtx *svc.ServiceContext) http.HandlerFunc {return func(w http.ResponseWriter, r *http.Request) {{{if .HasRequest}}var req types.{{.RequestType}}if err := httpx.Parse(r, &req); err != nil {response.Response(r, w, nil, err)return}{{end}}l := logic.New{{.LogicType}}(r.Context(), svcCtx){{if .HasResp}}resp, {{end}}err := l.{{.Call}}({{if .HasRequest}}&req{{end}}){{if .HasResp}}response.Response(r, w, resp, err){{else}}response.Response(w, nil, err){{end}}}
}

简单来分析下这个代码逻辑,就是使用了模板引擎的语法(如 {{.HandlerName}}{{if .HasRequest}}),这些模板变量和条件判断在代码生成时会被具体的值替换。

首先,“fim/common/response”:项目中自定义的模块,提供了统一的响应处理方法。

然后是:{{.ImportPackages}}:模板变量,表示在代码生成时会根据需要动态导入其他必要的包。

    {{.ImportPackages}}{{if .HasRequest}}"github.com/zeromicro/go-zero/rest/httpx"{{end}}

func {{.HandlerName}}(svcCtx *svc.ServiceContext) http.HandlerFunc{{.HandlerName}} 是模板变量,表示具体的处理函数名称。例如,它可能会被替换为 LoginHandler

svcCtx *svc.ServiceContext:服务上下文,包含了依赖注入的配置和数据库连接等信息。然后返回handlerFunc


如果当前接口需要解析请求体({{if .HasRequest}}),则会执行以下操作:定义一个变量 req,类型为 types.{{.RequestType}}{{.RequestType}} 是模板变量,表示请求体的类型,例如 LoginRequest

{{if .HasRequest}}var req types.{{.RequestType}}if err := httpx.Parse(r, &req); err != nil {response.Response(r, w, nil, err)return}{{end}}

使用 httpx.Parse(r, &req) 解析 HTTP 请求体到 req 中。如果解析失败(err != nil),调用 response.Response 方法返回错误响应,并结束处理。


然后是进行逻辑处理:创建一个业务逻辑对象 l,类型为 logic.New{{.LogicType}}{{.LogicType}} 是模板变量,表示具体的业务逻辑类型,例如 LoginLogic。

调用业务逻辑对象的 {{.Call}} 方法({{.Call}} 是模板变量,表示具体的业务逻辑方法名,例如 Login)。

       l := logic.New{{.LogicType}}(r.Context(), svcCtx){{if .HasResp}}resp, {{end}}err := l.{{.Call}}({{if .HasRequest}}&req{{end}}){{if .HasResp}}response.Response(r, w, resp, err){{else}}response.Response(w, nil, err){{end}}

如果接口有返回值({{if .HasResp}}),则将返回值存储到 resp 中;否则,仅处理错误。

如果接口有返回值({{if .HasResp}}),调用 response.Response(r, w, resp, err),将业务逻辑的返回值作为响应数据返回。

如果接口没有返回值,仅调用 response.Response(w, nil, err),返回错误信息或成功状态。


然后把原来的api生成的handler和logic删除,然后重新生成一下。注意选对好对应目录下的template(这里我是在auth_api路径下去运行这个命令,也就是跟api文件同级目录下去运行)。

goctl api go -api auth_api.api -dir . --home ../../template

在这里插入图片描述
运行成功,看看效果。

在这里插入图片描述
这个时候发现生成的接口函数那些就没问题了。

在这里插入图片描述

相关文章:

  • Python基于知识图谱的医疗问答系统【附源码、文档说明】
  • A股周度复盘与下周策略 的deepseek提示词模板
  • VsCode搭建
  • ueditorplus编辑器已增加AI智能
  • Java Date 类深度解析
  • ISO26262-浅谈用例导出方法和测试方法
  • x-ui重新申请ssl证书失败
  • c++冒泡排序实现
  • 部署rocketmq集群
  • 高效的项目构建:用 Makefile 自动化你的构建过程
  • 【记录】服务器安装ffmpeg
  • 实验4基于神经网络的模式识别实验
  • leetcode 300. Longest Increasing Subsequence
  • C#.net core部署IIS
  • CSS中的`transform-style`属性:3D变换的秘密武器
  • LeetCode 热题 100:回溯
  • sqlilabs-Less之HTTP头部参数的注入——基础篇
  • QML中的3D功能--模型导入与修改
  • QML中的3D功能--入门开发
  • Doris 本地部署集群重启后报错
  • 新闻1+1丨全球首场人机共跑马拉松,有何看点?
  • 美法官裁定谷歌非法垄断在线广告
  • 西北政法大学推无手机课堂,有学生称要求全交,学校:并非强制
  • 观察|药企竞逐千亿抗癌药赛道,AI有多大助力?
  • 中国驻德国大使馆公使曾颖如,调任广州医科大学党委书记
  • 黄仁勋时隔3个月再次到访北京