我是靠谱客的博主 傻傻帽子,最近开发中收集的这篇文章主要介绍第七课 实战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介绍
- micro是一个专注于简化分布式系统开发的微服务生态系统。
1.2 go-micro介绍
- go-micro是一个插件化的基础框架,基于此可以构建微服务.
- Micro api , micro api -handler=api
- Micro web
1.3 etcd环境安装
- 是一个服务管理软件。这里我们使用etcd作为服务发现,因为最新版本中已经不支持consul
- etcd安装,下载压缩包,解压缩直接执行 ./etcd
- github.com/etcd-io/etcd/releases
1.4 安装go-micro
- go get github.com/micro/go-micro
- go get github.com/micro/protobuf/{proto,proto-gen-go}
- go get github.com/micro/protoc-gen-micro
1.5 protobuf
- 通过命令直接生成go文件和micro风格的go文件。
- 后缀名.proto
- protobuf是一种语言无关、协议无关、高效轻便的数据存储方式。
# proto的路径 生成go文件路径 micro风格go文件路径 生成的proto文件
protoc -proto_path=xxx -go_out=xxx -micro_out=xxx xxx.proto
1.6 安装micro
- go get安装或者二进制包安装
- go get github.com/micro/micro
- 配置环境变量指定服务发现为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 微服务基本流程
- 编写proto
- 实现服务端代码,实现客户端代码
- 实现API代码,测试
2.2 编写proto并注册
- 编写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;
}
- 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 编写服务端业务逻辑
- 在controllers文件夹中创建一个userRpc.go文件。
- 运行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 编写客户端逻辑
- 在micro中user文件夹下创建client文件夹。创建main程序测试调用下微服务的端口,看下能否成功登录。
- 和上面服务端配合看是否可以登录成功。
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
-
在micro中user文件夹下创建api文件夹下创建main.go
-
访问127.0.0.1:8082/services 可以看到我们注册的服务。测试一下
-
测试成功后,替换前端代码为微服务接口。并验证。
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 改造过程
- 编写proto,包含顶部广告和推荐视频两个接口
- 实现服务端代码,实现客户端代码
- 实现API代码,测试
3.2 编写proto
- 编写video.proto。包含顶部广告和推荐视频两个接口。先找到要改造的接口定义下service VideoService。这里主要是函数名、参数、返回值
- 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 服务端代码编写
- 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)
}
}
- 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 客户端代码编写
- 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
- 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仿优酷-微服务实践所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
发表评论 取消回复