<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          帶你十天輕松搞定 Go 微服務系列(四)

          共 14081字,需瀏覽 29分鐘

           ·

          2022-02-21 21:03

          序言

          我們通過一個系列文章跟大家詳細展示一個 go-zero 微服務示例,整個系列分十篇文章,目錄結構如下:

          1. 環(huán)境搭建:帶你十天輕松搞定 Go 微服務系列(一)
          2. 服務拆分:帶你十天輕松搞定 Go 微服務系列(二)
          3. 用戶服務:帶你十天輕松搞定 Go 微服務系列(三)
          4. 產(chǎn)品服務(本文)
          5. 訂單服務
          6. 支付服務
          7. RPC 服務 Auth 驗證
          8. 服務監(jiān)控
          9. 鏈路追蹤
          10. 分布式事務

          期望通過本系列帶你在本機利用 Docker 環(huán)境利用 go-zero 快速開發(fā)一個商城系統(tǒng),讓你快速上手微服務。

          完整示例代碼:https://github.com/nivin-studio/go-zero-mall

          首先,我們來看一下整體的服務拆分圖:

          4. 產(chǎn)品服務(product)

          • 進入服務工作區(qū)
          $?cd?mall/service/product

          4.1 生成 product model 模型

          • 創(chuàng)建 sql 文件
          $?vim?model/product.sql
          • 編寫 sql 文件
          CREATE?TABLE?`product`?(
          ?`id`?bigint?unsigned?NOT?NULL?AUTO_INCREMENT,
          ?`name`?varchar(255)??NOT?NULL?DEFAULT?''?COMMENT?'產(chǎn)品名稱',
          ?`desc`?varchar(255)??NOT?NULL?DEFAULT?''?COMMENT?'產(chǎn)品描述',
          ????????`stock`?int(10)?unsigned?NOT?NULL?DEFAULT?'0'?COMMENT?'產(chǎn)品庫存',
          ?`amount`?int(10)?unsigned?NOT?NULL?DEFAULT?'0'??COMMENT?'產(chǎn)品金額',
          ?`status`?tinyint(3)?unsigned?NOT?NULL?DEFAULT?'0'?COMMENT?'產(chǎn)品狀態(tài)',
          ?`create_time`?timestamp?NULL?DEFAULT?CURRENT_TIMESTAMP,
          ?`update_time`?timestamp?NULL?DEFAULT?CURRENT_TIMESTAMP?ON?UPDATE?CURRENT_TIMESTAMP,
          ?PRIMARY?KEY?(`id`)
          )?ENGINE=InnoDB??DEFAULT?CHARSET=utf8mb4;
          • 運行模板生成命令
          $?goctl?model?mysql?ddl?-src?./model/product.sql?-dir?./model?-c

          4.2 生成 product api 服務

          • 創(chuàng)建 api 文件
          $?vim?api/product.api
          • 編寫 api 文件
          type?(
          ?//?產(chǎn)品創(chuàng)建
          ?CreateRequest?{
          ??Name???string?`json:"name"`
          ??Desc???string?`json:"desc"`
          ??Stock??int64??`json:"stock"`
          ??Amount?int64??`json:"amount"`
          ??Status?int64??`json:"status"`
          ?}
          ?CreateResponse?{
          ??Id?int64?`json:"id"`
          ?}
          ?//?產(chǎn)品創(chuàng)建

          ?//?產(chǎn)品修改
          ?UpdateRequest?{
          ??Id?????int64??`json:"id"`
          ??Name???string?`json:"name,optional"`
          ??Desc???string?`json:"desc,optional"`
          ??Stock??int64??`json:"stock"`
          ??Amount?int64??`json:"amount,optional"`
          ??Status?int64??`json:"status,optional"`
          ?}
          ?UpdateResponse?{
          ?}
          ?//?產(chǎn)品修改

          ?//?產(chǎn)品刪除
          ?RemoveRequest?{
          ??Id?int64?`json:"id"`
          ?}
          ?RemoveResponse?{
          ?}
          ?//?產(chǎn)品刪除

          ?//?產(chǎn)品詳情
          ?DetailRequest?{
          ??Id?int64?`json:"id"`
          ?}
          ?DetailResponse?{
          ??Id?????int64??`json:"id"`
          ??Name???string?`json:"name"`
          ??Desc???string?`json:"desc"`
          ??Stock??int64??`json:"stock"`
          ??Amount?int64??`json:"amount"`
          ??Status?int64??`json:"status"`
          ?}
          ?//?產(chǎn)品詳情
          )

          @server(
          ?jwt:?Auth
          )
          service?Product?{
          ?@handler?Create
          ?post?/api/product/create(CreateRequest)?returns?(CreateResponse)
          ?
          ?@handler?Update
          ?post?/api/product/update(UpdateRequest)?returns?(UpdateResponse)
          ?
          ?@handler?Remove
          ?post?/api/product/remove(RemoveRequest)?returns?(RemoveResponse)
          ?
          ?@handler?Detail
          ?post?/api/product/detail(DetailRequest)?returns?(DetailResponse)
          }
          • 運行模板生成命令
          $?goctl?api?go?-api?./api/product.api?-dir?./api

          4.3 生成 product rpc 服務

          • 創(chuàng)建 proto 文件
          $?vim?rpc/product.proto
          • 編寫 proto 文件
          syntax = "proto3";

          package productclient;

          option go_package = "product";

          // 產(chǎn)品創(chuàng)建
          message CreateRequest {
          string Name = 1;
          string Desc = 2;
          int64 Stock = 3;
          int64 Amount = 4;
          int64 Status = 5;
          }
          message CreateResponse {
          int64 id = 1;
          }
          // 產(chǎn)品創(chuàng)建

          // 產(chǎn)品修改
          message UpdateRequest {
          int64 id = 1;
          string Name = 2;
          string Desc = 3;
          int64 Stock = 4;
          int64 Amount = 5;
          int64 Status = 6;
          }
          message UpdateResponse {
          }
          // 產(chǎn)品修改

          // 產(chǎn)品刪除
          message RemoveRequest {
          int64 id = 1;
          }
          message RemoveResponse {
          }
          // 產(chǎn)品刪除

          // 產(chǎn)品詳情
          message DetailRequest {
          int64 id = 1;
          }
          message DetailResponse {
          int64 id = 1;
          string Name = 2;
          string Desc = 3;
          int64 Stock = 4;
          int64 Amount = 5;
          int64 Status = 6;
          }
          // 產(chǎn)品詳情

          service Product {
          rpc Create(CreateRequest) returns(CreateResponse);
          rpc Update(UpdateRequest) returns(UpdateResponse);
          rpc Remove(RemoveRequest) returns(RemoveResponse);
          rpc Detail(DetailRequest) returns(DetailResponse);
          }
          • 運行模板生成命令
          $?goctl?rpc?proto?-src?./rpc/product.proto?-dir?./rpc

          4.4 編寫 product rpc 服務

          4.4.1 修改配置文件

          • 修改 product.yaml 配置文件
          $?vim?rpc/etc/product.yaml
          • 修改服務監(jiān)聽地址,端口號為0.0.0.0:9001,Etcd 服務配置,Mysql 服務配置,CacheRedis 服務配置
          Name:?product.rpc
          ListenOn:?0.0.0.0:9001

          Etcd:
          ??Hosts:
          ??-?etcd:2379
          ??Key:?product.rpc

          Mysql:
          ??DataSource:?root:123456@tcp(mysql:3306)/mall?charset=utf8mb4&parseTime=true&loc=Asia%2FShanghai

          CacheRedis:
          -?Host:?redis:6379
          ??Type:?node?#?node可以不寫,可以設為cluster
          ??#?Pass:?xxx?#?如果有密碼

          4.4.2 添加 product model 依賴

          • 添加 Mysql 服務配置,CacheRedis 服務配置的實例化
          $?vim?rpc/internal/config/config.go
          package?config

          import?(
          ?"github.com/tal-tech/go-zero/core/stores/cache"
          ?"github.com/tal-tech/go-zero/zrpc"
          )

          type?Config?struct?{
          ?zrpc.RpcServerConf

          ?Mysql?struct?{
          ??DataSource?string
          ?}
          ??
          ?CacheRedis?cache.CacheConf
          }
          • 注冊服務上下文 product model 的依賴
          $?vim?rpc/internal/svc/servicecontext.go
          package?svc

          import?(
          ?"mall/service/product/model"
          ?"mall/service/product/rpc/internal/config"

          ?"github.com/tal-tech/go-zero/core/stores/sqlx"
          )

          type?ServiceContext?struct?{
          ?Config?config.Config
          ????
          ?ProductModel?model.ProductModel
          }

          func?NewServiceContext(c?config.Config)?*ServiceContext?{
          ?conn?:=?sqlx.NewMysql(c.Mysql.DataSource)
          ?return?&ServiceContext{
          ??Config:???????c,
          ??ProductModel:?model.NewProductModel(conn,?c.CacheRedis),
          ?}
          }

          4.4.3 添加產(chǎn)品創(chuàng)建邏輯 Create

          $?vim?rpc/internal/logic/createlogic.go
          package?logic

          import?(
          ?"context"

          ?"mall/service/product/model"
          ?"mall/service/product/rpc/internal/svc"
          ?"mall/service/product/rpc/product"

          ?"github.com/tal-tech/go-zero/core/logx"
          ?"google.golang.org/grpc/status"
          )

          type?CreateLogic?struct?{
          ?ctx????context.Context
          ?svcCtx?*svc.ServiceContext
          ?logx.Logger
          }

          func?NewCreateLogic(ctx?context.Context,?svcCtx?*svc.ServiceContext)?*CreateLogic?{
          ?return?&CreateLogic{
          ??ctx:????ctx,
          ??svcCtx:?svcCtx,
          ??Logger:?logx.WithContext(ctx),
          ?}
          }

          func?(l?*CreateLogic)?Create(in?*product.CreateRequest)?(*product.CreateResponse,?error)?{
          ?newProduct?:=?model.Product{
          ??Name:???in.Name,
          ??Desc:???in.Desc,
          ??Stock:??in.Stock,
          ??Amount:?in.Amount,
          ??Status:?in.Status,
          ?}

          ?res,?err?:=?l.svcCtx.ProductModel.Insert(&newProduct)
          ?if?err?!=?nil?{
          ??return?nil,?status.Error(500,?err.Error())
          ?}

          ?newProduct.Id,?err?=?res.LastInsertId()
          ?if?err?!=?nil?{
          ??return?nil,?status.Error(500,?err.Error())
          ?}

          ?return?&product.CreateResponse{
          ??Id:?newProduct.Id,
          ?},?nil
          }

          4.4.4 添加產(chǎn)品詳情邏輯 Detail

          $?vim?rpc/internal/logic/detaillogic.go
          package?logic

          import?(
          ?"context"

          ?"mall/service/product/model"
          ?"mall/service/product/rpc/internal/svc"
          ?"mall/service/product/rpc/product"

          ?"github.com/tal-tech/go-zero/core/logx"
          ?"google.golang.org/grpc/status"
          )

          type?DetailLogic?struct?{
          ?ctx????context.Context
          ?svcCtx?*svc.ServiceContext
          ?logx.Logger
          }

          func?NewDetailLogic(ctx?context.Context,?svcCtx?*svc.ServiceContext)?*DetailLogic?{
          ?return?&DetailLogic{
          ??ctx:????ctx,
          ??svcCtx:?svcCtx,
          ??Logger:?logx.WithContext(ctx),
          ?}
          }

          func?(l?*DetailLogic)?Detail(in?*product.DetailRequest)?(*product.DetailResponse,?error)?{
          ?//?查詢產(chǎn)品是否存在
          ?res,?err?:=?l.svcCtx.ProductModel.FindOne(in.Id)
          ?if?err?!=?nil?{
          ??if?err?==?model.ErrNotFound?{
          ???return?nil,?status.Error(100,?"產(chǎn)品不存在")
          ??}
          ??return?nil,?status.Error(500,?err.Error())
          ?}

          ?return?&product.DetailResponse{
          ??Id:?????res.Id,
          ??Name:???res.Name,
          ??Desc:???res.Desc,
          ??Stock:??res.Stock,
          ??Amount:?res.Amount,
          ??Status:?res.Status,
          ?},?nil
          }

          4.4.5 添加產(chǎn)品更新邏輯 Update

          $?vim?rpc/internal/logic/updatelogic.go
          package?logic

          import?(
          ?"context"

          ?"mall/service/product/model"
          ?"mall/service/product/rpc/internal/svc"
          ?"mall/service/product/rpc/product"

          ?"github.com/tal-tech/go-zero/core/logx"
          ?"google.golang.org/grpc/status"
          )

          type?UpdateLogic?struct?{
          ?ctx????context.Context
          ?svcCtx?*svc.ServiceContext
          ?logx.Logger
          }

          func?NewUpdateLogic(ctx?context.Context,?svcCtx?*svc.ServiceContext)?*UpdateLogic?{
          ?return?&UpdateLogic{
          ??ctx:????ctx,
          ??svcCtx:?svcCtx,
          ??Logger:?logx.WithContext(ctx),
          ?}
          }

          func?(l?*UpdateLogic)?Update(in?*product.UpdateRequest)?(*product.UpdateResponse,?error)?{
          ?//?查詢產(chǎn)品是否存在
          ?res,?err?:=?l.svcCtx.ProductModel.FindOne(in.Id)
          ?if?err?!=?nil?{
          ??if?err?==?model.ErrNotFound?{
          ???return?nil,?status.Error(100,?"產(chǎn)品不存在")
          ??}
          ??return?nil,?status.Error(500,?err.Error())
          ?}

          ?if?in.Name?!=?""?{
          ??res.Name?=?in.Name
          ?}
          ?if?in.Desc?!=?""?{
          ??res.Desc?=?in.Desc
          ?}
          ?if?in.Stock?!=?0?{
          ??res.Stock?=?in.Stock
          ?}
          ?if?in.Amount?!=?0?{
          ??res.Amount?=?in.Amount
          ?}
          ?if?in.Status?!=?0?{
          ??res.Status?=?in.Status
          ?}

          ?err?=?l.svcCtx.ProductModel.Update(res)
          ?if?err?!=?nil?{
          ??return?nil,?status.Error(500,?err.Error())
          ?}

          ?return?&product.UpdateResponse{},?nil
          }

          4.4.6 添加產(chǎn)品刪除邏輯 Remove

          $?vim?rpc/internal/logic/removelogic.go
          package?logic

          import?(
          ?"context"

          ?"mall/service/product/model"
          ?"mall/service/product/rpc/internal/svc"
          ?"mall/service/product/rpc/product"

          ?"github.com/tal-tech/go-zero/core/logx"
          ?"google.golang.org/grpc/status"
          )

          type?RemoveLogic?struct?{
          ?ctx????context.Context
          ?svcCtx?*svc.ServiceContext
          ?logx.Logger
          }

          func?NewRemoveLogic(ctx?context.Context,?svcCtx?*svc.ServiceContext)?*RemoveLogic?{
          ?return?&RemoveLogic{
          ??ctx:????ctx,
          ??svcCtx:?svcCtx,
          ??Logger:?logx.WithContext(ctx),
          ?}
          }

          func?(l?*RemoveLogic)?Remove(in?*product.RemoveRequest)?(*product.RemoveResponse,?error)?{
          ?//?查詢產(chǎn)品是否存在
          ?res,?err?:=?l.svcCtx.ProductModel.FindOne(in.Id)
          ?if?err?!=?nil?{
          ??if?err?==?model.ErrNotFound?{
          ???return?nil,?status.Error(100,?"產(chǎn)品不存在")
          ??}
          ??return?nil,?status.Error(500,?err.Error())
          ?}

          ?err?=?l.svcCtx.ProductModel.Delete(res.Id)
          ?if?err?!=?nil?{
          ??return?nil,?status.Error(500,?err.Error())
          ?}

          ?return?&product.RemoveResponse{},?nil
          }

          4.5 編寫 product api 服務

          4.5.1 修改配置文件

          • 修改 product.yaml 配置文件
          $?vim?api/etc/product.yaml
          • 修改服務地址,端口號為0.0.0.0:8001,Mysql 服務配置,CacheRedis 服務配置,Auth 驗證配置
          Name:?Product
          Host:?0.0.0.0
          Port:?8001

          Mysql:
          ??DataSource:?root:123456@tcp(mysql:3306)/mall?charset=utf8mb4&parseTime=true&loc=Asia%2FShanghai

          CacheRedis:
          -?Host:?redis:6379
          ??Type:?node?#?node可以不寫,可以設為cluster
          ??#?Pass:?xxx?#?如果有密碼

          Auth:
          ??AccessSecret:?uOvKLmVfztaXGpNYd4Z0I1SiT7MweJhl
          ??AccessExpire:?86400

          4.5.2 添加 product rpc 依賴

          • 添加 product rpc 服務配置
          $?vim?api/etc/product.yaml
          Name:?Product
          Host:?0.0.0.0
          Port:?8001
          ...
          ProductRpc:
          ??Etcd:
          ????Hosts:
          ????-?etcd:2379
          ????Key:?product.rpc
          • 添加 product rpc 服務配置的實例化
          $?vim?api/internal/config/config.go
          package?config

          import?(
          ?"github.com/tal-tech/go-zero/rest"
          ?"github.com/tal-tech/go-zero/zrpc"
          )

          type?Config?struct?{
          ?rest.RestConf

          ?Auth?struct?{
          ??AccessSecret?string
          ??AccessExpire?int64
          ?}

          ?ProductRpc?zrpc.RpcClientConf
          }
          • 注冊服務上下文 product rpc 的依賴
          $?vim?api/internal/svc/servicecontext.go
          package?svc

          import?(
          ?"mall/service/product/api/internal/config"
          ?"mall/service/product/rpc/productclient"

          ?"github.com/tal-tech/go-zero/zrpc"
          )

          type?ServiceContext?struct?{
          ?Config?config.Config
          ????
          ?ProductRpc?productclient.Product
          }

          func?NewServiceContext(c?config.Config)?*ServiceContext?{
          ?return?&ServiceContext{
          ??Config:?????c,
          ??ProductRpc:?productclient.NewProduct(zrpc.MustNewClient(c.ProductRpc)),
          ?}
          }

          4.5.3 添加產(chǎn)品創(chuàng)建邏輯 Create

          $?vim?api/internal/logic/createlogic.go
          package?logic

          import?(
          ?"context"

          ?"mall/service/product/api/internal/svc"
          ?"mall/service/product/api/internal/types"
          ?"mall/service/product/rpc/product"

          ?"github.com/tal-tech/go-zero/core/logx"
          )

          type?CreateLogic?struct?{
          ?logx.Logger
          ?ctx????context.Context
          ?svcCtx?*svc.ServiceContext
          }

          func?NewCreateLogic(ctx?context.Context,?svcCtx?*svc.ServiceContext)?CreateLogic?{
          ?return?CreateLogic{
          ??Logger:?logx.WithContext(ctx),
          ??ctx:????ctx,
          ??svcCtx:?svcCtx,
          ?}
          }

          func?(l?*CreateLogic)?Create(req?types.CreateRequest)?(resp?*types.CreateResponse,?err?error)?{
          ?res,?err?:=?l.svcCtx.ProductRpc.Create(l.ctx,?&product.CreateRequest{
          ??Name:???req.Name,
          ??Desc:???req.Desc,
          ??Stock:??req.Stock,
          ??Amount:?req.Amount,
          ??Status:?req.Status,
          ?})
          ?if?err?!=?nil?{
          ??return?nil,?err
          ?}

          ?return?&types.CreateResponse{
          ??Id:?res.Id,
          ?},?nil
          }

          4.5.4 添加產(chǎn)品詳情邏輯 Detail

          $?vim?api/internal/logic/detaillogic.go
          package?logic

          import?(
          ?"context"

          ?"mall/service/product/api/internal/svc"
          ?"mall/service/product/api/internal/types"
          ?"mall/service/product/rpc/product"

          ?"github.com/tal-tech/go-zero/core/logx"
          )

          type?DetailLogic?struct?{
          ?logx.Logger
          ?ctx????context.Context
          ?svcCtx?*svc.ServiceContext
          }

          func?NewDetailLogic(ctx?context.Context,?svcCtx?*svc.ServiceContext)?DetailLogic?{
          ?return?DetailLogic{
          ??Logger:?logx.WithContext(ctx),
          ??ctx:????ctx,
          ??svcCtx:?svcCtx,
          ?}
          }

          func?(l?*DetailLogic)?Detail(req?types.DetailRequest)?(resp?*types.DetailResponse,?err?error)?{
          ?res,?err?:=?l.svcCtx.ProductRpc.Detail(l.ctx,?&product.DetailRequest{
          ??Id:?req.Id,
          ?})
          ?if?err?!=?nil?{
          ??return?nil,?err
          ?}

          ?return?&types.DetailResponse{
          ??Id:?????res.Id,
          ??Name:???res.Name,
          ??Desc:???res.Desc,
          ??Stock:??res.Stock,
          ??Amount:?res.Amount,
          ??Status:?res.Status,
          ?},?nil
          }

          4.5.5 添加產(chǎn)品更新邏輯 Update

          $?vim?api/internal/logic/updatelogic.go
          package?logic

          import?(
          ?"context"

          ?"mall/service/product/api/internal/svc"
          ?"mall/service/product/api/internal/types"
          ?"mall/service/product/rpc/product"

          ?"github.com/tal-tech/go-zero/core/logx"
          )

          type?UpdateLogic?struct?{
          ?logx.Logger
          ?ctx????context.Context
          ?svcCtx?*svc.ServiceContext
          }

          func?NewUpdateLogic(ctx?context.Context,?svcCtx?*svc.ServiceContext)?UpdateLogic?{
          ?return?UpdateLogic{
          ??Logger:?logx.WithContext(ctx),
          ??ctx:????ctx,
          ??svcCtx:?svcCtx,
          ?}
          }

          func?(l?*UpdateLogic)?Update(req?types.UpdateRequest)?(resp?*types.UpdateResponse,?err?error)?{
          ?_,?err?=?l.svcCtx.ProductRpc.Update(l.ctx,?&product.UpdateRequest{
          ??Id:?????req.Id,
          ??Name:???req.Name,
          ??Desc:???req.Desc,
          ??Stock:??req.Stock,
          ??Amount:?req.Amount,
          ??Status:?req.Status,
          ?})
          ?if?err?!=?nil?{
          ??return?nil,?err
          ?}

          ?return?&types.UpdateResponse{},?nil
          }

          4.5.6 添加產(chǎn)品刪除邏輯 Remove

          $?vim?api/internal/logic/removelogic.go
          package?logic

          import?(
          ?"context"

          ?"mall/service/product/api/internal/svc"
          ?"mall/service/product/api/internal/types"
          ?"mall/service/product/rpc/product"

          ?"github.com/tal-tech/go-zero/core/logx"
          )

          type?RemoveLogic?struct?{
          ?logx.Logger
          ?ctx????context.Context
          ?svcCtx?*svc.ServiceContext
          }

          func?NewRemoveLogic(ctx?context.Context,?svcCtx?*svc.ServiceContext)?RemoveLogic?{
          ?return?RemoveLogic{
          ??Logger:?logx.WithContext(ctx),
          ??ctx:????ctx,
          ??svcCtx:?svcCtx,
          ?}
          }

          func?(l?*RemoveLogic)?Remove(req?types.RemoveRequest)?(resp?*types.RemoveResponse,?err?error)?{
          ?_,?err?=?l.svcCtx.ProductRpc.Remove(l.ctx,?&product.RemoveRequest{
          ??Id:?req.Id,
          ?})
          ?if?err?!=?nil?{
          ??return?nil,?err
          ?}

          ?return?&types.RemoveResponse{},?nil
          }

          4.6 啟動 product rpc 服務

          提示:啟動服務需要在 golang 容器中啟動

          $?cd?mall/service/product/rpc
          $?go?run?product.go?-f?etc/product.yaml
          Starting?rpc?server?at?127.0.0.1:9001...

          4.7 啟動 product api 服務

          提示:啟動服務需要在 golang 容器中啟動

          $?cd?mall/service/product/api
          $?go?run?product.go?-f?etc/product.yaml
          Starting?server?at?0.0.0.0:8001...

          項目地址

          https://github.com/zeromicro/go-zero

          歡迎使用 go-zerostar 支持我們!



          推薦閱讀


          福利

          我為大家整理了一份從入門到進階的Go學習資料禮包,包含學習建議:入門看什么,進階看什么。關注公眾號 「polarisxu」,回復?ebook?獲取;還可以回復「進群」,和數(shù)萬 Gopher 交流學習。

          瀏覽 98
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  第四色大香蕉 | 成人黄色免费在线 | 巨乳波霸在线 | 大鸡巴欧美 | 人人干人人插人人摸 |