upgrade
This commit is contained in:
@@ -26,6 +26,7 @@
|
||||
- third_party_requests,当前请求涉及到调用第三方的信息
|
||||
- debugs,当前请求的调试信息
|
||||
- sqls,当前请求执行的 sql 信息
|
||||
- redis,当前请求执行的 redis 信息
|
||||
- success,当前请求结果
|
||||
- cost_seconds,执行时长,单位秒
|
||||
|
||||
@@ -60,6 +61,7 @@
|
||||
- [x] 支持设置 third_party_requests 三方请求信息
|
||||
- [x] 支持设置 debugs 打印调试信息
|
||||
- [x] 支持设置 sqls 执行 SQL 信息
|
||||
- [x] 支持设置 redis 执行 Redis 信息
|
||||
- [x] 可记录 cost_seconds 执行时长
|
||||
- [x] [errno] 统一定义错误码
|
||||
- [x] [env] 支持 FAT、UAT、PRO 环境
|
||||
|
||||
@@ -49,7 +49,8 @@ type Config struct {
|
||||
} `toml:"mail"`
|
||||
|
||||
JWT struct {
|
||||
Secret string `toml:"secret"`
|
||||
Secret string `toml:"secret"`
|
||||
ExpireDuration time.Duration `toml:"expireDuration"`
|
||||
} `toml:"jwt"`
|
||||
|
||||
Aes struct {
|
||||
|
||||
@@ -1,37 +1,38 @@
|
||||
[mysql]
|
||||
|
||||
[mysql.read]
|
||||
addr = ''
|
||||
user = ''
|
||||
pass = ''
|
||||
name = ''
|
||||
[mysql.write]
|
||||
addr = ''
|
||||
user = ''
|
||||
pass = ''
|
||||
name = ''
|
||||
[mysql.base]
|
||||
maxOpenConn = 10
|
||||
maxIdleConn = 60
|
||||
connMaxLifeTime = 60
|
||||
[mysql.read] # 从库信息,可读
|
||||
addr = '127.0.0.1:3306' # MySQL 地址:端口
|
||||
user = 'root' # 用户名
|
||||
pass = 'root' # 密码
|
||||
name = 'go_gin_api' # 数据库名称
|
||||
[mysql.write] # 主库信息,可读写
|
||||
addr = '127.0.0.1:3306' # MySQL 地址:端口
|
||||
user = 'root' # 用户名
|
||||
pass = 'root' # 密码
|
||||
name = 'go_gin_api' # 数据库名称
|
||||
[mysql.base] # 基础配置
|
||||
maxOpenConn = 10 # 最大打开的连接数
|
||||
maxIdleConn = 60 # 闲置的连接数
|
||||
connMaxLifeTime = 60 # 最大连接超时(单位:分)
|
||||
|
||||
[redis]
|
||||
addr = ''
|
||||
pass = ''
|
||||
db = 0
|
||||
maxRetries = 3
|
||||
poolSize = 10
|
||||
minIdleConns = 5
|
||||
addr = '127.0.0.1:6379' # Redis 地址:端口
|
||||
pass = '' # 密码
|
||||
db = 0 # 序号从 0 开始,默认是0,可以不用设置
|
||||
maxRetries = 3 # 命令执行失败时,最多重试多少次,默认为 0 即不重试
|
||||
poolSize = 10 # 连接池最大连接数,默认为 CPU 数 * 10
|
||||
minIdleConns = 5 # 最小空闲连接数
|
||||
|
||||
[mail]
|
||||
host = 'smtp.163.com'
|
||||
port = 465
|
||||
user = ""
|
||||
pass = ""
|
||||
to = ""
|
||||
host = 'smtp.163.com' # 邮箱服务器,比如 smtp.163.com
|
||||
port = 465 # 端口
|
||||
user = "" # 发件人邮箱
|
||||
pass = "" # 发件人邮箱密码或授权码,根据邮箱服务器而定
|
||||
to = "" # 收件人邮箱,多个可以逗号(,)分割
|
||||
|
||||
[jwt]
|
||||
secret = 'i1ydX9RtHyuJTrw7frcu'
|
||||
secret = 'i1ydX9RtHyuJTrw7frcu' # JWT secret
|
||||
expireDuration = 24 # JWT ExpiresAt 过期时间(单位:小时)
|
||||
|
||||
[aes]
|
||||
key = 'IgkibX71IEf382PT'
|
||||
|
||||
184
docs/docs.go
184
docs/docs.go
@@ -19,14 +19,18 @@ var doc = `{
|
||||
"description": "{{.Description}}",
|
||||
"title": "{{.Title}}",
|
||||
"contact": {},
|
||||
"license": {
|
||||
"name": "MIT",
|
||||
"url": "https://github.com/xinliangnote/go-gin-api/blob/master/LICENSE"
|
||||
},
|
||||
"version": "{{.Version}}"
|
||||
},
|
||||
"host": "{{.Host}}",
|
||||
"basePath": "{{.BasePath}}",
|
||||
"paths": {
|
||||
"/demo/user/{name}": {
|
||||
"get": {
|
||||
"description": "获取用户信息",
|
||||
"/auth/get": {
|
||||
"post": {
|
||||
"description": "获取授权信息",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
@@ -36,15 +40,31 @@ var doc = `{
|
||||
"tags": [
|
||||
"Demo"
|
||||
],
|
||||
"summary": "获取用户信息",
|
||||
"summary": "获取授权信息",
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "返回信息",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/demo.authResponse"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/demo/trace": {
|
||||
"get": {
|
||||
"description": "Trace 示例",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"Demo"
|
||||
],
|
||||
"summary": "Trace 示例",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "string",
|
||||
"description": "用户名(Tom)",
|
||||
"name": "name",
|
||||
"in": "path",
|
||||
"required": true
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"description": "签名",
|
||||
@@ -86,7 +106,7 @@ var doc = `{
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"Demo"
|
||||
"User"
|
||||
],
|
||||
"summary": "创建用户",
|
||||
"parameters": [
|
||||
@@ -98,6 +118,13 @@ var doc = `{
|
||||
"schema": {
|
||||
"$ref": "#/definitions/user_model.CreateRequest"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"description": "签名",
|
||||
"name": "Authorization",
|
||||
"in": "header",
|
||||
"required": true
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
@@ -110,6 +137,42 @@ var doc = `{
|
||||
}
|
||||
}
|
||||
},
|
||||
"/user/delete/{id}": {
|
||||
"patch": {
|
||||
"description": "删除用户 - 更新 is_deleted = 1",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"User"
|
||||
],
|
||||
"summary": "删除用户 - 更新 is_deleted = 1",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "integer",
|
||||
"description": "用户ID",
|
||||
"name": "id",
|
||||
"in": "path",
|
||||
"required": true
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"description": "签名",
|
||||
"name": "Authorization",
|
||||
"in": "header",
|
||||
"required": true
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "返回信息"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/user/info/{username}": {
|
||||
"get": {
|
||||
"description": "用户详情",
|
||||
@@ -120,7 +183,7 @@ var doc = `{
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"Demo"
|
||||
"User"
|
||||
],
|
||||
"summary": "用户详情",
|
||||
"parameters": [
|
||||
@@ -130,6 +193,13 @@ var doc = `{
|
||||
"name": "username",
|
||||
"in": "path",
|
||||
"required": true
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"description": "签名",
|
||||
"name": "Authorization",
|
||||
"in": "header",
|
||||
"required": true
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
@@ -142,43 +212,9 @@ var doc = `{
|
||||
}
|
||||
}
|
||||
},
|
||||
"/user/login": {
|
||||
"post": {
|
||||
"description": "用户登录",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"Demo"
|
||||
],
|
||||
"summary": "用户登录",
|
||||
"parameters": [
|
||||
{
|
||||
"description": "请求信息",
|
||||
"name": "RequestInfo",
|
||||
"in": "body",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"$ref": "#/definitions/user_model.LoginRequest"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "返回信息",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/user_model.LoginResponse"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/user/update": {
|
||||
"post": {
|
||||
"description": "更新用户名称",
|
||||
"put": {
|
||||
"description": "编辑用户 - 通过用户主键ID更新用户昵称",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
@@ -186,9 +222,9 @@ var doc = `{
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"Demo"
|
||||
"User"
|
||||
],
|
||||
"summary": "更新用户名称",
|
||||
"summary": "编辑用户 - 通过用户主键ID更新用户昵称",
|
||||
"parameters": [
|
||||
{
|
||||
"description": "请求信息",
|
||||
@@ -198,6 +234,13 @@ var doc = `{
|
||||
"schema": {
|
||||
"$ref": "#/definitions/user_model.UpdateNickNameByIDRequest"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"description": "签名",
|
||||
"name": "Authorization",
|
||||
"in": "header",
|
||||
"required": true
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
@@ -212,6 +255,19 @@ var doc = `{
|
||||
}
|
||||
},
|
||||
"definitions": {
|
||||
"demo.authResponse": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"authorization": {
|
||||
"description": "签名",
|
||||
"type": "string"
|
||||
},
|
||||
"expire_time": {
|
||||
"description": "过期时间",
|
||||
"type": "integer"
|
||||
}
|
||||
}
|
||||
},
|
||||
"user_model.CreateRequest": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
@@ -259,32 +315,6 @@ var doc = `{
|
||||
}
|
||||
}
|
||||
},
|
||||
"user_model.LoginRequest": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"user_id": {
|
||||
"description": "用户ID(\u003e0)",
|
||||
"type": "integer"
|
||||
},
|
||||
"user_name": {
|
||||
"description": "用户名",
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"user_model.LoginResponse": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"authorization": {
|
||||
"description": "签名",
|
||||
"type": "string"
|
||||
},
|
||||
"expire_time": {
|
||||
"description": "过期时间",
|
||||
"type": "integer"
|
||||
}
|
||||
}
|
||||
},
|
||||
"user_model.UpdateNickNameByIDRequest": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
|
||||
@@ -2,13 +2,17 @@
|
||||
"swagger": "2.0",
|
||||
"info": {
|
||||
"title": "go-gin-api docs api",
|
||||
"contact": {}
|
||||
"contact": {},
|
||||
"license": {
|
||||
"name": "MIT",
|
||||
"url": "https://github.com/xinliangnote/go-gin-api/blob/master/LICENSE"
|
||||
}
|
||||
},
|
||||
"host": "127.0.0.1:9999",
|
||||
"paths": {
|
||||
"/demo/user/{name}": {
|
||||
"get": {
|
||||
"description": "获取用户信息",
|
||||
"/auth/get": {
|
||||
"post": {
|
||||
"description": "获取授权信息",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
@@ -18,15 +22,31 @@
|
||||
"tags": [
|
||||
"Demo"
|
||||
],
|
||||
"summary": "获取用户信息",
|
||||
"summary": "获取授权信息",
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "返回信息",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/demo.authResponse"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/demo/trace": {
|
||||
"get": {
|
||||
"description": "Trace 示例",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"Demo"
|
||||
],
|
||||
"summary": "Trace 示例",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "string",
|
||||
"description": "用户名(Tom)",
|
||||
"name": "name",
|
||||
"in": "path",
|
||||
"required": true
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"description": "签名",
|
||||
@@ -68,7 +88,7 @@
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"Demo"
|
||||
"User"
|
||||
],
|
||||
"summary": "创建用户",
|
||||
"parameters": [
|
||||
@@ -80,6 +100,13 @@
|
||||
"schema": {
|
||||
"$ref": "#/definitions/user_model.CreateRequest"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"description": "签名",
|
||||
"name": "Authorization",
|
||||
"in": "header",
|
||||
"required": true
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
@@ -92,6 +119,42 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"/user/delete/{id}": {
|
||||
"patch": {
|
||||
"description": "删除用户 - 更新 is_deleted = 1",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"User"
|
||||
],
|
||||
"summary": "删除用户 - 更新 is_deleted = 1",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "integer",
|
||||
"description": "用户ID",
|
||||
"name": "id",
|
||||
"in": "path",
|
||||
"required": true
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"description": "签名",
|
||||
"name": "Authorization",
|
||||
"in": "header",
|
||||
"required": true
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "返回信息"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/user/info/{username}": {
|
||||
"get": {
|
||||
"description": "用户详情",
|
||||
@@ -102,7 +165,7 @@
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"Demo"
|
||||
"User"
|
||||
],
|
||||
"summary": "用户详情",
|
||||
"parameters": [
|
||||
@@ -112,6 +175,13 @@
|
||||
"name": "username",
|
||||
"in": "path",
|
||||
"required": true
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"description": "签名",
|
||||
"name": "Authorization",
|
||||
"in": "header",
|
||||
"required": true
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
@@ -124,43 +194,9 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"/user/login": {
|
||||
"post": {
|
||||
"description": "用户登录",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"Demo"
|
||||
],
|
||||
"summary": "用户登录",
|
||||
"parameters": [
|
||||
{
|
||||
"description": "请求信息",
|
||||
"name": "RequestInfo",
|
||||
"in": "body",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"$ref": "#/definitions/user_model.LoginRequest"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "返回信息",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/user_model.LoginResponse"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/user/update": {
|
||||
"post": {
|
||||
"description": "更新用户名称",
|
||||
"put": {
|
||||
"description": "编辑用户 - 通过用户主键ID更新用户昵称",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
@@ -168,9 +204,9 @@
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"Demo"
|
||||
"User"
|
||||
],
|
||||
"summary": "更新用户名称",
|
||||
"summary": "编辑用户 - 通过用户主键ID更新用户昵称",
|
||||
"parameters": [
|
||||
{
|
||||
"description": "请求信息",
|
||||
@@ -180,6 +216,13 @@
|
||||
"schema": {
|
||||
"$ref": "#/definitions/user_model.UpdateNickNameByIDRequest"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"description": "签名",
|
||||
"name": "Authorization",
|
||||
"in": "header",
|
||||
"required": true
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
@@ -194,6 +237,19 @@
|
||||
}
|
||||
},
|
||||
"definitions": {
|
||||
"demo.authResponse": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"authorization": {
|
||||
"description": "签名",
|
||||
"type": "string"
|
||||
},
|
||||
"expire_time": {
|
||||
"description": "过期时间",
|
||||
"type": "integer"
|
||||
}
|
||||
}
|
||||
},
|
||||
"user_model.CreateRequest": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
@@ -241,32 +297,6 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"user_model.LoginRequest": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"user_id": {
|
||||
"description": "用户ID(\u003e0)",
|
||||
"type": "integer"
|
||||
},
|
||||
"user_name": {
|
||||
"description": "用户名",
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"user_model.LoginResponse": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"authorization": {
|
||||
"description": "签名",
|
||||
"type": "string"
|
||||
},
|
||||
"expire_time": {
|
||||
"description": "过期时间",
|
||||
"type": "integer"
|
||||
}
|
||||
}
|
||||
},
|
||||
"user_model.UpdateNickNameByIDRequest": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
|
||||
@@ -1,4 +1,13 @@
|
||||
definitions:
|
||||
demo.authResponse:
|
||||
properties:
|
||||
authorization:
|
||||
description: 签名
|
||||
type: string
|
||||
expire_time:
|
||||
description: 过期时间
|
||||
type: integer
|
||||
type: object
|
||||
user_model.CreateRequest:
|
||||
properties:
|
||||
mobile:
|
||||
@@ -32,24 +41,6 @@ definitions:
|
||||
description: 用户名
|
||||
type: string
|
||||
type: object
|
||||
user_model.LoginRequest:
|
||||
properties:
|
||||
user_id:
|
||||
description: 用户ID(>0)
|
||||
type: integer
|
||||
user_name:
|
||||
description: 用户名
|
||||
type: string
|
||||
type: object
|
||||
user_model.LoginResponse:
|
||||
properties:
|
||||
authorization:
|
||||
description: 签名
|
||||
type: string
|
||||
expire_time:
|
||||
description: 过期时间
|
||||
type: integer
|
||||
type: object
|
||||
user_model.UpdateNickNameByIDRequest:
|
||||
properties:
|
||||
id:
|
||||
@@ -68,19 +59,32 @@ definitions:
|
||||
host: 127.0.0.1:9999
|
||||
info:
|
||||
contact: {}
|
||||
license:
|
||||
name: MIT
|
||||
url: https://github.com/xinliangnote/go-gin-api/blob/master/LICENSE
|
||||
title: go-gin-api docs api
|
||||
paths:
|
||||
/demo/user/{name}:
|
||||
/auth/get:
|
||||
post:
|
||||
consumes:
|
||||
- application/json
|
||||
description: 获取授权信息
|
||||
produces:
|
||||
- application/json
|
||||
responses:
|
||||
"200":
|
||||
description: 返回信息
|
||||
schema:
|
||||
$ref: '#/definitions/demo.authResponse'
|
||||
summary: 获取授权信息
|
||||
tags:
|
||||
- Demo
|
||||
/demo/trace:
|
||||
get:
|
||||
consumes:
|
||||
- application/json
|
||||
description: 获取用户信息
|
||||
description: Trace 示例
|
||||
parameters:
|
||||
- description: 用户名(Tom)
|
||||
in: path
|
||||
name: name
|
||||
required: true
|
||||
type: string
|
||||
- description: 签名
|
||||
in: header
|
||||
name: Authorization
|
||||
@@ -102,7 +106,7 @@ paths:
|
||||
type: string
|
||||
type: object
|
||||
type: array
|
||||
summary: 获取用户信息
|
||||
summary: Trace 示例
|
||||
tags:
|
||||
- Demo
|
||||
/user/create:
|
||||
@@ -117,6 +121,11 @@ paths:
|
||||
required: true
|
||||
schema:
|
||||
$ref: '#/definitions/user_model.CreateRequest'
|
||||
- description: 签名
|
||||
in: header
|
||||
name: Authorization
|
||||
required: true
|
||||
type: string
|
||||
produces:
|
||||
- application/json
|
||||
responses:
|
||||
@@ -126,7 +135,31 @@ paths:
|
||||
$ref: '#/definitions/user_model.CreateResponse'
|
||||
summary: 创建用户
|
||||
tags:
|
||||
- Demo
|
||||
- User
|
||||
/user/delete/{id}:
|
||||
patch:
|
||||
consumes:
|
||||
- application/json
|
||||
description: 删除用户 - 更新 is_deleted = 1
|
||||
parameters:
|
||||
- description: 用户ID
|
||||
in: path
|
||||
name: id
|
||||
required: true
|
||||
type: integer
|
||||
- description: 签名
|
||||
in: header
|
||||
name: Authorization
|
||||
required: true
|
||||
type: string
|
||||
produces:
|
||||
- application/json
|
||||
responses:
|
||||
"200":
|
||||
description: 返回信息
|
||||
summary: 删除用户 - 更新 is_deleted = 1
|
||||
tags:
|
||||
- User
|
||||
/user/info/{username}:
|
||||
get:
|
||||
consumes:
|
||||
@@ -138,6 +171,11 @@ paths:
|
||||
name: username
|
||||
required: true
|
||||
type: string
|
||||
- description: 签名
|
||||
in: header
|
||||
name: Authorization
|
||||
required: true
|
||||
type: string
|
||||
produces:
|
||||
- application/json
|
||||
responses:
|
||||
@@ -147,34 +185,12 @@ paths:
|
||||
$ref: '#/definitions/user_model.DetailResponse'
|
||||
summary: 用户详情
|
||||
tags:
|
||||
- Demo
|
||||
/user/login:
|
||||
post:
|
||||
consumes:
|
||||
- application/json
|
||||
description: 用户登录
|
||||
parameters:
|
||||
- description: 请求信息
|
||||
in: body
|
||||
name: RequestInfo
|
||||
required: true
|
||||
schema:
|
||||
$ref: '#/definitions/user_model.LoginRequest'
|
||||
produces:
|
||||
- application/json
|
||||
responses:
|
||||
"200":
|
||||
description: 返回信息
|
||||
schema:
|
||||
$ref: '#/definitions/user_model.LoginResponse'
|
||||
summary: 用户登录
|
||||
tags:
|
||||
- Demo
|
||||
- User
|
||||
/user/update:
|
||||
post:
|
||||
put:
|
||||
consumes:
|
||||
- application/json
|
||||
description: 更新用户名称
|
||||
description: 编辑用户 - 通过用户主键ID更新用户昵称
|
||||
parameters:
|
||||
- description: 请求信息
|
||||
in: body
|
||||
@@ -182,6 +198,11 @@ paths:
|
||||
required: true
|
||||
schema:
|
||||
$ref: '#/definitions/user_model.UpdateNickNameByIDRequest'
|
||||
- description: 签名
|
||||
in: header
|
||||
name: Authorization
|
||||
required: true
|
||||
type: string
|
||||
produces:
|
||||
- application/json
|
||||
responses:
|
||||
@@ -189,7 +210,7 @@ paths:
|
||||
description: 返回信息
|
||||
schema:
|
||||
$ref: '#/definitions/user_model.UpdateNickNameByIDResponse'
|
||||
summary: 更新用户名称
|
||||
summary: 编辑用户 - 通过用户主键ID更新用户昵称
|
||||
tags:
|
||||
- Demo
|
||||
- User
|
||||
swagger: "2.0"
|
||||
|
||||
1
go.mod
1
go.mod
@@ -4,7 +4,6 @@ go 1.15
|
||||
|
||||
require (
|
||||
github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751
|
||||
github.com/davecgh/go-spew v1.1.1
|
||||
github.com/dgrijalva/jwt-go v3.2.0+incompatible
|
||||
github.com/gin-contrib/pprof v1.2.1
|
||||
github.com/gin-gonic/gin v1.6.3
|
||||
|
||||
@@ -18,10 +18,11 @@ var (
|
||||
|
||||
// 模块级错误码 - 用户模块
|
||||
ErrUser = errno.NewError(http.StatusBadRequest, 20101, "非法用户")
|
||||
ErrUserCreate = errno.NewError(http.StatusBadRequest, 20102, "创建用户失败")
|
||||
ErrUserUpdate = errno.NewError(http.StatusBadRequest, 20103, "更新用户失败")
|
||||
ErrUserSearch = errno.NewError(http.StatusBadRequest, 20104, "查询用户失败")
|
||||
ErrUserHTTP = errno.NewError(http.StatusBadRequest, 20105, "调用他方接口失败")
|
||||
ErrUserName = errno.NewError(http.StatusBadRequest, 20102, "账号不能为空")
|
||||
ErrUserCreate = errno.NewError(http.StatusBadRequest, 20103, "创建用户失败")
|
||||
ErrUserUpdate = errno.NewError(http.StatusBadRequest, 20104, "更新用户失败")
|
||||
ErrUserSearch = errno.NewError(http.StatusBadRequest, 20105, "查询用户失败")
|
||||
ErrUserHTTP = errno.NewError(http.StatusBadRequest, 20106, "调用他方接口失败")
|
||||
|
||||
// ...
|
||||
)
|
||||
|
||||
@@ -3,21 +3,32 @@ package demo
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/xinliangnote/go-gin-api/configs"
|
||||
"github.com/xinliangnote/go-gin-api/internal/api/code"
|
||||
"github.com/xinliangnote/go-gin-api/internal/api/repository/third_party_request/go_gin_api_repo"
|
||||
"github.com/xinliangnote/go-gin-api/internal/api/service/user_service"
|
||||
"github.com/xinliangnote/go-gin-api/internal/pkg/cache"
|
||||
"github.com/xinliangnote/go-gin-api/internal/pkg/core"
|
||||
"github.com/xinliangnote/go-gin-api/internal/pkg/db"
|
||||
"github.com/xinliangnote/go-gin-api/pkg/httpclient"
|
||||
"github.com/xinliangnote/go-gin-api/pkg/p"
|
||||
"github.com/xinliangnote/go-gin-api/pkg/token"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"go.uber.org/zap"
|
||||
)
|
||||
|
||||
type Demo struct {
|
||||
logger *zap.Logger
|
||||
logger *zap.Logger
|
||||
cache cache.Repo
|
||||
userService user_service.UserService
|
||||
}
|
||||
|
||||
func NewDemo(logger *zap.Logger) *Demo {
|
||||
func NewDemo(logger *zap.Logger, db db.Repo, cache cache.Repo) *Demo {
|
||||
return &Demo{
|
||||
logger: logger,
|
||||
logger: logger,
|
||||
cache: cache,
|
||||
userService: user_service.NewUserService(db, cache),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -35,16 +46,16 @@ func (d *Demo) Get() core.HandlerFunc {
|
||||
return func(c core.Context) {
|
||||
req := new(request)
|
||||
if err := c.ShouldBindURI(req); err != nil {
|
||||
c.AbortWithError(code.ErrParamBind)
|
||||
c.AbortWithError(code.ErrParamBind.WithErr(err))
|
||||
return
|
||||
}
|
||||
|
||||
if req.Name != "Tom" {
|
||||
c.AbortWithError(code.ErrUser)
|
||||
c.AbortWithError(code.ErrUser.WithErr(errors.New("req.Name != Tom")))
|
||||
return
|
||||
}
|
||||
|
||||
c.SetPayload(code.OK.WithData(&response{
|
||||
c.Payload(code.OK.WithData(&response{
|
||||
Name: "Tom",
|
||||
Job: "Student",
|
||||
}))
|
||||
@@ -64,56 +75,70 @@ func (d *Demo) Post() core.HandlerFunc {
|
||||
return func(c core.Context) {
|
||||
req := new(request)
|
||||
if err := c.ShouldBindPostForm(req); err != nil {
|
||||
c.AbortWithError(code.ErrParamBind)
|
||||
c.AbortWithError(code.ErrParamBind.WithErr(err))
|
||||
return
|
||||
}
|
||||
|
||||
if req.Name != "Jack" {
|
||||
c.AbortWithError(code.ErrUser)
|
||||
c.AbortWithError(code.ErrUser.WithErr(errors.New("req.Name != Jack")))
|
||||
return
|
||||
}
|
||||
|
||||
c.SetPayload(code.OK.WithData(&response{
|
||||
c.Payload(code.OK.WithData(&response{
|
||||
Name: "Jack",
|
||||
Job: "Teacher",
|
||||
}))
|
||||
}
|
||||
}
|
||||
|
||||
type request struct {
|
||||
Name string `uri:"name"`
|
||||
type authResponse struct {
|
||||
Authorization string `json:"authorization"` // 签名
|
||||
ExpireTime int64 `json:"expire_time"` // 过期时间
|
||||
}
|
||||
|
||||
type response []struct {
|
||||
type traceResponse []struct {
|
||||
Name string `json:"name"` //用户名
|
||||
Job string `json:"job"` //工作
|
||||
}
|
||||
|
||||
// Get 获取用户信息
|
||||
// @Summary 获取用户信息
|
||||
// @Description 获取用户信息
|
||||
// 获取授权信息
|
||||
// @Summary 获取授权信息
|
||||
// @Description 获取授权信息
|
||||
// @Tags Demo
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param name path string true "用户名(Tom)"
|
||||
// @Param Authorization header string true "签名"
|
||||
// @Success 200 {object} response "用户信息"
|
||||
// @Router /demo/user/{name} [get]
|
||||
func (d *Demo) User() core.HandlerFunc {
|
||||
// @Success 200 {object} authResponse "返回信息"
|
||||
// @Router /auth/get [post]
|
||||
func (d *Demo) Auth() core.HandlerFunc {
|
||||
return func(c core.Context) {
|
||||
req := new(request)
|
||||
if err := c.ShouldBindURI(req); err != nil {
|
||||
c.AbortWithError(code.ErrParamBind)
|
||||
cfg := configs.Get().JWT
|
||||
tokenString, err := token.New(cfg.Secret).Sign(1, "xinliangnote", time.Hour*cfg.ExpireDuration)
|
||||
if err != nil {
|
||||
c.AbortWithError(code.ErrAuthorization.WithErr(err))
|
||||
return
|
||||
}
|
||||
|
||||
if req.Name != "Tom" {
|
||||
c.AbortWithError(code.ErrUser)
|
||||
return
|
||||
}
|
||||
res := new(authResponse)
|
||||
res.Authorization = tokenString
|
||||
res.ExpireTime = time.Now().Add(time.Hour * cfg.ExpireDuration).Unix()
|
||||
|
||||
c.Payload(code.OK.WithData(res))
|
||||
}
|
||||
}
|
||||
|
||||
res1, err := go_gin_api_repo.DemoGet(req.Name,
|
||||
// Trace 示例
|
||||
// @Summary Trace 示例
|
||||
// @Description Trace 示例
|
||||
// @Tags Demo
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param Authorization header string true "签名"
|
||||
// @Success 200 {object} traceResponse "用户信息"
|
||||
// @Router /demo/trace [get]
|
||||
func (d *Demo) Trace() core.HandlerFunc {
|
||||
return func(c core.Context) {
|
||||
// 三方请求信息
|
||||
res1, err := go_gin_api_repo.DemoGet("Tom",
|
||||
httpclient.WithTTL(time.Second*5),
|
||||
httpclient.WithTrace(c.Trace()),
|
||||
httpclient.WithLogger(c.Logger()),
|
||||
@@ -123,10 +148,14 @@ func (d *Demo) User() core.HandlerFunc {
|
||||
|
||||
if err != nil {
|
||||
d.logger.Error("get [demo/get] err", zap.Error(err))
|
||||
c.AbortWithError(code.ErrUserHTTP)
|
||||
c.AbortWithError(code.ErrUserHTTP.WithErr(err))
|
||||
return
|
||||
}
|
||||
|
||||
// 调试信息
|
||||
p.Println("res1.Data.Name", res1.Data.Name, p.WithTrace(c.Trace()))
|
||||
|
||||
// 三方请求信息
|
||||
res2, err := go_gin_api_repo.DemoPost("Jack",
|
||||
httpclient.WithTTL(time.Second*5),
|
||||
httpclient.WithTrace(c.Trace()),
|
||||
@@ -137,11 +166,22 @@ func (d *Demo) User() core.HandlerFunc {
|
||||
|
||||
if err != nil {
|
||||
d.logger.Error("post [demo/post] err", zap.Error(err))
|
||||
c.AbortWithError(code.ErrUserHTTP)
|
||||
c.AbortWithError(code.ErrUserHTTP.WithErr(err))
|
||||
return
|
||||
}
|
||||
|
||||
data := &response{
|
||||
// 调试信息
|
||||
p.Println("res2.Data.Name", res2.Data.Name, p.WithTrace(c.Trace()))
|
||||
|
||||
// 执行 SQL 信息
|
||||
d.userService.GetUserByUserName(c, "test_user")
|
||||
|
||||
// 执行 Redis 信息
|
||||
_ = d.cache.Set("name", "tom", time.Minute*10, cache.WithTrace(c.Trace()))
|
||||
val, _ := d.cache.Get("name", cache.WithTrace(c.Trace()))
|
||||
p.Println("redis-name", val, p.WithTrace(c.Trace()))
|
||||
|
||||
data := &traceResponse{
|
||||
{
|
||||
Name: res1.Data.Name,
|
||||
Job: res1.Data.Job,
|
||||
@@ -151,6 +191,6 @@ func (d *Demo) User() core.HandlerFunc {
|
||||
Job: res2.Data.Job,
|
||||
},
|
||||
}
|
||||
c.SetPayload(code.OK.WithData(data))
|
||||
c.Payload(code.OK.WithData(data))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
package user_handler
|
||||
|
||||
import (
|
||||
"github.com/xinliangnote/go-gin-api/configs"
|
||||
"errors"
|
||||
|
||||
"github.com/xinliangnote/go-gin-api/internal/api/code"
|
||||
"github.com/xinliangnote/go-gin-api/internal/api/model/user_model"
|
||||
"github.com/xinliangnote/go-gin-api/internal/api/repository/cache_repo"
|
||||
"github.com/xinliangnote/go-gin-api/internal/api/repository/db_repo"
|
||||
"github.com/xinliangnote/go-gin-api/internal/api/service/user_service"
|
||||
"github.com/xinliangnote/go-gin-api/internal/pkg/cache"
|
||||
"github.com/xinliangnote/go-gin-api/internal/pkg/core"
|
||||
"github.com/xinliangnote/go-gin-api/pkg/token"
|
||||
"github.com/xinliangnote/go-gin-api/internal/pkg/db"
|
||||
|
||||
"go.uber.org/zap"
|
||||
)
|
||||
@@ -18,24 +18,30 @@ var _ UserDemo = (*userDemo)(nil)
|
||||
type UserDemo interface {
|
||||
// i 为了避免被其他包实现
|
||||
i()
|
||||
// 创建用户
|
||||
|
||||
// Create 创建用户
|
||||
Create() core.HandlerFunc
|
||||
// 通过用户主键ID更新用户昵称
|
||||
|
||||
// UpdateNickNameByID 编辑用户 - 通过主键ID更新用户昵称
|
||||
UpdateNickNameByID() core.HandlerFunc
|
||||
// 用户登录
|
||||
Login() core.HandlerFunc
|
||||
// 用户详情
|
||||
|
||||
// Delete 删除用户 - 通过主键ID更新 is_deleted = 1
|
||||
Delete() core.HandlerFunc
|
||||
|
||||
// Detail 用户详情
|
||||
Detail() core.HandlerFunc
|
||||
}
|
||||
|
||||
type userDemo struct {
|
||||
logger *zap.Logger
|
||||
cache cache.Repo
|
||||
userService user_service.UserService
|
||||
}
|
||||
|
||||
func NewUserDemo(logger *zap.Logger, db db_repo.Repo, cache cache_repo.Repo) UserDemo {
|
||||
func NewUserDemo(logger *zap.Logger, db db.Repo, cache cache.Repo) UserDemo {
|
||||
return &userDemo{
|
||||
logger: logger,
|
||||
cache: cache,
|
||||
userService: user_service.NewUserService(db, cache),
|
||||
}
|
||||
}
|
||||
@@ -45,10 +51,11 @@ func (u *userDemo) i() {}
|
||||
// 创建用户
|
||||
// @Summary 创建用户
|
||||
// @Description 创建用户
|
||||
// @Tags Demo
|
||||
// @Tags User
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param RequestInfo body user_model.CreateRequest true "请求信息"
|
||||
// @Param Authorization header string true "签名"
|
||||
// @Success 200 {object} user_model.CreateResponse "返回信息"
|
||||
// @Router /user/create [post]
|
||||
func (u *userDemo) Create() core.HandlerFunc {
|
||||
@@ -56,102 +63,92 @@ func (u *userDemo) Create() core.HandlerFunc {
|
||||
req := new(user_model.CreateRequest)
|
||||
res := new(user_model.CreateResponse)
|
||||
if err := c.ShouldBindJSON(req); err != nil {
|
||||
u.logger.Error("[user] should bind json err", zap.Error(err))
|
||||
c.AbortWithError(code.ErrParamBind)
|
||||
c.AbortWithError(code.ErrParamBind.WithErr(err))
|
||||
return
|
||||
}
|
||||
|
||||
if req.UserName == "" {
|
||||
c.AbortWithError(code.ErrUserName.WithErr(errors.New("req.UserName = ''")))
|
||||
return
|
||||
}
|
||||
|
||||
id, err := u.userService.Create(c, req)
|
||||
if err != nil {
|
||||
u.logger.Error("[user] Create err", zap.Error(err))
|
||||
c.AbortWithError(code.ErrUserCreate)
|
||||
c.AbortWithError(code.ErrUserCreate.WithErr(err))
|
||||
return
|
||||
}
|
||||
|
||||
res.Id = id
|
||||
c.SetPayload(code.OK.WithData(res))
|
||||
c.Payload(code.OK.WithData(res))
|
||||
}
|
||||
}
|
||||
|
||||
// 更新用户名称
|
||||
// @Summary 更新用户名称
|
||||
// @Description 更新用户名称
|
||||
// @Tags Demo
|
||||
// 编辑用户 - 通过用户主键ID更新用户昵称
|
||||
// @Summary 编辑用户 - 通过用户主键ID更新用户昵称
|
||||
// @Description 编辑用户 - 通过用户主键ID更新用户昵称
|
||||
// @Tags User
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param RequestInfo body user_model.UpdateNickNameByIDRequest true "请求信息"
|
||||
// @Param Authorization header string true "签名"
|
||||
// @Success 200 {object} user_model.UpdateNickNameByIDResponse "返回信息"
|
||||
// @Router /user/update [post]
|
||||
// @Router /user/update [put]
|
||||
func (u *userDemo) UpdateNickNameByID() core.HandlerFunc {
|
||||
return func(c core.Context) {
|
||||
req := new(user_model.UpdateNickNameByIDRequest)
|
||||
res := new(user_model.UpdateNickNameByIDResponse)
|
||||
if err := c.ShouldBindJSON(req); err != nil {
|
||||
u.logger.Error("[user] should bind json err", zap.Error(err))
|
||||
c.AbortWithError(code.ErrParamBind)
|
||||
c.AbortWithError(code.ErrParamBind.WithErr(err))
|
||||
return
|
||||
}
|
||||
|
||||
err := u.userService.UpdateNickNameByID(c, req.Id, req.NickName)
|
||||
if err != nil {
|
||||
u.logger.Error("[user] UpdateNickNameByID err", zap.Error(err))
|
||||
c.AbortWithError(code.ErrUserUpdate)
|
||||
c.AbortWithError(code.ErrUserUpdate.WithErr(err))
|
||||
return
|
||||
}
|
||||
|
||||
res.Id = req.Id
|
||||
c.SetPayload(code.OK.WithData(res))
|
||||
c.Payload(code.OK.WithData(res))
|
||||
}
|
||||
}
|
||||
|
||||
// 用户登录
|
||||
// @Summary 用户登录
|
||||
// @Description 用户登录
|
||||
// @Tags Demo
|
||||
// 删除用户 - 更新 is_deleted = 1
|
||||
// @Summary 删除用户 - 更新 is_deleted = 1
|
||||
// @Description 删除用户 - 更新 is_deleted = 1
|
||||
// @Tags User
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param RequestInfo body user_model.LoginRequest true "请求信息"
|
||||
// @Success 200 {object} user_model.LoginResponse "返回信息"
|
||||
// @Router /user/login [post]
|
||||
func (u *userDemo) Login() core.HandlerFunc {
|
||||
// @Param id path int true "用户ID"
|
||||
// @Param Authorization header string true "签名"
|
||||
// @Success 200 "返回信息"
|
||||
// @Router /user/delete/{id} [patch]
|
||||
func (u *userDemo) Delete() core.HandlerFunc {
|
||||
return func(c core.Context) {
|
||||
req := new(user_model.LoginRequest)
|
||||
res := new(user_model.LoginResponse)
|
||||
if err := c.ShouldBindJSON(req); err != nil {
|
||||
u.logger.Error("should bind json err", zap.Error(err))
|
||||
c.AbortWithError(code.ErrParamBind)
|
||||
req := new(user_model.DeleteRequest)
|
||||
if err := c.ShouldBindURI(req); err != nil {
|
||||
c.AbortWithError(code.ErrParamBind.WithErr(err))
|
||||
return
|
||||
}
|
||||
|
||||
cfg := configs.Get().JWT
|
||||
tokenString, err := token.New(cfg.Secret).Sign(req.UserID, req.UserName)
|
||||
err := u.userService.Delete(c, req.Id)
|
||||
if err != nil {
|
||||
u.logger.Error("token sign err", zap.Error(err))
|
||||
c.AbortWithError(code.ErrAuthorization)
|
||||
c.AbortWithError(code.ErrUserUpdate.WithErr(err))
|
||||
return
|
||||
}
|
||||
|
||||
claims, err := token.New(cfg.Secret).Parse(tokenString)
|
||||
if err != nil {
|
||||
u.logger.Error("token parse err", zap.Error(err))
|
||||
c.AbortWithError(code.ErrAuthorization)
|
||||
return
|
||||
}
|
||||
|
||||
res.Authorization = tokenString
|
||||
res.ExpireTime = claims.ExpiresAt
|
||||
|
||||
c.SetPayload(code.OK.WithData(res))
|
||||
c.Payload(code.OK.WithData(nil))
|
||||
}
|
||||
}
|
||||
|
||||
// 用户详情
|
||||
// @Summary 用户详情
|
||||
// @Description 用户详情
|
||||
// @Tags Demo
|
||||
// @Tags User
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param username path string true "用户名"
|
||||
// @Param Authorization header string true "签名"
|
||||
// @Success 200 {object} user_model.DetailResponse "返回信息"
|
||||
// @Router /user/info/{username} [get]
|
||||
func (u *userDemo) Detail() core.HandlerFunc {
|
||||
@@ -159,15 +156,13 @@ func (u *userDemo) Detail() core.HandlerFunc {
|
||||
req := new(user_model.DetailRequest)
|
||||
res := new(user_model.DetailResponse)
|
||||
if err := c.ShouldBindURI(req); err != nil {
|
||||
u.logger.Error("should bind uri err", zap.Error(err))
|
||||
c.AbortWithError(code.ErrParamBind)
|
||||
c.AbortWithError(code.ErrParamBind.WithErr(err))
|
||||
return
|
||||
}
|
||||
|
||||
user, err := u.userService.GetUserByUserName(c, req.UserName)
|
||||
if err != nil {
|
||||
u.logger.Error("[user] GetUserByUserName err", zap.Error(err))
|
||||
c.AbortWithError(code.ErrUserSearch)
|
||||
c.AbortWithError(code.ErrUserSearch.WithErr(err))
|
||||
return
|
||||
}
|
||||
|
||||
@@ -175,6 +170,6 @@ func (u *userDemo) Detail() core.HandlerFunc {
|
||||
res.UserName = user.UserName
|
||||
res.NickName = user.NickName
|
||||
res.Mobile = user.Mobile
|
||||
c.SetPayload(code.OK.WithData(res))
|
||||
c.Payload(code.OK.WithData(res))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -28,7 +28,7 @@ type CreateRequest struct {
|
||||
|
||||
// user_handler Create Response
|
||||
type CreateResponse struct {
|
||||
Id uint `json:"id"` //主键ID
|
||||
Id uint `json:"id"` // 主键ID
|
||||
}
|
||||
|
||||
// user_handler UpdateNickNameByID Request
|
||||
@@ -42,16 +42,9 @@ type UpdateNickNameByIDResponse struct {
|
||||
Id uint `json:"id"` // 用户主键ID
|
||||
}
|
||||
|
||||
// user_handler Login Request
|
||||
type LoginRequest struct {
|
||||
UserID int `json:"user_id" form:"user_id"` // 用户ID(>0)
|
||||
UserName string `json:"user_name" form:"user_name"` // 用户名
|
||||
}
|
||||
|
||||
// user_handler Login Response
|
||||
type LoginResponse struct {
|
||||
Authorization string `json:"authorization"` // 签名
|
||||
ExpireTime int64 `json:"expire_time"` // 过期时间
|
||||
// user_handler Delete Request
|
||||
type DeleteRequest struct {
|
||||
Id uint `uri:"id"` // 用户ID
|
||||
}
|
||||
|
||||
// user_handler Detail Request
|
||||
|
||||
@@ -2,8 +2,8 @@ package user_demo_repo
|
||||
|
||||
import (
|
||||
"github.com/xinliangnote/go-gin-api/internal/api/model/user_model"
|
||||
"github.com/xinliangnote/go-gin-api/internal/api/repository/db_repo"
|
||||
"github.com/xinliangnote/go-gin-api/internal/pkg/core"
|
||||
"github.com/xinliangnote/go-gin-api/internal/pkg/db"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
@@ -16,14 +16,15 @@ type UserRepo interface {
|
||||
Create(ctx core.Context, user user_model.UserDemo) (id uint, err error)
|
||||
UpdateNickNameByID(ctx core.Context, id uint, username string) (err error)
|
||||
GetUserByUserName(ctx core.Context, username string) (*user_model.UserDemo, error)
|
||||
Delete(ctx core.Context, id uint) (err error)
|
||||
getUserByID(ctx core.Context, id uint) (*user_model.UserDemo, error)
|
||||
}
|
||||
|
||||
type userRepo struct {
|
||||
db db_repo.Repo
|
||||
db db.Repo
|
||||
}
|
||||
|
||||
func NewUserRepo(db db_repo.Repo) UserRepo {
|
||||
func NewUserRepo(db db.Repo) UserRepo {
|
||||
return &userRepo{
|
||||
db: db,
|
||||
}
|
||||
@@ -32,7 +33,7 @@ func NewUserRepo(db db_repo.Repo) UserRepo {
|
||||
func (u *userRepo) i() {}
|
||||
|
||||
func (u *userRepo) Create(ctx core.Context, user user_model.UserDemo) (id uint, err error) {
|
||||
err = u.db.GetDbW().WithContext(ctx).Create(&user).Error
|
||||
err = u.db.GetDbW().WithContext(ctx.RequestContext()).Create(&user).Error
|
||||
if err != nil {
|
||||
return 0, errors.Wrap(err, "[user_repo] create user err")
|
||||
}
|
||||
@@ -41,7 +42,7 @@ func (u *userRepo) Create(ctx core.Context, user user_model.UserDemo) (id uint,
|
||||
|
||||
func (u *userRepo) getUserByID(ctx core.Context, id uint) (*user_model.UserDemo, error) {
|
||||
data := new(user_model.UserDemo)
|
||||
err := u.db.GetDbR().WithContext(ctx).First(data, id).Error
|
||||
err := u.db.GetDbR().WithContext(ctx.RequestContext()).First(data, id).Where("is_deleted = ?", -1).Error
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "[user_demo] get user data err")
|
||||
}
|
||||
@@ -53,15 +54,23 @@ func (u *userRepo) UpdateNickNameByID(ctx core.Context, id uint, nickname string
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "[user_demo] update user data err")
|
||||
}
|
||||
return u.db.GetDbW().WithContext(ctx).Model(user).Update("nick_name", nickname).Error
|
||||
return u.db.GetDbW().WithContext(ctx.RequestContext()).Model(user).Update("nick_name", nickname).Error
|
||||
}
|
||||
|
||||
func (u *userRepo) Delete(ctx core.Context, id uint) (err error) {
|
||||
user, err := u.getUserByID(ctx, id)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "[user_demo] update user data err")
|
||||
}
|
||||
return u.db.GetDbW().WithContext(ctx.RequestContext()).Model(user).Update("is_deleted", 1).Error
|
||||
}
|
||||
|
||||
func (u *userRepo) GetUserByUserName(ctx core.Context, username string) (*user_model.UserDemo, error) {
|
||||
data := new(user_model.UserDemo)
|
||||
err := u.db.GetDbR().
|
||||
WithContext(ctx).
|
||||
WithContext(ctx.RequestContext()).
|
||||
Select([]string{"id", "user_name", "nick_name", "mobile"}).
|
||||
Where("user_name = ?", username).
|
||||
Where("user_name = ? and is_deleted = ?", username, -1).
|
||||
First(data).Error
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "[user_demo] get user data err")
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
package middleware
|
||||
package auth
|
||||
|
||||
import (
|
||||
"github.com/xinliangnote/go-gin-api/configs"
|
||||
@@ -6,25 +6,27 @@ import (
|
||||
"github.com/xinliangnote/go-gin-api/internal/pkg/core"
|
||||
"github.com/xinliangnote/go-gin-api/pkg/errno"
|
||||
"github.com/xinliangnote/go-gin-api/pkg/token"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
func AuthHandler(ctx core.Context) (userId int, userName string, err errno.Error) {
|
||||
func AuthHandler(ctx core.Context) (userId int64, userName string, err errno.Error) {
|
||||
auth := ctx.GetHeader("Authorization")
|
||||
if auth == "" {
|
||||
err = code.ErrAuthorization
|
||||
err = code.ErrAuthorization.WithErr(errors.New("Header 中缺少 Authorization 参数"))
|
||||
return
|
||||
}
|
||||
|
||||
cfg := configs.Get().JWT
|
||||
claims, errParse := token.New(cfg.Secret).Parse(auth)
|
||||
if errParse != nil {
|
||||
err = code.ErrAuthorization
|
||||
err = code.ErrAuthorization.WithErr(errParse)
|
||||
return
|
||||
}
|
||||
|
||||
userId = claims.UserID
|
||||
if userId <= 0 {
|
||||
err = code.ErrAuthorization
|
||||
err = code.ErrAuthorization.WithErr(errors.New("claims.UserID <= 0 "))
|
||||
return
|
||||
}
|
||||
userName = claims.UserName
|
||||
@@ -3,10 +3,10 @@ package router
|
||||
import (
|
||||
"github.com/xinliangnote/go-gin-api/internal/api/controller/demo"
|
||||
"github.com/xinliangnote/go-gin-api/internal/api/controller/user_handler"
|
||||
"github.com/xinliangnote/go-gin-api/internal/api/repository/cache_repo"
|
||||
"github.com/xinliangnote/go-gin-api/internal/api/repository/db_repo"
|
||||
auth "github.com/xinliangnote/go-gin-api/internal/api/router/middleware"
|
||||
"github.com/xinliangnote/go-gin-api/internal/api/router/middleware/auth"
|
||||
"github.com/xinliangnote/go-gin-api/internal/pkg/cache"
|
||||
"github.com/xinliangnote/go-gin-api/internal/pkg/core"
|
||||
"github.com/xinliangnote/go-gin-api/internal/pkg/db"
|
||||
"github.com/xinliangnote/go-gin-api/internal/pkg/metrics"
|
||||
"github.com/xinliangnote/go-gin-api/internal/pkg/notify"
|
||||
|
||||
@@ -14,7 +14,7 @@ import (
|
||||
"go.uber.org/zap"
|
||||
)
|
||||
|
||||
func NewHTTPMux(logger *zap.Logger, db db_repo.Repo, cache cache_repo.Repo) (core.Mux, error) {
|
||||
func NewHTTPMux(logger *zap.Logger, db db.Repo, cache cache.Repo) (core.Mux, error) {
|
||||
|
||||
if logger == nil {
|
||||
return nil, errors.New("logger required")
|
||||
@@ -31,20 +31,29 @@ func NewHTTPMux(logger *zap.Logger, db db_repo.Repo, cache cache_repo.Repo) (cor
|
||||
panic(err)
|
||||
}
|
||||
|
||||
demoHandler := demo.NewDemo(logger)
|
||||
demoHandler := demo.NewDemo(logger, db, cache)
|
||||
userHandler := user_handler.NewUserDemo(logger, db, cache)
|
||||
|
||||
u := mux.Group("/user")
|
||||
// user_demo CURD
|
||||
user := mux.Group("/user", core.WrapAuthHandler(auth.AuthHandler))
|
||||
{
|
||||
u.POST("/login", userHandler.Login())
|
||||
u.POST("/create", userHandler.Create())
|
||||
u.GET("/info/:username", core.AliasForRecordMetrics("/user/info"), userHandler.Detail())
|
||||
u.POST("/update", userHandler.UpdateNickNameByID())
|
||||
user.POST("/create", userHandler.Create())
|
||||
user.PUT("/update", userHandler.UpdateNickNameByID())
|
||||
user.PATCH("/delete/:id", userHandler.Delete())
|
||||
user.GET("/info/:username", core.AliasForRecordMetrics("/user/info"), userHandler.Detail())
|
||||
}
|
||||
|
||||
// auth
|
||||
a := mux.Group("/auth")
|
||||
{
|
||||
a.POST("/get", demoHandler.Auth())
|
||||
}
|
||||
|
||||
// demo
|
||||
d := mux.Group("/demo", core.WrapAuthHandler(auth.AuthHandler)) //使用 auth 验证
|
||||
{
|
||||
d.GET("user/:name", core.AliasForRecordMetrics("/demo/user"), demoHandler.User())
|
||||
// 为了演示 Trace ,增加了一些看起来无意义的调试信息和 SQL 信息。
|
||||
d.GET("/trace", demoHandler.Trace())
|
||||
|
||||
// 模拟数据
|
||||
d.GET("get/:name", core.AliasForRecordMetrics("/demo/get"), demoHandler.Get())
|
||||
|
||||
@@ -2,10 +2,10 @@ package user_service
|
||||
|
||||
import (
|
||||
"github.com/xinliangnote/go-gin-api/internal/api/model/user_model"
|
||||
"github.com/xinliangnote/go-gin-api/internal/api/repository/cache_repo"
|
||||
"github.com/xinliangnote/go-gin-api/internal/api/repository/db_repo"
|
||||
"github.com/xinliangnote/go-gin-api/internal/api/repository/db_repo/user_demo_repo"
|
||||
"github.com/xinliangnote/go-gin-api/internal/pkg/cache"
|
||||
"github.com/xinliangnote/go-gin-api/internal/pkg/core"
|
||||
"github.com/xinliangnote/go-gin-api/internal/pkg/db"
|
||||
)
|
||||
|
||||
var _ UserService = (*userSer)(nil)
|
||||
@@ -17,15 +17,16 @@ type UserService interface {
|
||||
Create(ctx core.Context, user *user_model.CreateRequest) (id uint, err error)
|
||||
UpdateNickNameByID(ctx core.Context, id uint, username string) (err error)
|
||||
GetUserByUserName(ctx core.Context, username string) (user *user_model.UserDemo, err error)
|
||||
Delete(ctx core.Context, id uint) (err error)
|
||||
}
|
||||
|
||||
type userSer struct {
|
||||
db db_repo.Repo
|
||||
cache cache_repo.Repo
|
||||
db db.Repo
|
||||
cache cache.Repo
|
||||
userRepo user_demo_repo.UserRepo
|
||||
}
|
||||
|
||||
func NewUserService(db db_repo.Repo, cache cache_repo.Repo) UserService {
|
||||
func NewUserService(db db.Repo, cache cache.Repo) UserService {
|
||||
userRepo := user_demo_repo.NewUserRepo(db)
|
||||
return &userSer{
|
||||
db: db,
|
||||
@@ -65,3 +66,11 @@ func (u *userSer) GetUserByUserName(ctx core.Context, username string) (user *us
|
||||
}
|
||||
return user, nil
|
||||
}
|
||||
|
||||
func (u *userSer) Delete(ctx core.Context, id uint) (err error) {
|
||||
err = u.userRepo.Delete(ctx, id)
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -1,25 +1,40 @@
|
||||
package cache_repo
|
||||
package cache
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/xinliangnote/go-gin-api/configs"
|
||||
"github.com/xinliangnote/go-gin-api/internal/pkg/trace"
|
||||
"github.com/xinliangnote/go-gin-api/pkg/time_parse"
|
||||
|
||||
"github.com/go-redis/redis/v7"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
type Option func(*option)
|
||||
|
||||
type Trace = trace.T
|
||||
|
||||
type option struct {
|
||||
Trace *trace.Trace
|
||||
Redis *trace.Redis
|
||||
}
|
||||
|
||||
func newOption() *option {
|
||||
return &option{}
|
||||
}
|
||||
|
||||
var _ Repo = (*cacheRepo)(nil)
|
||||
|
||||
type Repo interface {
|
||||
i()
|
||||
Set(key, value string, ttl time.Duration) error
|
||||
Get(key string) (string, error)
|
||||
Set(key, value string, ttl time.Duration, options ...Option) error
|
||||
Get(key string, options ...Option) (string, error)
|
||||
TTL(key string) (time.Duration, error)
|
||||
Expire(key string, ttl time.Duration) bool
|
||||
ExpireAt(key string, ttl time.Time) bool
|
||||
Del(keys ...string) bool
|
||||
Incr(key string) int64
|
||||
Incr(key string, options ...Option) int64
|
||||
Close()
|
||||
}
|
||||
|
||||
@@ -59,7 +74,23 @@ func redisConnect() (*redis.Client, error) {
|
||||
}
|
||||
|
||||
// Set set some <key,value> into redis
|
||||
func (c *cacheRepo) Set(key, value string, ttl time.Duration) error {
|
||||
func (c *cacheRepo) Set(key, value string, ttl time.Duration, options ...Option) error {
|
||||
opt := newOption()
|
||||
defer func() {
|
||||
if opt.Trace != nil {
|
||||
opt.Redis.Timestamp = time_parse.CSTLayoutString()
|
||||
opt.Redis.Handle = "set"
|
||||
opt.Redis.Key = key
|
||||
opt.Redis.Value = value
|
||||
opt.Redis.TTL = ttl
|
||||
opt.Trace.AppendRedis(opt.Redis)
|
||||
}
|
||||
}()
|
||||
|
||||
for _, f := range options {
|
||||
f(opt)
|
||||
}
|
||||
|
||||
if err := c.client.Set(key, value, ttl).Err(); err != nil {
|
||||
return errors.Wrapf(err, "redis set key: %s err", key)
|
||||
}
|
||||
@@ -68,7 +99,21 @@ func (c *cacheRepo) Set(key, value string, ttl time.Duration) error {
|
||||
}
|
||||
|
||||
// Get get some key from redis
|
||||
func (c *cacheRepo) Get(key string) (string, error) {
|
||||
func (c *cacheRepo) Get(key string, options ...Option) (string, error) {
|
||||
opt := newOption()
|
||||
defer func() {
|
||||
if opt.Trace != nil {
|
||||
opt.Redis.Timestamp = time_parse.CSTLayoutString()
|
||||
opt.Redis.Handle = "get"
|
||||
opt.Redis.Key = key
|
||||
opt.Trace.AppendRedis(opt.Redis)
|
||||
}
|
||||
}()
|
||||
|
||||
for _, f := range options {
|
||||
f(opt)
|
||||
}
|
||||
|
||||
value, err := c.client.Get(key).Result()
|
||||
if err != nil {
|
||||
return "", errors.Wrapf(err, "redis get key: %s err", key)
|
||||
@@ -109,7 +154,20 @@ func (c *cacheRepo) Del(keys ...string) bool {
|
||||
return value > 0
|
||||
}
|
||||
|
||||
func (c *cacheRepo) Incr(key string) int64 {
|
||||
func (c *cacheRepo) Incr(key string, options ...Option) int64 {
|
||||
opt := newOption()
|
||||
defer func() {
|
||||
if opt.Trace != nil {
|
||||
opt.Redis.Timestamp = time_parse.CSTLayoutString()
|
||||
opt.Redis.Handle = "incr"
|
||||
opt.Redis.Key = key
|
||||
opt.Trace.AppendRedis(opt.Redis)
|
||||
}
|
||||
}()
|
||||
|
||||
for _, f := range options {
|
||||
f(opt)
|
||||
}
|
||||
value, _ := c.client.Incr(key).Result()
|
||||
return value
|
||||
}
|
||||
@@ -118,3 +176,13 @@ func (c *cacheRepo) Incr(key string) int64 {
|
||||
func (c *cacheRepo) Close() {
|
||||
c.client.Close()
|
||||
}
|
||||
|
||||
// WithTrace 设置trace信息
|
||||
func WithTrace(t Trace) Option {
|
||||
return func(opt *option) {
|
||||
if t != nil {
|
||||
opt.Trace = t.(*trace.Trace)
|
||||
opt.Redis = new(trace.Redis)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2,12 +2,12 @@ package core
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
stdctx "context"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/xinliangnote/go-gin-api/internal/pkg/trace"
|
||||
"github.com/xinliangnote/go-gin-api/pkg/errno"
|
||||
@@ -55,72 +55,90 @@ var _ Context = (*context)(nil)
|
||||
type Context interface {
|
||||
init()
|
||||
|
||||
// ShouldBindQuery 反序列化querystring
|
||||
// tag: `form:"xxx"` (注:不要写成query)
|
||||
// ShouldBindQuery 反序列化 querystring
|
||||
// tag: `form:"xxx"` (注:不要写成 query)
|
||||
ShouldBindQuery(obj interface{}) error
|
||||
|
||||
// ShouldBindPostForm 反序列化postform(querystring会被忽略)
|
||||
// ShouldBindPostForm 反序列化 postform (querystring会被忽略)
|
||||
// tag: `form:"xxx"`
|
||||
ShouldBindPostForm(obj interface{}) error
|
||||
|
||||
// ShouldBindForm 同时反序列化querystring和postform;
|
||||
// 当querystring和postform存在相同字段时,postform优先使用。
|
||||
// ShouldBindForm 同时反序列化 querystring 和 postform;
|
||||
// 当 querystring 和 postform 存在相同字段时,postform 优先使用。
|
||||
// tag: `form:"xxx"`
|
||||
ShouldBindForm(obj interface{}) error
|
||||
|
||||
// ShouldBindJSON 反序列化postjson
|
||||
// ShouldBindJSON 反序列化 postjson
|
||||
// tag: `json:"xxx"`
|
||||
ShouldBindJSON(obj interface{}) error
|
||||
|
||||
// ShouldBindURI 反序列化path参数(如路由路径为 /user/:name)
|
||||
// ShouldBindURI 反序列化 path 参数(如路由路径为 /user/:name)
|
||||
// tag: `uri:"xxx"`
|
||||
ShouldBindURI(obj interface{}) error
|
||||
|
||||
// Redirect 重定向
|
||||
Redirect(code int, location string)
|
||||
|
||||
// Trace 获取 Trace 对象
|
||||
Trace() Trace
|
||||
setTrace(trace Trace)
|
||||
disableTrace()
|
||||
|
||||
// Logger 获取 Logger 对象
|
||||
Logger() *zap.Logger
|
||||
setLogger(logger *zap.Logger)
|
||||
|
||||
// Payload 正确返回
|
||||
Payload(payload errno.Error)
|
||||
getPayload() errno.Error
|
||||
SetPayload(payload errno.Error)
|
||||
|
||||
Header() http.Header
|
||||
GetHeader(key string) string
|
||||
SetHeader(key, value string)
|
||||
|
||||
UserID() int
|
||||
setUserID(userID int)
|
||||
|
||||
UserName() string
|
||||
setUserName(userName string)
|
||||
|
||||
// AbortWithError 错误返回
|
||||
AbortWithError(err errno.Error)
|
||||
abortError() errno.Error
|
||||
|
||||
// Header 获取 Header 对象
|
||||
Header() http.Header
|
||||
// GetHeader 获取 Header
|
||||
GetHeader(key string) string
|
||||
// SetHeader 设置 Header
|
||||
SetHeader(key, value string)
|
||||
|
||||
// UserID 获取 JWT 中 UserID
|
||||
UserID() int64
|
||||
setUserID(userID int64)
|
||||
|
||||
// UserName 获取 JWT 中 UserName
|
||||
UserName() string
|
||||
setUserName(userName string)
|
||||
|
||||
// Alias 设置路由别名 for metrics uri
|
||||
Alias() string
|
||||
setAlias(path string)
|
||||
|
||||
// RawData 获取 Request.Body
|
||||
RawData() []byte
|
||||
// Method 获取 Request.Method
|
||||
Method() string
|
||||
// Host 获取 Request.Host
|
||||
Host() string
|
||||
// Path 获取 请求的路径 Request.URL.Path (不附带 querystring)
|
||||
Path() string
|
||||
// URI 获取 unescape 后的 Request.URL.RequestURI()
|
||||
URI() string
|
||||
|
||||
Deadline() (deadline time.Time, ok bool)
|
||||
Done() <-chan struct{}
|
||||
Err() error
|
||||
Value(key interface{}) interface{}
|
||||
// RequestContext 获取请求的 context (当 client 关闭后,会自动 canceled)
|
||||
RequestContext() StdContext
|
||||
}
|
||||
|
||||
type context struct {
|
||||
ctx *gin.Context
|
||||
}
|
||||
|
||||
type StdContext struct {
|
||||
stdctx.Context
|
||||
Trace
|
||||
*zap.Logger
|
||||
}
|
||||
|
||||
func (c *context) init() {
|
||||
body, err := c.ctx.GetRawData()
|
||||
if err != nil {
|
||||
@@ -137,7 +155,7 @@ func (c *context) ShouldBindQuery(obj interface{}) error {
|
||||
return c.ctx.ShouldBindWith(obj, binding.Query)
|
||||
}
|
||||
|
||||
// ShouldBindPostForm 反序列化postform(querystring会被忽略)
|
||||
// ShouldBindPostForm 反序列化 postform (querystring 会被忽略)
|
||||
// tag: `form:"xxx"`
|
||||
func (c *context) ShouldBindPostForm(obj interface{}) error {
|
||||
return c.ctx.ShouldBindWith(obj, binding.FormPost)
|
||||
@@ -202,7 +220,7 @@ func (c *context) getPayload() errno.Error {
|
||||
return payload.(errno.Error)
|
||||
}
|
||||
|
||||
func (c *context) SetPayload(payload errno.Error) {
|
||||
func (c *context) Payload(payload errno.Error) {
|
||||
c.ctx.Set(_PayloadName, payload)
|
||||
}
|
||||
|
||||
@@ -227,16 +245,16 @@ func (c *context) SetHeader(key, value string) {
|
||||
c.ctx.Header(key, value)
|
||||
}
|
||||
|
||||
func (c *context) UserID() int {
|
||||
func (c *context) UserID() int64 {
|
||||
val, ok := c.ctx.Get(_UserID)
|
||||
if !ok {
|
||||
return 0
|
||||
}
|
||||
|
||||
return val.(int)
|
||||
return val.(int64)
|
||||
}
|
||||
|
||||
func (c *context) setUserID(userID int) {
|
||||
func (c *context) setUserID(userID int64) {
|
||||
c.ctx.Set(_UserID, userID)
|
||||
}
|
||||
|
||||
@@ -315,25 +333,11 @@ func (c *context) URI() string {
|
||||
return uri
|
||||
}
|
||||
|
||||
func (c *context) Deadline() (deadline time.Time, ok bool) {
|
||||
return
|
||||
}
|
||||
|
||||
func (c *context) Done() <-chan struct{} {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *context) Err() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *context) Value(key interface{}) interface{} {
|
||||
if key == 0 {
|
||||
return c.ctx.Request
|
||||
// RequestContext 获取请求的 context (当client关闭后,会自动canceled)
|
||||
func (c *context) RequestContext() StdContext {
|
||||
return StdContext{
|
||||
c.ctx.Request.Context(),
|
||||
c.Trace(),
|
||||
c.Logger(),
|
||||
}
|
||||
if keyAsString, ok := key.(string); ok {
|
||||
val, _ := c.ctx.Get(keyAsString)
|
||||
return val
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -121,11 +121,10 @@ func AliasForRecordMetrics(path string) HandlerFunc {
|
||||
}
|
||||
|
||||
// WrapAuthHandler 用来处理 Auth 的入口,在之后的handler中只需 ctx.UserID() ctx.UserName() 即可。
|
||||
func WrapAuthHandler(handler func(Context) (userID int, userName string, err errno.Error)) HandlerFunc {
|
||||
func WrapAuthHandler(handler func(Context) (userID int64, userName string, err errno.Error)) HandlerFunc {
|
||||
return func(ctx Context) {
|
||||
userID, userName, err := handler(ctx)
|
||||
if err != nil {
|
||||
ctx.Logger().Error("auth handler err", zap.Error(errors.WithStack(errors.New(err.GetMsg()))))
|
||||
ctx.AbortWithError(err)
|
||||
return
|
||||
}
|
||||
@@ -362,7 +361,7 @@ func New(logger *zap.Logger, options ...Option) (Mux, error) {
|
||||
}
|
||||
|
||||
if err := context.abortError(); err != nil { // customer err
|
||||
multierr.AppendInto(&abortErr, errors.New(err.GetMsg()))
|
||||
multierr.AppendInto(&abortErr, err.GetErr())
|
||||
response = err
|
||||
}
|
||||
} else {
|
||||
@@ -389,7 +388,15 @@ func New(logger *zap.Logger, options ...Option) (Mux, error) {
|
||||
uri = alias
|
||||
}
|
||||
|
||||
opt.recordMetrics(context.Method(), uri, !ctx.IsAborted() && ctx.Writer.Status() == http.StatusOK, ctx.Writer.Status(), businessCode, time.Since(ts).Seconds(), traceId)
|
||||
opt.recordMetrics(
|
||||
context.Method(),
|
||||
uri,
|
||||
!ctx.IsAborted() && ctx.Writer.Status() == http.StatusOK,
|
||||
ctx.Writer.Status(),
|
||||
businessCode,
|
||||
time.Since(ts).Seconds(),
|
||||
traceId,
|
||||
)
|
||||
}
|
||||
|
||||
var t *trace.Trace
|
||||
@@ -420,7 +427,12 @@ func New(logger *zap.Logger, options ...Option) (Mux, error) {
|
||||
t.Success = !ctx.IsAborted() && ctx.Writer.Status() == http.StatusOK
|
||||
t.CostSeconds = time.Since(ts).Seconds()
|
||||
|
||||
logger.Info("core-interceptor", zap.Any("trace", t))
|
||||
if abortErr == nil {
|
||||
logger.Info("core-interceptor", zap.Any("trace", t))
|
||||
} else {
|
||||
logger.Info("core-interceptor", zap.Any("trace", t), zap.Error(abortErr))
|
||||
}
|
||||
|
||||
}()
|
||||
|
||||
ctx.Next()
|
||||
@@ -436,6 +448,7 @@ func New(logger *zap.Logger, options ...Option) (Mux, error) {
|
||||
context.AbortWithError(code.ErrManyRequest)
|
||||
return
|
||||
}
|
||||
|
||||
ctx.Next()
|
||||
})
|
||||
}
|
||||
@@ -457,7 +470,7 @@ func New(logger *zap.Logger, options ...Option) (Mux, error) {
|
||||
Host: ctx.Host(),
|
||||
Status: "ok",
|
||||
}
|
||||
ctx.SetPayload(code.OK.WithData(resp))
|
||||
ctx.Payload(code.OK.WithData(resp))
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
package db_repo
|
||||
package db
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
@@ -1,4 +1,4 @@
|
||||
package db_repo
|
||||
package db
|
||||
|
||||
import (
|
||||
"time"
|
||||
@@ -51,7 +51,7 @@ func before(db *gorm.DB) {
|
||||
|
||||
func after(db *gorm.DB) {
|
||||
_ctx := db.Statement.Context
|
||||
ctx, ok := _ctx.(core.Context)
|
||||
ctx, ok := _ctx.(core.StdContext)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
@@ -74,7 +74,7 @@ func after(db *gorm.DB) {
|
||||
sqlInfo.Stack = utils.FileWithLineNum()
|
||||
sqlInfo.Rows = db.Statement.RowsAffected
|
||||
sqlInfo.CostSeconds = time.Since(ts).Seconds()
|
||||
ctx.Trace().AppendSQL(sqlInfo)
|
||||
ctx.Trace.AppendSQL(sqlInfo)
|
||||
|
||||
return
|
||||
}
|
||||
@@ -5,30 +5,45 @@ import (
|
||||
"github.com/spf13/cast"
|
||||
)
|
||||
|
||||
// requestsCounter 定义计数器(Counter)
|
||||
var requestsCounter = prometheus.NewCounterVec(
|
||||
const (
|
||||
namespace = "xinliangnote"
|
||||
subsystem = "go_gin_api"
|
||||
)
|
||||
|
||||
// metricsRequestsTotal metrics for request total 计数器(Counter)
|
||||
var metricsRequestsTotal = prometheus.NewCounterVec(
|
||||
prometheus.CounterOpts{
|
||||
Name: "api_requests_total",
|
||||
Namespace: namespace,
|
||||
Subsystem: subsystem,
|
||||
Name: "requests_total",
|
||||
Help: "request(s) total",
|
||||
},
|
||||
[]string{"method", "path"},
|
||||
)
|
||||
|
||||
// httpDurationsHistogram 定义累积直方图(Histogram)
|
||||
var httpDurationsHistogram = prometheus.NewHistogramVec(
|
||||
// metricsRequestsCost metrics for requests cost 累积直方图(Histogram)
|
||||
var metricsRequestsCost = prometheus.NewHistogramVec(
|
||||
prometheus.HistogramOpts{
|
||||
Name: "api_http_durations_histogram_seconds",
|
||||
Buckets: []float64{0.01, 0.02, 0.03},
|
||||
Namespace: namespace,
|
||||
Subsystem: subsystem,
|
||||
Name: "requests_cost",
|
||||
Help: "request(s) cost seconds",
|
||||
},
|
||||
[]string{"method", "path", "success", "http_code", "business_code", "cost_seconds", "trace_id"},
|
||||
)
|
||||
|
||||
func init() {
|
||||
prometheus.MustRegister(requestsCounter, httpDurationsHistogram)
|
||||
prometheus.MustRegister(metricsRequestsTotal, metricsRequestsCost)
|
||||
}
|
||||
|
||||
// RecordMetrics 记录指标
|
||||
func RecordMetrics(method, uri string, success bool, httpCode, businessCode int, costSeconds float64, traceId string) {
|
||||
httpDurationsHistogram.With(prometheus.Labels{
|
||||
metricsRequestsTotal.With(prometheus.Labels{
|
||||
"method": method,
|
||||
"path": uri,
|
||||
}).Inc()
|
||||
|
||||
metricsRequestsCost.With(prometheus.Labels{
|
||||
"method": method,
|
||||
"path": uri,
|
||||
"success": cast.ToString(success),
|
||||
@@ -37,9 +52,4 @@ func RecordMetrics(method, uri string, success bool, httpCode, businessCode int,
|
||||
"cost_seconds": cast.ToString(costSeconds),
|
||||
"trace_id": traceId,
|
||||
}).Observe(costSeconds)
|
||||
|
||||
requestsCounter.With(prometheus.Labels{
|
||||
"method": method,
|
||||
"path": uri,
|
||||
}).Add(1)
|
||||
}
|
||||
|
||||
@@ -8,7 +8,7 @@ import (
|
||||
"go.uber.org/zap"
|
||||
)
|
||||
|
||||
// OnPanicNotify
|
||||
// OnPanicNotify 发生 panic 时进行通知
|
||||
func OnPanicNotify(ctx core.Context, err interface{}, stackInfo string) {
|
||||
cfg := configs.Get().Mail
|
||||
if cfg.Host == "" || cfg.Port == 0 || cfg.User == "" || cfg.Pass == "" || cfg.To == "" {
|
||||
@@ -16,11 +16,19 @@ func OnPanicNotify(ctx core.Context, err interface{}, stackInfo string) {
|
||||
return
|
||||
}
|
||||
|
||||
subject, body, htmlErr := NewPanicHTMLEmail(ctx.Method(), ctx.Host(), ctx.URI(), ctx.Trace().ID(), err, stackInfo)
|
||||
subject, body, htmlErr := NewPanicHTMLEmail(
|
||||
ctx.Method(),
|
||||
ctx.Host(),
|
||||
ctx.URI(),
|
||||
ctx.Trace().ID(),
|
||||
err,
|
||||
stackInfo,
|
||||
)
|
||||
if htmlErr != nil {
|
||||
ctx.Logger().Error("NewPanicHTMLEmail error", zap.Error(htmlErr))
|
||||
return
|
||||
}
|
||||
|
||||
options := &mail.Options{
|
||||
MailHost: cfg.Host,
|
||||
MailPort: cfg.Port,
|
||||
@@ -34,5 +42,6 @@ func OnPanicNotify(ctx core.Context, err interface{}, stackInfo string) {
|
||||
if sendErr != nil {
|
||||
ctx.Logger().Error("Mail Send error", zap.Error(sendErr))
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
@@ -9,13 +9,13 @@ type D interface {
|
||||
AppendResponse(resp *Response)
|
||||
}
|
||||
|
||||
// Dialog 内部调用其它方接口的会话信息;失败时会有retry操作,所以response会有多次。
|
||||
// Dialog 内部调用其它方接口的会话信息;失败时会有retry操作,所以 response 会有多次。
|
||||
type Dialog struct {
|
||||
mux sync.Mutex
|
||||
Request *Request `json:"request"` // 请求信息
|
||||
Responses []*Response `json:"responses"` // 返回信息
|
||||
Success bool `json:"success"` // 是否成功,true 或 false
|
||||
CostSeconds float64 `json:"cost_seconds"` // 执行时长,单位:秒
|
||||
CostSeconds float64 `json:"cost_seconds"` // 执行时长(单位秒)
|
||||
}
|
||||
|
||||
func (d *Dialog) i() {}
|
||||
|
||||
11
internal/pkg/trace/redis.go
Normal file
11
internal/pkg/trace/redis.go
Normal file
@@ -0,0 +1,11 @@
|
||||
package trace
|
||||
|
||||
import "time"
|
||||
|
||||
type Redis struct {
|
||||
Timestamp string `json:"timestamp"` // 时间,格式:2006-01-02 15:04:05
|
||||
Handle string `json:"handle"` // 操作,function
|
||||
Key string `json:"key"`
|
||||
Value string `json:"value,omitempty"`
|
||||
TTL time.Duration `json:"ttl,omitempty"`
|
||||
}
|
||||
@@ -3,7 +3,7 @@ package trace
|
||||
type SQL struct {
|
||||
Timestamp string `json:"timestamp"` // 时间,格式:2006-01-02 15:04:05
|
||||
Stack string `json:"stack"` // 文件地址和行号
|
||||
CostSeconds float64 `json:"cost_seconds"` // 执行时长,单位:秒
|
||||
CostSeconds float64 `json:"cost_seconds"` // 执行时长(单位秒)
|
||||
SQL string `json:"sql"` // SQL 语句
|
||||
Rows int64 `json:"rows_affected"` // 影响行数
|
||||
}
|
||||
|
||||
@@ -23,34 +23,35 @@ type T interface {
|
||||
// Trace 记录的参数
|
||||
type Trace struct {
|
||||
mux sync.Mutex
|
||||
Identifier string `json:"trace_id"`
|
||||
Request *Request `json:"request"`
|
||||
Response *Response `json:"response"`
|
||||
ThirdPartyRequests []*Dialog `json:"third_party_requests"`
|
||||
Debugs []*Debug `json:"debugs"`
|
||||
SQLs []*SQL `json:"sqls"`
|
||||
Success bool `json:"success"`
|
||||
CostSeconds float64 `json:"cost_seconds"`
|
||||
Identifier string `json:"trace_id"` // 链路ID
|
||||
Request *Request `json:"request"` // 请求信息
|
||||
Response *Response `json:"response"` // 返回信息
|
||||
ThirdPartyRequests []*Dialog `json:"third_party_requests"` // 调用第三方接口的信息
|
||||
Debugs []*Debug `json:"debugs"` // 调试信息
|
||||
SQLs []*SQL `json:"sqls"` // 执行的 SQL 信息
|
||||
Redis []*Redis `json:"redis"` // 执行的 Redis 信息
|
||||
Success bool `json:"success"` // 请求结果 true or false
|
||||
CostSeconds float64 `json:"cost_seconds"` // 执行时长(单位秒)
|
||||
}
|
||||
|
||||
// Request 请求信息
|
||||
type Request struct {
|
||||
TTL string `json:"ttl"`
|
||||
Method string `json:"method"`
|
||||
DecodedURL string `json:"decoded_url"`
|
||||
Header interface{} `json:"header"`
|
||||
Body interface{} `json:"body"`
|
||||
TTL string `json:"ttl"` // 请求超时时间
|
||||
Method string `json:"method"` // 请求方式
|
||||
DecodedURL string `json:"decoded_url"` // 请求地址
|
||||
Header interface{} `json:"header"` // 请求 Header 信息
|
||||
Body interface{} `json:"body"` // 请求 Body 信息
|
||||
}
|
||||
|
||||
// Response 响应信息
|
||||
type Response struct {
|
||||
Header interface{} `json:"header"`
|
||||
Body interface{} `json:"body"`
|
||||
BusinessCode int `json:"business_code,omitempty"`
|
||||
BusinessCodeMsg string `json:"business_code_msg,omitempty"`
|
||||
HttpCode int `json:"http_code"`
|
||||
HttpCodeMsg string `json:"http_code_msg"`
|
||||
CostSeconds float64 `json:"cost_seconds"`
|
||||
Header interface{} `json:"header"` // Header 信息
|
||||
Body interface{} `json:"body"` // Body 信息
|
||||
BusinessCode int `json:"business_code,omitempty"` // 业务码
|
||||
BusinessCodeMsg string `json:"business_code_msg,omitempty"` // 提示信息
|
||||
HttpCode int `json:"http_code"` // HTTP 状态码
|
||||
HttpCodeMsg string `json:"http_code_msg"` // HTTP 状态码信息
|
||||
CostSeconds float64 `json:"cost_seconds"` // 执行时间(单位秒)
|
||||
}
|
||||
|
||||
func New(id string) *Trace {
|
||||
@@ -122,3 +123,16 @@ func (t *Trace) AppendSQL(sql *SQL) *Trace {
|
||||
t.SQLs = append(t.SQLs, sql)
|
||||
return t
|
||||
}
|
||||
|
||||
// AppendRedis 追加 Redis
|
||||
func (t *Trace) AppendRedis(redis *Redis) *Trace {
|
||||
if redis == nil {
|
||||
return t
|
||||
}
|
||||
|
||||
t.mux.Lock()
|
||||
defer t.mux.Unlock()
|
||||
|
||||
t.Redis = append(t.Redis, redis)
|
||||
return t
|
||||
}
|
||||
|
||||
11
main.go
11
main.go
@@ -7,9 +7,9 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/xinliangnote/go-gin-api/configs"
|
||||
"github.com/xinliangnote/go-gin-api/internal/api/repository/cache_repo"
|
||||
"github.com/xinliangnote/go-gin-api/internal/api/repository/db_repo"
|
||||
"github.com/xinliangnote/go-gin-api/internal/api/router"
|
||||
"github.com/xinliangnote/go-gin-api/internal/pkg/cache"
|
||||
"github.com/xinliangnote/go-gin-api/internal/pkg/db"
|
||||
"github.com/xinliangnote/go-gin-api/pkg/logger"
|
||||
"github.com/xinliangnote/go-gin-api/pkg/shutdown"
|
||||
|
||||
@@ -24,6 +24,9 @@ import (
|
||||
// @contact.url
|
||||
// @contact.email
|
||||
|
||||
// @license.name MIT
|
||||
// @license.url https://github.com/xinliangnote/go-gin-api/blob/master/LICENSE
|
||||
|
||||
// @host 127.0.0.1:9999
|
||||
// @BasePath
|
||||
func main() {
|
||||
@@ -39,13 +42,13 @@ func main() {
|
||||
defer loggers.Sync()
|
||||
|
||||
// 初始化数据库
|
||||
dbRepo, err := db_repo.New()
|
||||
dbRepo, err := db.New()
|
||||
if err != nil {
|
||||
loggers.Fatal("new db err", zap.Error(err))
|
||||
}
|
||||
|
||||
// 初始化缓存
|
||||
cacheRepo, err := cache_repo.New()
|
||||
cacheRepo, err := cache.New()
|
||||
if err != nil {
|
||||
loggers.Fatal("new cache err", zap.Error(err))
|
||||
}
|
||||
|
||||
@@ -2,6 +2,8 @@ package errno
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
var _ Error = (*err)(nil)
|
||||
@@ -13,12 +15,16 @@ type Error interface {
|
||||
WithData(data interface{}) Error
|
||||
// WithID 设置当前请求的唯一ID
|
||||
WithID(id string) Error
|
||||
// WithErr 设置错误信息
|
||||
WithErr(err error) Error
|
||||
// GetBusinessCode 获取 Business Code
|
||||
GetBusinessCode() int
|
||||
// GetHttpCode 获取 HTTP Code
|
||||
GetHttpCode() int
|
||||
// GetMsg 获取 Msg
|
||||
GetMsg() string
|
||||
// GetErr 获取错误信息
|
||||
GetErr() error
|
||||
// ToString 返回 JSON 格式的错误详情
|
||||
ToString() string
|
||||
}
|
||||
@@ -26,8 +32,9 @@ type Error interface {
|
||||
type err struct {
|
||||
HttpCode int `json:"-"` // HTTP Code
|
||||
BusinessCode int `json:"code"` // Business Code
|
||||
Msg string `json:"msg"` // 错误描述
|
||||
Data interface{} `json:"data"` // 成功时返回的数据
|
||||
Msg string `json:"msg"` // 描述信息
|
||||
Data interface{} `json:"data"` // 接口数据
|
||||
Err error `json:"-"` // 错误信息
|
||||
ID string `json:"id,omitempty"` // 当前请求的唯一ID,便于问题定位,忽略也可以
|
||||
}
|
||||
|
||||
@@ -37,6 +44,7 @@ func NewError(httpCode, businessCode int, msg string) Error {
|
||||
BusinessCode: businessCode,
|
||||
Msg: msg,
|
||||
Data: nil,
|
||||
Err: nil,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -52,6 +60,11 @@ func (e *err) WithID(id string) Error {
|
||||
return e
|
||||
}
|
||||
|
||||
func (e *err) WithErr(err error) Error {
|
||||
e.Err = errors.WithStack(err)
|
||||
return e
|
||||
}
|
||||
|
||||
func (e *err) GetHttpCode() int {
|
||||
return e.HttpCode
|
||||
}
|
||||
@@ -64,6 +77,10 @@ func (e *err) GetMsg() string {
|
||||
return e.Msg
|
||||
}
|
||||
|
||||
func (e *err) GetErr() error {
|
||||
return e.Err
|
||||
}
|
||||
|
||||
// ToString 返回 JSON 格式的错误详情
|
||||
func (e *err) ToString() string {
|
||||
err := &struct {
|
||||
|
||||
@@ -29,6 +29,9 @@ var defaultClient = &http.Client{
|
||||
TLSClientConfig: &tls.Config{
|
||||
InsecureSkipVerify: true,
|
||||
},
|
||||
MaxIdleConns: 100,
|
||||
MaxConnsPerHost: 100,
|
||||
MaxIdleConnsPerHost: 100,
|
||||
},
|
||||
}
|
||||
|
||||
@@ -47,12 +50,11 @@ func doHTTP(ctx context.Context, method, url string, payload []byte, opt *option
|
||||
return mock(), http.StatusOK, nil
|
||||
}
|
||||
|
||||
req, err := http.NewRequest(method, url, bytes.NewReader(payload))
|
||||
req, err := http.NewRequestWithContext(ctx, method, url, bytes.NewReader(payload))
|
||||
if err != nil {
|
||||
return nil, -1, errors.Wrapf(err, "new request [%s %s] err", method, url)
|
||||
}
|
||||
|
||||
req = req.WithContext(ctx)
|
||||
for key, value := range opt.header {
|
||||
req.Header.Set(key, value[0])
|
||||
}
|
||||
|
||||
@@ -14,6 +14,7 @@ import (
|
||||
const (
|
||||
// DefaultLevel the default log level
|
||||
DefaultLevel = zapcore.InfoLevel
|
||||
|
||||
// DefaultTimeLayout the default time layout;
|
||||
DefaultTimeLayout = time.RFC3339
|
||||
)
|
||||
|
||||
@@ -7,7 +7,9 @@ import (
|
||||
)
|
||||
|
||||
func TestJSONLogger(t *testing.T) {
|
||||
logger, err := NewJSONLogger(WithField("defined_key", "defined_value"))
|
||||
logger, err := NewJSONLogger(
|
||||
WithField("defined_key", "defined_value"),
|
||||
)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -18,3 +20,16 @@ func TestJSONLogger(t *testing.T) {
|
||||
logger.Error("err occurs", WrapMeta(err, NewMeta("para1", "value1"), NewMeta("para2", "value2"))...)
|
||||
|
||||
}
|
||||
|
||||
func BenchmarkJsonLogger(b *testing.B) {
|
||||
b.ResetTimer()
|
||||
logger, err := NewJSONLogger(
|
||||
WithField("defined_key", "defined_value"),
|
||||
)
|
||||
if err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
|
||||
defer logger.Sync()
|
||||
|
||||
}
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
package p
|
||||
|
||||
import (
|
||||
"github.com/xinliangnote/go-gin-api/internal/pkg/trace"
|
||||
"fmt"
|
||||
|
||||
"github.com/davecgh/go-spew/spew"
|
||||
"github.com/xinliangnote/go-gin-api/internal/pkg/trace"
|
||||
)
|
||||
|
||||
type Option func(*option)
|
||||
@@ -19,7 +19,7 @@ func newOption() *option {
|
||||
return &option{}
|
||||
}
|
||||
|
||||
func Print(key string, value interface{}, options ...Option) {
|
||||
func Println(key string, value interface{}, options ...Option) {
|
||||
opt := newOption()
|
||||
defer func() {
|
||||
if opt.Trace != nil {
|
||||
@@ -33,7 +33,7 @@ func Print(key string, value interface{}, options ...Option) {
|
||||
f(opt)
|
||||
}
|
||||
|
||||
spew.Dump(key, value)
|
||||
fmt.Println(fmt.Sprintf("KEY: %s | VALUE: %v", key, value))
|
||||
}
|
||||
|
||||
// WithTrace 设置trace信息
|
||||
|
||||
@@ -45,24 +45,24 @@ QbHmKuHIRFHCFv+XX8c0aK2mDZMUlzJdy4FgD/YCEZ7kZMZKyvZW/ZuV
|
||||
)
|
||||
|
||||
func TestEncrypt(t *testing.T) {
|
||||
rsaPublic := NewPublic(publicKey)
|
||||
str, err := rsaPublic.Encrypt("123456")
|
||||
str, err := NewPublic(publicKey).Encrypt("123456")
|
||||
if err != nil {
|
||||
t.Error("rsa public encrypt error", err)
|
||||
return
|
||||
}
|
||||
|
||||
t.Log(str)
|
||||
}
|
||||
|
||||
func TestDecrypt(t *testing.T) {
|
||||
decryptStr := "KTKXckjkCLI6Vk_y_XROnY-a6nJpllruL-CX-v_2AFxfghA2tZ2nkQyS6d1-IIYMlgwm4ivwlzy-phLtaN9BB03htA5D9rwjA_JwYtqAG4iwuvgaDl2SiZ_H2ACv-aV1kNRgnyjh14hs0JiSt5VHEiJ3D2xYzOCKwtEzoo0WczJ-MYb3u_-bfcnm9YtvgtG5-y3Jy7WYr-IwXdBKqPO0E-jzrtY7m3Q1yC4znHdzjNpxCj0I6YRx4CZ362b706qNX7sl3E5KTJeSmYrsurB-SxQT1CaqGzVt7mshx1v2qGnv5NBNXpj7ZPKWGJbgaCUxcuxd1Mg0o81HnfbsGuSlFQ=="
|
||||
|
||||
rsaPrivate := NewPrivate(privateKey)
|
||||
str, err := rsaPrivate.Decrypt(decryptStr)
|
||||
str, err := NewPrivate(privateKey).Decrypt(decryptStr)
|
||||
if err != nil {
|
||||
t.Error("rsa private decrypt error", err)
|
||||
return
|
||||
}
|
||||
|
||||
t.Log(str)
|
||||
}
|
||||
|
||||
|
||||
@@ -11,7 +11,7 @@ var _ Token = (*token)(nil)
|
||||
type Token interface {
|
||||
// i 为了避免被其他包实现
|
||||
i()
|
||||
Sign(userId int, userName string) (tokenString string, err error)
|
||||
Sign(userId int64, userName string, expireDuration time.Duration) (tokenString string, err error)
|
||||
Parse(tokenString string) (*claims, error)
|
||||
}
|
||||
|
||||
@@ -20,7 +20,7 @@ type token struct {
|
||||
}
|
||||
|
||||
type claims struct {
|
||||
UserID int
|
||||
UserID int64
|
||||
UserName string
|
||||
jwt.StandardClaims
|
||||
}
|
||||
@@ -33,7 +33,7 @@ func New(secret string) Token {
|
||||
|
||||
func (t *token) i() {}
|
||||
|
||||
func (t *token) Sign(userId int, userName string) (tokenString string, err error) {
|
||||
func (t *token) Sign(userId int64, userName string, expireDuration time.Duration) (tokenString string, err error) {
|
||||
// The token content.
|
||||
// iss: (Issuer)签发者
|
||||
// iat: (Issued At)签发时间,用Unix时间戳表示
|
||||
@@ -48,8 +48,7 @@ func (t *token) Sign(userId int, userName string) (tokenString string, err error
|
||||
jwt.StandardClaims{
|
||||
NotBefore: time.Now().Unix(),
|
||||
IssuedAt: time.Now().Unix(),
|
||||
ExpiresAt: time.Now().Add(24 * time.Hour).Unix(),
|
||||
Issuer: "go-gin-api",
|
||||
ExpiresAt: time.Now().Add(expireDuration).Unix(),
|
||||
},
|
||||
}
|
||||
tokenString, err = jwt.NewWithClaims(jwt.SigningMethodHS256, claims).SignedString([]byte(t.secret))
|
||||
|
||||
@@ -2,12 +2,13 @@ package token
|
||||
|
||||
import (
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
const secret = "i1ydX9RtHyuJTrw7frcu"
|
||||
|
||||
func TestSign(t *testing.T) {
|
||||
tokenString, err := New(secret).Sign(123456789, "xinliangnote")
|
||||
tokenString, err := New(secret).Sign(123456789, "xinliangnote", 24*time.Hour)
|
||||
if err != nil {
|
||||
t.Error("sign error", err)
|
||||
return
|
||||
@@ -29,7 +30,7 @@ func BenchmarkSignAndParse(b *testing.B) {
|
||||
b.ResetTimer()
|
||||
token := New(secret)
|
||||
for i := 0; i < b.N; i++ {
|
||||
tokenString, _ := token.Sign(123456789, "xinliangnote")
|
||||
tokenString, _ := token.Sign(123456789, "xinliangnote", 24*time.Hour)
|
||||
token.Parse(tokenString)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user