go实践之apiserver搭建
go实践之apiserver搭建
本文主要记录下博主用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实现相关的代码。
1、配置文件读取
配置文件读取的代码如下:
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()
。具体可以参考官方文档:链接。
2、数据连接
本文件主要实现的是数据库连接,以及增删查改操作。具体代码如下:
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根据配置文件配置值连接数据库。
3、日志初始化
日志主要的是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!")
}
4、server初始化
主要就是调用配置读取函数,数据库连接和日志初始化函数,再启动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)
}
.....//此处省略部分代码
5、接口编写
下面是简单的两个接口实现的例子:一个是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
go实践之apiserver搭建的更多相关文章
- 从零开始针对 .NET 应用的 DevOps 运营实践 - 运行环境搭建
一.Overview 最近的一段时间,在公司里我都在进行基于 Jenkins 和 SonarQube 配合已有的 Gitlab 搭建部门的持续集成环境的工作,虽然之前有使用过 GitHub Actio ...
- 前端项目模块化的实践1:搭建 NPM 私有仓库管理源码及依赖
以下是关于前端项目模块化的实践,包含以下内容: 搭建 NPM 私有仓库管理源码及依赖: 使用 Webpack 打包基础设施代码: 使用 TypeScript 编写可靠类库 使用 TypeScript ...
- 【机器学习PAI实践一】搭建心脏病预测案例
一.背景 心脏病是人类健康的头号杀手.全世界1/3的人口死亡是因心脏病引起的,而我国,每年有几十万人死于心脏病. 所以,如果可以通过提取人体相关的体侧指标,通过数据挖掘的方式来分析不同特征对于心脏病的 ...
- OceanBase数据库实践入门——手动搭建OceanBase集群
前言 目前有关OceanBase功能.案例.故事的文章已经很多,对OceanBase感兴趣的朋友都想安装一个数据库试试.本文就是分享初学者如何手动搭建一个OceanBase集群.这也是学习理解Ocea ...
- 运维开发实践——基于Sentry搭建错误日志监控系统
错误日志监控也可称为业务逻辑监控, 旨在对业务系统运行过程中产生的错误日志进行收集归纳和监控告警.似乎有那么点曾相识?没错... 就是提到的“APM应用性能监控”.但它又与APM不同,APM系统主要注 ...
- django入门与实践 3-1 环境搭建
Python 2.7 .Django对2.7.3.5.3.4都是支持的. https://www.djangoproject.com/download/ django对python的兼容情况 pip安 ...
- 2. react 编程实践 俄罗斯方块-环境搭建
1. 创建 demo 目录 mkdir demo 2. 初始化应用 npm init 工程信息 package name : tetris-class-demo version: descriptio ...
- go实践之swagger自动生成api文档
文章目录 go实践之swagger自动生成api文档 1.安装需要用到的包 2.接口代码支持swagger 3. 生成swagger接口 go实践之swagger自动生成api文档 作为一个后端开发, ...
- MySQL5.6 GTID新特性实践
MySQL5.6 GTID新特性实践 GTID简介 搭建 实验一:如果slave所需要事务对应的GTID在master上已经被purge了 实验二:忽略purged的部分,强行同步 本文将简单介绍基于 ...
随机推荐
- 易初大数据 spss 2019年10月31日 wangqingchao
---恢复内容开始--- 1.描述性统计分析方法是指应用分类.制表.图形及概括性数据指标来概括数据分析特征的方法. 2.而推断性统计分析方法则是通过随机抽样,应用统计方法把从样本数据得到的结论推广到总 ...
- python——多线程
多线程特点: • 线程的并发是利用cpu上下文的切换(是并发,不是并行) • 多线程执行的顺序是无序的 • 多线程共享全局变量 • 线程是继承在进程里的,没有进程就没有线程 • GIL全局解释器锁 • ...
- Electron 菜单切换主题与css替换 ts编写
////目标css<link rel="stylesheet" id="theme_css" href="路径"> ////ts ...
- ASP.NET Core 1.0: 指定Default Page
前不久写过一篇Blog<指定Static File中的文件作为Default Page>,详细参见链接. 然而,今天偶然发现了一个更加简洁的方法,直接使用Response的Redirect ...
- 一个类GraphQL的ORM数据访问框架发布
Zongsoft.Data 发布公告 很高兴我们的 ORM 数据访问框架(Zongsoft.Data)在历经两个 SaaS 产品的应用之后,今天正式宣布对外推广! 这是一个类 GraphQL 风格的 ...
- SQL Server 2014:在修改表的内容时,提示“此单元格已更改,尚未将更改提交到数据库”,怎么处理?
那一行上的属性为“不允许为null”的所有字段都填上对应信息,按回车键或者点击下一行任意一个单元格便会自动将更改的信息提交到数据库.
- hdu 1083 Courses (最大匹配)
CoursesTime Limit: 20000/10000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)Total Su ...
- 领扣(LeetCode)两数之和II - 输入有序数组 个人题解
给定一个已按照升序排列 的有序数组,找到两个数使得它们相加之和等于目标数. 函数应该返回这两个下标值 index1 和 index2,其中 index1 必须小于 index2. 说明: 返回的下标值 ...
- 四 linuk常用命令 2. 权限管理命令
一 权限管理命令chmod 所有者u 所属组g 其他人o 所有人a 所有者和root超级用户可以更改该权限 普通更改权限是不会改变子目录的权限的,要想改变用递归修改 useradd增加用户 目录的r和 ...
- 【01】主函数main
java和C#非常相似,它们大部分的语法是一样的,但尽管如此,也有一些地方是不同的. 为了更好地学习java或C#,有必要分清它们两者到底在哪里不同. 首先,我们将探讨主函数main. java的主函 ...