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

封装统一格式的body响应,但是不修改go-zero原有代码生成模板 #60

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
168 changes: 167 additions & 1 deletion i18n/cn/docusaurus-plugin-content-docs/current/advance/template.md
Original file line number Diff line number Diff line change
Expand Up @@ -155,4 +155,170 @@ func GreetHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
本文档仅对http相应为例讲述了自定义模板的流程,除此之外,自定义模板的场景还有:
* model 层添加kmq
* model 层生成待有效期option的model实例
* http自定义相应格式
* http自定义相应格式

# 方案二:logic层使用response封装方法统一格式的body响应
可以自定义code和data的返回内容

以用户登录功能模块为例

* user.api
```
syntax = "v1"

// 统一格式的响应
type Response {
Code int `json:"code"`
Msg string `json:"msg"`
Data interface{} `json:"data,omitempty"`
}

// 用户登录
type LoginRequest {
Username string `json:"username"`
Password string `json:"password"`
}

type LoginResult {
Id int64 `json:"id"`
Username string `json:"username"`
AccessToken string `json:"access_token"`
AccessExpire int64 `json:"access_expire"`
RefreshAfter int64 `json:"refresh_after"`
}

// 用户注册
type SignupRequest {
Username string `json:"username"`
Password string `json:"password"`
}

type SignupResult {
Id int64 `json:"id"`
Username string `json:"username"`
AccessToken string `json:"access_token"`
AccessExpire int64 `json:"access_expire"`
RefreshAfter int64 `json:"refresh_after"`
}

@server(
group: user
)
service gateway-api {
@handler LoginHandler
post /user/login (LoginRequest) returns (Response)

@handler SignupHandler
post /user/signup (SignupRequest) returns (Response)
}
```

* response.go 代码修改为
```go
package response

import "datacenter/gateway/internal/types"

// 封装统一格式的body响应,data的类型可以自定义
func Response(code int, msg string, data interface{}) (*types.Response, error) {
return &types.Response{
Code: code,
Msg: msg,
Data: data,
}, nil
}

```

* internal/logic/user/loginlogic.go 代码修改为
```go
package user

import (
"context"
"strings"
"time"

"datacenter/gateway/common/response"
"datacenter/gateway/internal/svc"
"datacenter/gateway/internal/types"
"datacenter/user/rpc/userclient"

jwt "github.com/golang-jwt/jwt/v4"
"github.com/zeromicro/go-zero/core/hash"
"github.com/zeromicro/go-zero/core/logx"
)

type LoginLogic struct {
logx.Logger
ctx context.Context
svcCtx *svc.ServiceContext
}

func NewLoginLogic(ctx context.Context, svcCtx *svc.ServiceContext) *LoginLogic {
return &LoginLogic{
Logger: logx.WithContext(ctx),
ctx: ctx,
svcCtx: svcCtx,
}
}

func (l *LoginLogic) Login(req *types.LoginRequest) (resp *types.Response, err error) {
if len(strings.TrimSpace(req.Username)) == 0 || len(strings.TrimSpace(req.Password)) == 0 {
return response.Response(2001, "用户名或密码错误", nil)
}
// 使用user rpc
userInfo, err := l.svcCtx.UserRpc.GetUserInfoByUsername(l.ctx, &userclient.UserNameRequest{
Username: req.Username,
})
if err != nil {
return response.Response(2003, "login调用userRpc错误:"+err.Error(), nil)
// return nil, err
}

// 判断登录密码
if userInfo.Password != hash.Md5Hex([]byte(req.Password)) {
return response.Response(2001, "用户名或密码错误", nil)
}

// jwt token
now := time.Now().Unix()
accessSecret := l.svcCtx.Config.Auth.AccessSecret
accessExpire := l.svcCtx.Config.Auth.AccessExpire
jwtToken, err := l.getJwtToken(accessSecret, now, accessExpire, int64(userInfo.Id))
if err != nil {
return response.Response(2002, "login获取jwttoken错误:" + err.Error(), nil)
// return nil, err
}

// data类型可以是map
// return response.Response(200, "ok", map[string]interface{}{
// "id": userInfo.Id,
// "username": userInfo.Username,
// "access_token": jwtToken,
// "access_expire": now + accessExpire,
// "refresh_after": now + accessExpire/2,
// })

// data类型可以是结构体
return response.Response(200, "ok", &types.LoginResult{
Id: userInfo.Id,
Username: userInfo.Username,
AccessToken: jwtToken,
AccessExpire: now + accessExpire,
RefreshAfter: now + accessExpire/2,
})
}

func (l *LoginLogic) getJwtToken(secretKey string, iat, seconds, userId int64) (string, error) {
claims := make(jwt.MapClaims)
claims["exp"] = iat + seconds
claims["iat"] = iat
claims["userId"] = userId
token := jwt.New(jwt.SigningMethodHS256)
token.Claims = claims
return token.SignedString([]byte(secretKey))
}

```