我们将要创建一个什么项目呢?
我们要创建的项目是一个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服务内容请搜索好代码网以前的文章或继续浏览下面的相关文章希望大家以后多多支持好代码网!