# account
**Repository Path**: zhangyaoo/account
## Basic Information
- **Project Name**: account
- **Description**: 账户管理
- **Primary Language**: Unknown
- **License**: MIT
- **Default Branch**: master
- **Homepage**: None
- **GVP Project**: No
## Statistics
- **Stars**: 0
- **Forks**: 0
- **Created**: 2021-09-14
- **Last Updated**: 2021-10-27
## Categories & Tags
**Categories**: Uncategorized
**Tags**: None
## README
# Account
一套基于 Gin 框架的 MVC 脚手架
- 封装了 Gin Web 服务配置、数据库/连接池配置、视图配置,方便快速构建 Go Web 工程
- 自带一套用于体验及演示的 Restful Api 代码示例
## 快速构建体验
```sh
# 需要注意的是golang 的第三方包是否能够正常的获取
# 快速构建镜像
docker build -t account_xt .
# 快速的启动服务
docker run -itd --name accountXt -p 8000:5000 $(imageId)
```
## 安装步骤
### 安装govendor包管理工具
### 拉取源码
```sh
# git clone https://gitee.com/zhangyaoo/account.git && go mod init account && go mod tidy
```
### 使用 govendor 安装依赖包
```sh
# govendor sync
```
### 服务配置
```go
package configs
// 服务配置 防止变量污染故用函数组织
func GetServerConfig() (serverConfig map[string]string) {
serverConfig = make(map[string]string)
serverConfig["HOST"] = "0.0.0.0" //监听地址
serverConfig["PORT"] = "8080" //监听端口
serverConfig["VIEWS_PATTERN"] = "account/views/*/*" //视图模板路径pattern
serverConfig["ENV"] = "debug" //环境模式 release/debug/test
return
}
```
### 数据库及连接池配置
因框架启动时会创建连接池服务,故需配置好数据库后运行
```go
package configs
// 数据库配置
func GetDbConfig() map[string]string {
// 初始化数据库配置map
dbConfig := make(map[string]string)
dbConfig["DB_HOST"] = "154.209.69.12"
dbConfig["DB_PORT"] = "33306"
dbConfig["DB_NAME"] = "test"
dbConfig["DB_USER"] = "root"
dbConfig["DB_PWD"] = "123456"
dbConfig["DB_CHARSET"] = "utf8"
dbConfig["DB_LOC"] = "Local"
dbConfig["DB_PARSETIME"] = "True"
dbConfig["DB_MAX_OPEN_CONNS"] = "20" // 连接池最大连接数
dbConfig["DB_MAX_IDLE_CONNS"] = "10" // 连接池最大空闲数
dbConfig["DB_MAX_LIFETIME_CONNS"] = "7200" // 连接池链接最长生命周期
return dbConfig
}
node 默认设置3个节点减少内存动态开辟的资源
*/
func GetDBClusterConfig() map[string]map[string]string {
// 初始化数据库配置map
TemPoraryNode := "154.209.69.12"
TemPoraryPort := "33306"
dbConfig := map[string]map[string]string{
"master": {
"DB_HOST": TemPoraryNode,
"DB_PORT": TemPoraryPort,
"DB_NAME": "test",
"DB_USER": "root",
"DB_PWD": "123456",
"DB_CHARSET": "utf8",
"DB_LOC": "Local",
"DB_PARSETIME": "True",
"DB_MAX_OPEN_CONNS": "20",
"DB_MAX_IDLE_CONNS": "10",
"DB_MAX_LIFETIME_CONNS": "7200",
},
"slave1": {
"DB_HOST": TemPoraryNode,
"DB_PORT": TemPoraryPort,
"DB_NAME": "test",
"DB_USER": "root",
"DB_PWD": "123456",
"DB_CHARSET": "utf8",
"DB_LOC": "Local",
"DB_PARSETIME": "True",
"DB_MAX_OPEN_CONNS": "20",
"DB_MAX_IDLE_CONNS": "10",
"DB_MAX_LIFETIME_CONNS": "7200",
},
"slave2": {
"DB_HOST": TemPoraryNode,
"DB_PORT": TemPoraryPort,
"DB_NAME": "test",
"DB_USER": "root",
"DB_PWD": "123456",
"DB_CHARSET": "utf8",
"DB_LOC": "Local",
"DB_PARSETIME": "True",
"DB_MAX_OPEN_CONNS": "20",
"DB_MAX_IDLE_CONNS": "10",
"DB_MAX_LIFETIME_CONNS": "7200",
},
}
return dbConfig
}
// 加载集群开关
func DBSelectNodeOrCluster() bool {
isClusterNode := true
return isClusterNode
}
```
### 启动服务
```sh
# go run main.go
API server listening at: 127.0.0.1:11485
MyRedis-Init
[Sentry] 2021/09/27 11:28:36 Integration installed: ContextifyFrames
[Sentry] 2021/09/27 11:28:36 Integration installed: Environment
[Sentry] 2021/09/27 11:28:36 Integration installed: Modules
[Sentry] 2021/09/27 11:28:36 Integration installed: IgnoreErrors
[Sentry] 2021/09/27 11:28:36 Buffer flushed successfully.
启动后台任务成....
数据库迁移成功....
加载服务器配置....
加载服务器环境....
[GIN-debug] [WARNING] Creating an Engine instance with the Logger and Recovery middleware already attached.
[GIN-debug] [WARNING] Running in "debug" mode. Switch to "release" mode in production.
- using env: export GIN_MODE=release
- using code: gin.SetMode(gin.ReleaseMode)
[GIN-debug] Loaded HTML Templates (3):
-
- index.html
- index/index.html
加载服务器前端配置....
[GIN-debug] GET /swagger/*any --> github.com/swaggo/gin-swagger.CustomWrapHandler.func1 (3 handlers)
[GIN-debug] GET /api/v1/account/user --> account/controllers/api/v1/user.UserInfo (3 handlers)
[GIN-debug] GET /api/v1/account/user/one --> account/controllers/api/v1/user.UserOne (3 handlers)
```
### 访问服务
http://yourhost:8080/
## 快速体验
### 导入框架示例 Sql
```sql
CREATE DATABASE `test` DEFAULT CHARSET uft8mb4 DEFAULT utf8mb4_general_ci;
USE `test`;
-- 创建account表
CREATE TABLE `account` (
`id` int NOT NULL AUTO_INCREMENT,
`parent_id` int DEFAULT NULL,
`note` varchar(100) DEFAULT NULL COMMENT '备注',
`level` varchar(100) DEFAULT NULL,
`role` varchar(100) DEFAULT NULL,
`capital` varchar(100) DEFAULT NULL,
`cur_fund` varchar(100) DEFAULT NULL,
`base_fund` varchar(100) DEFAULT NULL,
`reserved` varchar(100) DEFAULT NULL,
`market_id` int DEFAULT NULL,
`exchange_id` int DEFAULT NULL,
`name` varchar(100) DEFAULT NULL COMMENT '账户名',
`access_key` varchar(100) DEFAULT NULL COMMENT '公钥',
`secret_key` varchar(256) DEFAULT NULL COMMENT '私钥',
`deleted` tinyint(1) DEFAULT NULL COMMENT '是否删除',
`active` tinyint(1) DEFAULT NULL COMMENT '风险级别是否启用',
`create_time` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`write_time` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '修改时间',
PRIMARY KEY (`id`),
UNIQUE KEY `access_key` (`access_key`),
UNIQUE KEY `name` (`name`),
UNIQUE KEY `secret_key` (`secret_key`),
KEY `exchange_id` (`exchange_id`),
KEY `market_id` (`market_id`),
KEY `parent_id` (`parent_id`),
CONSTRAINT `account_ibfk_1` FOREIGN KEY (`exchange_id`) REFERENCES `exchange` (`id`) ON DELETE CASCADE,
CONSTRAINT `account_ibfk_2` FOREIGN KEY (`market_id`) REFERENCES `market` (`id`) ON DELETE CASCADE,
CONSTRAINT `account_ibfk_3` FOREIGN KEY (`parent_id`) REFERENCES `account` (`id`) ON DELETE CASCADE
) ENGINE=InnoDB AUTO_INCREMENT=361 DEFAULT CHARSET=utf8mb3
-- 创建balance_change_line表
CREATE TABLE `balance_change_line` (
`id` int NOT NULL AUTO_INCREMENT,
`market` varchar(10) NOT NULL COMMENT '市场',
`risk_id` int DEFAULT NULL,
`account_id` int DEFAULT NULL,
`balance_rate` float(10,2) NOT NULL COMMENT '不同时刻资金差比',
`cur_fund` float(100,2) NOT NULL COMMENT 'cur 资金',
`base_fund` float(100,2) NOT NULL COMMENT 'base 资金',
`cur_inflow` float(100,2) NOT NULL COMMENT 'cur 净流入资金',
`base_outflow` float(100,2) NOT NULL COMMENT 'base 净流出资金',
`note` text COMMENT '备注',
`account_balance` float(100,2) NOT NULL COMMENT '账户资产等值usdt',
`account_balance_change` float(100,2) NOT NULL COMMENT '账户资产变化等值usdt',
`account_balance_pct_change` float(10,4) NOT NULL COMMENT '账户资产变化率等值usdt',
`total_balance` float(100,2) NOT NULL COMMENT '总资产等值usdt',
`total_balance_change` float(100,2) NOT NULL COMMENT '总资产变化等值usdt',
`total_balance_pct_change` float(10,4) NOT NULL COMMENT '总资产变化率',
`exclude_fund` float(100,2) DEFAULT NULL COMMENT '不计算内的资金',
`create_time` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`write_time` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '修改时间',
PRIMARY KEY (`id`),
KEY `account_id` (`account_id`),
KEY `risk_id` (`risk_id`),
CONSTRAINT `balance_change_line_ibfk_1` FOREIGN KEY (`account_id`) REFERENCES `account` (`id`) ON UPDATE CASCADE,
CONSTRAINT `balance_change_line_ibfk_2` FOREIGN KEY (`risk_id`) REFERENCES `risk` (`id`) ON UPDATE CASCADE
) ENGINE=InnoDB AUTO_INCREMENT=5853 DEFAULT CHARSET=utf8mb3
-- 创建common_alerts表
CREATE TABLE `common_alerts` (
`id` int NOT NULL AUTO_INCREMENT,
`risk_level` varchar(100) DEFAULT NULL COMMENT '风险等级',
`active` tinyint(1) DEFAULT NULL COMMENT '风险警告是否启用',
`message` text COMMENT '风险信息',
`created_at` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`deleted_at` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '删除时间',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8mb3
-- 创建exchang表
CREATE TABLE `exchange` (
`id` int NOT NULL AUTO_INCREMENT,
`name` varchar(100) DEFAULT NULL COMMENT '交易所名称',
`short_name` varchar(100) DEFAULT NULL COMMENT '交易所名称简写',
`deleted` tinyint(1) DEFAULT NULL COMMENT '是否删除',
`active` tinyint(1) DEFAULT NULL COMMENT '风险级别是否启用',
`create_time` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`write_time` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '修改时间',
PRIMARY KEY (`id`),
UNIQUE KEY `name` (`name`)
) ENGINE=InnoDB AUTO_INCREMENT=9 DEFAULT CHARSET=utf8mb3
-- 创建market表
CREATE TABLE `market` (
`id` int NOT NULL AUTO_INCREMENT,
`name` varchar(100) DEFAULT NULL COMMENT '市场名',
`code` varchar(100) DEFAULT NULL COMMENT '市场代码',
`deleted` tinyint(1) DEFAULT NULL COMMENT '是否删除',
`active` tinyint(1) DEFAULT NULL COMMENT '市场是否启用',
`create_time` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`write_time` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '修改时间',
PRIMARY KEY (`id`),
UNIQUE KEY `name` (`name`)
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8mb3
-- 创建risk表
CREATE TABLE `risk` (
`id` int NOT NULL AUTO_INCREMENT,
`name` varchar(100) NOT NULL COMMENT '风险级别名字',
`status` float(10,2) NOT NULL COMMENT '风险级别',
`deleted` tinyint(1) DEFAULT NULL COMMENT '是否删除',
`active` tinyint(1) DEFAULT NULL COMMENT '风险级别是否启用',
`description` text COMMENT '描述',
`create_time` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`write_time` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '修改时间',
PRIMARY KEY (`id`),
UNIQUE KEY `name` (`name`),
UNIQUE KEY `status` (`status`)
) ENGINE=InnoDB AUTO_INCREMENT=7 DEFAULT CHARSET=utf8mb3
-- 创建risk_alerts表
CREATE TABLE `risk_alerts` (
`id` int NOT NULL AUTO_INCREMENT,
`risk_level` varchar(100) NOT NULL COMMENT '风险级别名字',
`total_balance_change` float(100,2) NOT NULL COMMENT '总资产变化等值usdt',
`total_balance_pct_change` float(10,4) NOT NULL COMMENT '总资产变化率',
`deleted` tinyint(1) DEFAULT NULL COMMENT '是否删除',
`active` tinyint(1) DEFAULT NULL COMMENT '风险警告是否启用',
`description` text COMMENT '描述',
`create_time` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`write_time` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '修改时间',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8mb3
-- 创建script_cron
CREATE TABLE `script_cron` (
`id` int NOT NULL AUTO_INCREMENT,
`name` varchar(100) NOT NULL COMMENT '任务名',
`period` int NOT NULL COMMENT '任务周期',
`active` tinyint(1) DEFAULT NULL COMMENT '任务是否启用',
`deleted` tinyint(1) DEFAULT NULL COMMENT '任务是否删除',
`create_time` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`write_time` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '修改时间',
PRIMARY KEY (`id`),
UNIQUE KEY `name` (`name`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3
```
### 定义控制器
controllers
controllers/api/v1/account/IndexController.go
```go
package account
import (
"account/models"
"account/server"
"fmt"
"net/http"
"strconv"
"strings"
"github.com/gin-gonic/gin"
)
// @Summary 获取所有账户信息
// @Description get account info
// @Accept json
// @Produce json
// @Success 200 {string} string "success"
// @Router /api/v1/account [get]
func AccountAllInfos(ctx *gin.Context) {
var response *server.Response
result, err := server.GetAccountAllInfos()
if err != nil {
message := fmt.Sprintf("没有获取导数据 : %s", err.Error())
response = server.NewResponse(http.StatusNoContent, message, result)
ctx.JSON(http.StatusNoContent, response)
return
}
message := "success"
response = server.NewResponse(http.StatusOK, message, result)
ctx.JSON(http.StatusOK, response)
}
```
### 定义模型
models
models/account.go
```go
package models
import "encoding/json"
type Account struct {
BaseModel
Name string `json:"name" binding:"required" form:"name" gorm:"column:name;unique"`
Deleted bool `json:"deleted" form:"deleted" gorm:"column:deleted"`
AccessKey string `json:"accesskey" binding:"required" form:"accesskey" gorm:"column:access_key"`
SecretKey string `json:"secretkey" binding:"required" form:"secretkey" gorm:"column:secret_key"`
Active bool `json:"active" form:"active" gorm:"column:active"`
Note string `json:"note" binding:"required" form:"note" gorm:"column:note"`
Level string `json:"level" form:"level" gorm:"column:level"`
Role string `json:"role" form:"role" gorm:"column:role"`
Capital string `json:"capital" binding:"required" form:"capital" gorm:"column:capital"`
CurFund string `json:"cur_fund" form:"cur_fund" gorm:"column:cur_fund"`
BaseFund string `json:"base_fund" form:"base_fund" gorm:"column:base_fund"`
Reserved string `json:"reserved" form:"reserved" gorm:"column:reserved"`
MarketId uint64 `json:"marketId" form:"marketId"`
Market Market `json:"-" gorm:"foreignkey:Id;association_foreignkey:MarketId;omitempty"`
ExchangeId uint64 `json:"exchangeId" form:"exchangeId"`
Exchange Exchange `json:"-" gorm:"foreignkey:Id;association_foreignkey:ExchangeId;omitempty"`
ParentId uint64 `json:"parentId" form:"parentId" gorm:"default:null"`
Childs []Account `json:"childs" form:"childs" gorm:"foreignkey:ParentId"`
}
type FakeAccount Account
// 定义序列化的格式
func (a Account) MarshalJSON() ([]byte, error) {
return json.Marshal(struct {
FakeAccount
Market string `json:"marketName"`
Exchange string `json:"exchangeName"`
}{
FakeAccount: FakeAccount(a),
Market: a.Market.Name,
Exchange: a.Exchange.Name})
}
```
### 定义业务逻辑
```go
server
server/account.go
package server
import (
"account/drivers"
"account/models"
)
// 获取所有账户信息
// 需要注意的是数据字段的类型跟自定义的结构体类型部分会有一些字段冲突
// 冲突情况可以通过Debug SQL 日志来进行分析
func GetAccountAllInfos() ([]models.Account, error) {
...
}
// 新增账户信息
func AddAccountInfo(account models.Account) ([]models.Account, error) {
...
}
// 更新账户信息
func UpdateAccountInfo(id int, account models.Account) error {
...
}
// 更新账户信息
func ActiveAccountInfo(id int) error {
...
}
// 根据条件获取某个或者某些账户信息
func GetAccountFilterInfos(query interface{}, args ...interface{}) ([]models.Account, error) {
...
}
// 处理队列的过滤条件
func GetAccountFilterQueueInfos() ([]models.Account, error) {
...
}
```
### 定义视图
MVT
views
views/index
views/index/index.html
### 定义路由 Restful
routes
routes/router.go
```go
package routes
import (
"account/routes/account"
"account/routes/exchange"
"account/routes/health"
"account/routes/market"
_ "account/docs"
"github.com/gin-gonic/gin"
ginSwagger "github.com/swaggo/gin-swagger"
"github.com/swaggo/gin-swagger/swaggerFiles"
)
// @title account project
// @version 1.0
// @description this is account server.
// @host 127.0.0.1:8080
// @BasePath /api/v1/
func RegisterRouterGroup(router *gin.Engine) {
RouterGroup := router.Group("api/v1/account")
router.GET("/swagger/*any", ginSwagger.WrapHandler(swaggerFiles.Handler))
{
exchange.InitPlatRouter(RouterGroup)
market.InitMarketRouter(RouterGroup)
account.InitAccountRouter(RouterGroup)
health.InitHealthRouter(RouterGroup)
}
}
```
### 热更新开发模式借用 rizla 插件
```sh
# go get -u github.com/kataras/rizla
# rizla main.go
```
### 注意
因 golang 的包载入机制问题,项目名如需改为其他,需修改框架内的部分包的代码 `account` to `your-projectName`
main.go
server/server.go
routes/router.go
server/server.go
models/*