• go zero手把手教你入门案例


    一、入门案例

    • 1、在黑窗口上安装

      go install github.com/zeromicro/go-zero/tools/goctl@latest
      
      • 1
    • 2、使用goland创建一个项目

    • 3、在项目中安装依赖

      go get -u github.com/zeromicro/go-zero@latest
      
      • 1
    • 4、模拟创建一个user的项目

      goctl api new user
      
      • 1
    • 5、安装依赖包

      go mod tidy
      
      • 1
    • 6、补充代码段

      func (l *UserLogic) User(req *types.Request) (resp *types.Response, err error) {
      	// todo: add your logic here and delete this line
      
      	return &types.Response{
      		Message: "你好,水痕",
      	}, nil
      }
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
    • 7、在浏览器上输入http://localhost:8888/from/me,关于为什么是me可以查看types.go文件

      package types
      
      type Request struct {
      	Name string `path:"name,options=you|me"`
      }
      
      • 1
      • 2
      • 3
      • 4
      • 5
    • 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
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      • 17
      • 18
      • 19

    二、自己编写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 login
      	post /api/users/login (LoginRequest) returns (LoginResponse)
      
      	@handler userInfo
      	get /api/users/userInfo returns (UserInfoResponse)
      }
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      • 17
      • 18
      • 19
      • 20
      • 21
      • 22
      • 23
      • 24
      • 25
      • 26
      • 27
      • 28
      • 29
    • 3、执行脚本

      goctl api go -api user.api -dir .
      
      • 1
    • 4、等生成文件后,安装依赖包

    • 5、书写一个获取用户信息的代码

      
      func (l *UserInfoLogic) UserInfo() (resp *types.UserInfoResponse, err error) {
      	// todo: add your logic here and delete this line
      	return &types.UserInfoResponse{
      		Code:    0,
      		Message: "请求成功",
      		Data: types.UserInfo{
      			Id:       1,
      			Username: "水痕",
      		},
      	}, nil
      }
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
    • 6、运行启动

    三、封装自定义返回模板

    • 1、创建一个utils的文件夹

      package utils
      
      import (
      	"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)
      }
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      • 17
      • 18
      • 19
      • 20
      • 21
      • 22
      • 23
      • 24
      • 25
      • 26
      • 27
      • 28
      • 29
      • 30
    • 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 login
      	post /api/users/login (LoginRequest) returns (string )
      
      	@handler userInfo
      	get /api/users/userInfo returns (UserInfoResponse)
      }
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      • 17
    • 3、重新执行转换脚本

      goctl api go -api user.api -dir .
      
      • 1
    • 4、改写代码,后运行

    四、统一前缀

    • 1、上面每次在service里面都要写/api/users/这个路径,如果都是一样的,可以提取出去统一到前面

      // 定义要被方法的方法
      @server(
      	prefix: /api/users
      )
      service users {
      	@handler login
      	post /login (LoginRequest) returns (string)
      
      	@handler userInfo
      	get /userInfo returns (UserInfoResponse)
      }
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
    • 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 login
      	post /login (LoginRequest) returns (string)
      }
      
      @server(
      	prefix: /api/users
      	jwt: Auth
      )
      service users {
      	@handler userInfo
      	get /userInfo returns (UserInfoResponse)
      }
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      • 17
      • 18
      • 19
      • 20
      • 21
      • 22
      • 23
      • 24
      • 25
      • 26
    • 2、重新执行转换文件的脚本

      goctl api go -api user.api -dir .
      goctl api go -api *.api -dir .
      
      • 1
      • 2
    • 3、在etc/users.yaml文件中添加jwt的配置

      Name: users
      Host: 0.0.0.0
      Port: 8888
      Auth:
        AccessSecret: test1test1  # 随机一个数就可以
        AccessExpire: 3600 # 过期时间
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
    • 4、在internal/config/config.go中配置,任何在yaml中添加的配置都要在config.go中添加配置

      package config
      
      import "github.com/zeromicro/go-zero/rest"
      
      type Config struct {
      	rest.RestConf
      	Auth struct {
      		AccessSecret string
      		AccessExpire int64
      	}
      }
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
    • 5、在utils文件夹下创建一个jwt.go的文件

      package utils
      
      import (
      	"errors"
      	"github.com/golang-jwt/jwt/v4"
      	"time"
      )
      
      // JwtPayLoad jwt中payload数据
      type JwtPayLoad struct {
      	UserID   uint   `json:"userId"`   // 用户id
      	Username string `json:"username"` // 用户名
      }
      
      type CustomClaims struct {
      	JwtPayLoad
      	jwt.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")
      }
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      • 17
      • 18
      • 19
      • 20
      • 21
      • 22
      • 23
      • 24
      • 25
      • 26
      • 27
      • 28
      • 29
      • 30
      • 31
      • 32
      • 33
      • 34
      • 35
      • 36
      • 37
      • 38
      • 39
      • 40
      • 41
      • 42
      • 43
      • 44
      • 45
      • 46
    • 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.Auth
      		token, 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("账号或密码错误")
      	}
      }
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      • 17
    • 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
      }
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
    • 8、登录接口生成token

    • 9、测试获取用户信息

      {
      	"Authorization":"Bearer eyJhbGciOiJIUzI1Ni"
      }
      
      • 1
      • 2
      • 3

      在这里插入图片描述

    六、获取客户端参数

    • 1、获取path参数,url上请求的地址为:``,这里xx就是要获取的地址

      type MessageReq {
          Id int64  `path:"id"`
      }
      @server(
          prefix: /api/messages
      )
      service users {
         
          @handler message
          get /message/:id(MessageReq) returns (string)
      }
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
    • 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 messageInfo
          get /messageInfo(MessageInfoReq) returns (string)
      }
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
    • 3、获取post提交的json数据

      type LoginRequest {
      	Username string `json:"username"`
      	Password string `json:"password"`
      }
      
      @server(
      	prefix: /api/users
      )
      service users {
      	@handler login
      	post /login (LoginRequest) returns (string)
      }
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
    • 4、接收方法根据转码后会自动生成,且都是一样的

      var req types.MessageReq
      if err := httpx.Parse(r, &req); err != nil {
          httpx.ErrorCtx(r.Context(), w, err)
          return
      }
      // 直接从req中获取数据就可以
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6

    七、一个项目下多个api文件

    • 1、在实际开发中,我更喜欢一张表就对应一个api文件,这样更好维护,唯一注意点就是每个文件里面的service users这个users是要一样的就可以,实际根据你项目来写的

    • 2、在根目录下创建一个api的文件夹,里面包括message.apiuser.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 messageInfo
          get /messageInfo(MessageInfoReq) returns (string)
      
          @handler message
          get /message/:id(MessageReq) returns (string)
      }
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      • 17
      • 18
      • 19
      • 20
    • 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 login
      	post /login (LoginRequest) returns (string)
      }
      
      @server(
      	prefix: /api/users
      	jwt: Auth
      )
      service users {
      	@handler userInfo
      	get /userInfo returns (UserInfoResponse)
      }
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      • 17
      • 18
      • 19
      • 20
      • 21
      • 22
      • 23
      • 24
      • 25
      • 26
      • 27
      • 28
    • 5、根目录下创建一个api.api的文件

      syntax = "v2"
      
      import "api/user.api"
      import "api/message.api"
      
      • 1
      • 2
      • 3
      • 4
    • 6、运行转码命令

      goctl api go -api api.api -dir .
      # 或者直接使用下面的
      goctl api go -api *.api -dir .
      
      • 1
      • 2
      • 3
  • 相关阅读:
    【设计模式】Java设计模式 - 装饰者模式
    SpringBoot - 集成SWAGGER的常见问题
    消息队列项目创建第二部分
    非关系型数据库-Redis
    RPG Maker MV-场所移动
    流量染色SDK设计的思考
    iOS开发M1芯片遇到的问题
    【AIGC调研系列】利用AIGC技术进行DevOps流水线智能排查
    四旋翼飞行器基本模型(Matlab&Simulink)
    (02)Cartographer源码无死角解析-(15) Node::AddTrajectory()→回调函数之数据流向分析
  • 原文地址:https://blog.csdn.net/kuangshp128/article/details/134475349