我是靠谱客的博主 傻傻帽子,最近开发中收集的这篇文章主要介绍第七课 实战go语言改造php仿优酷-微服务实践第七课 实战go语言改造php仿优酷-微服务实践,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

第七课 实战go语言改造php仿优酷-微服务实践

tags:

  • Beego
  • 慕课网

categories:

  • 微服务

文章目录

  • 第七课 实战go语言改造php仿优酷-微服务实践
    • 第一节 微服务环境工具
      • 1.1 Micro介绍
      • 1.2 go-micro介绍
      • 1.3 etcd环境安装
      • 1.4 安装go-micro
      • 1.5 protobuf
      • 1.6 安装micro
    • 第二节 微服务改造用户登录功能
      • 2.1 微服务基本流程
      • 2.2 编写proto并注册
      • 2.3 编写服务端业务逻辑
      • 2.4 编写客户端逻辑
      • 2.5 封装成API
    • 第三节 微服务改造频道页
      • 3.1 改造过程
      • 3.2 编写proto
      • 3.3 服务端代码编写
      • 3.4 客户端代码编写
      • 3.5 封装成API

第一节 微服务环境工具

1.1 Micro介绍

  1. micro是一个专注于简化分布式系统开发的微服务生态系统。
    在这里插入图片描述

1.2 go-micro介绍

  1. go-micro是一个插件化的基础框架,基于此可以构建微服务.
  2. Micro api , micro api -handler=api
  3. Micro web
    在这里插入图片描述

1.3 etcd环境安装

  1. 是一个服务管理软件。这里我们使用etcd作为服务发现,因为最新版本中已经不支持consul
  2. etcd安装,下载压缩包,解压缩直接执行 ./etcd
  3. github.com/etcd-io/etcd/releases

1.4 安装go-micro

  1. go get github.com/micro/go-micro
  2. go get github.com/micro/protobuf/{proto,proto-gen-go}
  3. go get github.com/micro/protoc-gen-micro

1.5 protobuf

  1. 通过命令直接生成go文件和micro风格的go文件。
  2. 后缀名.proto
  3. protobuf是一种语言无关、协议无关、高效轻便的数据存储方式。
# proto的路径 生成go文件路径 micro风格go文件路径 生成的proto文件
protoc -proto_path=xxx -go_out=xxx -micro_out=xxx xxx.proto

1.6 安装micro

  1. go get安装或者二进制包安装
  2. go get github.com/micro/micro
  3. 配置环境变量指定服务发现为etcd,MICRO_REGISTRY
# 配置环境变量
vi ~/.bash_profile
export MICRO_REGISTRY=etcd
# 保存生效
source ~/.bash_profile
# 执行以下api
micro api --handler=api --address=0.0.0.0:8085

# 重开一个终端 执行以下web
micro web

# 测试一下 访问
127.0.0.1:8085 #api 的服务
127.0.0.1:8082 #web 的服务

第二节 微服务改造用户登录功能

2.1 微服务基本流程

  1. 编写proto
  2. 实现服务端代码,实现客户端代码
  3. 实现API代码,测试

2.2 编写proto并注册

在这里插入图片描述

  1. 编写proto文件。 进入micro文件夹下执行命令:protoc -proto_path=user/proto --go_out=user/proto --micro_out=user/proto user/proto/user.proto
    • 可以成功生成上面的两个文件。
syntax = "proto3"

package proto;

service UserService {
    rpc LoginDo(RequestLoginDo) returns (ResponseLoginDo) {}
}

message RequestLoginDo {
    string mobile = 1;
    string password = 2;
}

message ResponseLoginDo {
    int64 code = 1;
    string msg = 2;
    LoginUser items = 3;
    int64 count = 4;
}

message LoginUser {
    int64 uid = 1;
    string username = 2;
}
  1. ETCD服务发现写在当前micro文件夹的main中。
