IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 区块链 -> 三,用户管理微服务(library-user-service) -> 正文阅读

[区块链]三,用户管理微服务(library-user-service)

微服务 library-user-service ,用户管理服务。提供用户管理的 Restful 接口,主要实现用户注册、根据用户ID或者 email 查询用户、查询用户所借书籍等功能。

完整代码:

https://github.com/Justin02180218/micro-kit

包结构说明

图片

?

  • dao:数据访问层

  • dto:数据传输层

  • models:数据库表映射层

  • service:业务逻辑层

  • endpoint:go-kit 的概念,将服务提供的每一个方法封装成一个 endpoint。

  • transport:go-kit 的概念,协议传输层,支持?grpc,thrift,http 等协议,这里与gin web框架结合使用。

  • user.yaml:服务使用的配置文件

  • main.go:服务启动程序

代码实现

数据库表

首先在 library 数据库建立 user 表

CREATE TABLE `user` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT,
  `username` varchar(255) DEFAULT '',
  `password` varchar(255) DEFAULT '',
  `email` varchar(255) DEFAULT '',
  `created_at` datetime DEFAULT NULL,
  `updated_at` datetime DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

models层

对应在 models 层创建 user.go,定义与表 user 对应的 User struct:

type User struct {
    ID        uint64    `gorm:"primary_key" json:"id" form:"id"`
    CreatedAt time.Time `form:"created_at" json:"created_at"`
    UpdatedAt time.Time `form:"updated_at" json:"updated_at"`
    Username  string
    Password  string
    Email     string
}

dao层

在 dao 层创建与数据库交互的 user_dao.go

定义 UserDao 接口及实现:

type UserDao interface {
    SelectByID(id uint64) (*models.User, error)
    SelectByEmail(email string) (*models.User, error)
    Save(user *models.User) error
}

type UserDaoImpl struct{}

func NewUserDaoImpl() UserDao {
    return &UserDaoImpl{}
}
  • SelectByID:根据用户ID查询用户信息

  • SelectByEail:根据用户email查询用户信息

  • Save:保存用户信息

UserDao 接口的函数实现:

func (u *UserDaoImpl) SelectByID(id uint64) (*models.User, error) {
    user := &models.User{}
    err := databases.DB.Where("id = ?", id).First(user).Error
    if err != nil {
        return nil, err
    }
    return user, nil
}

func (u *UserDaoImpl) SelectByEmail(email string) (*models.User, error) {
    user := &models.User{}
    err := databases.DB.Where("email = ?", email).First(user).Error
    if err != nil {
        return nil, err
    }
    return user, nil
}

func (u *UserDaoImpl) Save(user *models.User) error {
    return databases.DB.Create(user).Error
}

dto层

在 dto 层的 user_dto.go 中创建用于数据传输的struct UserInfo 和 RegisterUser:

type UserInfo struct {
    ID       uint64 `json:"id"`
    Username string `json:"username"`
    Email    string `json:"email"`
}

type RegisterUser struct {
    Username string
    Password string
    Email    string
}

service层

在 service 层创建 user_service.go

定义 UserService 接口及实现:

type UserService interface {
    Register(ctx context.Context, vo *dto.RegisterUser) (*dto.UserInfo, error)
    FindByID(ctx context.Context, id uint64) (*dto.UserInfo, error)
    FindByEmail(ctx context.Context, email string) (*dto.UserInfo, error)
}

type UserServiceImpl struct {
    userDao dao.UserDao
}

func NewUserServiceImpl(userDao dao.UserDao) UserService {
    return &UserServiceImpl{
        userDao: userDao,
    }
}

UserService 接口的函数实现:

func (u *UserServiceImpl) Register(ctx context.Context, vo *dto.RegisterUser) (*dto.UserInfo, error) {
    user, err := u.userDao.SelectByEmail(vo.Email)
    if user != nil {
        log.Println("User is already exist!")
        return &dto.UserInfo{}, ErrUserExisted
    }
    if err == gorm.ErrRecordNotFound || err == nil {
        newUser := &models.User{
            Username: vo.Username,
            Password: vo.Password,
            Email:    vo.Email,
        }
        err = u.userDao.Save(newUser)
        if err != nil {
            return nil, ErrRegistering
        }
        return &dto.UserInfo{
            ID:       newUser.ID,
            Username: newUser.Username,
            Email:    newUser.Email,
        }, nil
    }
    return nil, err
}

func (u *UserServiceImpl) FindByID(ctx context.Context, id uint64) (*dto.UserInfo, error) {
    user, err := u.userDao.SelectByID(id)
    if err != nil {
        return nil, ErrNotFound
    }
    return &dto.UserInfo{
        ID:       user.ID,
        Username: user.Username,
        Email:    user.Email,
    }, nil
}

func (u *UserServiceImpl) FindByEmail(ctx context.Context, email string) (*dto.UserInfo, error) {
    user, err := u.userDao.SelectByEmail(email)
    if err != nil {
        return nil, ErrNotFound
    }
    return &dto.UserInfo{
        ID:       user.ID,
        Username: user.Username,
        Email:    user.Email,
    }, nil
}

?

endpoint层

在 endpoint 层创建 user_endpoint.go,

定义 UserEndpoints struct,每一个请求对应一个endpoint。

