本文主要记录下博主用gin搭建app server的过程,方便后续学习。web框架用的gin,日志用的zap,数据库连接用的mysql driver,配置文件读取用的是viper。整个项目的框架如下:
.
├── app
│ ├── comment.go
│ ├── server.go
│ └── user.go
├── config.toml
├── Gopkg.lock
├── Gopkg.toml
├── LICENSE
├── main.go
├── README.md
├── tool
│ ├── config
│ │ ├── config.go
│ │ └── config_test.go
│ ├── db
│ │ ├── mysql.go
│ │ └── mysql_test.go
│ └── log
│ ├── log.go
│ └── log_test.go
└── vendor
├── github.com
......
main.go作为整个api server 的入口文件,tool文件夹下面存放了日志,数据库,配置文件相关代码。app文件夹里面是api实现相关的代码。
配置文件读取的代码如下:
package config
import(
"fmt"
"github.com/spf13/viper"
)
func ParseConfig() error {
viper.SetConfigName("config") // name of config file (without extension)
viper.AddConfigPath("./conf") // call multiple times to add many search paths
viper.AddConfigPath(".") // optionally look for config in the working directory
err := viper.ReadInConfig() // Find and read the config file
if err != nil { // Handle errors reading the config file
return fmt.Errorf("Fatal error config file: %s \n", err)
}
viper.WatchConfig()
return nil
}
这里只是简单的一个demo,viper还有更多的功能,比如设置默认值 viper.SetDefault("ContentDir", "content")
,可以加载环境变量中的值AutomaticEnv()
,热更新配置文件 viper.WatchConfig()
。具体可以参考官方文档:链接。
本文件主要实现的是数据库连接,以及增删查改操作。具体代码如下:
package db
import (
"database/sql"
_ "github.com/go-sql-driver/mysql"
"time"
"github.com/spf13/viper"
"fmt"
)
type DbConn struct {
Db *sql.DB
}
func InitDbConn()(*DbConn, error) {
dbConn := viper.GetString("Database.DbConn")
db, err := sql.Open("mysql", dbConn)
if err != nil {
return nil, fmt.Errorf("get db connection error")
}
maxOpenConns := viper.GetInt("Database.MaxOpenConn") //从配置文件中获取配置值
maxIdleConns := viper.GetInt("Database.MaxIdleConn")
maxLifetime := viper.GetInt("Database.MaxLifetime")
......//省略部分代码
err = db.Ping()
if err != nil {
return nil,fmt.Errorf("connect to db error")
}else{
dbconn := &DbConn{Db:db}
return dbconn,nil
}
}
func (c *DbConn) Insert(sql string, args ...interface{}) (lastInsertId int64, err error) {
res, err := c.Db.Exec(sql, args...)
if err != nil {
return
}
return res.LastInsertId()
}
......//省略部分代码
主要是调用mysql driver根据配置文件配置值连接数据库。
日志主要的是uber的zap日志框架,这是一个高性能的日志框架,在这里有点小用它了。也只是一个简单的使用举例。更多功能需要去学习。
package log
import (
"fmt"
"strings"
"github.com/spf13/viper"
"go.uber.org/zap"
"go.uber.org/zap/zapcore"
"gopkg.in/natefinch/lumberjack.v2"
)
var Logger *zap.SugaredLogger //global logger
func InitLog() {
logLevel := viper.GetString("Log.LogLevel")
logName := viper.GetString("Log.LogName")
logAge := viper.GetInt("Log.LogAge")
logSize := viper.GetInt("Log.LogSize")
w := zapcore.AddSync(&lumberjack.Logger{
Filename: logName,
MaxSize: logSize, // megabytes
MaxBackups: 3,
LocalTime: true,
MaxAge: logAge, // days
})
zapLogLevel := zap.NewAtomicLevel()
if err := zapLogLevel.UnmarshalText([]byte(strings.ToLower(logLevel))); err != nil {
panic(fmt.Errorf("get config log level:%v config error: %v", logLevel, err))
}
.....//此处省略部分代码
logger := zap.New(core, zap.AddCaller())
Logger = logger.Sugar()
Logger.Info("logger init successful!")
}
主要就是调用配置读取函数,数据库连接和日志初始化函数,再启动http server
package main
import (
"fmt"
"os"
"os/signal"
"syscall"
"github.com/zhanben/go_site/app"
"github.com/zhanben/go_site/tool/config"
"github.com/zhanben/go_site/tool/db"
"github.com/zhanben/go_site/tool/log"
"go.uber.org/zap"
)
func main() {
//Read config file
err := config.ParseConfig()
if err != nil {
panic(fmt.Errorf("Failed to read config file: %s \n", err))
}
//Init log
log.InitLog()
//Init db connection
db, err := db.InitDbConn()
if err != nil {
panic("connect db error!")
}
log.Logger.Info("Db init successful!")
//start http sever
startServer(db)
}
.....//此处省略部分代码
下面是简单的两个接口实现的例子:一个是URL中带有参数,一个没有带的。
package app
import (
"github.com/gin-gonic/gin"
"go.uber.org/zap"
"net/http"
"github.com/zhanben/go_site/tool/db"
)
.....//此处省略部分代码
func (u *User) initRouter(r *gin.RouterGroup) {
//在此添加接口
r.GET("/users", u.getAllUsers) //获取所有用户信息
r.GET("/users/:name", u.getOneUser) //根据用户名获取用户详细信息
}
func (u *User) getAllUsers(c *gin.Context) {
//构建返回结构体
res := map[string]interface{}{
"Action": "GetAllUserResponse",
"RetCode": 0,
}
sql := "select * from user limit 10"
result, err := u.db.Select(sql)
if err != nil {
u.Logger.Error("get user info from db error!")
abortWithError(u.Logger, c, err)
}
res["UserInfo"] = result
c.JSON(http.StatusOK, res)
}
func (u *User) getOneUser(c *gin.Context) {
//构建返回结构体
res := map[string]interface{}{
"Action": "GetOneUserResponse",
"RetCode": 0,
}
userName, ok :=c.Params.Get("name")
if !ok {
u.Logger.Error("parameter name must be fixed!")
}
u.Logger.Infof("get user name from url:%s",userName)
sql := "select * from user where username=?"
result, err := u.db.Select(sql,userName)
if err != nil {
u.Logger.Error("get user info from db error!")
res["RetCode"]= "-1"
res["Error"] = "user not exist!"
}else{
res["UserInfo"] = result
u.Logger.Info("get one user info successful!")
}
c.JSON(http.StatusOK, res)
}
至此一个简单的go api sever的框架就搭建好了。当然后续还有单元测试的代码需要补充。本文的全部的代码可以到github下载:git clone --branch v0.1 git@github.com:Zhanben/go_site.git
手机扫一扫
移动阅读更方便
你可能感兴趣的文章