func main() {
	beego.LoadAppConfig("ini", "../../conf/app.conf")
	defaultdb := beego.AppConfig.String("defaultdb")
	orm.RegisterDriver("mysql", orm.DRMySQL)
	orm.RegisterDataBase("default", "mysql", defaultdb, 30, 30)

	// 服务发现
	reg := etcdv3.NewRegistry(func(op *registry.Options) {
		op.Addrs = []string{"http://127.0.0.1:2379"}
	})

	// 注册服务
	service := micro.NewService(
		micro.Registry(reg),
		micro.Name("go.micro.srv.fyoukuApi.user"),
		micro.RegisterTTL(time.Second*30),
		micro.RegisterInterval(time.Second*10),
	)

	service.Init()
	proto.RegisterUserServiceHandler(service.Server(), new(controllers.UserRpcController))

	if err := service.Run(); err != nil {
		fmt.Println(err)
	}
}

2.3 编写服务端业务逻辑

  1. 在controllers文件夹中创建一个userRpc.go文件。
  2. 运行main.go
//用户登录
// @router /login/do [*]
func (this *UserRpcController) LoginDo(ctx context.Context, req *userRpcProto.RequestLoginDo, res *userRpcProto.ResponseLoginDo) error {
	var (
		userLoginProto userRpcProto.LoginUser
		isorno         bool
		uid            int
		name           string
	)

	mobile := req.Mobile
	password := req.Password

	if mobile == "" {
		res.Code = 4001
		res.Msg = "手机号不能为空"
		goto ERR
	}
	isorno, _ = regexp.MatchString(`^1(3|4|5|7|8)[0-9]d{8}$`, mobile)
	if !isorno {
		res.Code = 4002
		res.Msg = "手机号格式不正确"
		goto ERR
	}
	if password == "" {
		res.Code = 4003
		res.Msg = "密码不能为空"
		goto ERR
	}
	uid, name = models.IsMobileLogin(mobile, MD5V(password))
	if uid != 0 {
		userLoginProto.Uid = int64(uid)
		userLoginProto.Username = name
		res.Code = 0
		res.Msg = "登录成功"
		res.Items = &userLoginProto
		res.Count = 1
		return nil
	} else {
		res.Code = 4004
		res.Msg = "手机号或密码不正确"
		goto ERR
	}
ERR:
	res.Items = &userLoginProto
	res.Count = 0
	return nil
}

2.4 编写客户端逻辑

  1. 在micro中user文件夹下创建client文件夹。创建main程序测试调用下微服务的端口,看下能否成功登录。
  2. 和上面服务端配合看是否可以登录成功。
package main

import (
	"context"
	"fmt"
	userProto "fyoukuApi/micro/user/proto"

	"github.com/micro/go-micro"
	"github.com/micro/go-micro/registry"
	"github.com/micro/go-plugins/registry/etcdv3"
)

func main() {
	reg := etcdv3.NewRegistry(func(op *registry.Options) {
		op.Addrs = []string{"http://127.0.0.1:2379"}
	})
	service := micro.NewService(
		micro.Registry(reg),
	)

	service.Init()

	user := userProto.NewUserService("go.micro.srv.fyoukuApi.user", service.Client())

	rsp, err := user.LoginDo(context.TODO(), &userProto.RequestLoginDo{
		Mobile:   "18600001111",
		Password: "111111",
	})
	if err != nil {
		fmt.Println(err)
		return
	}
	fmt.Println(rsp)
}

2.5 封装成API

  1. 在micro中user文件夹下创建api文件夹下创建main.go

  2. 访问127.0.0.1:8082/services 可以看到我们注册的服务。测试一下
    在这里插入图片描述

  3. 测试成功后,替换前端代码为微服务接口。并验证。

package main

import (
	"context"
	"encoding/json"
	user "fyoukuApi/micro/user/proto"
	"log"
	"strings"
	"time"

	"github.com/micro/go-micro"
	api "github.com/micro/go-micro/api/proto"
	"github.com/micro/go-micro/errors"
	"github.com/micro/go-micro/registry"
	"github.com/micro/go-plugins/registry/etcdv3"
)

type User struct {
	Client user.UserService
}

