go zero手把手教你入门案例

一、入门案例

  • 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 line
    
    	return &types.Response{
    		Message: "你好,水痕",
    	}, nil
    }
    
  • 7、在浏览器上输入http://localhost:8888/from/me,关于为什么是me可以查看types.go文件

    package types
    
    type 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 login
    	post /api/users/login (LoginRequest) returns (LoginResponse)
    
    	@handler userInfo
    	get /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 line
    	return &types.UserInfoResponse{
    		Code:    0,
    		Message: "请求成功",
    		Data: types.UserInfo{
    			Id:       1,
    			Username: "水痕",
    		},
    	}, nil
    }
    
  • 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)
    }
    
  • 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)
    }
    
  • 3、重新执行转换脚本

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

四、统一前缀

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

    // 定义要被方法的方法
    @server(
    	prefix: /api/users
    )
    service users {
    	@handler login
    	post /login (LoginRequest) returns (string)
    
    	@handler userInfo
    	get /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 login
    	post /login (LoginRequest) returns (string)
    }
    
    @server(
    	prefix: /api/users
    	jwt: Auth
    )
    service users {
    	@handler userInfo
    	get /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 config
    
    import "github.com/zeromicro/go-zero/rest"
    
    type Config struct {
    	rest.RestConf
    	Auth struct {
    		AccessSecret string
    		AccessExpire int64
    	}
    }
    
  • 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")
    }
    
  • 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("账号或密码错误")
    	}
    }
    
  • 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"
    }
    

    go zero手把手教你入门案例_第1张图片

六、获取客户端参数

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

    type MessageReq {
        Id int64  `path:"id"`
    }
    @server(
        prefix: /api/messages
    )
    service users {
       
        @handler message
        get /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 messageInfo
        get /messageInfo(MessageInfoReq) returns (string)
    }
    
  • 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)
    }
    
  • 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.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)
    }
    
  • 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)
    }
    
  • 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 .
    

你可能感兴趣的:(go,golang,开发语言,后端)