序言

我们通过一个系列文章跟大家详细展示一个 go-zero 微服务示例,整个系列分十篇文章,目录结构如下:

  1. 环境搭建
  2. 服务拆分
  3. 用户服务(本文)
  4. 产品服务
  5. 订单服务
  6. 支付服务
  7. RPC 服务 Auth 验证
  8. 服务监控
  9. 链路追踪
  10. 分布式事务

期望通过本系列带你在本机利用 Docker 环境利用 go-zero 快速开发一个商城系统,让你快速上手微服务。

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

首先,我们来更新一下上篇文章中的服务拆分图片,由于微信公众号手机和电脑端不同步,导致美化的图片没有跟大家见面,特此补上,如图:

3 用户服务(user)

  • 进入服务工作区
  1. $ cd mall/service/user

3.1 生成 user model 模型

  • 创建 sql 文件
  1. $ vim model/user.sql
  • 编写 sql 文件
  1. CREATE TABLE `user` (
  2. `id` bigint unsigned NOT NULL AUTO_INCREMENT,
  3. `name` varchar(255) NOT NULL DEFAULT '' COMMENT '用户姓名',
  4. `gender` tinyint(3) unsigned NOT NULL DEFAULT '0' COMMENT '用户性别',
  5. `mobile` varchar(255) NOT NULL DEFAULT '' COMMENT '用户电话',
  6. `password` varchar(255) NOT NULL DEFAULT '' COMMENT '用户密码',
  7. `create_time` timestamp NULL DEFAULT CURRENT_TIMESTAMP,
  8. `update_time` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  9. PRIMARY KEY (`id`),
  10. UNIQUE KEY `idx_mobile_unique` (`mobile`)
  11. ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
  • 运行模板生成命令
  1. $ goctl model mysql ddl -src ./model/user.sql -dir ./model -c

3.2 生成 user api 服务

  • 创建 api 文件
  1. $ vim api/user.api
  • 编写 api 文件
  1. type (
  2. // 用户登录
  3. LoginRequest {
  4. Mobile string `json:"mobile"`
  5. Password string `json:"password"`
  6. }
  7. LoginResponse {
  8. AccessToken string `json:"accessToken"`
  9. AccessExpire int64 `json:"accessExpire"`
  10. }
  11. // 用户登录
  12. // 用户注册
  13. RegisterRequest {
  14. Name string `json:"name"`
  15. Gender int64 `json:"gender"`
  16. Mobile string `json:"mobile"`
  17. Password string `json:"password"`
  18. }
  19. RegisterResponse {
  20. Id int64 `json:"id"`
  21. Name string `json:"name"`
  22. Gender int64 `json:"gender"`
  23. Mobile string `json:"mobile"`
  24. }
  25. // 用户注册
  26. // 用户信息
  27. UserInfoResponse {
  28. Id int64 `json:"id"`
  29. Name string `json:"name"`
  30. Gender int64 `json:"gender"`
  31. Mobile string `json:"mobile"`
  32. }
  33. // 用户信息
  34. )
  35. service User {
  36. @handler Login
  37. post /api/user/login(LoginRequest) returns (LoginResponse)
  38. @handler Register
  39. post /api/user/register(RegisterRequest) returns (RegisterResponse)
  40. }
  41. @server(
  42. jwt: Auth
  43. )
  44. service User {
  45. @handler UserInfo
  46. post /api/user/userinfo() returns (UserInfoResponse)
  47. }
  • 运行模板生成命令
  1. $ goctl api go -api ./api/user.api -dir ./api

3.3 生成 user rpc 服务

  • 创建 proto 文件
  1. $ vim rpc/user.proto
  • 编写 proto 文件
  1. syntax = "proto3";
  2. package userclient;
  3. option go_package = "user";
  4. // 用户登录
  5. message LoginRequest {
  6. string Mobile = 1;
  7. string Password = 2;
  8. }
  9. message LoginResponse {
  10. int64 Id = 1;
  11. string Name = 2;
  12. int64 Gender = 3;
  13. string Mobile = 4;
  14. }
  15. // 用户登录
  16. // 用户注册
  17. message RegisterRequest {
  18. string Name = 1;
  19. int64 Gender = 2;
  20. string Mobile = 3;
  21. string Password = 4;
  22. }
  23. message RegisterResponse {
  24. int64 Id = 1;
  25. string Name = 2;
  26. int64 Gender = 3;
  27. string Mobile = 4;
  28. }
  29. // 用户注册
  30. // 用户信息
  31. message UserInfoRequest {
  32. int64 Id = 1;
  33. }
  34. message UserInfoResponse {
  35. int64 Id = 1;
  36. string Name = 2;
  37. int64 Gender = 3;
  38. string Mobile = 4;
  39. }
  40. // 用户信息
  41. service User {
  42. rpc Login(LoginRequest) returns(LoginResponse);
  43. rpc Register(RegisterRequest) returns(RegisterResponse);
  44. rpc UserInfo(UserInfoRequest) returns(UserInfoResponse);
  45. }
  • 运行模板生成命令
  1. $ goctl rpc proto -src ./rpc/user.proto -dir ./rpc
  • 添加下载依赖包

    回到 mall 项目根目录执行如下命令:

  1. $ go mod tidy

3.4 编写 user rpc 服务

3.4.1 修改配置文件

  • 修改 user.yaml 配置文件
  1. $ vim rpc/etc/user.yaml
  • 修改服务监听地址,端口号为0.0.0.0:9000,Etcd 服务配置,Mysql 服务配置,CacheRedis 服务配置
  1. Name: user.rpc
  2. ListenOn: 0.0.0.0:9000
  3. Etcd:
  4. Hosts:
  5. - etcd:2379
  6. Key: user.rpc
  7. Mysql:
  8. DataSource: root:123456@tcp(mysql:3306)/mall?charset=utf8mb4&parseTime=true&loc=Asia%2FShanghai
  9. CacheRedis:
  10. - Host: redis:6379
  11. Type: node
  12. Pass:

3.4.2 添加 user model 依赖

  • 添加 Mysql 服务配置,CacheRedis 服务配置的实例化
  1. $ vim rpc/internal/config/config.go
  1. package config
  2. import (
  3. "github.com/tal-tech/go-zero/core/stores/cache"
  4. "github.com/tal-tech/go-zero/zrpc"
  5. )
  6. type Config struct {
  7. zrpc.RpcServerConf
  8. Mysql struct {
  9. DataSource string
  10. }
  11. CacheRedis cache.CacheConf
  12. }
  • 注册服务上下文 user model 的依赖
  1. $ vim rpc/internal/svc/servicecontext.go
  1. package svc
  2. import (
  3. "mall/service/user/model"
  4. "mall/service/user/rpc/internal/config"
  5. "github.com/tal-tech/go-zero/core/stores/sqlx"
  6. )
  7. type ServiceContext struct {
  8. Config config.Config
  9. UserModel model.UserModel
  10. }
  11. func NewServiceContext(c config.Config) *ServiceContext {
  12. conn := sqlx.NewMysql(c.Mysql.DataSource)
  13. return &ServiceContext{
  14. Config: c,
  15. UserModel: model.NewUserModel(conn, c.CacheRedis),
  16. }
  17. }

3.4.3 添加用户注册逻辑 Register

  • 添加密码加密工具

    在根目录 common 新建 crypt 工具库,此工具方法主要用于密码的加密处理。

  1. $ vim common/cryptx/crypt.go
  1. package cryptx
  2. import (
  3. "fmt"
  4. "golang.org/x/crypto/scrypt"
  5. )
  6. func PasswordEncrypt(salt, password string) string {
  7. dk, _ := scrypt.Key([]byte(password), []byte(salt), 32768, 8, 1, 32)
  8. return fmt.Sprintf("%x", string(dk))
  9. }
  • 添加密码加密 Salt 配置
  1. $ vim rpc/etc/user.yaml
  1. Name: user.rpc
  2. ListenOn: 0.0.0.0:9000
  3. ...
  4. Salt: HWVOFkGgPTryzICwd7qnJaZR9KQ2i8xe
  1. $ vim rpc/internal/config/config.go
  1. package config
  2. import (
  3. "github.com/tal-tech/go-zero/core/stores/cache"
  4. "github.com/tal-tech/go-zero/zrpc"
  5. )
  6. type Config struct {
  7. ...
  8. Salt string
  9. }
  • 添加用户注册逻辑

    用户注册流程,先判断注册手机号是否已经被注册,手机号未被注册,将用户信息写入数据库,用户密码需要进行加密存储。

  1. $ vim rpc/internal/logic/registerlogic.go
  1. package logic
  2. import (
  3. "context"
  4. "mall/common/cryptx"
  5. "mall/service/user/model"
  6. "mall/service/user/rpc/internal/svc"
  7. "mall/service/user/rpc/user"
  8. "github.com/tal-tech/go-zero/core/logx"
  9. "google.golang.org/grpc/status"
  10. )
  11. type RegisterLogic struct {
  12. ctx context.Context
  13. svcCtx *svc.ServiceContext
  14. logx.Logger
  15. }
  16. func NewRegisterLogic(ctx context.Context, svcCtx *svc.ServiceContext) *RegisterLogic {
  17. return &RegisterLogic{
  18. ctx: ctx,
  19. svcCtx: svcCtx,
  20. Logger: logx.WithContext(ctx),
  21. }
  22. }
  23. func (l *RegisterLogic) Register(in *user.RegisterRequest) (*user.RegisterResponse, error) {
  24. // 判断手机号是否已经注册
  25. _, err := l.svcCtx.UserModel.FindOneByMobile(in.Mobile)
  26. if err == nil {
  27. return nil, status.Error(100, "该用户已存在")
  28. }
  29. if err == model.ErrNotFound {
  30. newUser := model.User{
  31. Name: in.Name,
  32. Gender: in.Gender,
  33. Mobile: in.Mobile,
  34. Password: cryptx.PasswordEncrypt(l.svcCtx.Config.Salt, in.Password),
  35. }
  36. res, err := l.svcCtx.UserModel.Insert(&newUser)
  37. if err != nil {
  38. return nil, status.Error(500, err.Error())
  39. }
  40. newUser.Id, err = res.LastInsertId()
  41. if err != nil {
  42. return nil, status.Error(500, err.Error())
  43. }
  44. return &user.RegisterResponse{
  45. Id: newUser.Id,
  46. Name: newUser.Name,
  47. Gender: newUser.Gender,
  48. Mobile: newUser.Mobile,
  49. }, nil
  50. }
  51. return nil, status.Error(500, err.Error())
  52. }

3.4.4 添加用户登录逻辑 Login

用户登录流程,通过手机号查询判断用户是否是注册用户,如果是注册用户,需要将用户输入的密码进行加密与数据库中用户加密密码进行对比验证。

  1. $ vim rpc/internal/logic/loginlogic.go
  1. package logic
  2. import (
  3. "context"
  4. "mall/common/cryptx"
  5. "mall/service/user/model"
  6. "mall/service/user/rpc/internal/svc"
  7. "mall/service/user/rpc/user"
  8. "github.com/tal-tech/go-zero/core/logx"
  9. "google.golang.org/grpc/status"
  10. )
  11. type LoginLogic struct {
  12. ctx context.Context
  13. svcCtx *svc.ServiceContext
  14. logx.Logger
  15. }
  16. func NewLoginLogic(ctx context.Context, svcCtx *svc.ServiceContext) *LoginLogic {
  17. return &LoginLogic{
  18. ctx: ctx,
  19. svcCtx: svcCtx,
  20. Logger: logx.WithContext(ctx),
  21. }
  22. }
  23. func (l *LoginLogic) Login(in *user.LoginRequest) (*user.LoginResponse, error) {
  24. // 查询用户是否存在
  25. res, err := l.svcCtx.UserModel.FindOneByMobile(in.Mobile)
  26. if err != nil {
  27. if err == model.ErrNotFound {
  28. return nil, status.Error(100, "用户不存在")
  29. }
  30. return nil, status.Error(500, err.Error())
  31. }
  32. // 判断密码是否正确
  33. password := cryptx.PasswordEncrypt(l.svcCtx.Config.Salt, in.Password)
  34. if password != res.Password {
  35. return nil, status.Error(100, "密码错误")
  36. }
  37. return &user.LoginResponse{
  38. Id: res.Id,
  39. Name: res.Name,
  40. Gender: res.Gender,
  41. Mobile: res.Mobile,
  42. }, nil
  43. }

3.4.5 添加用户信息逻辑 UserInfo

  1. $ vim rpc/internal/logic/userinfologic.go
  1. package logic
  2. import (
  3. "context"
  4. "mall/service/user/model"
  5. "mall/service/user/rpc/internal/svc"
  6. "mall/service/user/rpc/user"
  7. "github.com/tal-tech/go-zero/core/logx"
  8. "google.golang.org/grpc/status"
  9. )
  10. type UserInfoLogic struct {
  11. ctx context.Context
  12. svcCtx *svc.ServiceContext
  13. logx.Logger
  14. }
  15. func NewUserInfoLogic(ctx context.Context, svcCtx *svc.ServiceContext) *UserInfoLogic {
  16. return &UserInfoLogic{
  17. ctx: ctx,
  18. svcCtx: svcCtx,
  19. Logger: logx.WithContext(ctx),
  20. }
  21. }
  22. func (l *UserInfoLogic) UserInfo(in *user.UserInfoRequest) (*user.UserInfoResponse, error) {
  23. // 查询用户是否存在
  24. res, err := l.svcCtx.UserModel.FindOne(in.Id)
  25. if err != nil {
  26. if err == model.ErrNotFound {
  27. return nil, status.Error(100, "用户不存在")
  28. }
  29. return nil, status.Error(500, err.Error())
  30. }
  31. return &user.UserInfoResponse{
  32. Id: res.Id,
  33. Name: res.Name,
  34. Gender: res.Gender,
  35. Mobile: res.Mobile,
  36. }, nil
  37. }

3.5 编写 user api 服务

3.5.1 修改配置文件

  • 修改 user.yaml 配置文件
  1. $ vim api/etc/user.yaml
  • 修改服务地址,端口号为0.0.0.0:8000,Mysql 服务配置,CacheRedis 服务配置,Auth 验证配置
  1. Name: User
  2. Host: 0.0.0.0
  3. Port: 8000
  4. Mysql:
  5. DataSource: root:123456@tcp(mysql:3306)/mall?charset=utf8mb4&parseTime=true&loc=Asia%2FShanghai
  6. CacheRedis:
  7. - Host: redis:6379
  8. Pass:
  9. Type: node
  10. Auth:
  11. AccessSecret: uOvKLmVfztaXGpNYd4Z0I1SiT7MweJhl
  12. AccessExpire: 86400

3.5.2 添加 user rpc 依赖

  • 添加 user rpc 服务配置
  1. $ vim api/etc/user.yaml
  1. Name: User
  2. Host: 0.0.0.0
  3. Port: 8000
  4. ......
  5. UserRpc:
  6. Etcd:
  7. Hosts:
  8. - etcd:2379
  9. Key: user.rpc
  • 添加 user rpc 服务配置的实例化
  1. $ vim api/internal/config/config.go
  1. package config
  2. import (
  3. "github.com/tal-tech/go-zero/rest"
  4. "github.com/tal-tech/go-zero/zrpc"
  5. )
  6. type Config struct {
  7. rest.RestConf
  8. Auth struct {
  9. AccessSecret string
  10. AccessExpire int64
  11. }
  12. UserRpc zrpc.RpcClientConf
  13. }
  • 注册服务上下文 user rpc 的依赖
  1. $ vim api/internal/svc/servicecontext.go
  1. package svc
  2. import (
  3. "mall/service/user/api/internal/config"
  4. "mall/service/user/rpc/userclient"
  5. "github.com/tal-tech/go-zero/zrpc"
  6. )
  7. type ServiceContext struct {
  8. Config config.Config
  9. UserRpc userclient.User
  10. }
  11. func NewServiceContext(c config.Config) *ServiceContext {
  12. return &ServiceContext{
  13. Config: c,
  14. UserRpc: userclient.NewUser(zrpc.MustNewClient(c.UserRpc)),
  15. }
  16. }

3.5.3 添加用户注册逻辑 Register

  1. $ vim api/internal/logic/registerlogic.go
  1. package logic
  2. import (
  3. "context"
  4. "mall/service/user/api/internal/svc"
  5. "mall/service/user/api/internal/types"
  6. "mall/service/user/rpc/userclient"
  7. "github.com/tal-tech/go-zero/core/logx"
  8. )
  9. type RegisterLogic struct {
  10. logx.Logger
  11. ctx context.Context
  12. svcCtx *svc.ServiceContext
  13. }
  14. func NewRegisterLogic(ctx context.Context, svcCtx *svc.ServiceContext) RegisterLogic {
  15. return RegisterLogic{
  16. Logger: logx.WithContext(ctx),
  17. ctx: ctx,
  18. svcCtx: svcCtx,
  19. }
  20. }
  21. func (l *RegisterLogic) Register(req types.RegisterRequest) (resp *types.RegisterResponse, err error) {
  22. res, err := l.svcCtx.UserRpc.Register(l.ctx, &userclient.RegisterRequest{
  23. Name: req.Name,
  24. Gender: req.Gender,
  25. Mobile: req.Mobile,
  26. Password: req.Password,
  27. })
  28. if err != nil {
  29. return nil, err
  30. }
  31. return &types.RegisterResponse{
  32. Id: res.Id,
  33. Name: res.Name,
  34. Gender: res.Gender,
  35. Mobile: res.Mobile,
  36. }, nil
  37. }

3.5.4 添加用户登录逻辑 Login

  • 添加 JWT 工具

    在根目录 common 新建 jwtx 工具库,用于生成用户 token

  1. $ vim common/jwtx/jwt.go
  1. package jwtx
  2. import "github.com/golang-jwt/jwt"
  3. func GetToken(secretKey string, iat, seconds, uid int64) (string, error) {
  4. claims := make(jwt.MapClaims)
  5. claims["exp"] = iat + seconds
  6. claims["iat"] = iat
  7. claims["uid"] = uid
  8. token := jwt.New(jwt.SigningMethodHS256)
  9. token.Claims = claims
  10. return token.SignedString([]byte(secretKey))
  11. }
  • 添加用户登录逻辑

    通过调用 user rpc 服务进行登录验证,登录成功后,使用用户信息生成对应的 token 以及 token 的有效期。

  1. $ vim api/internal/logic/loginlogic.go
  1. package logic
  2. import (
  3. "context"
  4. "time"
  5. "mall/common/jwtx"
  6. "mall/service/user/api/internal/svc"
  7. "mall/service/user/api/internal/types"
  8. "mall/service/user/rpc/userclient"
  9. "github.com/tal-tech/go-zero/core/logx"
  10. )
  11. type LoginLogic struct {
  12. logx.Logger
  13. ctx context.Context
  14. svcCtx *svc.ServiceContext
  15. }
  16. func NewLoginLogic(ctx context.Context, svcCtx *svc.ServiceContext) LoginLogic {
  17. return LoginLogic{
  18. Logger: logx.WithContext(ctx),
  19. ctx: ctx,
  20. svcCtx: svcCtx,
  21. }
  22. }
  23. func (l *LoginLogic) Login(req types.LoginRequest) (resp *types.LoginResponse, err error) {
  24. res, err := l.svcCtx.UserRpc.Login(l.ctx, &userclient.LoginRequest{
  25. Mobile: req.Mobile,
  26. Password: req.Password,
  27. })
  28. if err != nil {
  29. return nil, err
  30. }
  31. now := time.Now().Unix()
  32. accessExpire := l.svcCtx.Config.Auth.AccessExpire
  33. accessToken, err := jwtx.GetToken(l.svcCtx.Config.Auth.AccessSecret, now, accessExpire, res.Id)
  34. if err != nil {
  35. return nil, err
  36. }
  37. return &types.LoginResponse{
  38. AccessToken: accessToken,
  39. AccessExpire: now + accessExpire,
  40. }, nil
  41. }

3.5.5 添加用户信息逻辑 UserInfo

  1. $ vim api/internal/logic/userinfologic.go
  1. package logic
  2. import (
  3. "context"
  4. "encoding/json"
  5. "mall/service/user/api/internal/svc"
  6. "mall/service/user/api/internal/types"
  7. "mall/service/user/rpc/userclient"
  8. "github.com/tal-tech/go-zero/core/logx"
  9. )
  10. type UserInfoLogic struct {
  11. logx.Logger
  12. ctx context.Context
  13. svcCtx *svc.ServiceContext
  14. }
  15. func NewUserInfoLogic(ctx context.Context, svcCtx *svc.ServiceContext) UserInfoLogic {
  16. return UserInfoLogic{
  17. Logger: logx.WithContext(ctx),
  18. ctx: ctx,
  19. svcCtx: svcCtx,
  20. }
  21. }
  22. func (l *UserInfoLogic) UserInfo() (resp *types.UserInfoResponse, err error) {
  23. uid, _ := l.ctx.Value("uid").(json.Number).Int64()
  24. res, err := l.svcCtx.UserRpc.UserInfo(l.ctx, &userclient.UserInfoRequest{
  25. Id: uid,
  26. })
  27. if err != nil {
  28. return nil, err
  29. }
  30. return &types.UserInfoResponse{
  31. Id: res.Id,
  32. Name: res.Name,
  33. Gender: res.Gender,
  34. Mobile: res.Mobile,
  35. }, nil
  36. }

通过 l.ctx.Value("uid") 可获取 jwt token 中自定义的参数

3.6 启动 user rpc 服务

提示:启动服务需要在 golang 容器中启动

  1. $ cd mall/service/user/rpc
  2. $ go run user.go -f etc/user.yaml
  3. Starting rpc server at 127.0.0.1:9000...

3.7 启动 user api 服务

提示:启动服务需要在 golang 容器中启动

  1. $ cd mall/service/user/api
  2. $ go run user.go -f etc/user.yaml
  3. Starting server at 0.0.0.0:8000...

项目地址

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

欢迎使用 go-zerostar 支持我们!

微信交流群

关注『微服务实践』公众号并点击 交流群 获取社区群二维码。

带你十天轻松搞定 Go 微服务系列(三)的更多相关文章

  1. 带你十天轻松搞定 Go 微服务系列(一)

    本文开始,我们会出一个系列文章跟大家详细展示一个 go-zero 微服务示例,整个系列分十篇文章,目录结构如下: 环境搭建(本文) 服务拆分 用户服务 产品服务 订单服务 支付服务 RPC 服务 Au ...

  2. 带你十天轻松搞定 Go 微服务系列(二)

    上篇文章开始,我们通过一个系列文章跟大家详细展示一个 go-zero 微服务示例,整个系列分十篇文章,目录结构如下: 环境搭建 服务拆分(本文) 用户服务 产品服务 订单服务 支付服务 RPC 服务 ...

  3. 带你十天轻松搞定 Go 微服务系列(五)

    序言 我们通过一个系列文章跟大家详细展示一个 go-zero 微服务示例,整个系列分十篇文章,目录结构如下: 环境搭建 服务拆分 用户服务 产品服务 订单服务(本文) 支付服务 RPC 服务 Auth ...

  4. 带你十天轻松搞定 Go 微服务系列(六)

    序言 我们通过一个系列文章跟大家详细展示一个 go-zero 微服务示例,整个系列分十篇文章,目录结构如下: 环境搭建 服务拆分 用户服务 产品服务 订单服务 支付服务(本文) RPC 服务 Auth ...

  5. 带你十天轻松搞定 Go 微服务系列(七)

    序言 我们通过一个系列文章跟大家详细展示一个 go-zero 微服务示例,整个系列分十篇文章,目录结构如下: 环境搭建 服务拆分 用户服务 产品服务 订单服务 支付服务 RPC 服务 Auth 验证( ...

  6. 带你十天轻松搞定 Go 微服务系列(八、服务监控)

    序言 我们通过一个系列文章跟大家详细展示一个 go-zero 微服务示例,整个系列分十篇文章,目录结构如下: 环境搭建 服务拆分 用户服务 产品服务 订单服务 支付服务 RPC 服务 Auth 验证 ...

  7. 带你十天轻松搞定 Go 微服务系列(九、链路追踪)

    序言 我们通过一个系列文章跟大家详细展示一个 go-zero 微服务示例,整个系列分十篇文章,目录结构如下: 环境搭建 服务拆分 用户服务 产品服务 订单服务 支付服务 RPC 服务 Auth 验证 ...

  8. 带你十天轻松搞定 Go 微服务之大结局(分布式事务)

    序言 我们通过一个系列文章跟大家详细展示一个 go-zero 微服务示例,整个系列分十篇文章,目录结构如下: 环境搭建 服务拆分 用户服务 产品服务 订单服务 支付服务 RPC 服务 Auth 验证 ...

  9. 【微服务】之二:从零开始,轻松搞定SpringCloud微服务系列--注册中心(一)

    微服务体系,有效解决项目庞大.互相依赖的问题.目前SpringCloud体系有强大的一整套针对微服务的解决方案.本文中,重点对微服务体系中的服务发现注册中心进行详细说明.本篇中的注册中心,采用Netf ...

随机推荐

  1. 写了个适用于vscode的minio图床客户端插件

    缘起 自己搭建minio做我的个人博客图床好一段时间了, 一直用minio自带的web管理后台来上传图片, 它的界面长下面这个样子 上传完后, 需要点下文件列表里刚刚传上去的文件的分享按钮 然后会出来 ...

  2. python语法糖之有参装饰器、无参装饰器

    python的装饰器简单来说就是函数的一种形式,是为了扩展原来的函数功能而设计的. 装饰器的特别之处在于它的返回值也是一个函数,可以在不改变原有函数代码的基础上添加新的功能 # 先定义一个函数及引用# ...

  3. css--深入理解z-index引发的层叠上下文、层叠等级和层叠顺序

    前言 在编写css样式代码的时候,我们经常会遇到z-index属性的使用,我们可能只了解z-index能够提高元素的层级,并不知道具体是怎么实现的.本文就来总结一个由z-index 引发的层叠上下文和 ...

  4. fork之后,子进程从父进程那继承了什么(转载)

    转载自:https://blog.csdn.net/xiaojun111111/article/details/51764389 知道子进程自父进程继承什么或未继承什么将有助于我们.下面这个名单会因为 ...

  5. 「ARC096C」Everything on It

    Solution 容斥,钦定 \(i\) 个数 \(\leq 1\) 次. \[Ans=\sum_{i=0}^n (-1)^i\binom{n}{i}F(i) \] 其中 \(F(i)\) 表示有 \ ...

  6. Java实习生常规技术面试题每日十题Java基础(五)

    目录 1.启动一个线程是用run()还是start()? . 2.线程的基本状态以及状态之间的关系. 3.Set和List的区别,List和Map的区别? 4.同步方法.同步代码块区别? 5.描述Ja ...

  7. 面试中问你MySql,这一篇就够了

    说一说主键索引与唯一索引 主键是一种约束,唯一索引是一种索引,两者在本质上是不同的. 主键索引默认是聚簇索引.唯一索引一般是非聚簇索引. 主键索引不能为空,唯一索引在InnoDB中可以出现多个null ...

  8. SpringBoot 之 JSR303 数据校验

    使用示例: @Component @ConfigurationProperties(prefix = "person") @Validated //使用数据校验注解 public ...

  9. 利用 Maven 创建 Docker 镜像并且推送到私有注册中心

    利用 Maven 命令生成项目框架 mvn archetype:generate -DgroupId=com.mycompany.app -DartifactId=my-app -Darchetype ...

  10. LC 只出现一次的数字

    Given a non-empty array of integers nums, every element appears twice except for one. Find that sing ...