func (u *User) LoginDo(ctx context.Context, req *api.Request, rsp *api.Response) error {
	log.Print("收到User.LoginDo API请求")
	//接受参数
	mobile, ok := req.Post["mobile"]
	if !ok || len(mobile.Values) == 0 {
		return errors.BadRequest("go.micro.api.fyoukuApi.user", "mobile为空")
	}
	password, ok := req.Post["password"]
	if !ok || len(password.Values) == 0 {
		return errors.BadRequest("go.micro.api.fyoukuApi.user", "password为空")
	}

	response, err := u.Client.LoginDo(ctx, &user.RequestLoginDo{
		Mobile:   strings.Join(mobile.Values, ""),
		Password: strings.Join(password.Values, ""),
	})
	if err != nil {
		return err
	}
	rsp.StatusCode = 200
	b, _ := json.Marshal(map[string]interface{}{
		"code":  response.Code,
		"msg":   response.Msg,
		"items": response.Items,
		"count": response.Count,
	})
	rsp.Body = string(b)
	return nil
}

func main() {
	reg := etcdv3.NewRegistry(func(op *registry.Options) {
		op.Addrs = []string{"http://127.0.0.1:2379"}
	})
	service := micro.NewService(
		micro.Registry(reg),
		micro.Name("go.micro.api.fyoukuApi.user"),
		micro.RegisterTTL(time.Second*30),
		micro.RegisterInterval(time.Second*10),
	)

	service.Init()
	service.Server().Handle(
		service.Server().NewHandler(
			&User{Client: user.NewUserService("go.micro.srv.fyoukuApi.user", service.Client())},
		),
	)

	if err := service.Run(); err != nil {
		log.Fatal(err)
	}
}

第三节 微服务改造频道页

3.1 改造过程

  1. 编写proto,包含顶部广告和推荐视频两个接口
  2. 实现服务端代码,实现客户端代码
  3. 实现API代码,测试
    在这里插入图片描述

3.2 编写proto

  1. 编写video.proto。包含顶部广告和推荐视频两个接口。先找到要改造的接口定义下service VideoService。这里主要是函数名、参数、返回值
  2. protoc -proto_path=video/proto --go_out=video/proto --micro_out=video/proto video/proto/video.proto
syntax = "proto3"

package proto;

service VideoService {
    rpc ChannelAdvert(RequestChannelAdvert) returns (ResponseChannelAdvert) {}
    rpc ChannelHotList(RequestChannelHotList) returns (ResponseChannelHotList) {}
}

message RequestChannelAdvert {
    string channelId = 1;
}

message ResponseChannelAdvert {
    int64 code = 1;
    string msg = 2;
    repeated ChannelAdvertData items = 3;
    int64 count = 4;
}

message ChannelAdvertData {
    int64 id = 1;
    string title = 2;
    string subTitle = 3;
    int64 addTime = 4;
    string img = 5;
    string url = 6;
}

message RequestChannelHotList {
    string channelId = 1;
}

message ResponseChannelHotList {
    int64 code = 1;
    string msg = 2;
    repeated ResponseChannelHotList items = 3;
    int64 count = 4;
}

message ResponseChannelHotList {
    int64 id = 1;
    string title = 2;
    string subTitle = 3;
    int64 addTime = 4;
    string img = 5;
    string img1 = 6;
    int64 episodesCount = 7;
    int64 isEnd = 8;
    int64 comment = 9;
}

3.3 服务端代码编写

  1. mian.go
package main

import (
	"fmt"
	"fyoukuApi/controllers"
	"fyoukuApi/micro/video/proto"
	_ "fyoukuApi/routers"
	"time"

	"github.com/astaxie/beego"
	"github.com/astaxie/beego/orm"
	_ "github.com/go-sql-driver/mysql"
	"github.com/micro/go-micro"
	"github.com/micro/go-micro/registry"
	"github.com/micro/go-plugins/registry/etcdv3"
)

