YoyoGo微服務框架入門系列-快速編寫WEB API

YOYOFx發表於2020-12-04

前言

YoyoGo是一個使用Golang編寫的一個簡單、輕量、快速、基於依賴注入的微服務框架,目前依然在研發階段,歡迎Star以及一起參與到框架的研發

GitHub地址:https://github.com/yoyofx/yoyogo

正在為YoyoGo寫第一個部落格應用,感謝Tassdar的加入,原始碼:https://github.com/yoyofxteam/YoyoBlog.git 請先Clone Star,專案會持續更新,~

本文通過一套最為基本的增刪改查,來例項應該如何在最短的時間內最輕鬆的使用YoyoGo建立出一個自己的Web應用

開發工具與環境

本文開發環境及依賴版本:

  • OS: macOS Big Sur v11.0.1
  • GoLang SDK: go1.15.5 windows/amd64
  • IDE: GoLand 2020
  • YoyoGo: v1.5.8
  • MySQL: 5.7
  • MySQL_Deiver: v1.5.0

現在開始我們的造物之旅 o(////▽////)q

安裝框架

go為我們自帶了包管理 go get ,會從github幫我們下載依賴,但是由於總所周知的複雜原因,我們需要為自己的本地配置一下代理加速:

go env -w GOPROXY=https://goproxy.cn,direct

建立專案

開啟GoLand ->new Project -->go modules

開啟命令列,輸入:

go get github.com/yoyofx/yoyogo

成功的話會出現上圖的結果,如果超時請檢查自己是否成功的配置了加速,檢查方式為:go env 檢視GOPRIXY選項

Hello World跑起來

package main

import (
    YoyoGo "github.com/yoyofx/yoyogo/WebFramework"
    "github.com/yoyofx/yoyogo/WebFramework/Context"
    "github.com/yoyofx/yoyogo/WebFramework/Router"
)

func main()  {
    YoyoGo.CreateDefaultBuilder(func(router Router.IRouterBuilder) {
        router.GET("/info",func (ctx *Context.HttpContext) {    
            ctx.JSON(200, Context.H{"msg": "Hello World"})
        })
    }).Build().Run()       //預設埠號 :8080
}

啟動main函式,框架列印出程式ID和監聽埠號,Host啟動成功

我們使用PostMan訪問一下我們在上面程式碼中建立的路由,Host返回Hello World,到這一步恭喜你完成了自己的第一個YoyoGo的Web應用的建立~( ̄▽ ̄~)(~ ̄▽ ̄)~

當然,這麼簡單的功能是不能滿足我們的,接下里我們要完成一個單表的增刪改查來更加深入的瞭解YoyoGo的使用:

為專案新增內容

編寫配置檔案

一個正常的Web框架是肯定需要一個配置檔案來儲存它的相關配置的,YoyoGo使用golang編寫,我們基於雲原生的基調採用了YAML檔案格式座位我們的配置檔案格式

首先我們在根目錄下建立一個名為:config_dev.yml的檔案,檔名可以隨意編寫,字尾標識當前環境是開發還是生產,我們在檔案中輸入以下配置,接下來檔案中的各個配置我們都會在後面用到

yoyogo:
  application:
    name: Blogs  #應用名
    metadata: "develop" #當前env
    server:
      type: "fasthttp" #Server型別
      address: ":8081" #監聽埠
      path: ""
      max_request_size: 2096157 #最大請求體限制
      mvc:
        template: "v1/{controller}/{action}" #路由規則  
  database:
    url: tcp(localhost:3306)/yoyoBlog?charset=utf8&parseTime=True #資料庫連線字串
    username: root
    password: 1234abcd

新增資料庫支援

連線資料庫首先要獲取資料庫驅動

go get github.com/go-sql-driver/mysql

然後我們要從上面的配置檔案中讀取出配置檔案的資料庫配置節點,進行連線,在YoyoGo中,讀取配置檔案配置使用的介面是:Abstractions.IConfiguration,通過使用Iconfiguration的get方法讀取去配置檔案的內容,語法為“xxx.xxx.xxx , 我們通過建構函式初始化一下這個介面的例項,至於是如何實現建構函式初始化的這個是YoyoGo的依賴注入實現的,到後面我們會演示講解。

import (
    "database/sql"
    "fmt"
    _ "github.com/go-sql-driver/mysql"
    "github.com/yoyofx/yoyogo/Abstractions"
    "strings"
)

type BaseRepository struct {
    config Abstractions.IConfiguration
}

func NewBaseRepository(config Abstractions.IConfiguration) *BaseRepository {
    return &BaseRepository{config: config}
}
//初始化一個連線物件
func (baseRepository *BaseRepository) InitDBConn() *sql.DB {
    url := fmt.Sprint(baseRepository.config.Get("yoyogo.database.url"))  ”
    username := fmt.Sprint(baseRepository.config.Get("yoyogo.database.username"))
    password := fmt.Sprint(baseRepository.config.Get("yoyogo.database.password"))
    var sb = strings.Builder{}
    sb.WriteString(username)
    sb.WriteString(":")
    sb.WriteString(password)
    sb.WriteString("@")
    sb.WriteString(url)
    connStr := sb.String()
    fmt.Println(connStr)
    conn, err := sql.Open("mysql", connStr)
    if err != nil {
        fmt.Println(err)
    }
    return conn
}

資料庫操作類

這部分程式碼比較枯燥,唯一需要注意的依然是通過建構函式來進行BaseRepository的注入

import (
    "fmt"
    "yoyoFxBlog/domain"
    "yoyoFxBlog/repository/repository_impl"
)

type BlogService struct {
    baseRepository *repository_impl.BaseRepository
}

func NewBlogService(baseRepository *repository_impl.BaseRepository) *BlogService {
    return &BlogService{baseRepository: baseRepository}
}

func (service *BlogService) AddLog(blog domain.Blog) domain.Blog {

    conn := service.baseRepository.InitDBConn()
    defer conn.Close()
    stmt, err := conn.Prepare("INSERT INTO `blog` SET title=?,introduction=?,content=?")
    fmt.Println(err)
    res, err := stmt.Exec(blog.Title, blog.Introduction, blog.Content)
    fmt.Println(err)
    id, err := res.LastInsertId()
    blog.Id = int(id)
    return blog
}

func (service *BlogService) QueryBlogList(pageIndex int, pageSize int) domain.Page {
    conn := service.baseRepository.InitDBConn()
    defer conn.Close()
    res := domain.Page{}
    rows, err := conn.Query("SELECT COUNT(0) as count FROM `blog` ")
    if err != nil {

    }
    for rows.Next() {
        var count int
        err = rows.Scan(&count)
        res.TotalCount = count
    }
    start := (pageIndex - 1) * pageSize
    sql := fmt.Sprintf("SELECT *FROM `blog` ORDER BY creation_date LIMIT %d,%d", start, pageSize)
    rows, err = conn.Query(sql)
    if err != nil {
        fmt.Println(err)
    }
    blogList := make([]domain.Blog, 0)
    for rows.Next() {
        element := domain.Blog{}
        err := rows.Scan(&element.Id, &element.Title, &element.Introduction, &element.Content, &element.ViewCount, &element.Author, &element.CreationDate)
        if err != nil {
            continue
        }
        blogList = append(blogList, element)

    }
    res.Data = blogList
    return res
}

MVC建立控制器

首先我們建立一個控制器和幾個介面,建立控制器要注意以下幾點:

  1. 所有控制器必須和 Mvc.ApiController的指標進行組合

  2. 為了從請求中抓取引數,我們使用到了go的tag特性,獲取引數的格式為 param:"arg" 注意引數名要用雙引號包裹,切用於進行引數繫結的結構體必須和 *Mvc.Requst組合

  3. 介面中用於進行自動繫結的結構體必須是指標型別

  4. 通過控制器的名稱字首來實現HTTP請求型別的限制,例如 GETXXX即為只能使用Get請求

import (
    "github.com/yoyofx/yoyogo/WebFramework/ActionResult"
    "github.com/yoyofx/yoyogo/WebFramework/Mvc"
    "yoyoFxBlog/domain"
    "yoyoFxBlog/service"
)

type BlogController struct {
    *Mvc.ApiController
    blogService *service.BlogService
}

func NewBlogController(blogService *service.BlogService) *BlogController {
    return &BlogController{blogService: blogService}
}
//宣告用於從請求中自動繫結引數的結構體
type BlogRequest struct {
    *Mvc.RequestBody  //必須新增標識可以自動繫結
    Id           int    `param:"id"`
    Title        string `param:"title"`        //標題
    Introduction string `param:"introduction"` //簡介
    Content      string `param:"content"`      //內容
    ViewCount    int    `param:"viewCount"`    //瀏覽次數
}

type PageRequest struct {
    *Mvc.RequestBody
    PageIndex int `param:"pageIndex"`
    PageSize  int `param:"pageSize"`

}


///這裡注意引數必須是指標型別
func (controller *BlogController) AddBlog(blog *BlogRequest) ActionResult.IActionResult {
    data := controller.blogService.AddLog(domain.Blog{Id: blog.Id, Title: blog.Title, Introduction: blog.Introduction, Content: blog.Content, ViewCount: blog.ViewCount})
    return ActionResult.Json{Data: data}
}
//使用GET開頭限制這個介面只能使用GET請求方式
func (controller *BlogController) GetBlogList(PageRequest *PageRequest) ActionResult.IActionResult {
    data := controller.blogService.QueryBlogList(PageRequest.PageIndex, PageRequest.PageSize)
    return ActionResult.Json{Data: data}
}

func (controller *BlogController) BlogList(PageRequest *PageRequest) ActionResult.IActionResult {
    data := controller.blogService.QueryBlogList(PageRequest.PageIndex, PageRequest.PageSize)
    return ActionResult.Json{Data: data}
}

這裡有我們們上文中講到的,自定義Host啟動依賴注入 ,我們在這一步我們初始化了配置檔案,以及控制器和通過呼叫我們前幾步定義的建構函式來實現依賴的注入

重寫Main

import (
   "github.com/yoyofx/yoyogo/Abstractions"
   "github.com/yoyofx/yoyogo/DependencyInjection"
   YoyoGo "github.com/yoyofx/yoyogo/WebFramework"
   "github.com/yoyofx/yoyogo/WebFramework/Mvc"
   "yoyoFxBlog/controller"
   "yoyoFxBlog/repository/repository_impl"
   "yoyoFxBlog/service"
)

func main() {
   webHost := CreateYoyoBlogBuilder().Build()
   webHost.Run()
}

func CreateYoyoBlogBuilder() *Abstractions.HostBuilder {
   //讀取配置檔案
   configuration := Abstractions.NewConfigurationBuilder().AddYamlFile("config").Build()
   return YoyoGo.NewWebHostBuilder().
      UseConfiguration(configuration).
      Configure(func(app *YoyoGo.WebApplicationBuilder) {
         //配置我們上一步寫好的Controller
         app.UseMvc(func(builder *Mvc.ControllerBuilder) {
            builder.AddController(controller.NewBlogController)
         })
      }).
//配置我們之前幾步中定義好的建構函式來進行注入
      ConfigureServices(func(serviceCollection *DependencyInjection.ServiceCollection) {
         serviceCollection.AddTransient(repository_impl.NewBaseRepository)
         serviceCollection.AddTransient(service.NewBlogService)
      })
}

IOC與依賴注入

關於IOC生命週期,我們暫時提供了單例和瞬時兩種方式使用方法為:

func ConfigBusiness(serviceCollection *DependencyInjection.ServiceCollection) {

   //瞬時
   //直接注入一個容器
   serviceCollection.AddTransient(repository_impl.NewBaseRepository)
   //為注入的容器起一個名字,類似於Spring中為 Bean命名
   serviceCollection.AddTransientByName("NewBaseRepository",repository_impl.NewBaseRepository)
   //用介面的形式進行注入,用於一個介面多種實現的情況
   serviceCollection.AddTransientByImplements(repository_impl.NewBaseRepository, new(repository.BaseRepository))

   //單例
   serviceCollection.AddSingleton(repository_impl.NewBaseRepository)
   serviceCollection.AddSingletonByName("NewBaseRepository",repository_impl.NewBaseRepository)
   serviceCollection.AddTransientByImplements(repository_impl.NewBaseRepository, new(repository.BaseRepository))
}

最後

啟動專案,訪問我們剛才定義的介面,如果你能看到下圖結果,恭喜你,你已經陳工掌握了YoyoGo的基本入門使用!(o゜▽゜)o☆[BINGO!]

相關文章