一、入门案例
-
1、在黑窗口上安装
go install github.com/zeromicro/go-zero/tools/goctl@latest
-
2、使用
goland
创建一个项目 -
3、在项目中安装依赖
go get -u github.com/zeromicro/go-zero@latest
-
4、模拟创建一个
user
的项目goctl api new user
-
5、安装依赖包
go mod tidy
-
6、补充代码段
func (l *UserLogic) User(req *types.Request) (resp *types.Response, err error) {// todo: add your logic here and delete this linereturn &types.Response{Message: "你好,水痕",}, nil }
-
7、在浏览器上输入
http://localhost:8888/from/me
,关于为什么是me
可以查看types.go
文件package typestype Request struct {Name string `path:"name,options=you|me"` }
-
8、关于
user
项目目录解说. ├── etc │ └── user-api.yaml # 配置文件 ├── internal │ ├── config │ │ └── config.go │ ├── handler │ │ ├── routes.go # 路由文件 │ │ └── userhandler.go # 可以理解为控制层 │ ├── logic │ │ └── userlogic.go # 可以理解为服务层 │ ├── svc │ │ └── servicecontext.go │ └── types │ └── types.go # 可以理解为DTO、VO ├── user.api └── user.go # 启动文件7 directories, 9 files
二、自己编写api
文件来生成别的文件
-
1、创建一个空的
module
项目 -
2、在根目录下创建一个
user.api
的文件type LoginRequest {Username string `json:"username"`Password string `json:"password"` }type LoginResponse {Code int64 `json:"code"`Data string `json:"data"`Message string `json:"message"` }type UserInfo {Id int64 `json:"id"`Username string `json:"username"` }type UserInfoResponse {Code int64 `json:"code"`Data UserInfo `json:"data"`Message string `json:"message"` } // 定义要被方法的方法 service users {@handler loginpost /api/users/login (LoginRequest) returns (LoginResponse)@handler userInfoget /api/users/userInfo returns (UserInfoResponse) }
-
3、执行脚本
goctl api go -api user.api -dir .
-
4、等生成文件后,安装依赖包
-
5、书写一个获取用户信息的代码
func (l *UserInfoLogic) UserInfo() (resp *types.UserInfoResponse, err error) {// todo: add your logic here and delete this linereturn &types.UserInfoResponse{Code: 0,Message: "请求成功",Data: types.UserInfo{Id: 1,Username: "水痕",},}, nil }
-
6、运行启动
三、封装自定义返回模板
-
1、创建一个
utils
的文件夹package utilsimport ("github.com/zeromicro/go-zero/rest/httpx""net/http" )type Body struct {Code int `json:"code"`Message string `json:"message"`Result interface{} `json:"result,omitempty"` }func Response(w http.ResponseWriter, code int, message string, data interface{}) {httpx.OkJson(w, Body{Code: code,Message: message,Result: data,}) }// Success 成功的请求 func Success(w http.ResponseWriter, data interface{}) {Response(w, 0, "请求成功", data) }// Fail 失败的请求 func Fail(w http.ResponseWriter, message string) {Response(w, 1, message, nil) }
-
2、定义
api
的时候就可以去除这些固定的写法type LoginRequest {Username string `json:"username"`Password string `json:"password"` }type UserInfoResponse {Id int64 `json:"id"`Username string `json:"username"` } // 定义要被方法的方法 service users {@handler loginpost /api/users/login (LoginRequest) returns (string )@handler userInfoget /api/users/userInfo returns (UserInfoResponse) }
-
3、重新执行转换脚本
goctl api go -api user.api -dir .
-
4、改写代码,后运行
四、统一前缀
-
1、上面每次在
service
里面都要写/api/users/
这个路径,如果都是一样的,可以提取出去统一到前面// 定义要被方法的方法 @server(prefix: /api/users ) service users {@handler loginpost /login (LoginRequest) returns (string)@handler userInfoget /userInfo returns (UserInfoResponse) }
-
2、重新转换下
五、jwt
的使用
-
1、改写
user.api
文件type LoginRequest {Username string `json:"username"`Password string `json:"password"` }type UserInfoResponse {Id int64 `json:"id"`Username string `json:"username"` } // 定义要被方法的方法 @server(prefix: /api/users ) service users {@handler loginpost /login (LoginRequest) returns (string) }@server(prefix: /api/usersjwt: Auth ) service users {@handler userInfoget /userInfo returns (UserInfoResponse) }
-
2、重新执行转换文件的脚本
goctl api go -api user.api -dir . goctl api go -api *.api -dir .
-
3、在
etc/users.yaml
文件中添加jwt
的配置Name: users Host: 0.0.0.0 Port: 8888 Auth:AccessSecret: test1test1 # 随机一个数就可以AccessExpire: 3600 # 过期时间
-
4、在
internal/config/config.go
中配置,任何在yaml
中添加的配置都要在config.go
中添加配置package configimport "github.com/zeromicro/go-zero/rest"type Config struct {rest.RestConfAuth struct {AccessSecret stringAccessExpire int64} }
-
5、在
utils
文件夹下创建一个jwt.go
的文件package utilsimport ("errors""github.com/golang-jwt/jwt/v4""time" )// JwtPayLoad jwt中payload数据 type JwtPayLoad struct {UserID uint `json:"userId"` // 用户idUsername string `json:"username"` // 用户名 }type CustomClaims struct {JwtPayLoadjwt.RegisteredClaims }// GenToken 创建 Token func GenToken(user JwtPayLoad, accessSecret string, expires int64) (string, error) {claim := CustomClaims{JwtPayLoad: user,RegisteredClaims: jwt.RegisteredClaims{ExpiresAt: jwt.NewNumericDate(time.Now().Add(time.Hour * time.Duration(expires))),},}token := jwt.NewWithClaims(jwt.SigningMethodHS256, claim)return token.SignedString([]byte(accessSecret)) }// ParseToken 解析 token func ParseToken(tokenStr string, accessSecret string, expires int64) (*CustomClaims, error) {token, err := jwt.ParseWithClaims(tokenStr, &CustomClaims{}, func(token *jwt.Token) (interface{}, error) {return []byte(accessSecret), nil})if err != nil {return nil, err}if claims, ok := token.Claims.(*CustomClaims); ok && token.Valid {return claims, nil}return nil, errors.New("invalid token") }
-
6、在登录的时候返回
token
给前端func (l *LoginLogic) Login(req *types.LoginRequest) (resp string, err error) {// TODO 模拟查询数据库操作if req.Username == "admin" && req.Password == "123456" {auth := l.svcCtx.Config.Authtoken, err := utils.GenToken(utils.JwtPayLoad{UserID: 1,Username: req.Username,}, auth.AccessSecret, auth.AccessExpire)if err != nil {fmt.Println("生成token失败")return "", errors.New("账号或密码错误")}return token, nil} else {return "", errors.New("账号或密码错误")} }
-
7、在需要从
token
中获取用户信息func (l *UserInfoLogic) UserInfo() (resp *types.UserInfoResponse, err error) {// todo: add your logic here and delete this line// 从请求头中获取token,解析出来userId := l.ctx.Value("userId").(json.Number)fmt.Println(userId)fmt.Printf("数据类型:%v,%T\n", userId, userId)username := l.ctx.Value("username").(string)fmt.Println(username)uid, _ := userId.Int64()return &types.UserInfoResponse{Id: uid,Username: username,}, nil }
-
8、登录接口生成
token
-
9、测试获取用户信息
{"Authorization":"Bearer eyJhbGciOiJIUzI1Ni" }
六、获取客户端参数
-
1、获取
path
参数,url
上请求的地址为:``,这里xx
就是要获取的地址type MessageReq {Id int64 `path:"id"` } @server(prefix: /api/messages ) service users {@handler messageget /message/:id(MessageReq) returns (string) }
-
2、获取
query
参数,url
上请求的地址为localhost:8888/api/message?name=xx&age=zz
type MessageInfoReq {Name string `form:"name"`Age int64 `form:"age"` }@server(prefix: /api/messages ) service users {@handler messageInfoget /messageInfo(MessageInfoReq) returns (string) }
-
3、获取
post
提交的json
数据type LoginRequest {Username string `json:"username"`Password string `json:"password"` }@server(prefix: /api/users ) service users {@handler loginpost /login (LoginRequest) returns (string) }
-
4、接收方法根据转码后会自动生成,且都是一样的
var req types.MessageReq if err := httpx.Parse(r, &req); err != nil {httpx.ErrorCtx(r.Context(), w, err)return } // 直接从req中获取数据就可以
七、一个项目下多个api
文件
-
1、在实际开发中,我更喜欢一张表就对应一个
api
文件,这样更好维护,唯一注意点就是每个文件里面的service users
这个users
是要一样的就可以,实际根据你项目来写的 -
2、在根目录下创建一个
api
的文件夹,里面包括message.api
和user.api
-
3、
message.api
文件内容syntax = "v2"type MessageInfoReq {Name string `form:"name,default=word"`Age int64 `form:"age,default=20"` }type MessageReq {Id int64 `path:"id"` } @server(prefix: /api/messages ) service users {@handler messageInfoget /messageInfo(MessageInfoReq) returns (string)@handler messageget /message/:id(MessageReq) returns (string) }
-
4、
user.api
文件内容syntax = "v2"type LoginRequest {Username string `json:"username"`Password string `json:"password"` }type UserInfoResponse {Id int64 `json:"id"`Username string `json:"username"` } // 定义要被方法的方法 @server(prefix: /api/users ) service users {@handler loginpost /login (LoginRequest) returns (string) }@server(prefix: /api/usersjwt: Auth ) service users {@handler userInfoget /userInfo returns (UserInfoResponse) }
-
5、根目录下创建一个
api.api
的文件syntax = "v2"import "api/user.api" import "api/message.api"
-
6、运行转码命令
goctl api go -api api.api -dir . # 或者直接使用下面的 goctl api go -api *.api -dir .