type UserEndpoints struct {
    RegisterEndpoint    endpoint.Endpoint
    FindByIDEndpoint    endpoint.Endpoint
    FindByEmailEndpoint endpoint.Endpoint
}

?

创建各endpoint

func MakeRegisterEndpoint(svc service.UserService) endpoint.Endpoint {
    return func(ctx context.Context, request interface{}) (response interface{}, err error) {
        req := request.(*dto.RegisterUser)
        user, err := svc.Register(ctx, req)
        if err != nil {
            return nil, err
        }
        return user, nil
    }
}

func MakeFindByIDEndpoint(svc service.UserService) endpoint.Endpoint {
    return func(ctx context.Context, request interface{}) (response interface{}, err error) {
        id, _ := strconv.ParseUint(request.(string), 10, 64)
        user, err := svc.FindByID(ctx, id)
        if err != nil {
            return nil, err
        }
        return user, nil
    }
}

func MakeFindByEmailEndpoint(svc service.UserService) endpoint.Endpoint {
    return func(ctx context.Context, request interface{}) (response interface{}, err error) {
        email := request.(string)
        user, err := svc.FindByEmail(ctx, email)
        if err != nil {
            return nil, err
        }
        return user, nil
    }
}

transport层

请求转发我们采用 gin web 框架与 go-kit transport 相结合的方式,因此在 http_util.go 中定 义 Router ,返回 gin.Engine

func NewRouter(mode string) *gin.Engine {
    gin.SetMode(mode)
    r := gin.New()
    r.Use(gin.Recovery())
    return r
}

在 user_transport.go 中定义 NewHttpHandler 返回 gin.Engine,gin 的请求处理 handler 由 go-kit 的http.NewServer 处理。

func NewHttpHandler(ctx context.Context, endpoints *endpoint.UserEndpoints) *gin.Engine {
    r := utils.NewRouter(ctx.Value("ginMod").(string))

    e := r.Group("/api/v1")
    {
        e.POST("register", func(c *gin.Context) {
            kithttp.NewServer(
                endpoints.RegisterEndpoint,
                decodeRegisterRequest,
                utils.EncodeJsonResponse,
            ).ServeHTTP(c.Writer, c.Request)
        })

        e.GET("findByID", func(c *gin.Context) {
            kithttp.NewServer(
                endpoints.FindByIDEndpoint,
                decodeFindByIDRequest,
                utils.EncodeJsonResponse,
            ).ServeHTTP(c.Writer, c.Request)
        })

        e.GET("findByEmail", func(c *gin.Context) {
            kithttp.NewServer(
                endpoints.FindByEmailEndpoint,
                decodeFindByEmailRequest,
                utils.EncodeJsonResponse,
            ).ServeHTTP(c.Writer, c.Request)
        })
    }

    return r
}

?

启动服务

补全 main.go

var confFile = flag.String("f", "user.yaml", "user config file")

func main() {
    flag.Parse()

    err := configs.Init(*confFile)
    if err != nil {
        panic(err)
    }

    err = databases.InitMySql(configs.Conf.MySQLConfig)
    if err != nil {
        fmt.Println("load mysql failed")
    }

    ctx := context.Background()

    userDao := dao.NewUserDaoImpl()
    userService := service.NewUserServiceImpl(userDao)
    userEndpoints := &endpoint.UserEndpoints{
        RegisterEndpoint:    endpoint.MakeRegisterEndpoint(userService),
        FindByIDEndpoint:    endpoint.MakeFindByIDEndpoint(userService),
        FindByEmailEndpoint: endpoint.MakeFindByEmailEndpoint(userService),
    }

    ctx = context.WithValue(ctx, "ginMod", configs.Conf.ServerConfig.Mode)
    r := transport.NewHttpHandler(ctx, userEndpoints)

    errChan := make(chan error)
    go func() {
        errChan <- r.Run(fmt.Sprintf(":%s", strconv.Itoa(configs.Conf.ServerConfig.Port)))
    }()

    go func() {
        c := make(chan os.Signal, 1)
        signal.Notify(c, syscall.SIGINT, syscall.SIGTERM)
        errChan <- fmt.Errorf("%s", <-c)
    }()
    fmt.Println(<-errChan)
}

启动

进入 library-user-service 目录,执行 go run main.go 如图:?

图片

服务成功启动,监听10086端口

接口测试

使用postman进行接口测试,在这里进行了 register 的接口测试,结果如图:

图片

测试成功,数据库成功插入一条用户记录

图片

?

下一篇文章,我们开始编写书籍管理微服务:library-book-service

完整代码:

https://github.com/Justin02180218/micro-kit


更多【分布式专辑】【架构实战专辑】系列文章,请关注公众号

  区块链 最新文章
盘点具备盈利潜力的几大加密板块,以及潜在
阅读笔记|让区块空间成为商品,打造Web3云
区块链1.0-比特币的数据结构
Team Finance被黑分析|黑客自建Token“瞒天
区块链≠绿色?波卡或成 Web3“生态环保”标
期货从入门到高深之手动交易系列D1课
以太坊基础---区块验证
进入以太坊合并的五个数字
经典同态加密算法Paillier解读 - 原理、实现
IPFS/Filecoin学习知识科普(四)
上一篇文章      下一篇文章      查看所有文章
加:2021-09-13 09:19:47  更:2021-09-13 09:19:55 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年12日历 -2024/12/28 3:00:36-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码
数据统计