func main() {
	beego.LoadAppConfig("ini", "../../conf/app.conf")
	defaultdb := beego.AppConfig.String("defaultdb")
	orm.RegisterDriver("mysql", orm.DRMySQL)
	orm.RegisterDataBase("default", "mysql", defaultdb, 30, 30)

	reg := etcdv3.NewRegistry(func(op *registry.Options) {
		op.Addrs = []string{"http://127.0.0.1:2379"}
	})

	service := micro.NewService(
		micro.Registry(reg),
		micro.Name("go.micro.srv.fyoukuApi.video"),
		micro.RegisterTTL(time.Second*30),
		micro.RegisterInterval(time.Second*10),
	)

	service.Init()
	proto.RegisterVideoServiceHandler(service.Server(), new(controllers.VideoRpcController))

	if err := service.Run(); err != nil {
		fmt.Println(err)
	}
}
  1. videoRpc.go
package controllers

import (
	"context"
	videoRpcProto "fyoukuApi/micro/video/proto"
	"fyoukuApi/models"
	"strconv"

	"github.com/astaxie/beego"
)

// Operations about Users
type VideoRpcController struct {
	beego.Controller
}

func (this *VideoRpcController) ChannelAdvert(ctx context.Context, req *videoRpcProto.RequestChannelAdvert, res *videoRpcProto.ResponseChannelAdvert) error {
	var (
		channelAdvertDatas []*videoRpcProto.ChannelAdvertData
		num                int64
		videos             []models.Advert
		err                error
	)

	channelId, _ := strconv.Atoi(req.ChannelId)

	if channelId == 0 {
		res.Code = 4001
		res.Msg = "必须指定频道"
		goto ERR
	}
	num, videos, err = models.GetChannelAdvert(channelId)

	if err == nil {
		for _, v := range videos {
			var channelAdvertData videoRpcProto.ChannelAdvertData
			channelAdvertData.Id = int64(v.Id)
			channelAdvertData.Title = v.Title
			channelAdvertData.SubTitle = v.SubTitle
			channelAdvertData.Img = v.Img
			channelAdvertData.Url = v.Url
			channelAdvertData.AddTime = v.AddTime
			channelAdvertDatas = append(channelAdvertDatas, &channelAdvertData)
		}
		res.Code = 0
		res.Msg = "success"
		res.Items = channelAdvertDatas
		res.Count = num
		return nil
	} else {
		res.Code = 4004
		res.Msg = "请求数据失败,请稍后重试~"
		goto ERR
	}
ERR:
	res.Items = channelAdvertDatas
	res.Count = 0
	return nil
}

func (this *VideoRpcController) ChannelHotList(ctx context.Context, req *videoRpcProto.RequestChannelHotList, res *videoRpcProto.ResponseChannelHotList) error {
	var (
		channelHotListDatas []*videoRpcProto.ChannelHotListData
		num                 int64
		videos              []models.VideoData
		err                 error
	)

	channelId, _ := strconv.Atoi(req.ChannelId)

	if channelId == 0 {
		res.Code = 4001
		res.Msg = "必须指定频道"
		goto ERR
	}
	num, videos, err = models.GetChannelHotList(channelId)

	if err == nil {
		for _, v := range videos {
			var channelHotListData videoRpcProto.ChannelHotListData
			channelHotListData.Id = int64(v.Id)
			channelHotListData.Title = v.Title
			channelHotListData.SubTitle = v.SubTitle
			channelHotListData.Img = v.Img
			channelHotListData.Img1 = v.Img1
			channelHotListData.IsEnd = int64(v.IsEnd)
			channelHotListData.AddTime = v.AddTime
			channelHotListData.EpisodesCount = int64(v.EpisodesCount)
			channelHotListData.Comment = int64(v.Comment)
			channelHotListDatas = append(channelHotListDatas, &channelHotListData)
		}

		res.Code = 0
		res.Msg = "success"
		res.Items = channelHotListDatas
		res.Count = num
		return nil
	} else {
		res.Code = 4004
		res.Msg = "没有相关内容"
		goto ERR
	}
ERR:
	res.Items = channelHotListDatas
	res.Count = 0
	return nil
}

3.4 客户端代码编写

  1. client/main.go
package main

import (
	"context"
	"fmt"
	videoProto "fyoukuApi/micro/video/proto"

	"github.com/micro/go-micro"
	"github.com/micro/go-micro/registry"
	"github.com/micro/go-plugins/registry/etcdv3"
)

