Golang

关注公众号 jb51net

关闭
首页 > 脚本专栏 > Golang > Go语言标准库 实现Web服务

用Go语言标准库实现Web服务之项目介绍

作者:LightSaid

从本节开始将从后端到前端一步一步实现一个Go语言Web服务,后端除了MySQL驱动,全部使用Go语言标准库来实现一个小型项目,本篇将简单的介绍一下项目开发要准备的流程,感兴趣的同学可以阅读一下

我们将要创建一个什么项目呢?

我们要创建的项目是一个EBook电子书平台,接受用户注册登录浏览图书,用户可以购买图书,系统自动将电子书(pdf、epub 等格式电子书)发送到用户邮箱。这就是整个系统主线任务。

当然整个项目不是一蹴而就马上编写完成,而是分阶段实现,每个阶段都有不同技术栈,像一个真实项目一样迭代开发。

用户可以浏览平台所有电子书,管理员可以对图书进行CRUD操作。

在第一阶段,我将使用Go语言标准库实现单表CRUD API 接口。

在这一个阶段先创建一个电子书表book,使用 MySQL 5.7版本 先维护好book表的功能,继而迭代开发;建库建表 SQL 语句如下:

CREATE DATABASE db_ebook; 
USE db_ebook;

CREATE TABLE book (
    id INT UNSIGNED PRIMARY KEY AUTO_INCREMENT COMMENT '主键',
    isbn VARCHAR(13) NOT NULL COMMENT '国际标准书号',
    title VARCHAR(255) NOT NULL COMMENT '图书名字',
    poster  VARCHAR(255) NOT NULL COMMENT '图书封面图地址',
    pages INT UNSIGNED NOT NULL COMMENT '总页数',
    price DECIMAL(6, 2) UNSIGNED COMMENT '图书单价',
    published_at DATE NOT NULL COMMENT '发售日期',
    created_at TIMESTAMP NOT NULL default NOW() COMMENT '创建时间',
    updated_at TIMESTAMP NOT NULL default NOW() COMMENT '更新时间',
    unique index unq_isbn(`isbn`)
) ENGINE=InnoDB CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT '图书表';

项目目录结构组织

在这一步,我将设计一个简洁实用的代码组织架构,符合Go语言哲学思想,所见即所得。

初始化项目,使用 Go Module 开发;

mkdir -p $GOPATH/src/github.com/lightsaid/ebook
cd $GOPATH/src/github.com/lightsaid/ebook
go mod init github.com/lightsaid/ebook
code .

目录结构

        ├── configs         配置文件,可以有多个,例如开发/生产环境配置
        │   └── app.json    
        ├── go.mod         
        ├── go.sum
        ├── internal       系统内部逻辑在此处实现
        │   ├── app        app 要实现的api应用程序
        │   ├── config     加载配置
        │   ├── dbrepo     数据库操作
        │   └── models     实体模型
        ├── main.go        入口函数
        ├── pkg            公共模块,可以提供给其他项目使用的模块
        │   └── logger     日志库
        └── schema.sql

在Go中,internal 目录是本项目内部代码,不提供给其他项目使用,而且不管internal嵌套在一级、二级、三级...都是同样不允许外部项目访问;Go在编译的时候做了区分。如果你想详细了解Go如何组织代码可以参考这个项目 project-layout

在上面其中pkg目录是存放公共模块代码,如核心业务没有太多联系辅助模块,它可以提供给其他项目使用,尽管其他项目也不会用到😂。

在这一阶段,先来热身一下,先编写简单的 logger 日志输出功能和加载配置功能。 好在这一部分先介绍到这么多,下一节将开始编码。

logger/logger.go

package logger
import (
    "log"
    "os"
)
var InfoLog *log.Logger
var ErrorfoLog *log.Logger
func SetGlobalLogger() {
    InfoLog = log.New(os.Stdout, "[INFO]\t", log.Ldate|log.Ltime)
    ErrorfoLog = log.New(os.Stdout, "[ERROR]\t", log.Ldate|log.Ltime|log.Lshortfile)
}

上面创建两个log实例,并配置日志输出前缀,和日期文件名等信息

app.json (端口根据自己实际配置)

{
    "env": "dev",
    "port": 9527,
    "dsn": "root:rootcc@tcp(127.0.0.1:3318)/db_ebook?charset=utf8mb4&parseTime=True",
    "maxOpenConns": 30,
    "maxIdleConns": 15,
    "maxIdleTime": "5m"
}

config/config.go

package config

import (
	"encoding/json"
	"fmt"
	"os"
	"time"

	"github.com/lightsaid/ebook/pkg/logger"
)

// AppConfig 应用程序配置
type AppConfig struct {
	Env          string `json:"env"`          // 环境参数:dev | prod
	Port         int    `json:"port"`         // 服务端口
	DSN          string `json:"dsn"`          // 数据库链接
	MaxOpenConns int    `json:"maxOpenConns"` // 数据库最大链接数
	MaxIdleConns int    `json:"maxIdleConns"` // 数据库链接最大空闲数
	MaxIdleTime  string `json:"maxIdleTime"`  // 数据库链接最大空闲时间
}

// MaxIdleTimeToDuration 将 MaxIdleTime 转换成 time.Duration 返回,如果转换出错,返回默认值
func (app *AppConfig) MaxIdleTimeToDuration() time.Duration {
	dur, err := time.ParseDuration(app.MaxIdleTime)
	if err != nil {
		logger.ErrorfoLog.Println("time.ParseDuration(app.MaxIdleTime) failed: " + err.Error())
		return time.Minute * 5
	}
	return dur
}

// LoadAppConfig 根据配置文件路径加载配置
func LoadAppConfig(path string) (cfg AppConfig, err error) {
	var buf []byte
	buf, err = os.ReadFile(path)
	if err != nil {
		return
	}
	if err = json.Unmarshal(buf, &cfg); err != nil {
		return
	}

	return
}

func (a *AppConfig) Println() {
	if a.Env == "dev" {
		buf, _ := json.MarshalIndent(a, "", " ")
		fmt.Println(string(buf))
	}
}

在上面创建一个AppConfig结构体,并绑定json tag,这样json.Unmarshal才能解码。 在 Println 方法中 json.MarshalIndent 是格式化输出json函数。上面格式输出如图:

这部分内容分享到这里,下一节将初始化App路由。

到此这篇关于用Go语言标准库实现Web服务之项目介绍的文章就介绍到这了,更多相关Go语言标准库 实现Web服务内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

您可能感兴趣的文章:
阅读全文