Gpt微信小程序 只需要几个API,API上一小节也有讲到。直接用 gin 或者 beego 简单搭web服务器就够了。我们这里还用 go-micro微服务 去搭建,主要也是为了学以致用,把之前go-micro系列播客衔接上,以及后续好的横纵向扩展。
整体的代码框架:
pkg通用库中用到的db数据库,redis和mq队列,大部分都是前面go-micro系列有用到的。internal内部的微服务目录也是在之前go-micro单个微服务目录格式上调整。
这里主要看配置解析, 配置解析用得是toml库, github.com/BurntSushi/toml
pkg/config/config.go
type IConfig interface {
//服务名
AppName() string
//运行模式
AppEnv() string
//日志的定义
LogFilePath() string
LogMaxAge() int
LogMaxSize() int
LogBackUpNum() int
//mysql关系型数据库
SchemeConfig() map[string]*SchemeConfig
//redis
RedisConfig() map[string]*RedisConfig
//rabbitmq
AmqpConfig() map[string]*AmqpConfig
}
// log日志库基本配置
type LogConfig struct {
Type string `yaml:"Type",toml:"Type"`
LogDir string `yaml:"LogDir",toml:"LogDir"`
LogName string `yaml:"LogName",toml:"LogName"`
LogMaxAge int `yaml:"LogMaxAge",toml:"LogMaxAge"` // 日志的过期时间,单位为天
LogMaxSize int `yaml:"LogMaxSize",toml:"LogMaxSize"` // 日志文件的最大
LogBackUpNum int `yaml:"LogBackUpNum",toml:"LogBackUpNum"` // 日志文件最多保留个数
}
// 服务配置
type Config struct {
ConfPath string //配置路径
AppPath string //项目路径
Scheme map[string]*SchemeConfig `yaml:"Scheme",toml:"Scheme"`
Redis map[string]*RedisConfig `yaml:"Redis",toml:"Redis"`
Amqp map[string]*AmqpConfig `yaml:"Amqp",toml:"Amqp"`
Log *LogConfig `yaml:"Log",toml:"Log"`
}
// App 的基本配置
type AppBaseConfig struct {
AppName string `yaml:"AppName",toml:"AppName"`
Env string `yaml:"Env",toml:"Env"`
Version string `yaml:"Version",toml:"Version"` // 版本
}
type AppConfig struct {
Config
App AppBaseConfig
}
pkg/config/scheme.go
// 关系型数据库的配置
type SchemeConfig struct {
// mysql pgsql
Driver string `yaml:"Driver",toml:"Driver"`
Dsn string `yaml:"Dsn",toml:"Dsn"`
// 建立最大的连接数
MaxOpenConns int `yaml:"MaxOpenConns",toml:"MaxOpenConns"`
// 最大的空闲连接数
MaxIdleConns int `yaml:"MaxIdleConns",toml:"MaxIdleConns"`
// 一条连接存活的最长时间
ConnMaxLifeTime int `yaml:"ConnMaxLifeTime",toml:"ConnMaxLifeTime"`
}
pkg/config/redis.go
// redis配置
type RedisConfig struct {
Addr string `yaml:"Addr",toml:"Addr"` // host:port
Password string `yaml:"Password",toml:"Password"`
MaxConnNum int `yaml:"MaxConnNum",toml:"MaxConnNum"`
InitConnNum int `yaml:"InitConnNum",toml:"InitConnNum"`
IdleTimeout int `yaml:"IdleTimeout",toml:"IdleTimeout"`
PingStep int `yaml:"PingStep",toml:"PingStep"`
RetryTimes int `yaml:"RetryTimes",toml:"RetryTimes"`
}
pkg/config/amqp.go
// rabbitmq
type AmqpConfig struct {
Addr string `toml:"Addr"`
Port int `toml:"Port"`
User string `toml:"User"`
Pwd string `toml:"Pwd"`
MaxConnection int `toml:"MaxConnection"`
MaxChannel int `toml:"MaxChannel"`
VirtualHost string `toml:"VirtualHost"`
Type int `toml:"Type"`
}
对应的toml配置格式:
config/test_service/app.toml
[App]
AppName = "test_service"
Version = "1.0"
Env = "dev"
[Log]
Type = "log" # 默认是log, 可以是redis, kafka获取是其他的,如果是其他的请在 log中实现
LogDir = "/log"
LogName = "error_log.log"
LogMaxAge = 7 # 单位 day,日志最多可以保存多长时间。只有 Type 为File时才会有效
LogMaxSize = 10 # 文件大小(M),10M
LogBackUpNum = 10 # 文件保留最多个数
[Scheme]
# 放置数据库连接信息
[Scheme.base]
Driver = "mysql"
Dsn = "root:root@tcp(127.0.0.1:3306)/test?charset=utf8mb4&parseTime=true"
MaxOpenConns = 60
MaxIdleConns = 20
ConnMaxLifeTime = 1200
[Redis]
[Redis.base]
Addr = "127.0.0.1:6379"
Password = "11111111"
MaxConnNum = 20
InitConnNum = 1
IdleTimeout = 7200 #最大idle时间
PingStep = 10 #两次ping之间间隔
RetryTimes = 3 #获取连接重试次数
[Amqp]
[Amqp.publish]
Addr = "127.0.0.1"
Port = 5672
User = "guest"
Pwd = "guest"
MaxConnection = 4
VirtualHost = "/"
Type = 1 # 1生产者;2消费者
[Amqp.consume]
Addr = "127.0.0.1"
Port = 5672
User = "guest"
Pwd = "guest"
MaxConnection = 10
MaxChannel = 10
VirtualHost = "/"
Type = 2 # 1生产者;2消费者
最后的配置解析
pkg/config/parse.go
// 解析配置
func ParseConfig() {
verifyConf()
toml.DecodeFile(Conf.ConfPath, Conf)
}
func verifyConf() {
if fl, err := os.Stat(Conf.ConfPath); err != nil {
if os.IsNotExist(err) {
fmt.Println(Conf.ConfPath)
fmt.Printf("config file %s not exists", Conf.ConfPath)
os.Exit(0)
}
} else {
fl.Mode().Perm()
}
}
// 获取项目当前路径
func getRunPath() string {
rst, err := os.Getwd()
if err != nil {
return ""
}
return rst
}
这里,通用log日志库,mysql,redis,rabbitmq的配置解析和初始代码就好了,接下来就是微服务的初始化调用和启动了。
internal/test_service/init.go
// 服务
type EmicroService struct {
Server micro.Service
Host string
Port uint
Addr string
}
// 服务的自定义配置
type ServerConfig struct {
ServerLog map[string]*config.LogConfig
}
// 服务内部配置
type Conf struct {
Config *config.AppConfig //pkg通用配置
ServerConfig *ServerConfig
}
// 服务操作对象
var Service *EmicroService
// 日志库操作对象,对pkg的日志再封装
var Logger *zap.Logger
// 服务内部配置操作对象
var Config *Conf
func init() {
Service = NewService()
Config = NewConfig()
}
func NewService() *EmicroService {
service := new(EmicroService)
return service
}
func NewConfig() *Conf {
return new(Conf)
}
// 初始化
func Init(confPath string) {
//指定配置文件路径
config.Conf.ConfPath = confPath
//解析配置
config.ParseConfig()
// 处理日志文件路径和日志等级
config.Conf.Log.LogDir = config.Conf.GetAppPath() + config.Conf.Log.LogDir + "/" + config.Conf.AppName()
// 默认日志等级为error
var level string
if config.Conf.AppEnv() == "dev" {
level = "debug"
} else {
level = "error"
}
// 初始化通用日志库
logObj.LoggerInit(config.Conf, level)
Logger = logObj.Logger()
// 初始数据库,Redis等
database.Init(config.Conf)
// 解析服务内部自定义配置
Config.Config = config.Configer()
var serverConf = new(ServerConfig)
serverConfPath := Config.Config.GetAppPath() + "/internal/test_service/config/server.toml"
toml.DecodeFile(serverConfPath, serverConf)
Config.ServerConfig = serverConf
// 初始化自定义的log
initServerLog(level)
}
internal/test_service/elog.go
// 服务自定义的log日志库操作对象
var ServerLogger map[string]*zap.Logger
var logLevel string
// 初始化自定义的log
func initServerLog(level string){
ServerLogger = make(map[string]*zap.Logger, len(Config.ServerConfig.ServerLog))
logLevel = level
for logName, logInfo := range Config.ServerConfig.ServerLog{
logInfo.LogDir = config.Conf.AppPath + logInfo.LogDir + string(os.PathSeparator) +logName
log, err := newServerLog(logInfo)
if err != nil{
panic("init server log err:" + err.Error())
}
ServerLogger[logName] = log
}
}
func newServerLog(logInfo *config.LogConfig) (*zap.Logger, error){
var console bool
if Config.Config.AppEnv() == "dev" {
console = true
}else{
console = false
}
logInfo.LogName = getLogFilename()
return logObj.CreateLogger(logLevel, console, logInfo)
}
func getLogFilename() string {
currentTime := time.Now()
return currentTime.Format("2006-01-02") + ".log"
}
启动代码在internal/test_service/server/server.go,跟之前go-micro系列播客的微服务启动一样,这里不再列明。
启动脚本: cmd/test_service/main.go
package main
import(
"emicro-go-base/internal/test_service/server"
)
func main() {
server.RunTestService(":8080", "../../config/test_service/app.toml")
}
后端基础的框架就大概这样,一些太细的细节代码就没全贴出来了,后续具体实现API章节会再继续贴。
可以先体验如下的微信小程序,该专栏系列都是参考小柠AI智能聊天来展开,小程序整体的gpt交互直接,界面也容易,对我们上手仿照在实现方面也比较友好。