func main() {
	reg := etcdv3.NewRegistry(func(op *registry.Options) {
		op.Addrs = []string{"http://127.0.0.1:2379"}
	})
	service := micro.NewService(
		micro.Registry(reg),
	)

	service.Init()

	video := videoProto.NewVideoService("go.micro.srv.fyoukuApi.video", service.Client())

	rsp, err := video.ChannelAdvert(context.TODO(), &videoProto.RequestChannelAdvert{
		ChannelId: "1",
	})
	if err != nil {
		fmt.Println(err)
		return
	}
	fmt.Println(rsp)

	rspHot, _ := video.ChannelHotList(context.TODO(), &videoProto.RequestChannelHotList{
		ChannelId: "1",
	})
	if err != nil {
		fmt.Println(err)
		return
	}
	fmt.Println(rspHot)
}

3.5 封装成API

  1. api/main.go
package main

import (
	"context"
	"encoding/json"
	video "fyoukuApi/micro/video/proto"
	"log"
	"strings"
	"time"

	"github.com/micro/go-micro"
	api "github.com/micro/go-micro/api/proto"
	"github.com/micro/go-micro/errors"
	"github.com/micro/go-micro/registry"
	"github.com/micro/go-plugins/registry/etcdv3"
)

type Video struct {
	Client video.VideoService
}

func (v *Video) ChannelAdvert(ctx context.Context, req *api.Request, rsp *api.Response) error {
	log.Print("收到Video.ChannelAdvert API请求")
	//接受参数
	channelId, ok := req.Get["channelId"]
	if !ok || len(channelId.Values) == 0 {
		return errors.BadRequest("go.micro.api.fyoukuApi.video", "channelId为空")
	}

	response, err := v.Client.ChannelAdvert(ctx, &video.RequestChannelAdvert{
		ChannelId: strings.Join(channelId.Values, ""),
	})
	if err != nil {
		return err
	}
	rsp.StatusCode = 200
	b, _ := json.Marshal(map[string]interface{}{
		"code":  response.Code,
		"msg":   response.Msg,
		"items": response.Items,
		"count": response.Count,
	})
	rsp.Body = string(b)
	return nil
}
func (v *Video) ChannelHotList(ctx context.Context, req *api.Request, rsp *api.Response) error {
	log.Print("收到Video.ChannelHotList API请求")
	//接受参数
	channelId, ok := req.Get["channelId"]
	if !ok || len(channelId.Values) == 0 {
		return errors.BadRequest("go.micro.api.fyoukuApi.video", "channelId为空")
	}

	response, err := v.Client.ChannelHotList(ctx, &video.RequestChannelHotList{
		ChannelId: strings.Join(channelId.Values, ""),
	})
	if err != nil {
		return err
	}
	rsp.StatusCode = 200
	b, _ := json.Marshal(map[string]interface{}{
		"code":  response.Code,
		"msg":   response.Msg,
		"items": response.Items,
		"count": response.Count,
	})
	rsp.Body = string(b)
	return nil
}

func main() {
	reg := etcdv3.NewRegistry(func(op *registry.Options) {
		op.Addrs = []string{"http://127.0.0.1:2379"}
	})
	service := micro.NewService(
		micro.Registry(reg),
		micro.Name("go.micro.api.fyoukuApi.video"),
		micro.RegisterTTL(time.Second*30),
		micro.RegisterInterval(time.Second*10),
	)

	service.Init()
	service.Server().Handle(
		service.Server().NewHandler(
			&Video{Client: video.NewVideoService("go.micro.srv.fyoukuApi.video", service.Client())},
		),
	)

	if err := service.Run(); err != nil {
		log.Fatal(err)
	}
}

最后

以上就是傻傻帽子为你收集整理的第七课 实战go语言改造php仿优酷-微服务实践第七课 实战go语言改造php仿优酷-微服务实践的全部内容,希望文章能够帮你解决第七课 实战go语言改造php仿优酷-微服务实践第七课 实战go语言改造php仿优酷-微服务实践所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(42)

评论列表共有 0 条评论

立即
投稿
返回
顶部