├── README.md
├── app
├── cache
│ ├── abstract.go
│ ├── redis.go
│ └── redis_dao.go
├── core
│ ├── config.go
│ ├── exception.go
│ └── logger.go
├── db
│ ├── any_value.go
│ ├── config.go
│ ├── dao.go
│ ├── model
│ │ ├── define.go
│ │ ├── field.go
│ │ ├── table.go
│ │ └── tag.go
│ ├── query.go
│ ├── query
│ │ ├── combine.go
│ │ ├── define.go
│ │ ├── mysql.go
│ │ ├── parts
│ │ │ ├── field.go
│ │ │ ├── join.go
│ │ │ ├── limit.go
│ │ │ ├── order.go
│ │ │ ├── set.go
│ │ │ ├── table.go
│ │ │ ├── values.go
│ │ │ └── where.go
│ │ └── sql_server.go
│ └── table.go
├── http.go
├── https.go
└── service
│ ├── app.go
│ ├── init.go
│ ├── init_core.go
│ └── init_expand.go
├── base
├── any_value.go
├── app.go
├── app_action.go
├── app_data.go
├── app_redis.go
├── app_router.go
├── common.go
├── data_type.go
├── origin.go
├── origin_request.go
└── origin_result.go
├── guide.go
├── origin
├── engine.go
├── error.go
└── response.go
├── test
├── test1
│ ├── t1.go
│ ├── t2.go
│ ├── t3.go
│ ├── t4.go
│ ├── t5.go
│ ├── t6.go
│ ├── test1.go
│ ├── test2.go
│ ├── test3.go
│ ├── test4.go
│ ├── test5.go
│ ├── test6.go
│ ├── test7.go
│ ├── test8.go
│ └── test9.go
└── test2
│ ├── t1.go
│ ├── t2.go
│ ├── t3.go
│ ├── t4.go
│ └── test3.go
└── utils
├── config_parser.go
├── config_parser
├── base.go
├── ini.go
└── json.go
├── convert.go
├── curl
├── get.go
└── post.go
├── encrypt
├── md5.go
└── sha1.go
├── error.go
├── file.go
├── handler.go
├── log.go
├── timer.go
└── validator
├── field.go
├── form.go
├── handler.go
└── tag
├── define.go
├── length.go
└── require.go
/README.md:
--------------------------------------------------------------------------------
1 | # regin框架 #
2 | regin是一款基于go-gin框架封装的web框架,用于快速构建web应用和后端服务.
3 | ### 目录
4 | - [安装与配置](#安装与配置)
5 | - [快速开始](#快速开始)
6 | - [项目结构](#项目结构)
7 | - [路由配置](#路由配置)
8 | - [服务配置](#服务配置)
9 | - [Web应用](#Web应用)
10 | - [数据库](#数据库)
11 | - [Redis](#Redis)
12 | - [Utils工具](#Utils工具)
13 | - config文件解析器(支持json、ini)
14 | - 加密算法
15 | - 验证器
16 | - curl
17 | - 文件操作
18 | - ...
19 |
20 | ### 安装与配置
21 | #### 1. 安装Go (version 1.10+), 然后可使用下面命令进行安装regin
22 | $ go get github.com/go-touch/regin
23 | #### 2. 设置系统环境变量
24 | REGIN_RUNMODE = dev | test | prod
25 | #### 3. 依赖包安装(已安装可忽略)
26 | $ go get github.com/gin-gonic/gin
27 | $ go get github.com/unrolled/secure
28 | $ go get github.com/go-sql-driver/mysql
29 | $ go get github.com/garyburd/redigo/redis
30 | $ go get gopkg.in/ini.v1
31 | $ go get github.com/go-touch/mtype
32 | #### 4. 如使用go mod包依赖管理工具, 请参考下面命令
33 | ##### Windows 下开启 GO111MODULE 并设置 GOPROXY 的命令为:
34 | $ set GO111MODULE=on
35 | $ go env -w GOPROXY=https://goproxy.cn,direct
36 | ##### MacOS 或者 Linux 下开启 GO111MODULE 并设置 GOPROXY 的命令为:
37 | $ export GO111MODULE=on
38 | $ export GOPROXY=https://goproxy.cn
39 | ### 快速开始
40 | #### 入口文件: xxx/main.go (xxx 代表项目名称,后面也是)
41 | ```go
42 | package main
43 |
44 | import (
45 | "github.com/go-touch/regin"
46 | _ "xxx/application/router"
47 | )
48 |
49 | func main() {
50 | regin.Guide.HttpService()
51 | }
52 | ```
53 | $ go run main.go
54 | 或者:
55 | $ go build main.go
56 | $ ./xxx
57 | ### 项目结构
58 | - application
59 | - modules // action存放目录,
60 | - demo // 模块名
61 | - model
62 | - bussiness // 业务类
63 | - common // 公共处理函数
64 | - dao // 抽象数据模型
65 | - form // 校验数据模型
66 | - mysql // mysql表字段映射模型
67 | - redis // redis数据模型
68 | - router // 注册路由, 主要通过map存储modules对应的action实例的映射
69 | - config
70 | - dev // 必要配置项(通过系统环境变量选择配置路径)
71 | - database.ini
72 | - server.ini
73 | - redis.ini
74 | - test
75 | - prod
76 | - runtime
77 | - log // 存储系统错误日志
78 | - main.go // 入口文件
79 |
80 | ### 路由配置
81 | #### 举例: xxx/application/router/demo.go
82 | ```go
83 | package router
84 |
85 | import (
86 | "github.com/go-touch/regin/base"
87 | "mygin/application/modules/api/role"
88 | "mygin/application/modules/demo"
89 | )
90 |
91 | func init() {
92 | base.Router.General("demo", base.GeneralMap{
93 | "v1.index": &demo.Index{}, // demo包下的action:Index
94 | "role.checkapi": &role.CheckApi{}, // role包下的action:CheckApi
95 | })
96 | }
97 | ```
98 | ```go
99 | 访问:
100 | http://127.0.0.1/module/controller/action
101 |
102 | 示例:
103 | http://127.0.0.1/demo/v1/index
104 | http://127.0.0.1/demo/role/checkapi
105 | ```
106 | ```go
107 | Note: regin中的路由比较松散,url中pathinfo采用三段路径, 通过获取三段路由信息,使用 . 拼接作为key,读取路由map里面对应的action(action定义可查看web应用介绍). 因此路径的含义可依据路由配置定义,并无严格规定.
108 | ```
109 | ### 服务配置
110 | #### 配置项 xxx/config/server.ini
111 | ; 主配置
112 | [main]
113 | httpHost = 127.0.0.1:8080 // http服务地址端口
114 | httpsHost = 127.0.0.1:443 // https服务地址端口
115 |
116 | ; 错误配置
117 | [error]
118 | log = true // 是否开启错误日志
119 | 读取format = {date}-Error // 日志文件名格式
120 | pattern = local // 日志存储方式 local:本地 remote:远程
121 | #### 项目中使用配置
122 | 读取方式: (不会直接获取对应值,而是返回一个regin的configValue结构体指针,可实现对应类型转换)
123 | config := service.App.GetConfig("xxx.xxx.xxx")
124 |
125 | 调用示例:
126 | config := service.App.GetConfig("server.main.httpHost").ToString()
127 |
128 | 备注: server.ini、database.ini、redis.ini等必要配置项,文件和字段名均为regin使用,不可修改.
129 | ### Web应用
130 | #### 基类action的代码示例: regin/base/app.action.go
131 | ```go
132 | package base
133 |
134 | // action接口
135 | type AppAction interface {
136 | BeforeExec(request *Request) (result *Result) // 调用方法 Exec 前执行, 可通过其实现token验证、鉴权等业务
137 | Exec(request *Request) (result *Result) // 用于实现具体的业务逻辑
138 | }
139 |
140 | // action接口的一个实现
141 | type Action struct {
142 | AppAction
143 | }
144 |
145 | // Before action method
146 | func (a *Action) BeforeExec(request *Request) (result *Result) {
147 | return
148 | }
149 |
150 | // Action method.
151 | func (a *Action) Exec(request *Request) (result *Result) {
152 | return
153 | }
154 | ```
155 | #### 项目action的代码示例: xxx/application/modules/demo/mysql_select.go
156 | ```go
157 | package demo
158 |
159 | import (
160 | "github.com/go-touch/regin/app/db"
161 | "github.com/go-touch/regin/base"
162 | )
163 |
164 | type MysqlSelect struct {
165 | base.Action // 继承基类action
166 | }
167 |
168 | // 执行方法(重载方法)
169 | func (this *MysqlSelect) Exec(request *base.Request) *base.Result {
170 | result := base.JsonResult()
171 |
172 | // 查询一条数据
173 | ret := db.Model("PlusArticle").FetchRow(func(dao *db.Dao) {
174 | dao.Where("id", 202)
175 | })
176 |
177 | // 错误处理
178 | if err := ret.ToError(); err != nil {
179 | result.SetData("code", 1000)
180 | result.SetData("msg", "系统出了点问题~")
181 | return result
182 | }
183 |
184 | // json输出数据库查询结果
185 | result.SetData("data", ret.ToStringMap())
186 | return result
187 | }
188 | ```
189 | #### *base.Request实例(封装param、get、post方法,自动json、xml解析)
190 | ##### 获取请求方式
191 | func GetMethod() string
192 | ##### 获取error信息
193 | func GetError() error
194 | ##### 获取pathinfo数据. 参数key:路径名 defaultValue:默认值
195 | func Param(key string, defaultValue ...string)
196 | ##### 获取pathinfo数据map. 返回值: map[string]string
197 | func ParamAll() map[string]string
198 | ##### 获取GET数据. 参数key:路径名 defaultValue:默认值
199 | func (r *Request) Get(key string, defaultValue ...string) string
200 | ##### 获取GET数据map. 返回值: map[string]string
201 | func GetAll() map[string]string
202 | ##### 获取Post数据, json、xml等数据也用此方法. 返回值: *mtype.AnyMap(对应基础类型map[string]interface{} ,mtype更多使用可参考文档 https://github.com/go-touch/regin)
203 | func Post() *mtype.AnyMap
204 | ##### 获取上传文件io句柄. 返回值: []*multipart.FileHeader
205 | PostFile(name string) []*multipart.FileHeader
206 | ##### 获取POST元数据. 返回值: []byte
207 | func (r *Request) Raw() []byte
208 | ##### 映射请求数据为结构体. [参数]object: 要转换的结构体指针 method: 请求方式,默认post(可选参数).(内部采用json转换,可参考 encoding/json包的使用)
209 | func (r *Request) ToStruct(object interface{}, method ...string) error
210 | ##### 更多方法使用 request 调用
211 | ...
212 | #### *base.Result实例(用于响应客户端)
213 | ```go
214 | type Result struct {
215 | Type string // 可选值为:String、Json、Html、
216 | Page string // 响应页面(Type = Html时必填)
217 | Status int // 状态码 200正常状态
218 | Msg string // 提示消息
219 | Data AnyMap // 业务数据
220 | }
221 |
222 | // 定义RespResult
223 | var ResultInvoker *Result
224 |
225 | func init() {
226 | ResultInvoker = &Result{}
227 | }
228 |
229 | // 创建Json result
230 | func (r *Result) CreateJson(status int, msg string) *Result {
231 | return &Result{
232 | Type: "Json",
233 | Page: "",
234 | Status: status,
235 | Msg: msg,
236 | Data: AnyMap{"code": 0, "msg": "", "data": ""},
237 | }
238 | }
239 |
240 | // 创建Html result
241 | func (r *Result) CreateHtml(page string, status int, msg string) *Result {
242 | return &Result{
243 | Type: "Html",
244 | Page: page,
245 | Status: status,
246 | Msg: msg,
247 | Data: AnyMap{},
248 | }
249 | }
250 | ```
251 | ##### 获取一个可响应json的 *base.Result 实例
252 | base.ResultInvoker.CreateJson(status int, msg string) *Result
253 | ##### 获取一个可响应html的 *base.Result 实例
254 | base.ResultInvoker.CreateHtml(status int, msg string) *Result
255 | ##### 快速获取一个可响应json的 *base.Result 实例
256 | base.JsonResult() *Result
257 | ##### 修改业务数据即 *base.Result 的 Data 字段
258 | func (r *Result) SetData(key string, value interface{})
259 | ##### 获取业务数据即 *base.Result 的 Data 字段
260 | func (r *Result) GetData(key string) interface{}
261 | #### *base.AnyValue值类型(用于数据转换,对于不确定类型interfa{}比较适用)
262 | ##### 获取 *base.AnyValue. 参数value:interface{}(可传任意值)
263 | func base.Eval(value interface{}) *AnyValue
264 | ##### 返回错误信息
265 | func (av *AnyValue) ToError() error
266 | ##### 返回原值
267 | func (av *AnyValue) ToValue() interface{}
268 | ##### 转成int类型
269 | func (av *AnyValue) ToInt() int
270 | ##### 转成byte类型
271 | func (av *AnyValue) ToByte() byte
272 | ##### 转成string类型
273 | func (av *AnyValue) ToString() string
274 | ##### 转成bool类型
275 | func (av *AnyValue) ToBool() bool
276 | ##### 转成map[string]string类型
277 | func (av *AnyValue) ToStringMap() map[string]string
278 | ##### 更多方法使用 *base.AnyValue 调用
279 | ...
280 | ### 数据库
281 | #### 配置项 xxx/config/dev/database.ini
282 | [plus_center] // 配置分组,必填
283 | ; 主库
284 | master.driverName = mysql // 驱动名称
285 | master.dataSourceName = root:root@tcp(127.0.0.1:3306)/dbName?charset=utf8 // 连接参数
286 | master.maxIdleConn = 100 // 空闲连接数
287 | master.maxOpenConn = 100 // 最大连接数
288 |
289 | ; 从库
290 | slave.driverName = mysql
291 | slave.dataSourceName = root:root@tcp(127.0.0.1:3306)/dbName?charset=utf8
292 | slave.maxIdleConn = 100
293 | slave.maxOpenConn = 100
294 | #### Model的示例
295 | ```go
296 | package mysql
297 |
298 | import (
299 | "github.com/go-touch/regin/app/db"
300 | )
301 |
302 | type Users struct{
303 | Id string `field:id`
304 | Username string `field:"username"`
305 | }
306 |
307 | // 注册model
308 | func init() {
309 | db.RegisterModel(&Users{}, "Users")
310 | }
311 |
312 | // 数据库标识(此方法可重构,用于切换数据库,默认master)
313 | func (this *Users) Identify() string {
314 | return "plus_center.master"
315 | }
316 |
317 | // 数据库表名(此方法可重构,用于切换数据表)
318 | func (this *Users) TableName() string {
319 | return "users"
320 | }
321 |
322 | // 自定义方法
323 | func (this *Users) Method() string {
324 | ret := db.Model("Users").FetchAll(func(dao *db.Dao) {
325 | dao.Where("id", 202)
326 | })
327 | }
328 | ```
329 | ```go
330 | (this *Users) Identify() string //设置数据库连接标识,对应数据库配置的key链关系
331 | ```
332 | ```go
333 | (this *Users) TableName() string // 设置真实数据表名,如未设置则默认结构体名称(注: AdminUser 会转成 admin_user)
334 | ```
335 | #### 使用Model查询一条记录示例:
336 | ```go
337 | 第一种方式:
338 | row := db.Model(&Users{}).FetchRow(func(dao *db.Dao) {
339 | dao.Where("id", 1)
340 | })
341 |
342 | 第二种方式:
343 | // 注册 Model, 第一个参数传入model实例化的指针, 第二个可选参数,用于起别名方便调用,不传名称默认为 mysql.Users .
344 | db.RegisterModel(&Users{}, "Users")
345 |
346 | // 使用别名获取 Dao 数据对象并使用 FetchRow 方法查询
347 | row := db.Model("Users").FetchRow(func(dao *db.Dao) {
348 | dao.Where("id", 1)
349 | })
350 | ```
351 | ```go
352 | Node: 推荐使用第二种方式,可以在初始化函数 init 批量注册model,这样在系统加载的时候仅调用一次注入容器.
353 | ```
354 | #### db.Dao方法(举例均采用上述的第二种方式)
355 | ##### 获取Dao数据对象.
356 | ```go
357 | db.Model(userModel interface{})
358 |
359 | 调用示例:
360 | dao := db.Model(&Users{})
361 | 或
362 | db.RegisterModel(&Users{}, "Users")
363 | dao := db.Model("Users")
364 | ```
365 | ##### 设置表名.(通常无需调用,注册model时已获取表名)
366 | ```go
367 | (d *Dao) Table(tableName string) *Dao
368 |
369 | 示例:
370 | db.Model("Users").Table("message")
371 | ```
372 | ##### 设置表字段.参数field: 可为string或[]string
373 | ```go
374 | (d *Dao) Field(field interface{}) *Dao
375 |
376 | 示例:
377 | db.Model("Users").Field("a,b,c,d")
378 | db.Model("Users").Field([]string{"a,b,c,d"})
379 | ```
380 | ##### 设置查询条件. 参数field:字段名,参数value:字段值,参数linkSymbol:连接符(and[or] 默认and)
381 | ```go
382 | (d *Dao) Where(field interface{}, value interface{}, linkSymbol ...string) *Dao
383 |
384 | 示例:
385 | db.Model("Users").Where("id", 1)
386 | ```
387 | ##### 批量设置查询条件,和where类似. 参数是 key-value 的 map
388 | ```go
389 | (d *Dao) WhereMap(fieldMap map[string]interface{}, linkSymbol ...string) *Dao
390 |
391 | 示例:
392 | db.Model("Users").WhereMap(map[string]interface{}{"id":1})
393 | ```
394 | ##### 绑定数据,insert[update]时使用到.
395 | ```go
396 | (d *Dao) Values(valueMap map[string]interface{}) *Dao
397 |
398 | 示例:
399 | db.Model("Users").Values(map[string]interface{}{"username":"zhangsan"})
400 | ```
401 | ##### 设置排序. 参数不定
402 | ```go
403 | (d *Dao) Order(expr ...string) *Dao
404 |
405 | 示例:
406 | db.Model("Users").Order("id ASC","username Desc")
407 | ```
408 | ##### 批量设置排序. 与Order类似,参数为[]string
409 | ```go
410 | (d *Dao) OrderSlice(expr []string) *Dao
411 |
412 | 示例:
413 | db.Model("Users").OrderSlice([]string{"id ASC","username Desc"})
414 | ```
415 | ##### 设置查询检索记录行. 参数不定,对应sql语句 limit m,n
416 | ```go
417 | (d *Dao) Limit(limit ...int) *Dao
418 |
419 | 示例:
420 | db.Model("Users").Limit(1,10)
421 | ```
422 | ##### 是否返回sql. 需要在执行增删改查方法前调用
423 | ```go
424 | (d *Dao) Sql() *Dao
425 |
426 | 示例:
427 | ret := db.Model("Users").FetchRow(func(dao *db.Dao) {
428 | dao.Sql()
429 | })
430 | fmt.Println(ret.ToString()) // 打印字符串sql语句
431 | ```
432 | ##### 查询一条记录,返回 \*db.AnyValue,可实现数据转换.参数userFunc:用户回调函数,接收参数为 \*db.Dao
433 | ```go
434 | (d *Dao) FetchRow(userFunc ...UserFunc) *AnyValue
435 |
436 | 示例:
437 | ret := db.Model("Users").FetchRow(func(dao *db.Dao) {
438 | dao.Where("id", 1)
439 | })
440 | ret.ToError() // 可获取错误信息,如果返回nil,则说明无错误发生
441 | ret.ToStringMap // 返回 map[string]string 结构的一条数据
442 | ```
443 | ##### 查询多条记录,返回 \*db.AnyValue,可实现数据转换. 参数userFunc:用户回调函数,接收参数为 \*db.Dao
444 | ```go
445 | (d *Dao) FetchAll(userFunc ...UserFunc) *AnyValue
446 |
447 | 示例:
448 | ret := db.Model("Users").FetchAll(func(dao *db.Dao) {
449 | dao.Where("id", 1)
450 | })
451 | ret.ToError() // 可获取错误信息,如果返回nil,则说明无错误发生
452 | ret.ToStringMap // 返回 map[string]string 结构的一条数据
453 | ```
454 | ##### 插入一条记录,返回 \*db.AnyValue,可实现数据转换. 参数userFunc:用户回调函数,接收参数为 \*db.Dao
455 | ```go
456 | (d *Dao) Insert(userFunc ...UserFunc) *AnyValue
457 |
458 | 示例:
459 | ret := db.Model("Users").Insert(func(dao *db.Dao) {
460 | dao.Values(map[string]interface{}{"username":"zhangsan"})
461 | })
462 | ret.ToError() // 可获取错误信息,如果返回nil,则说明无错误发生
463 | ret.ToLastInsertId() // 返回最后插入的主键id
464 | ```
465 | ##### 更新一条记录,返回 \*db.AnyValue,可实现数据转换. 参数userFunc:用户回调函数,接收参数为 \*db.Dao
466 | ```go
467 | (d *Dao) Update(userFunc ...UserFunc) *AnyValue
468 |
469 | 示例:
470 | ret := db.Model("Users").Update(func(dao *db.Dao) {
471 | dao.Values(map[string]interface{}{"username":"zhangsan"})
472 | })
473 | ret.ToError() // 可获取错误信息,如果返回nil,则说明无错误发生
474 | ret.ToAffectedRows() // 返回受影响行数
475 | ```
476 | ##### 删除一条数据,返回 \*db.AnyValue,可实现数据转换. 参数userFunc:用户回调函数,接收参数为 \*db.Dao
477 | ```go
478 | (d *Dao) DELETE(userFunc ...UserFunc) *AnyValue
479 |
480 | 示例:
481 | ret := db.Model("Users").DELETE(func(dao *db.Dao) {
482 | dao.Where("id", 1)
483 | })
484 | ret.ToError() // 可获取错误信息,如果返回nil,则说明无错误发生
485 | ret.ToAffectedRows() // 返回受影响行数
486 | ```
487 | #### 完整数据库操作实例(假设model已注册)
488 | ##### 查询一条数据
489 | ```go
490 | // 链式操作
491 | ret := db.Model("Users").Field("username").Where("id", 1).FetchRow()
492 |
493 | // 匿名函数回调操作
494 | ret := db.Model("Users").FetchRow(func(dao *db.Dao) {
495 | dao.Field("username")
496 | dao.Where("id", 1)
497 | })
498 | ret.ToError()
499 | ret.ToStringMap()
500 | ```
501 | ##### 查询多条数据
502 | ```go
503 | // 链式操作
504 | ret := db.Model("Users").Field("username").Where("id", 1).FetchAll()
505 |
506 | // 匿名函数回调操作
507 | ret := db.Model("Users").FetchAll(func(dao *db.Dao) {
508 | dao.Field("username")
509 | dao.Where("id", 1)
510 | })
511 | ret.ToError()
512 | ret.ToStringMapSlice()
513 | ```
514 | ##### 插入一条数据
515 | ```go
516 | // 链式操作
517 | ret := db.Model("Users").Values(map[string]interface{}{"username":"zhangsan"}).Insert()
518 |
519 | // 匿名函数回调操作
520 | ret := db.Model("Users").Insert(func(dao *db.Dao) {
521 | dao.Values(map[string]interface{}{"username":"zhangsan"})
522 | })
523 | ret.ToError()
524 | ret.ToLastInsertId()
525 | ```
526 | ##### 更新一条数据
527 | ```go
528 | // 链式操作
529 | ret := db.Model("Users").Values(map[string]interface{}{"username":"zhangsan"}).Where("id", 1).Update()
530 |
531 | // 匿名函数回调操作
532 | ret := db.Model("Users").Update(func(dao *db.Dao) {
533 | dao.Values(map[string]interface{}{"username":"zhangsan"})
534 | dao.Where("id", 1)
535 | })
536 | ret.ToError()
537 | ret.ToAffectedRows()
538 | ```
539 | ##### 删除一条数据
540 | ```go
541 | // 链式操作
542 | ret := db.Model("Users").Where("id", 1).DELETE()
543 |
544 | // 匿名函数回调操作
545 | ret := db.Model("Users").DELETE(func(dao *db.Dao) {
546 | dao.Where("id", 1)
547 | })
548 | ret.ToError()
549 | ret.ToAffectedRows()
550 | ```
551 | ### Redis
552 |
553 | #### 配置项 xxx/config/dev/redis.ini
554 | [plus_center] // // 配置分组,必填
555 | master.host = 127.0.0.1:6379 // 主机端口
556 | master.password = "" // 密码
557 | master.db = 10 // 库标
558 | master.MaxIdle = 16 // 空闲连接数
559 | master.MaxActive = 32 // 最大连接数
560 | master.IdleTimeout = 120 // 超时时间
561 |
562 | #### RedisModel的示例
563 | ```go
564 | package redis
565 |
566 | type TestModel struct {}
567 |
568 | // Redis库标识
569 | func (b *Base) Identify() string {
570 | return "plus_center.master"
571 | }
572 | ```
573 | ```go
574 | (this *Users) Identify() string // 设置redis连接参数,对应Redis配置的key链关系
575 | ```
576 | #### Redis的使用示例:
577 | ##### 传入一个model获取 Redis Dao 实例
578 | ```go
579 | RedisModel(model interface{}) *RedisDao
580 |
581 | 示例:
582 | redisDao := RedisModel(&TestModel{})
583 | ```
584 | ##### 获取连接池对象,开发者可通过此返回值
585 | ```go
586 | (rd *RedisDao) Pool() *redis.Pool
587 |
588 | 示例:
589 | pool := RedisModel(&TestModel{}).Pool()
590 | ```
591 | ##### 执行redis命令,返回\*base.AnyValue,可进行类型转换. 参数name:命令名称 args:该命令对应的参数
592 | ```go
593 | (rd *RedisDao) Command(name string, args ...interface{}) *base.AnyValue
594 |
595 | 示例:
596 | RedisModel(&TestModel{}).Command("SET","username","admin")
597 | RedisModel(&TestModel{}).Command("HSET","user","username","admin")
598 | ret := RedisModel(&TestModel{}).Command("GET","username")
599 | ret.ToError() // 可获取错误信息,如果返回nil,则说明无错误发生
600 | ret.ToAffectedRows() // 返回受影响行数
601 | ```
602 | ### Utils工具
603 | #### Form表单验证
604 | ##### Form Model结构体示例
605 | ```go
606 | type PlusUsers struct {
607 | UserId int `key:"user_id" require:"true" length:"0|5"`
608 | Account string `key:"account" require:"true" length:"0|20"`
609 | }
610 | ```
611 | ##### Form验证器的使用
612 | ```go
613 | 第一种方式:
614 | result := validator.Form(&PlusUsers{}).Verify(&map[string]interface{}{
615 | "user_id": 1,
616 | })
617 |
618 | 第二种方式:
619 | validator.RegisterForm(&PlusUsers{}, "PlusUsers")
620 | result := validator.Form("PlusUsers").Verify(&map[string]interface{}{
621 | "user_id": 1,
622 | })
623 | ```
624 | ##### Form验证器方法:
625 | ##### 获取一个Form Dao
626 | ```go
627 | // 获取 Form Dao
628 | Form(userModel interface{}) *FormHandle
629 |
630 | 示例:
631 | formDao := validator.Form(&PlusUsers{})
632 | ```
633 | ##### 获取一个Form Dao(另一种方式)
634 | ```go
635 | // 注册 Form Model
636 | RegisterForm(userModel interface{}, alias ...string)
637 |
638 | // 获取 Form Dao
639 | Form(userModel interface{}) *FormHandle
640 |
641 | 示例:
642 | validator.RegisterForm(&PlusUsers{}, "PlusUsers")
643 | formDao := validator.Form("PlusUsers")
644 | ```
645 | ##### 验证一个*map[string]interface{}
646 | ```go
647 | (mh *FormHandle) Verify(vMap *map[string]interface{}) []*tag.Result
648 | ```
649 | #### Curl使用
650 | ##### GET请求
651 | ##### 获取一个 *curl.GetCaller
652 | ```go
653 | func Get() *GetCaller
654 | ```
655 | ##### 设置header信息
656 | ```go
657 | func (gc *GetCaller) Header(header map[string]string)
658 | ```
659 | ##### 发送一个GET请求
660 | ```go
661 | func (gc *GetCaller) Call(url string, args ...map[string]interface{}) *multitype.AnyValue
662 | ```
663 | ##### GET请求示例:
664 | ```go
665 | get := curl.Get()
666 |
667 | // 如需设置header, 则使用此方法
668 | get.Header(map[string]string{"Authorization":"Basic MTAwMToxMjM0NTY="})
669 |
670 | // 发送请求
671 | get.Call("http://www.baidu.com",map[string]interface{}{
672 | "user_id": 1,
673 | "username": "admin",
674 | "password": "123456",
675 | })
676 | ```
677 | ##### POST请求
678 | ##### 获取一个 *curl.PostCaller
679 | ```go
680 | func Post() *PostCaller
681 | ```
682 | ##### 设置header信息
683 | ```go
684 | func (pc *PostCaller) Header(header map[string]string)
685 | ```
686 | ##### 发送一个POST请求
687 | ```go
688 | func (pc *PostCaller) Call(url string, args ...interface{}) *multitype.AnyValue
689 | ```
690 | ##### POST请求示例:
691 | ```go
692 | post := curl.Post()
693 |
694 | // 如需设置header, 则使用此方法
695 | post.Header(map[string]string{"Authorization":"Basic MTAwMToxMjM0NTY="})
696 |
697 | // 设置 json 请求 header, 默认 header {"Content-Type": "application/x-www-form-urlencoded"}
698 | post.Header(map[string]string{"Content-Type": "application/json"})
699 |
700 | // 发送请求(key-value形式)
701 | post.Call("http://www.baidu.com",map[string]interface{}{
702 | "user_id": 1,
703 | "username": "admin",
704 | "password": "123456",
705 | })
706 |
707 | // 发送请求(json串形式)
708 | post.Call("http://www.baidu.com",`{"user_id":1,"username":"admin","password":"123456"}`)
709 | ```
710 |
711 |
712 |
713 |
714 |
715 |
716 |
717 |
718 |
719 |
720 |
721 |
722 |
--------------------------------------------------------------------------------
/app/cache/abstract.go:
--------------------------------------------------------------------------------
1 | package cache
2 |
3 | import (
4 | "errors"
5 | "strconv"
6 | "strings"
7 | )
8 |
9 | type Abstract struct {
10 | config interface{}
11 | }
12 |
13 | // Init config.
14 | func (a *Abstract) Init(config map[string]interface{}) {
15 | a.config = config
16 | }
17 |
18 | // 读取配置
19 | func (a *Abstract) GetConfig(arg string) (config map[string]string, err error) {
20 | config = make(map[string]string)
21 |
22 | // 解析参数
23 | argGroup := strings.Split(arg, ".")
24 | if argGroup[0] == "" {
25 | return config, errors.New("the database's identify is not set")
26 | }
27 |
28 | // 遍历处理
29 | configTmp := a.config
30 | for _, key := range argGroup {
31 | switch t := configTmp.(type) {
32 | case nil:
33 | configTmp = map[string]string{}
34 | case map[string]string:
35 | break
36 | case map[string]interface{}:
37 | if value, ok := configTmp.(map[string]interface{})[key]; ok {
38 | configTmp = value
39 | } else {
40 | configTmp = map[string]string{}
41 | }
42 | case []interface{}:
43 | if intKey, err := strconv.Atoi(key); err == nil {
44 | configTmp = configTmp.([]interface{})[intKey]
45 | }
46 | default:
47 | _ = t
48 | configTmp = map[string]string{}
49 | break
50 | }
51 | }
52 |
53 | // 类型断言并处理
54 | if value, ok := configTmp.(map[string]interface{}); ok {
55 | for k, v := range value {
56 | config[k] = v.(string)
57 | }
58 | } else { // 类型断言并处理
59 | value := configTmp.(map[string]string)
60 | if value != nil {
61 | config = value
62 | } else {
63 | config = map[string]string{}
64 | }
65 | }
66 | return config, nil
67 | }
68 |
--------------------------------------------------------------------------------
/app/cache/redis.go:
--------------------------------------------------------------------------------
1 | package cache
2 |
3 | import (
4 | "errors"
5 | "github.com/garyburd/redigo/redis"
6 | "strconv"
7 | "time"
8 | )
9 |
10 | type RedisCache struct {
11 | Abstract
12 | container map[string]*redis.Pool
13 | }
14 |
15 | // Define RedisDispatch.
16 | var Redis *RedisCache
17 |
18 | func init() {
19 | Redis = &RedisCache{
20 | container: make(map[string]*redis.Pool),
21 | }
22 | }
23 |
24 | // Get redis pool object.
25 | func (rc *RedisCache) Pool(identify string) *redis.Pool {
26 | if redisPool, ok := rc.container[identify]; ok {
27 | return redisPool
28 | }
29 | // Get config
30 | config, err := rc.GetConfig(identify)
31 | if err != nil {
32 | panic(err)
33 | }
34 |
35 | // 连接参数
36 | paramString := map[string]string{"host": "", "password": ""}
37 | for key := range paramString {
38 | if value, ok := config[key]; ok {
39 | paramString[key] = value
40 | }
41 | }
42 |
43 | // Redis配置参数
44 | paramInt := map[string]int{"db": 0, "MaxIdle": 0, "MaxActive": 0, "IdleTimeout": 0}
45 | for key := range paramInt {
46 | if value, ok := config[key]; ok {
47 | if v, err := strconv.Atoi(value); err == nil {
48 | paramInt[key] = v
49 | }
50 | }
51 | }
52 |
53 | // 服务地址
54 | if paramString["host"] == "" {
55 | panic(errors.New("the config's host can't be empty"))
56 | }
57 |
58 | // 创建连接池
59 | rc.container[identify] = &redis.Pool{
60 | MaxIdle: paramInt["MaxIdle"],
61 | MaxActive: paramInt["MaxActive"],
62 | IdleTimeout: time.Duration(paramInt["IdleTimeout"]),
63 | Dial: func() (redis.Conn, error) {
64 | dialOption := []redis.DialOption{
65 | redis.DialReadTimeout(time.Duration(paramInt["IdleTimeout"]) * time.Millisecond),
66 | redis.DialWriteTimeout(time.Duration(paramInt["IdleTimeout"]) * time.Millisecond),
67 | redis.DialConnectTimeout(time.Duration(paramInt["IdleTimeout"]) * time.Millisecond),
68 | redis.DialDatabase(paramInt["db"]),
69 | }
70 | if paramString["password"] != "" {
71 | dialOption = append(dialOption, redis.DialPassword(paramString["password"]))
72 | }
73 | return redis.Dial("tcp", paramString["host"], dialOption...)
74 | },
75 | }
76 | return rc.container[identify]
77 | }
78 |
--------------------------------------------------------------------------------
/app/cache/redis_dao.go:
--------------------------------------------------------------------------------
1 | package cache
2 |
3 | import (
4 | "errors"
5 | "github.com/garyburd/redigo/redis"
6 | "github.com/go-touch/mtype"
7 | )
8 |
9 | type Identify interface {
10 | Identify() string // Redis库标识(此方法可重构,用于切换库,默认master)
11 | }
12 |
13 | type RedisDao struct {
14 | pool *redis.Pool
15 | }
16 |
17 | // 获取RedisDao对象
18 | func RedisModel(model interface{}) *RedisDao {
19 | var redisPool *redis.Pool
20 | if ptr, ok := model.(Identify); !ok {
21 | panic(errors.New("need an pointer model"))
22 | } else {
23 | redisPool = Redis.Pool(ptr.Identify())
24 | }
25 | return &RedisDao{pool: redisPool}
26 | }
27 |
28 | // 获取连接池对象
29 | func (rd *RedisDao) Pool() *redis.Pool {
30 | return rd.pool
31 | }
32 |
33 | // 执行redis命令
34 | func (rd *RedisDao) Command(name string, args ...interface{}) *mtype.AnyValue {
35 | redisConn := rd.Pool().Get()
36 | defer func() { _ = redisConn.Close() }()
37 | result, err := redisConn.Do(name, args...)
38 | if err != nil {
39 | return mtype.Eval(err)
40 | }
41 | return mtype.Eval(result)
42 | }
43 |
--------------------------------------------------------------------------------
/app/core/config.go:
--------------------------------------------------------------------------------
1 | package core
2 |
3 | import (
4 | "github.com/go-touch/mtype"
5 | "github.com/go-touch/regin/utils"
6 | "strconv"
7 | "strings"
8 | )
9 |
10 | // Define Config.
11 | type Config struct {
12 | FileFormat string
13 | config map[string]interface{}
14 | }
15 |
16 | // Init config
17 | func (c *Config) Init(configPath string) {
18 | c.config = make(map[string]interface{})
19 |
20 | // Scan dir list & Load config
21 | configFiles := utils.File.ScanDir(configPath)
22 | for _, file := range configFiles {
23 | fileSplit := strings.Split(file.Name(), ".")
24 | filePath := utils.File.JoinPath(configPath, file.Name())
25 |
26 | // 配置类型过滤
27 | if fileSplit[1] == c.FileFormat {
28 | if config, err := utils.ConfigParser.ParserToMap(c.FileFormat, filePath); err != nil {
29 | panic(err.Error())
30 | } else {
31 | c.config[fileSplit[0]] = config
32 | }
33 | }
34 | }
35 | }
36 |
37 | // Get config.
38 | func (c *Config) GetConfig(args ...string) *mtype.AnyValue {
39 | // If args is nil
40 | if args == nil {
41 | return mtype.Eval(c.config)
42 | }
43 |
44 | // Parser args
45 | argsGroup := strings.Split(args[0], ".")
46 | if argsGroup[0] == "" {
47 | return mtype.Eval(c.config)
48 | }
49 |
50 | // Walk config.
51 | var config interface{} = c.config
52 | for _, key := range argsGroup {
53 | switch config.(type) {
54 | case map[string]string:
55 | if c, ok := config.(map[string]string)[key]; ok {
56 | config = c
57 | }
58 | case map[string]interface{}:
59 | if c, ok := config.(map[string]interface{})[key]; ok {
60 | config = c
61 | }
62 | case []interface{}:
63 | intKey, err := strconv.Atoi(key)
64 | if err != nil {
65 | continue
66 | }
67 | if c := config.([]interface{})[intKey]; c != nil {
68 | config = c
69 | }
70 | default:
71 | break
72 | }
73 | }
74 | return mtype.Eval(config)
75 | }
76 |
--------------------------------------------------------------------------------
/app/core/exception.go:
--------------------------------------------------------------------------------
1 | package core
2 |
3 | import (
4 | "runtime"
5 | "strings"
6 | "fmt"
7 | "strconv"
8 | )
9 |
10 | type Exception struct {
11 | callback func(string) error
12 | }
13 |
14 | func (e *Exception) Init(stackString string) error {
15 | return e.callback(stackString)
16 | }
17 |
18 | // 捕获异常信息
19 | func (e *Exception) Catch() error {
20 | if r := recover(); r != nil {
21 | var arr [4096]byte
22 | var stackString string
23 | buf := arr[:]
24 | n := runtime.Stack(buf, false)
25 |
26 | if n > 0 {
27 | stackString = e.Stack(r, buf)
28 | }
29 | _ = stackString
30 | }
31 | return nil
32 | }
33 |
34 | // Handle Stack message.
35 | func (e *Exception) Stack(err interface{}, buf []byte) string {
36 | var stackSlice []string
37 | var msg string
38 |
39 | // Filename、line
40 | if _, srcName, line, ok := runtime.Caller(3); ok {
41 | msg = fmt.Sprintf("[Error]File:%s Line:%s Msg:%s \nMethod Stack meassage:", srcName, strconv.Itoa(line), err)
42 | stackSlice = append(stackSlice, msg)
43 | } else {
44 | msg = fmt.Sprintf("[Error]Msg:%s \nMethod Stack meassage:", err)
45 | stackSlice = append(stackSlice, msg)
46 | }
47 |
48 | // Handle data.
49 | stringStack := string(buf) // Convert to string
50 | tmpStack := strings.Split(stringStack, "\n") // Split to []string by \n
51 | var receiveStack []string
52 |
53 | for _, v := range tmpStack {
54 | receiveStack = append(receiveStack, strings.TrimSpace(v))
55 | }
56 | for i, j, k := 0, 0, len(receiveStack)-1; i < k; i += 2 {
57 | stackSlice = append(stackSlice, "["+strconv.Itoa(j)+"]"+receiveStack[i]+" "+receiveStack[i+1])
58 |
59 | if j == 10 {
60 | stackSlice = append(stackSlice, "...")
61 | break
62 | }
63 | j ++
64 | }
65 | return strings.Join(stackSlice, "\n")
66 | }
--------------------------------------------------------------------------------
/app/core/logger.go:
--------------------------------------------------------------------------------
1 | package core
2 |
3 | import (
4 | "fmt"
5 | "github.com/go-touch/regin/utils"
6 | "path/filepath"
7 | "strings"
8 | "time"
9 | )
10 |
11 | const (
12 | Info string = "Info"
13 | Warning string = "Warning"
14 | Error string = "Error"
15 | )
16 |
17 | type Logger struct {
18 | pattern string // local、remote
19 | logPath string
20 | }
21 |
22 | // Init Logger
23 | func (l *Logger) Init(pattern string, logPath string) {
24 | l.pattern = pattern
25 | l.logPath = logPath
26 | }
27 |
28 | // Record log message by local.
29 | func (l *Logger) Local(logType string, content interface{}, path ...string) error {
30 | fileName := l.Filename(logType, path...)
31 | if err := utils.Log.Writer(fileName, content); err != nil {
32 | fmt.Println(err.Error())
33 | }
34 | return nil
35 | }
36 |
37 | // 获取文件名称
38 | func (l *Logger) Filename(logType string, path ...string) string {
39 | fileSlice := []string{l.logPath}
40 |
41 | if path != nil {
42 | fileSlice = append(fileSlice, path...)
43 | }
44 | // 文件扩展名
45 | extName := time.Now().Format("2006-01-02") + "-" + logType + ".txt"
46 | fileSlice = append(fileSlice, extName)
47 | return strings.Join(fileSlice, string(filepath.Separator))
48 | }
49 |
--------------------------------------------------------------------------------
/app/db/any_value.go:
--------------------------------------------------------------------------------
1 | package db
2 |
3 | import (
4 | "database/sql"
5 | "fmt"
6 | "strconv"
7 | )
8 |
9 | // 定义类型常量
10 | const (
11 | Int = "Int" // 类型: int
12 | Int64 = "Int64" // 类型: int64
13 | Byte = "Byte" // 类型: byte
14 | String = "String" // 类型: string
15 | Bool = "Bool" // 类型: bool
16 | IntSlice = "IntSlice" // 类型: []int
17 | ByteSlice = "ByteSlice" // 类型: []byte
18 | StringSlice = "StringSlice " // 类型: []string
19 | AnySlice = "AnySlice " // 类型: []interface{}
20 | StringMapSlice = "StringMapSlice" // 类型: []map[string]string
21 | AnyMapSlice = "AnyMapSlice" // 类型: []map[string]interface{}
22 | StringMap = "StringMap" // 类型: map[string]string
23 | AnyMap = "AnyMap" // 类型: map[string]interface{}
24 | SqlResult = "SqlResult" // 类型: sql.result
25 | Error = "Error" // 类型: error
26 | )
27 |
28 | type AnyValue struct {
29 | value interface{}
30 | }
31 |
32 | // 声明一个存储任意类型数据的结构体,然后可以进行类型转换
33 | func Eval(value interface{}) *AnyValue {
34 | return &AnyValue{value: value}
35 | }
36 |
37 | // 返回预定义类型
38 | func (av *AnyValue) getType() string {
39 | switch t := av.value.(type) {
40 | case int:
41 | return Int
42 | case int64:
43 | return Int64
44 | case byte:
45 | return Byte
46 | case string:
47 | return String
48 | case bool:
49 | return Bool
50 | case []int:
51 | return IntSlice
52 | case []byte:
53 | return ByteSlice
54 | case []string:
55 | return StringSlice
56 | case []interface{}:
57 | return AnySlice
58 | case []map[string]string:
59 | return StringMapSlice
60 | case []map[string]interface{}:
61 | return AnyMapSlice
62 | case map[string]string:
63 | return StringMap
64 | case map[string]interface{}:
65 | return AnyMap
66 | case sql.Result:
67 | return SqlResult
68 | case error:
69 | return Error
70 | default:
71 | _ = t
72 | }
73 | return ""
74 | }
75 |
76 | // 打印原值信息
77 | func (av *AnyValue) PrintValue() {
78 | fmt.Printf("[orgin value]%v\n", av.value)
79 | return
80 | }
81 |
82 | // 获取原值
83 | func (av *AnyValue) ToValue() interface{} {
84 | return av.value
85 | }
86 |
87 | // 转换成 - 操作数据库返回错误接口
88 | func (av *AnyValue) ToError() error {
89 | switch av.getType() {
90 | case SqlResult:
91 | if _, err := av.value.(sql.Result).RowsAffected(); err != nil {
92 | return err
93 | }
94 | if _, err := av.value.(sql.Result).LastInsertId(); err != nil {
95 | return err
96 | }
97 | case Error:
98 | return av.value.(error)
99 | }
100 | return nil
101 | }
102 |
103 | // 转换成 int
104 | func (av *AnyValue) ToInt() int {
105 | switch av.getType() {
106 | case String:
107 | if v, err := strconv.Atoi(av.value.(string)); err != nil {
108 | return 0
109 | } else {
110 | return v
111 | }
112 | case Int:
113 | return av.value.(int)
114 | case Int64:
115 | return int(av.value.(int64))
116 | }
117 | return 0
118 | }
119 |
120 | // 转换成 - 插入数据库记录主键id
121 | func (av *AnyValue) ToLastInsertId() int {
122 | switch av.getType() {
123 | case SqlResult:
124 | if v, err := av.value.(sql.Result).LastInsertId(); err == nil {
125 | return int(v)
126 | }
127 | }
128 | return 0
129 | }
130 |
131 | // 转换成 - 修改数据库记录受影响行数
132 | func (av *AnyValue) ToAffectedRows() int {
133 | switch av.getType() {
134 | case SqlResult:
135 | if v, err := av.value.(sql.Result).RowsAffected(); err == nil {
136 | return int(v)
137 | }
138 | }
139 | return 0
140 | }
141 |
142 | // 转换成 string
143 | func (av *AnyValue) ToString() string {
144 | switch av.getType() {
145 | case String:
146 | return av.value.(string)
147 | case Int:
148 | strconv.Itoa(av.value.(int))
149 | }
150 | return ""
151 | }
152 |
153 | // 转换成 map[string]string
154 | func (av *AnyValue) ToStringMap() map[string]string {
155 | rValue := map[string]string{}
156 | switch av.getType() {
157 | case StringMap:
158 | rValue = av.value.(map[string]string)
159 | case AnyMap:
160 | for key, value := range av.value.(map[string]interface{}) {
161 | if dv, ok := value.(string); ok {
162 | rValue[key] = dv
163 | } else if dv, ok := value.([]byte); ok {
164 | rValue[key] = string(dv)
165 | } else if dv, ok := value.(int64); ok {
166 | rValue[key] = strconv.Itoa(int(dv))
167 | } else if value == nil {
168 | rValue[key] = ""
169 | }
170 | }
171 | }
172 | return rValue
173 | }
174 |
175 | // 转换成 map[string]interface{}
176 | func (av *AnyValue) ToAnyMap() map[string]interface{} {
177 | rValue := map[string]interface{}{}
178 | switch av.getType() {
179 | case AnyMap:
180 | for key, value := range av.value.(map[string]interface{}) {
181 | if dv, ok := value.([]byte); ok {
182 | rValue[key] = string(dv)
183 | } else if dv, ok := value.(int64); ok {
184 | rValue[key] = strconv.Itoa(int(dv))
185 | } else if value == nil {
186 | rValue[key] = ""
187 | }
188 | }
189 | }
190 | return rValue
191 | }
192 |
193 | // 转换成 []map[string]interface
194 | func (av *AnyValue) ToAnyMapSlice() []map[string]interface{} {
195 | rValue := make([]map[string]interface{}, 0)
196 | switch av.getType() {
197 | case AnyMapSlice:
198 | for _, value := range av.value.([]map[string]interface{}) {
199 | subValue := map[string]interface{}{}
200 | for k, v := range value {
201 | if dv, ok := v.([]byte); ok {
202 | subValue[k] = string(dv)
203 | } else if dv, ok := v.(int64); ok {
204 | subValue[k] = int(dv)
205 | } else if v == nil {
206 | subValue[k] = ""
207 | }
208 | }
209 | rValue = append(rValue, subValue)
210 | }
211 | }
212 | return rValue
213 | }
214 |
215 | // 转换成 []map[string]string
216 | func (av *AnyValue) ToStringMapSlice() []map[string]string {
217 | rValue := make([]map[string]string, 0)
218 | switch av.getType() {
219 | case AnyMapSlice:
220 | for _, value := range av.value.([]map[string]interface{}) {
221 | subValue := map[string]string{}
222 | for k, v := range value {
223 | if dv, ok := v.([]byte); ok {
224 | subValue[k] = string(dv)
225 | } else if dv, ok := v.(int64); ok {
226 | subValue[k] = strconv.Itoa(int(dv))
227 | } else if v == nil {
228 | subValue[k] = ""
229 | }
230 | }
231 | rValue = append(rValue, subValue)
232 | }
233 | }
234 | return rValue
235 | }
236 |
--------------------------------------------------------------------------------
/app/db/config.go:
--------------------------------------------------------------------------------
1 | package db
2 |
3 | import (
4 | "errors"
5 | "strconv"
6 | "strings"
7 | )
8 |
9 | // 日志回调函数
10 | type LogWriter func(map[string]interface{})
11 |
12 | // 配置存储容器
13 | type ConfigStorage struct {
14 | config interface{}
15 | LogWriter LogWriter
16 | }
17 |
18 | var Config *ConfigStorage
19 |
20 | func init() {
21 | Config = &ConfigStorage{}
22 | }
23 |
24 | // 初始化数据库配置
25 | func (cs *ConfigStorage) Init(config map[string]interface{}) {
26 | cs.config = config
27 | }
28 |
29 | // 初始化日志方法
30 | func (cs *ConfigStorage) InitLogWriter(logWriter LogWriter) {
31 | cs.LogWriter = logWriter
32 | }
33 |
34 | // 获取配置
35 | func (cs *ConfigStorage) GetConfig(arg string) (config map[string]string, err error) {
36 | config = make(map[string]string)
37 |
38 | // 解析参数
39 | argGroup := strings.Split(arg, ".")
40 | if argGroup[0] == "" {
41 | return config, errors.New("the database's identify is not set")
42 | }
43 |
44 | // 遍历处理
45 | configTmp := cs.config
46 | for _, key := range argGroup {
47 | switch t := configTmp.(type) {
48 | case nil:
49 | configTmp = map[string]string{}
50 | case map[string]string:
51 | break
52 | case map[string]interface{}:
53 | if value, ok := configTmp.(map[string]interface{})[key]; ok {
54 | configTmp = value
55 | } else {
56 | configTmp = map[string]string{}
57 | }
58 | case []interface{}:
59 | if intKey, err := strconv.Atoi(key); err == nil {
60 | configTmp = configTmp.([]interface{})[intKey]
61 | }
62 | default:
63 | _ = t
64 | configTmp = map[string]string{}
65 | break
66 | }
67 | }
68 |
69 | // 类型断言并处理
70 | if value, ok := configTmp.(map[string]interface{}); ok {
71 | for k, v := range value {
72 | config[k] = v.(string)
73 | }
74 | } else { // 类型断言并处理
75 | value := configTmp.(map[string]string)
76 | if value != nil {
77 | config = value
78 | } else {
79 | config = map[string]string{}
80 | }
81 | }
82 | return config, nil
83 | }
84 |
--------------------------------------------------------------------------------
/app/db/dao.go:
--------------------------------------------------------------------------------
1 | package db
2 |
3 | import (
4 | "database/sql"
5 | "errors"
6 | "github.com/go-touch/regin/app/db/model"
7 | "github.com/go-touch/regin/app/db/query"
8 | "regexp"
9 | "strings"
10 | )
11 |
12 | // 用户自定义函数
13 | type UserFunc func(*Dao)
14 |
15 | // 数据对象Dao
16 | type Dao struct {
17 | table *model.Table
18 | query query.BaseQuery
19 | isSQL bool
20 | isTx bool
21 | }
22 |
23 | // 注册model
24 | func RegisterModel(userModel interface{}, alias ...string) {
25 | key := ""
26 | table, err := new(model.Table).Init(userModel)
27 | if err != nil {
28 | panic(err.Error())
29 | }
30 | if alias != nil && alias[0] != "" {
31 | key = alias[0]
32 | } else if name, err := table.GetName(); err != nil {
33 | panic(err.Error())
34 | } else {
35 | key = name
36 | }
37 | if err := tableContainer.Set(key, table.Factory()); err != nil {
38 | panic(err.Error())
39 | }
40 | }
41 |
42 | // 获取Dao
43 | func Model(userModel interface{}) *Dao {
44 | tableInstance := GetTable(userModel)
45 | queryInstance := GetQueryBuilder(tableInstance.Identify)
46 | queryInstance.Table(tableInstance.TableName)
47 | return &Dao{
48 | table: tableInstance,
49 | query: queryInstance,
50 | isSQL: false,
51 | }
52 | }
53 |
54 | // 执行SQL - 查询一条数据
55 | func (d *Dao) QueryRow(sql string, args ...interface{}) *AnyValue {
56 | defer d.reset()
57 | anyValue := d.Query(sql, args...)
58 | if err := anyValue.ToError(); err != nil {
59 | return Eval(err)
60 | }
61 | if anyMapSlice := anyValue.ToAnyMapSlice(); len(anyMapSlice) == 0 {
62 | return Eval(map[string]interface{}{})
63 | } else {
64 | return Eval(anyMapSlice[0])
65 | }
66 | }
67 |
68 | // 执行SQL - 增删改查
69 | func (d *Dao) Query(sql string, args ...interface{}) *AnyValue {
70 | defer d.reset()
71 | sqlArray := strings.Split(sql, " ")
72 | switch strings.ToUpper(sqlArray[0]) {
73 | case "SELECT":
74 | sqlRows, err := d.query.QueryAll(sql, args...)
75 | if err != nil {
76 | return Eval(err)
77 | }
78 | return d.parserRows(sqlRows)
79 | case "INSERT", "UPDATE", "DELETE":
80 | sqlResult, err := d.query.Exec(sql, args...)
81 | if err != nil {
82 | return Eval(err)
83 | }
84 | return Eval(sqlResult)
85 | }
86 | return Eval(errors.New("this sql is illegal, Please check it"))
87 | }
88 |
89 | // 获取查询构造器
90 | func (d *Dao) GetQuery() query.BaseQuery {
91 | return d.query
92 | }
93 |
94 | // 设置表名
95 | func (d *Dao) Table(tableName string) *Dao {
96 | d.query.Table(tableName)
97 | return d
98 | }
99 |
100 | // 设置字段
101 | func (d *Dao) Field(field interface{}) *Dao {
102 | d.query.Field(field)
103 | return d
104 | }
105 |
106 | // Where条件
107 | func (d *Dao) Where(field string, value interface{}, linkSymbol ...string) *Dao {
108 | expr := make([]string, 0)
109 | field = strings.TrimSpace(field)
110 | field = regexp.MustCompile(`\s+`+"").ReplaceAllString(field, " ")
111 |
112 | // Where expr.
113 | expr = append(expr, strings.Split(field, " ")...)
114 | if regexp.MustCompile(`(<|<=|=|>|>=|!=|like|not like)`+"").FindString(field) != "" {
115 | expr = append(expr, "?")
116 | } else if regexp.MustCompile("in").FindString(field) != "" {
117 | newValue := make([]interface{}, 0)
118 | if val, ok := value.(string); ok {
119 | stringSlice := strings.Split(val, ",")
120 | for _, val := range stringSlice {
121 | newValue = append(newValue, val)
122 | }
123 | } else if val, ok := value.([]interface{}); ok {
124 | for _, v := range val {
125 | newValue = append(newValue, v)
126 | }
127 | } else if val, ok := value.([]int); ok {
128 | for _, v := range val {
129 | newValue = append(newValue, v)
130 | }
131 | } else if val, ok := value.([]string); ok {
132 | for _, v := range val {
133 | newValue = append(newValue, v)
134 | }
135 | }
136 | inValue := strings.Repeat("?,", len(newValue))
137 | inValue = strings.Trim(inValue, ",")
138 | inValue = "(" + inValue + ")"
139 | expr = append(expr, inValue)
140 | value = newValue
141 | } else {
142 | expr = append(expr, "=", "?")
143 | }
144 | d.query.Where(strings.Join(expr, " "), value, linkSymbol...)
145 | return d
146 | }
147 |
148 | // Where组条件
149 | func (d *Dao) WhereMap(fieldMap map[string]interface{}, linkSymbol ...string) *Dao {
150 | for field, value := range fieldMap {
151 | d.Where(field, value, linkSymbol...)
152 | }
153 | return d
154 | }
155 |
156 | // Bind SQL VALUES for INSERT or UPDATE SQL.
157 | func (d *Dao) Values(valueMap map[string]interface{}) *Dao {
158 | if d.query.GetSqlType() == "INSERT" {
159 | d.query.Values(valueMap)
160 | } else {
161 | d.query.Set(valueMap)
162 | }
163 | return d
164 | }
165 |
166 | // Batch bind VALUES for INSERT SQL.
167 | func (d *Dao) BatchValues(anyMapSlice []map[string]interface{}) *Dao {
168 | if len(anyMapSlice) > 20 {
169 | anyMapSlice = anyMapSlice[0:20]
170 | }
171 | for _, anyMap := range anyMapSlice {
172 | d.query.Values(anyMap)
173 | }
174 | return d
175 | }
176 |
177 | // 设置字段
178 | func (d *Dao) Order(expr ...string) *Dao {
179 | for _, v := range expr {
180 | d.query.Order(v)
181 | }
182 | return d
183 | }
184 |
185 | // 设置字段
186 | func (d *Dao) OrderSlice(expr []string) *Dao {
187 | for _, v := range expr {
188 | d.query.Order(v)
189 | }
190 | return d
191 | }
192 |
193 | // 分页查询
194 | func (d *Dao) Limit(limit ...int) *Dao {
195 | d.query.Limit(limit...)
196 | return d
197 | }
198 |
199 | // 是否打印SQL
200 | func (d *Dao) Sql() *Dao {
201 | d.isSQL = true
202 | return d
203 | }
204 |
205 | // 查询一条记录
206 | func (d *Dao) FetchRow(userFunc ...UserFunc) *AnyValue {
207 | defer d.reset()
208 | _ = d.query.Limit(1)
209 | _ = d.fetch(userFunc...)
210 | if d.isSQL {
211 | return Eval(d.query.GetSql())
212 | }
213 | // Get row.
214 | sqlRow := d.query.FetchRow()
215 | return d.parserRow(sqlRow)
216 | }
217 |
218 | // 查询多条记录
219 | func (d *Dao) FetchAll(userFunc ...UserFunc) *AnyValue {
220 | defer d.reset()
221 | _ = d.fetch(userFunc...)
222 | if d.isSQL {
223 | return Eval(d.query.GetSql())
224 | }
225 | // Get rows.
226 | sqlRows, err := d.query.FetchAll()
227 | if err != nil {
228 | return Eval(err)
229 | }
230 | return d.parserRows(sqlRows)
231 | }
232 |
233 | // 插入记录
234 | func (d *Dao) Insert(userFunc ...UserFunc) *AnyValue {
235 | defer d.reset()
236 | return d.modify("INSERT", userFunc...)
237 | }
238 |
239 | // 更新记录
240 | func (d *Dao) Update(userFunc ...UserFunc) *AnyValue {
241 | defer d.reset()
242 | return d.modify("UPDATE", userFunc...)
243 | }
244 |
245 | // 删除记录
246 | func (d *Dao) Delete(userFunc ...UserFunc) *AnyValue {
247 | defer d.reset()
248 | return d.modify("DELETE", userFunc...)
249 | }
250 |
251 | // 事务接管
252 | func (d *Dao) Tx(dao *Dao) *Dao {
253 | if tx := dao.GetQuery().GetTx(); tx != nil {
254 | d.isTx = true
255 | d.GetQuery().SetTx(tx)
256 | }
257 | return d
258 | }
259 |
260 | // 开启事务
261 | func (d *Dao) Begin() {
262 | d.query.Begin()
263 | }
264 |
265 | // 提交事务
266 | func (d *Dao) Commit() {
267 | d.query.Commit()
268 | }
269 |
270 | // 回滚事务
271 | func (d *Dao) Rollback() {
272 | d.query.Rollback()
273 | }
274 |
275 | // Common SELECT part.
276 | func (d *Dao) fetch(userFunc ...UserFunc) *AnyValue {
277 | _ = d.query.SetSqlType("SELECT")
278 | // 执行过程
279 | if userFunc != nil {
280 | userFunc[0](d)
281 | }
282 | // 字段处理
283 | if d.query.GetField().GetExpr() == "" {
284 | d.query.Field(d.table.GetTableFields())
285 | }
286 | _ = d.query.SetSql() // SQL处理
287 | return nil
288 | }
289 |
290 | // 执行过程
291 | func (d *Dao) modify(sType string, userFunc ...UserFunc) *AnyValue {
292 | _ = d.query.SetSqlType(sType)
293 | // 执行过程
294 | if userFunc != nil {
295 | userFunc[0](d)
296 | }
297 | // SQL处理
298 | _ = d.query.SetSql()
299 | if d.isSQL {
300 | return Eval(d.query.GetSql())
301 | }
302 | // 执行结果
303 | result, err := d.query.Modify()
304 | if err != nil {
305 | return Eval(err)
306 | }
307 | return Eval(result)
308 | }
309 |
310 | // 解析单行记录
311 | func (d *Dao) parserRow(sqlRow *sql.Row) *AnyValue {
312 | column := d.query.GetField().GetNameArray()
313 | // 接收参数
314 | args := make([]interface{}, len(column))
315 | for k := range args {
316 | args[k] = &args[k]
317 | }
318 | // 接收查询结果
319 | row := make(map[string]interface{})
320 | err := sqlRow.Scan(args...)
321 | if err != nil {
322 | if regexp.MustCompile("no rows in result set"+"").FindString(err.Error()) != "" {
323 | return Eval(row)
324 | }
325 | return Eval(err)
326 | }
327 | // 结果处理
328 | for i := 0; i < len(column); i++ {
329 | row[column[i]] = args[i]
330 | }
331 | return Eval(row)
332 | }
333 |
334 | // 解析多行记录
335 | func (d *Dao) parserRows(sqlRows *sql.Rows) *AnyValue {
336 | defer func() { _ = sqlRows.Close() }()
337 | // 获取字段
338 | columns, err2 := sqlRows.Columns()
339 | if err2 != nil {
340 | return Eval(err2)
341 | }
342 | // 迭代后者的 Next() 方法,然后使用 Scan() 方法给对应类型变量赋值,以便取出结果,最后再把结果集关闭(释放连接)
343 | list := make([]map[string]interface{}, 0)
344 | length := len(columns) // 字段数组长度
345 | for sqlRows.Next() {
346 | // 接收参数
347 | args := make([]interface{}, length)
348 | for k := range args {
349 | args[k] = &args[k]
350 | }
351 | // 数据行接收
352 | if err := sqlRows.Scan(args...); err != nil {
353 | Eval(err)
354 | }
355 | // 数据赋值
356 | row := make(map[string]interface{})
357 | for i := 0; i < length; i++ {
358 | row[columns[i]] = args[i]
359 | }
360 | list = append(list, row)
361 | }
362 | return Eval(list)
363 | }
364 |
365 | // 重置结构体
366 | func (d *Dao) reset() {
367 | d.isSQL = false
368 | _ = d.query.Reset()
369 | if d.isTx == true {
370 | d.isTx = false
371 | d.query.UnsetTx()
372 | }
373 | d.log()
374 | }
375 |
376 | // Runtime data.
377 | func (d *Dao) log() {
378 | if Config.LogWriter != nil {
379 | runTime := d.query.GetDuration()
380 | Config.LogWriter(map[string]interface{}{
381 | "SQL": runTime.Sql,
382 | "Err": runTime.Err,
383 | "Args": runTime.Args,
384 | "ExecTime": runTime.ExecTime,
385 | })
386 | }
387 | }
--------------------------------------------------------------------------------
/app/db/model/define.go:
--------------------------------------------------------------------------------
1 | package model
2 |
3 | type Identify interface {
4 | Identify() string // 数据库标识(此方法可重构,用于切换数据库,默认master)
5 | }
6 |
7 | type TableName interface {
8 | TableName() string // 数据库表名(此方法可重构,用于切换数据表)
9 | }
10 |
11 | // 表字段类型
12 | type FieldTypes []string
13 | var FieldType *FieldTypes
14 |
15 | func init() {
16 | FieldType = &FieldTypes{"int", "int8", "int16", "int32", "int64", "string"}
17 | }
18 |
19 | // 是否设置
20 | func (ft *FieldTypes) InArray(t string) bool {
21 | for _, v := range *ft {
22 | if t == v {
23 | return true
24 | }
25 | }
26 | return false
27 | }
28 |
--------------------------------------------------------------------------------
/app/db/model/field.go:
--------------------------------------------------------------------------------
1 | package model
2 |
3 | // 字段结构体
4 | type Field struct {
5 | name string // 字段名称
6 | trueName string // 真实字段名称
7 | inType string // 字段类型
8 | tag *Tag // 字段标签
9 | }
10 |
11 | // 获取字段名称
12 | func (f *Field) GetName() string {
13 | return f.name
14 | }
15 |
16 | // 获取真实字段名称
17 | func (f *Field) GetTrueName() string {
18 | return f.trueName
19 | }
20 |
21 | // 获取字段类型
22 | func (f *Field) GetType() string {
23 | return f.inType
24 | }
25 |
--------------------------------------------------------------------------------
/app/db/model/table.go:
--------------------------------------------------------------------------------
1 | package model
2 |
3 | import (
4 | "errors"
5 | "reflect"
6 | "strings"
7 | )
8 |
9 | type Table struct {
10 | Model interface{} // 数据模型结构体指针
11 | Type reflect.Type // 反射类型
12 | Name string // 结构体名称
13 | Identify string // 数据库标识
14 | TableName string // 表名
15 | FieldNum int // 字段数
16 | FieldArray []*Field // 字段数组
17 | }
18 |
19 | // 获取反射类型
20 | func (t *Table) Init(model interface{}) (*Table, error) {
21 | t.Type = reflect.TypeOf(model)
22 | if t.Type.Kind() != reflect.Ptr || t.Type.Elem().Kind() != reflect.Struct {
23 | return nil, errors.New("accept an pointer model")
24 | } else {
25 | t.Model = model
26 | t.Type = t.Type.Elem()
27 | t.Name = t.Type.String()
28 | t.Identify = "master"
29 | t.TableName = t.Capitalize(t.Type.Name())
30 | t.FieldNum = t.Type.NumField()
31 | t.FieldArray = make([]*Field, 0)
32 | }
33 | return t, nil
34 | }
35 |
36 | // 工厂方法
37 | func (t *Table) Factory() *Table {
38 | // 表处理
39 | reflectModel := reflect.New(t.Type).Interface()
40 | if value, ok := reflectModel.(Identify); ok {
41 | if identify := value.Identify(); identify != "" {
42 | t.Identify = identify
43 | }
44 | }
45 | if value, ok := reflectModel.(TableName); ok {
46 | if tableName := value.TableName(); tableName != "" {
47 | t.TableName = tableName
48 | }
49 | }
50 |
51 | // 字段处理
52 | t.FieldArray = make([]*Field, 0)
53 | for i := 0; i < t.FieldNum; i++ {
54 | inType := t.Type.Field(i).Type.String()
55 | if FieldType.InArray(inType) {
56 | field := &Field{
57 | name: t.Type.Field(i).Name,
58 | trueName: "",
59 | inType: inType,
60 | tag: TagAttribute.Clone(),
61 | }
62 | // 结构体标签
63 | for k, _ := range *field.tag {
64 | if value, ok := t.Type.Field(i).Tag.Lookup(k); ok {
65 | field.tag.Set(k, value)
66 | }
67 | }
68 | if trueName := field.tag.GetField(); trueName != "" {
69 | field.trueName = trueName
70 | } else {
71 | field.trueName = t.Capitalize(field.name)
72 | }
73 | t.FieldArray = append(t.FieldArray, field)
74 | }
75 | }
76 | return t
77 | }
78 |
79 | // 首字母大写转换成 _
80 | func (t *Table) Capitalize(str string) string {
81 | newStr := strings.ToLower(string(str[0]))
82 | value := []rune(str)
83 | for i := 1; i < len(value); i++ {
84 | if value[i] >= 65 && value[i] <= 96 {
85 | newStr += "_" + strings.ToLower(string(value[i]))
86 | } else {
87 | newStr += string(value[i])
88 | }
89 | }
90 | return newStr
91 | }
92 |
93 | // 获取结构体名称
94 | func (t *Table) GetName() (string, error) {
95 | if t.Type == nil {
96 | return "", errors.New("the table struct is not init")
97 | }
98 | return t.Type.String(), nil
99 | }
100 |
101 | // 获取字段组
102 | func (t *Table) GetField() []*Field {
103 | return t.FieldArray
104 | }
105 |
106 | // 获取表字段列表
107 | func (t *Table) GetTableFields() []string {
108 | tableFields := make([]string, 0)
109 | for _, v := range t.FieldArray {
110 | tableFields = append(tableFields, v.trueName)
111 | }
112 | return tableFields
113 | }
114 |
--------------------------------------------------------------------------------
/app/db/model/tag.go:
--------------------------------------------------------------------------------
1 | package model
2 |
3 | type Tag map[string]string
4 | var TagAttribute *Tag
5 |
6 | func init() {
7 | TagAttribute = &Tag{
8 | "field": "",
9 | }
10 | }
11 |
12 | // 是否存在
13 | func (t *Tag) Clone() *Tag {
14 | return &Tag{
15 | "field": (*t)["field"],
16 | }
17 | }
18 |
19 | // 设置数据
20 | func (t *Tag) Set(key string, value string) {
21 | (*t)[key] = value
22 | }
23 |
24 | // 是否存在
25 | func (t *Tag) InArray(aType string) bool {
26 | for _, v := range *t {
27 | if aType == v {
28 | return true
29 | }
30 | }
31 | return false
32 | }
33 |
34 | // 数据表真实字段值
35 | func (t *Tag) GetField() string {
36 | return (*t)["field"]
37 | }
38 |
--------------------------------------------------------------------------------
/app/db/query.go:
--------------------------------------------------------------------------------
1 | package db
2 |
3 | import (
4 | "database/sql"
5 | "errors"
6 | _ "github.com/go-sql-driver/mysql"
7 | "github.com/go-touch/regin/app/db/query"
8 | "strconv"
9 | )
10 |
11 | // 查询构造器容器
12 | type QueryContainer map[string]query.BaseQuery
13 |
14 | var Query *QueryContainer
15 |
16 | func init() {
17 | Query = &QueryContainer{}
18 | }
19 |
20 | // 设置queryBuilder
21 | func (qc *QueryContainer) Set(key string, queryBuilder query.BaseQuery) error {
22 | (*qc)[key] = queryBuilder
23 | return nil
24 | }
25 |
26 | // 获取queryBuilder
27 | func (qc *QueryContainer) Get(key string) (query.BaseQuery, error) {
28 | if queryBuilder, ok := (*qc)[key]; ok {
29 | return queryBuilder, nil
30 | }
31 | return nil, errors.New("can't find this Query Builder '" + key + "'")
32 | }
33 |
34 | // 获取查询构造器
35 | func GetQueryBuilder(identify string) query.BaseQuery {
36 | if queryBuilder, err := Query.Get(identify); err == nil {
37 | return queryBuilder.Clone()
38 | }
39 |
40 | // 读取数据库配置并校验
41 | configParam := map[string]string{"driverName": "", "dataSourceName": "", "maxIdleConn": "", "maxOpenConn": ""}
42 | if config, err := Config.GetConfig(identify); err != nil {
43 | panic(err.Error())
44 | } else {
45 | for key, _ := range configParam {
46 | if v, ok := config[key]; !ok {
47 | panic("The database config's " + key + " is not set.")
48 | } else {
49 | configParam[key] = v
50 | }
51 | }
52 | }
53 |
54 | // 创建db对象、创建查询构造器
55 | if db, err := sql.Open(configParam["driverName"], configParam["dataSourceName"]); err != nil {
56 | panic(err.Error())
57 | } else if err = db.Ping(); err != nil {
58 | panic("Connect '" + configParam["driverName"] + "' failed: the target machine actively refused it.")
59 | } else if queryBuilder := query.GetQueryBuilder(configParam["driverName"]); queryBuilder == nil {
60 | panic("Create '" + configParam["driverName"] + "' Query Builder failed.")
61 | } else {
62 | if maxIdleConn, err := strconv.Atoi(configParam["maxIdleConn"]); err == nil {
63 | db.SetMaxIdleConns(maxIdleConn)
64 | }
65 | if maxOpenConn, err := strconv.Atoi(configParam["maxOpenConn"]); err == nil {
66 | db.SetMaxOpenConns(maxOpenConn)
67 | }
68 | queryBuilder.SetDb(db)
69 | _ = Query.Set(identify, queryBuilder)
70 | return queryBuilder.Clone()
71 | }
72 | }
73 |
--------------------------------------------------------------------------------
/app/db/query/combine.go:
--------------------------------------------------------------------------------
1 | package query
2 |
3 | import (
4 | "database/sql"
5 | "time"
6 | )
7 |
8 | // Define common struct.
9 | type Combine struct {
10 | BaseQuery
11 | db *sql.DB
12 | tx *sql.Tx
13 | Runtime Runtime
14 | }
15 |
16 | // Runtime data struct.
17 | type Runtime struct {
18 | Sql string // sql语句
19 | Args []interface{} // 参数
20 | ExecTime string // 执行时间
21 | Err error // 运行错误
22 | }
23 |
24 | // Set Db.
25 | func (c *Combine) SetDb(db *sql.DB) {
26 | c.db = db
27 | }
28 |
29 | // Set Tx.
30 | func (c *Combine) SetTx(tx *sql.Tx) {
31 | c.tx = tx
32 | }
33 |
34 | // Unset Tx.
35 | func (c *Combine) UnsetTx() {
36 | c.tx = nil
37 | }
38 |
39 | // Get Tx.
40 | func (c *Combine) GetTx() *sql.Tx {
41 | return c.tx
42 | }
43 |
44 | // 获取运行期间数据
45 | func (c *Combine) GetDuration() Runtime {
46 | return c.Runtime
47 | }
48 |
49 | // 查询一条记录
50 | func (c *Combine) QueryRow(sql string, args ...interface{}) (row *sql.Row) {
51 | startTime := time.Now()
52 | if c.tx != nil {
53 | row = c.tx.QueryRow(sql, args...)
54 | } else {
55 | row = c.db.QueryRow(sql, args...)
56 | }
57 | // Runtime data.
58 | c.Runtime.Sql = sql
59 | c.Runtime.Args = args
60 | c.Runtime.ExecTime = time.Since(startTime).String()
61 | c.Runtime.Err = nil
62 | return row
63 | }
64 |
65 | // 查询多条记录
66 | func (c *Combine) QueryAll(sql string, args ...interface{}) (rows *sql.Rows, err error) {
67 | startTime := time.Now()
68 | if c.tx != nil {
69 | rows, err = c.tx.Query(sql, args...)
70 | } else {
71 | rows, err = c.db.Query(sql, args...)
72 | }
73 | // Runtime data.
74 | c.Runtime.Sql = sql
75 | c.Runtime.Args = args
76 | c.Runtime.ExecTime = time.Since(startTime).String()
77 | c.Runtime.Err = err
78 | return rows, err
79 | }
80 |
81 | // 插入[更新][删除]n条记录
82 | func (c *Combine) Exec(sql string, args ...interface{}) (result sql.Result, err error) {
83 | startTime := time.Now()
84 | if c.tx != nil {
85 | result, err = c.tx.Exec(sql, args...)
86 | } else {
87 | result, err = c.db.Exec(sql, args...)
88 | }
89 | // Runtime data.
90 | c.Runtime.Sql = sql
91 | c.Runtime.Args = args
92 | c.Runtime.ExecTime = time.Since(startTime).String()
93 | c.Runtime.Err = err
94 | return result, err
95 | }
96 |
97 | // Begin starts a transaction.
98 | func (c *Combine) Begin() {
99 | if tx, err := c.db.Begin(); err != nil {
100 | panic(err.Error())
101 | } else {
102 | c.tx = tx
103 | }
104 | }
105 |
106 | // Commit commits the transaction.
107 | func (c *Combine) Commit() {
108 | err := c.tx.Commit()
109 | if err != nil {
110 | panic(err.Error())
111 | }
112 | c.tx = nil
113 | }
114 |
115 | // Rollback aborts the transaction.
116 | func (c *Combine) Rollback() {
117 | err := c.tx.Rollback()
118 | if err != nil {
119 | panic(err.Error())
120 | }
121 | c.tx = nil
122 | }
123 |
--------------------------------------------------------------------------------
/app/db/query/define.go:
--------------------------------------------------------------------------------
1 | package query
2 |
3 | import (
4 | "database/sql"
5 | "github.com/go-touch/regin/app/db/query/parts"
6 | )
7 |
8 | type BaseQuery interface {
9 | Clone() BaseQuery
10 | Reset() error
11 | SetDb(db *sql.DB)
12 | SetTx(tx *sql.Tx)
13 | UnsetTx()
14 | GetTx() *sql.Tx
15 | Begin() // Begin starts a transaction.
16 | Commit() // Commit commits the transaction.
17 | Rollback() // Rollback aborts the transaction.
18 | QueryRow(sql string, args ...interface{}) *sql.Row
19 | QueryAll(sql string, args ...interface{}) (*sql.Rows, error)
20 | Exec(sql string, args ...interface{}) (sql.Result, error)
21 | Table(tableName string) BaseQuery
22 | Field(field interface{}) BaseQuery
23 | GetField() *parts.Field
24 | Where(expr string, value interface{}, linkSymbol ...string) BaseQuery
25 | Order(expr string) BaseQuery
26 | Limit(limit ...int) BaseQuery
27 | Values(valueMap map[string]interface{}) BaseQuery
28 | Set(valueMap map[string]interface{}) BaseQuery
29 | SetSqlType(sType string) error
30 | GetSqlType() string
31 | SetSql() BaseQuery
32 | GetSql() string
33 | FetchRow() *sql.Row
34 | FetchAll() (*sql.Rows, error)
35 | Modify() (sql.Result, error)
36 | GetDuration() Runtime
37 | }
38 |
39 | // 获取查询构造器
40 | func GetQueryBuilder(driverName string) BaseQuery {
41 | switch driverName {
42 | case "mysql":
43 | return &MysqlQuery{
44 | Combine: Combine{
45 | Runtime: Runtime{},
46 | },
47 | }
48 | case "sql_server":
49 | return &SqlServerQuery{}
50 | }
51 | return nil
52 | }
53 |
--------------------------------------------------------------------------------
/app/db/query/mysql.go:
--------------------------------------------------------------------------------
1 | package query
2 |
3 | import (
4 | "database/sql"
5 | "fmt"
6 | "github.com/go-touch/regin/app/db/query/parts"
7 | "regexp"
8 | "strings"
9 | )
10 |
11 | const (
12 | sqlSELECT = "SELECT|{FIELD}|FROM|{TABLE}|{WHERE}|{ORDER}|{LIMIT}"
13 | sqlINSERT = "INSERT|INTO|{TABLE}|{FIELD}|VALUES|{VALUES}"
14 | sqlUPDATE = "UPDATE|{TABLE}|SET|{SET}|{WHERE}"
15 | sqlDELETE = "DELETE|FROM|{TABLE}|{WHERE}"
16 | )
17 |
18 | type MysqlQuery struct {
19 | Combine
20 | table *parts.Table
21 | field *parts.Field
22 | where *parts.Where
23 | order *parts.Order
24 | limit *parts.Limit
25 | values *parts.Values
26 | set *parts.Set
27 | sqlExprType string // SQL表达式类型
28 | sqlExpr string // SQL表达式
29 | sqlParam []interface{} // SQL参数
30 | result interface{}
31 | }
32 |
33 | // 复制结构体
34 | func (mq *MysqlQuery) Clone() BaseQuery {
35 | return &MysqlQuery{
36 | Combine: mq.Combine,
37 | table: parts.MakeTable(),
38 | field: parts.MakeField(),
39 | where: parts.MakeWhere(),
40 | order: parts.MakeOrder(),
41 | limit: parts.MakeLimit(0, 1000),
42 | values: parts.MakeValues(),
43 | set: parts.MakeSet(),
44 | sqlExprType: "",
45 | sqlExpr: "",
46 | sqlParam: make([]interface{}, 0),
47 | }
48 | }
49 |
50 | // 重置结构体
51 | func (mq *MysqlQuery) Reset() error {
52 | //mq.table = parts.MakeTable()
53 | mq.field = parts.MakeField()
54 | mq.where = parts.MakeWhere()
55 | mq.order = parts.MakeOrder()
56 | mq.limit = parts.MakeLimit(0, 1000)
57 | mq.values = parts.MakeValues()
58 | mq.set = parts.MakeSet()
59 | mq.sqlExprType = ""
60 | mq.sqlExpr = ""
61 | mq.sqlParam = make([]interface{}, 0)
62 | return nil
63 | }
64 |
65 | // 设置table
66 | func (mq *MysqlQuery) Table(tableName string) BaseQuery {
67 | mq.table.SetExpr(tableName)
68 | return mq
69 | }
70 |
71 | // 字段设置
72 | func (mq *MysqlQuery) Field(field interface{}) BaseQuery {
73 | mq.field.SetExpr(field)
74 | return mq
75 | }
76 |
77 | // 获取字段设置
78 | func (mq *MysqlQuery) GetField() *parts.Field {
79 | return mq.field
80 | }
81 |
82 | // 查询Where
83 | func (mq *MysqlQuery) Where(expr string, value interface{}, linkSymbol ...string) BaseQuery {
84 | ls := "AND"
85 | if linkSymbol != nil && linkSymbol[0] != "" {
86 | ls = linkSymbol[0]
87 | }
88 | mq.where.SetExpr(ls, expr, value)
89 | return mq
90 | }
91 |
92 | // 设置Order
93 | func (mq *MysqlQuery) Order(expr string) BaseQuery {
94 | mq.order.SetExpr(expr)
95 | return mq
96 | }
97 |
98 | // 设置limit
99 | func (mq *MysqlQuery) Limit(limit ...int) BaseQuery {
100 | mq.limit.SetExpr(limit...)
101 | return mq
102 | }
103 |
104 | // 设置数值
105 | func (mq *MysqlQuery) Values(valueMap map[string]interface{}) BaseQuery {
106 | mq.values.SetExpr(valueMap)
107 | return mq
108 | }
109 |
110 | // 设置数值
111 | func (mq *MysqlQuery) Set(valueMap map[string]interface{}) BaseQuery {
112 | mq.set.SetExpr(valueMap)
113 | return mq
114 | }
115 |
116 | // 设置表达式类型
117 | func (mq *MysqlQuery) SetSqlType(sType string) error {
118 | mq.sqlExprType = strings.ToUpper(sType)
119 | return nil
120 | }
121 |
122 | // 获取表达式类型
123 | func (mq *MysqlQuery) GetSqlType() string {
124 | return mq.sqlExprType
125 | }
126 |
127 | // 创建SQL表达式
128 | func (mq *MysqlQuery) SetSql() BaseQuery {
129 | switch strings.ToUpper(mq.sqlExprType) {
130 | case "SELECT":
131 | mq.sqlExpr = sqlSELECT
132 | mq.sqlExpr = strings.Replace(mq.sqlExpr, "{FIELD}", mq.field.GetExpr(), 1)
133 | mq.sqlExpr = strings.Replace(mq.sqlExpr, "{TABLE}", mq.table.GetExpr(), 1)
134 | // 查询条件
135 | mq.sqlExpr = strings.Replace(mq.sqlExpr, "{WHERE}", mq.where.GetExpr(), 1)
136 | mq.sqlExpr = strings.Replace(mq.sqlExpr, "{ORDER}", mq.order.GetExpr(), 1)
137 | mq.sqlExpr = strings.Replace(mq.sqlExpr, "{LIMIT}", mq.limit.GetExpr(), 1)
138 | mq.sqlParam = append(mq.sqlParam, mq.where.GetArgs()...)
139 | case "INSERT":
140 | mq.sqlExpr = sqlINSERT
141 | mq.sqlExpr = strings.Replace(mq.sqlExpr, "{TABLE}", mq.table.GetExpr(), 1)
142 | mq.sqlExpr = strings.Replace(mq.sqlExpr, "{FIELD}", mq.values.GetExpr(), 1)
143 | mq.sqlExpr = strings.Replace(mq.sqlExpr, "{VALUES}", mq.values.GetArgsExpr(), 1)
144 | mq.sqlParam = append(mq.sqlParam, mq.values.GetArgs()...)
145 | case "UPDATE":
146 | mq.sqlExpr = sqlUPDATE
147 | mq.sqlExpr = strings.Replace(mq.sqlExpr, "{TABLE}", mq.table.GetExpr(), 1)
148 | mq.sqlExpr = strings.Replace(mq.sqlExpr, "{SET}", mq.set.GetExpr(), 1)
149 | mq.sqlExpr = strings.Replace(mq.sqlExpr, "{WHERE}", mq.where.GetExpr(), 1)
150 | mq.sqlParam = append(mq.sqlParam, mq.set.GetArgs()...)
151 | mq.sqlParam = append(mq.sqlParam, mq.where.GetArgs()...)
152 | case "DELETE":
153 | mq.sqlExpr = sqlDELETE
154 | mq.sqlExpr = strings.Replace(mq.sqlExpr, "{TABLE}", mq.table.GetExpr(), 1)
155 | mq.sqlExpr = strings.Replace(mq.sqlExpr, "{WHERE}", mq.where.GetExpr(), 1)
156 | mq.sqlParam = append(mq.sqlParam, mq.where.GetArgs()...)
157 | }
158 | mq.sqlExpr = strings.Replace(mq.sqlExpr, "|", " ", -1)
159 | mq.sqlExpr = regexp.MustCompile("\\s+").ReplaceAllString(mq.sqlExpr, " ")
160 | return mq
161 | }
162 |
163 | // 获取SQL语句
164 | func (mq *MysqlQuery) GetSql() string {
165 | return mq.sqlExpr + "\n" + fmt.Sprintf("Args: %v", mq.sqlParam)
166 | }
167 |
168 | // 获取一条记录
169 | func (mq *MysqlQuery) FetchRow() *sql.Row {
170 | return mq.QueryRow(mq.sqlExpr, mq.sqlParam...)
171 | }
172 |
173 | // 获取多条记录
174 | func (mq *MysqlQuery) FetchAll() (*sql.Rows, error) {
175 | return mq.QueryAll(mq.sqlExpr, mq.sqlParam...)
176 | }
177 |
178 | // 插入|更新|删除记录
179 | func (mq *MysqlQuery) Modify() (sql.Result, error) {
180 | return mq.Exec(mq.sqlExpr, mq.sqlParam...)
181 | }
--------------------------------------------------------------------------------
/app/db/query/parts/field.go:
--------------------------------------------------------------------------------
1 | package parts
2 |
3 | import (
4 | "regexp"
5 | "strings"
6 | )
7 |
8 | type Field struct {
9 | expr []string
10 | nameArray []string
11 | sqlExpr string
12 | }
13 |
14 | // 构建Field结构体
15 | func MakeField() *Field {
16 | return &Field{
17 | nameArray: make([]string, 0),
18 | sqlExpr: "",
19 | }
20 | }
21 |
22 | // 设置表达式
23 | func (f *Field) SetExpr(expr interface{}) {
24 | exprArray := make([]string, 0)
25 |
26 | // 传入字段处理
27 | if exprValue, ok := expr.(string); ok {
28 | exprArray = strings.Split(f.Filter(exprValue), ",")
29 | } else if exprValue, ok := expr.([]string); ok {
30 | exprArray = exprValue
31 | }
32 | // 过滤字符串
33 | for k, v := range exprArray {
34 | exprArray[k] = f.Filter(v)
35 | }
36 | // 设置SQL表达式
37 | sqlExpr := make([]string, 0)
38 | for _, value := range exprArray {
39 | valueGroup := strings.Split(value, " ")
40 | f.nameArray = append(f.nameArray, valueGroup[len(valueGroup)-1])
41 | for k, v := range valueGroup {
42 | if f := regexp.MustCompile(`\.` + "").FindString(v); f != "" {
43 | valueGroup[k] = strings.Replace(v, ".", ".`", 1) + "`"
44 | } else if regexp.MustCompile(`(SUM|sum|COUNT|count|as|AS)+`+"").FindString(v) == "" {
45 | valueGroup[k] = "`" + v + "`"
46 | }
47 | }
48 | sqlExpr = append(sqlExpr, strings.Join(valueGroup, " "))
49 | }
50 | if len(sqlExpr) > 0 {
51 | f.sqlExpr = strings.Join(sqlExpr, ",")
52 | }
53 | }
54 |
55 | // 获取表达式
56 | func (f *Field) GetExpr() string {
57 | return f.sqlExpr
58 | }
59 |
60 | // 过滤字符串
61 | func (f *Field) Filter(str string) string {
62 | str = strings.TrimSpace(str)
63 | str = strings.Trim(str, ",")
64 | str = regexp.MustCompile(`\s+`+"").ReplaceAllString(str, " ")
65 | str = regexp.MustCompile("`"+"").ReplaceAllString(str, "")
66 | return str
67 | }
68 |
69 | // 获取字段列表
70 | func (f *Field) GetNameArray() []string {
71 | return f.nameArray
72 | }
73 |
--------------------------------------------------------------------------------
/app/db/query/parts/join.go:
--------------------------------------------------------------------------------
1 | package parts
2 |
3 | type Join struct {
4 | members []*SubJoin
5 | }
6 |
7 | type SubJoin struct {
8 | connector string // 连接符, for example: INNER JOIN、LEFT JOIN、RIGHT JOIN
9 | tableName string // 表名, for example: admin as a
10 | on string // 关联条件
11 | }
12 |
--------------------------------------------------------------------------------
/app/db/query/parts/limit.go:
--------------------------------------------------------------------------------
1 | package parts
2 |
3 | import (
4 | "strconv"
5 | "strings"
6 | )
7 |
8 | type Limit struct {
9 | expr []int
10 | }
11 |
12 | func MakeLimit(limit ...int) *Limit {
13 | return &Limit{
14 | expr: limit,
15 | }
16 | }
17 |
18 | func (l *Limit) SetExpr(limit ...int) {
19 | l.expr = limit
20 | }
21 |
22 | func (l *Limit) GetExpr() string {
23 | sqlExpr := []string{"LIMIT"}
24 | if len(l.expr) == 0 {
25 | return ""
26 | } else if len(l.expr) == 1 {
27 | sqlExpr = append(sqlExpr, strconv.Itoa(l.expr[0]))
28 | } else {
29 | sqlExpr = append(sqlExpr, strconv.Itoa(l.expr[0])+","+strconv.Itoa(l.expr[1]))
30 | }
31 | return strings.Join(sqlExpr, " ")
32 | }
33 |
--------------------------------------------------------------------------------
/app/db/query/parts/order.go:
--------------------------------------------------------------------------------
1 | package parts
2 |
3 | import (
4 | "regexp"
5 | "strings"
6 | )
7 |
8 | type Order struct {
9 | members []*SubOrder
10 | }
11 |
12 | type SubOrder struct {
13 | expr string // 表达式, for example: id ASC
14 | }
15 |
16 | func MakeOrder() *Order {
17 | return &Order{
18 | members: make([]*SubOrder, 0),
19 | }
20 | }
21 |
22 | // 设置表达式
23 | func (o *Order) SetExpr(expr string) {
24 | o.members = append(o.members, &SubOrder{
25 | expr: expr,
26 | })
27 | }
28 |
29 | // 获取表达式
30 | func (o *Order) GetExpr() string {
31 | sqlExpr := make([]string, 0, 10)
32 | for _, subOrder := range o.members {
33 | subOrder.expr = regexp.MustCompile(`\s+`+"").ReplaceAllString(subOrder.expr, "|")
34 | exprArray := strings.Split(subOrder.expr, "|")
35 | if len(exprArray) == 1 {
36 | exprArray[0] = "`" + exprArray[0] + "`"
37 | } else if len(exprArray) > 1 {
38 | exprArray = exprArray[0:2]
39 | if f := regexp.MustCompile(`\.` + "").FindString(exprArray[0]); f != "" {
40 | exprArray[0] = strings.Replace(exprArray[0], ".", ".`", 1) + "`"
41 | } else {
42 | exprArray[0] = "`" + exprArray[0] + "`"
43 | }
44 | exprArray[1] = strings.ToUpper(exprArray[1])
45 | }
46 | if len(exprArray) > 0{
47 | sqlExpr = append(sqlExpr, strings.Join(exprArray, " "))
48 | }
49 | }
50 | if len(sqlExpr) == 0 {
51 | return ""
52 | }
53 | return "ORDER BY " + strings.Join(sqlExpr, ",")
54 | }
55 |
--------------------------------------------------------------------------------
/app/db/query/parts/set.go:
--------------------------------------------------------------------------------
1 | package parts
2 |
3 | import (
4 | "regexp"
5 | "strings"
6 | )
7 |
8 | type Set struct {
9 | expr string // 表达式
10 | args []interface{} // 参数
11 | }
12 |
13 | // 创建Set结构体
14 | func MakeSet() *Set {
15 | return &Set{
16 | expr: "",
17 | args: make([]interface{}, 0),
18 | }
19 | }
20 |
21 | // 设置SQL表达式
22 | func (s *Set) SetExpr(valueMap map[string]interface{}) {
23 | sqlExpr := make([]string, 0)
24 | for key, value := range valueMap {
25 | key = strings.TrimSpace(key)
26 | var unit []string
27 | if regexp.MustCompile(`\s(\+|\-)`+"").FindString(key) != "" {
28 | key = regexp.MustCompile(`\s+`+"").ReplaceAllString(key, "|")
29 | keySlice := strings.Split(key, "|")
30 | unit = []string{"`" + keySlice[0] + "`", "=", "`" + keySlice[0] + "`", keySlice[1], "?"}
31 | } else {
32 | key = "`" + strings.TrimSpace(key) + "`"
33 | unit = []string{key, "=", "?"}
34 | }
35 | sqlExpr = append(sqlExpr, strings.Join(unit, " "))
36 | s.args = append(s.args, value)
37 | }
38 | if len(sqlExpr) > 0 {
39 | s.expr = strings.Join(sqlExpr, ",")
40 | }
41 | }
42 |
43 | // 获取SQL表达式
44 | func (s *Set) GetExpr() string {
45 | return s.expr
46 | }
47 |
48 | // 获取SQL表达式参数
49 | func (s *Set) GetArgs() []interface{} {
50 | return s.args
51 | }
52 |
--------------------------------------------------------------------------------
/app/db/query/parts/table.go:
--------------------------------------------------------------------------------
1 | package parts
2 |
3 | import (
4 | "regexp"
5 | "strings"
6 | )
7 |
8 | type Table struct {
9 | expr string
10 | }
11 |
12 | // make &Table.
13 | func MakeTable() *Table {
14 | return &Table{}
15 | }
16 |
17 | // Get SQL Express statement.
18 | func (t *Table) SetExpr(expr string) {
19 | t.expr = expr
20 | }
21 |
22 | // Get SQL Express statement.
23 | func (t *Table) GetExpr() string {
24 | sqlExpr := make([]string, 0)
25 |
26 | // 表名处理
27 | t.expr = strings.TrimSpace(t.expr)
28 | t.expr = regexp.MustCompile(`\s+`+"").ReplaceAllString(t.expr, "|")
29 | exprGroup := strings.Split(t.expr, "|")
30 | for _, v := range exprGroup {
31 | if f := regexp.MustCompile(`\.` + "").FindString(v); f != "" {
32 | v = strings.Replace(v, ".", ".`", 1) + "`"
33 | } else if v != "as" {
34 | v = "`" + v + "`"
35 | }
36 | sqlExpr = append(sqlExpr, v)
37 | }
38 | if len(sqlExpr) == 0 {
39 | return ""
40 | }
41 | return strings.Join(sqlExpr, " ")
42 | }
43 |
--------------------------------------------------------------------------------
/app/db/query/parts/values.go:
--------------------------------------------------------------------------------
1 | package parts
2 |
3 | import (
4 | "sort"
5 | "strings"
6 | )
7 |
8 | type Values struct {
9 | member []*SubValues
10 | }
11 |
12 | type SubValues struct {
13 | expr string
14 | argsExpr string
15 | args []interface{}
16 | }
17 |
18 | // Make SubValue.
19 | func MakeSubValues(anyMap map[string]interface{}) *SubValues {
20 | expr := ""
21 | argsExpr := ""
22 | args := make([]interface{}, 0)
23 |
24 | // SQL表达式
25 | sqlExpr := make([]string, 0)
26 | sqlValueExpr := make([]string, 0)
27 | sortBy := make([]string, 0)
28 | for key := range anyMap {
29 | key = strings.TrimSpace(key)
30 | sortBy = append(sortBy, key)
31 | }
32 | // Sort key.
33 | sort.Strings(sortBy)
34 | for _, key := range sortBy {
35 | sqlExpr = append(sqlExpr, "`"+key+"`")
36 | sqlValueExpr = append(sqlValueExpr, "?")
37 | args = append(args, anyMap[key])
38 | }
39 | if len(sqlExpr) > 0 {
40 | expr = "(" + strings.Join(sqlExpr, ",") + ")"
41 | argsExpr = "(" + strings.Join(sqlValueExpr, ",") + ")"
42 | }
43 | return &SubValues{
44 | expr: expr,
45 | argsExpr: argsExpr,
46 | args: args,
47 | }
48 | }
49 |
50 | // Set SQL expr.
51 | func (sv *SubValues) GetExpr() string {
52 | return sv.expr
53 | }
54 |
55 | // Get SQL VALUES expr.
56 | func (sv *SubValues) GetArgsExpr() string {
57 | return sv.argsExpr
58 | }
59 |
60 | // Get SQL VALUES args.
61 | func (sv *SubValues) GetArgs() []interface{} {
62 | return sv.args
63 | }
64 |
65 | // Make Values.
66 | func MakeValues() *Values {
67 | return &Values{
68 | member: make([]*SubValues, 0),
69 | }
70 | }
71 |
72 | // Set SQL expr.
73 | func (v *Values) SetExpr(anyMap map[string]interface{}) {
74 | v.member = append(v.member, MakeSubValues(anyMap))
75 | }
76 |
77 | // Get SQL expr.
78 | func (v *Values) GetExpr() string {
79 | if len(v.member) > 0 {
80 | return v.member[0].GetExpr()
81 | }
82 | return ""
83 | }
84 |
85 | // Get SQL args expr.
86 | func (v *Values) GetArgsExpr() string {
87 | argsExpr := make([]string, 0)
88 | for _, subValues := range v.member {
89 | argsExpr = append(argsExpr, subValues.GetArgsExpr())
90 | }
91 | return strings.Join(argsExpr, ",")
92 | }
93 |
94 | // 获取SQL表达式参数
95 | func (v *Values) GetArgs() []interface{} {
96 | args := make([]interface{}, 0)
97 | for _, subValues := range v.member {
98 | args = append(args, subValues.GetArgs()...)
99 | }
100 | return args
101 | }
102 |
--------------------------------------------------------------------------------
/app/db/query/parts/where.go:
--------------------------------------------------------------------------------
1 | package parts
2 |
3 | import (
4 | "regexp"
5 | "strings"
6 | )
7 |
8 | type Where struct {
9 | members []*SubWhere //
10 | args []interface{} // 参数
11 | }
12 |
13 | type SubWhere struct {
14 | linkSymbol string // 连接符, for example: AND
15 | expr string // 表达式, for example: `username` = ?
16 | value interface{} // 对应值, for example: admin
17 | }
18 |
19 | // 生成Where构件
20 | func MakeWhere() *Where {
21 | return &Where{
22 | members: make([]*SubWhere, 0),
23 | args: make([]interface{}, 0),
24 | }
25 | }
26 |
27 | // 设置表达式单元
28 | func (w *Where) SetExpr(linkSymbol string, expr string, value interface{}) {
29 | if len(w.members) == 0 {
30 | linkSymbol = ""
31 | }
32 | w.members = append(w.members, &SubWhere{
33 | linkSymbol: strings.ToUpper(linkSymbol),
34 | expr: strings.TrimSpace(expr),
35 | value: value,
36 | })
37 | }
38 |
39 | // 获取sql表达式
40 | func (w *Where) GetExpr() string {
41 | sqlExpr := []string{"WHERE"}
42 |
43 | // 遍历处理
44 | for _, subWhere := range w.members {
45 | subWhere.expr = regexp.MustCompile(`\s+`+"").ReplaceAllString(subWhere.expr, "|")
46 | exprArray := strings.Split(subWhere.expr, "|")
47 | // 长度判断
48 | if len(exprArray) > 0 {
49 | exprArray[0] = "`" + exprArray[0] + "`"
50 | subWhere.expr = strings.Join(exprArray, " ")
51 | if regexp.MustCompile(`\s(=|!=|like|not like|>|>=|<|<=)\s(\?)`+"$").FindString(subWhere.expr) != "" {
52 | sqlExpr = append(sqlExpr, subWhere.linkSymbol, subWhere.expr)
53 | w.args = append(w.args, subWhere.value)
54 | } else if regexp.MustCompile(`\s(in)\s\(\S+\)`+"$").FindString(subWhere.expr) != "" {
55 | sqlExpr = append(sqlExpr, subWhere.linkSymbol, subWhere.expr)
56 | if v, ok := subWhere.value.([]interface{}); ok {
57 | w.args = append(w.args, v...)
58 | }
59 | }
60 | }
61 | }
62 | if len(sqlExpr) == 1 {
63 | return ""
64 | }
65 | return strings.Join(sqlExpr, " ")
66 | }
67 |
68 | // 获取值
69 | func (w *Where) GetArgs() []interface{} {
70 | return w.args
71 | }
72 |
--------------------------------------------------------------------------------
/app/db/query/sql_server.go:
--------------------------------------------------------------------------------
1 | package query
2 |
3 | import (
4 | "database/sql"
5 | "github.com/go-touch/regin/app/db/query/parts"
6 | )
7 |
8 | type SqlServerQuery struct {
9 | Combine
10 | table *parts.Table
11 | field *parts.Field
12 | where *parts.Where
13 | order *parts.Order
14 | limit *parts.Limit
15 | values *parts.Values
16 | sqlExprType string // SQL表达式类型
17 | sqlExpr string
18 | sqlParam []interface{}
19 | result interface{}
20 | }
21 |
22 | // 获取SQL语句
23 | func (ssq *SqlServerQuery) Clone() BaseQuery {
24 | return &SqlServerQuery{
25 | Combine: ssq.Combine,
26 | table: parts.MakeTable(),
27 | field: parts.MakeField(),
28 | where: parts.MakeWhere(),
29 | order: parts.MakeOrder(),
30 | limit: parts.MakeLimit(0, 1000),
31 | values: parts.MakeValues(),
32 | sqlExpr: "",
33 | sqlParam: make([]interface{}, 0),
34 | }
35 | }
36 |
37 | // 重置结构体
38 | func (ssq *SqlServerQuery) Reset() error {
39 | ssq.table = parts.MakeTable()
40 | ssq.field = parts.MakeField()
41 | ssq.where = parts.MakeWhere()
42 | ssq.order = parts.MakeOrder()
43 | ssq.limit = parts.MakeLimit(0, 1000)
44 | ssq.values = parts.MakeValues()
45 | ssq.sqlExpr = ""
46 | ssq.sqlParam = make([]interface{}, 0)
47 | return nil
48 | }
49 |
50 | // 设置table
51 | func (ssq *SqlServerQuery) Table(tableName string) BaseQuery {
52 | ssq.table.SetExpr(tableName)
53 | return ssq
54 | }
55 |
56 | // 字段设置
57 | func (ssq *SqlServerQuery) Field(field interface{}) BaseQuery {
58 | return ssq
59 | }
60 |
61 | // 获取字段设置
62 | func (ssq *SqlServerQuery) GetField() *parts.Field {
63 | return ssq.field
64 | }
65 |
66 | // 查询条件
67 | func (ssq *SqlServerQuery) Where(expr string, value interface{}, linkSymbol ...string) BaseQuery {
68 | ssq.where.SetExpr("AND", expr, value)
69 | return ssq
70 | }
71 |
72 | // 设置limit
73 | func (ssq *SqlServerQuery) Order(expr string) BaseQuery {
74 | ssq.order.SetExpr(expr)
75 | return ssq
76 | }
77 |
78 | // 设置limit
79 | func (ssq *SqlServerQuery) Limit(limit ...int) BaseQuery {
80 | ssq.limit.SetExpr(limit...)
81 | return ssq
82 | }
83 |
84 | // 设置数值
85 | func (ssq *SqlServerQuery) Values(valueMap map[string]interface{}) BaseQuery {
86 | ssq.values.SetExpr(valueMap)
87 | return ssq
88 | }
89 |
90 | // 设置数值
91 | func (ssq *SqlServerQuery) Set(valueMap map[string]interface{}) BaseQuery {
92 | ssq.values.SetExpr(valueMap)
93 | return ssq
94 | }
95 |
96 | // 设置Db
97 | func (ssq *SqlServerQuery) SetDb(db *sql.DB) {
98 | ssq.db = db
99 | }
100 |
101 | // 获取SQL语句
102 | func (ssq *SqlServerQuery) GetSql() string {
103 | return ""
104 | }
105 |
106 | // 更新一条记录
107 | func (ssq *SqlServerQuery) Update() *SqlServerQuery {
108 | return ssq
109 | }
110 |
111 | // 删除一条记录
112 | func (ssq *SqlServerQuery) Delete() *SqlServerQuery {
113 | return ssq
114 | }
115 |
116 | // 获取一条记录
117 | func (ssq *SqlServerQuery) FetchRow() *sql.Row {
118 | return nil
119 | }
120 |
121 | // 获取多条记录
122 | func (ssq *SqlServerQuery) FetchAll() (*sql.Rows, error) {
123 | return ssq.QueryAll(ssq.sqlExpr, ssq.sqlParam...)
124 | }
125 |
126 | // 设置表达式类型
127 | func (ssq *SqlServerQuery) SetSqlType(t string) error {
128 | ssq.sqlExprType = t
129 | return nil
130 | }
131 |
132 | // 获取表达式类型
133 | func (ssq *SqlServerQuery) GetSqlType() string {
134 | return ssq.sqlExprType
135 | }
136 |
137 | // 创建SQL表达式
138 | func (ssq *SqlServerQuery) SetSql() BaseQuery {
139 | return ssq
140 | }
141 |
142 | // 插入一条记录
143 | func (ssq *SqlServerQuery) Modify() (sql.Result, error) {
144 | return ssq.Exec(ssq.sqlExpr, ssq.sqlParam)
145 | }
146 |
--------------------------------------------------------------------------------
/app/db/table.go:
--------------------------------------------------------------------------------
1 | package db
2 |
3 | import (
4 | "errors"
5 | "github.com/go-touch/regin/app/db/model"
6 | )
7 |
8 | // Table容器
9 | type TableContainer map[string]*model.Table
10 |
11 | var tableContainer *TableContainer
12 |
13 | func init() {
14 | tableContainer = &TableContainer{}
15 | }
16 |
17 | // 设置table
18 | func (tc *TableContainer) Set(key string, table *model.Table) error {
19 | (*tc)[key] = table
20 | return nil
21 | }
22 |
23 | // 获取table
24 | func (tc *TableContainer) Get(key string) (*model.Table, error) {
25 | if table, ok := (*tc)[key]; ok {
26 | return table, nil
27 | }
28 | return nil, errors.New("this model '" + key + "' is not registered")
29 | }
30 |
31 | // Get a table of Model
32 | func GetTable(userModel interface{}) *model.Table {
33 | var table *model.Table
34 | if key, ok := userModel.(string); ok {
35 | if value, err := tableContainer.Get(key); err == nil {
36 | table = value
37 | }
38 | } else if newTable, err := new(model.Table).Init(userModel); err != nil {
39 | panic(err.Error())
40 | } else if name, err := newTable.GetName(); err != nil {
41 | panic(err.Error())
42 | } else if storage, err := tableContainer.Get(name); err == nil {
43 | table = storage
44 | } else {
45 | table = newTable.Factory()
46 | if err := tableContainer.Set(name, table); err != nil {
47 | panic(err.Error())
48 | }
49 | }
50 | return table
51 | }
52 |
--------------------------------------------------------------------------------
/app/http.go:
--------------------------------------------------------------------------------
1 | package app
2 |
3 | import (
4 | "fmt"
5 | "github.com/go-touch/regin/app/core"
6 | "github.com/go-touch/regin/app/service"
7 | "github.com/go-touch/regin/base"
8 | "github.com/go-touch/regin/utils"
9 | )
10 |
11 | type Http struct {
12 | base.WebServer
13 | *service.Application
14 | addrAndPort string
15 | err error
16 | }
17 |
18 | // Create an new Http Server.
19 | func NewHttp() *Http {
20 | server := &Http{
21 | Application: service.App,
22 | }
23 |
24 | // 获取
25 | if host := service.App.GetConfig("server.main.httpHost").ToString(); host == "" {
26 | panic("服务器端口未设置")
27 | } else {
28 | server.addrAndPort = host
29 | }
30 | return server
31 | }
32 |
33 | // Http server work method.
34 | func (h *Http) Work(request *base.Request) *base.Result {
35 |
36 | fmt.Println(request.ParamAll())
37 |
38 |
39 | // Get action.
40 | paramArray := []string{request.Param("module"), request.Param("controller")}
41 | if request.Param("action") != "" {
42 | paramArray = append(paramArray, request.Param("action"))
43 | }
44 | actionKey := utils.StringJoinByDot(paramArray...)
45 | action, err := h.GetRouter().GetGeneral(actionKey)
46 | if err != nil {
47 | panic(err)
48 | }
49 |
50 | // Call Before Action
51 | if result := action.BeforeExec(request); result.Status != 200 || result.GetData("code") != 0 {
52 | return result
53 | }
54 |
55 | // Call Action
56 | return action.Exec(request)
57 | }
58 |
59 | // Http server work method.
60 | func (h *Http) Addr() string {
61 | return h.addrAndPort
62 | }
63 |
64 | // Error catch.
65 | func (h *Http) ErrorCatch(err error) {
66 | if openLog := h.GetConfig("server.error.log").ToBool(); openLog == true {
67 | _ = h.GetLogger().Local(core.Error, err.Error())
68 | }
69 | }
70 |
--------------------------------------------------------------------------------
/app/https.go:
--------------------------------------------------------------------------------
1 | package app
2 |
3 | import "github.com/go-touch/regin/base"
4 |
5 | type Https struct {
6 | base.WebServer
7 | addr string
8 | }
9 |
10 | func NewHttps() *Https {
11 | return &Https{
12 | addr: "127.0.0.1:443",
13 | }
14 | }
15 |
16 | //
17 | func (hs *Https) Work(request *base.Request) *base.Result {
18 | return &base.Result{}
19 | }
20 |
21 | func (hs *Https) Addr() string {
22 | return hs.addr
23 | }
24 |
25 | func (hs *Https) SSLCertPath() string {
26 | return hs.addr
27 | }
28 |
29 | func (hs *Https) ErrorCatch() error {
30 | return nil
31 | }
32 |
--------------------------------------------------------------------------------
/app/service/app.go:
--------------------------------------------------------------------------------
1 | package service
2 |
3 | import (
4 | "github.com/go-touch/mtype"
5 | "github.com/go-touch/regin/app/core"
6 | "github.com/go-touch/regin/base"
7 | )
8 |
9 | type Application struct {
10 | attribute map[string]string // System Attribute
11 | config *core.Config // Config Storage
12 | logger *core.Logger // core Logger
13 | exception *core.Exception // core Exception
14 | router *base.RouterStorage // Router Storage
15 | err error // Runtime error
16 | }
17 |
18 | // Define BaseServer.
19 | var App *Application
20 |
21 | func init() {
22 | App = &Application{
23 | attribute: make(map[string]string),
24 | config: &core.Config{FileFormat: "ini"},
25 | exception: &core.Exception{},
26 | logger: &core.Logger{},
27 | router: base.Router,
28 | }
29 | //defer App.ErrorCatch()
30 | App.init()
31 | App.initCore()
32 | App.initExpand()
33 | }
34 |
35 | // Get application ConfigValue.
36 | func (a *Application) GetConfig(args ...string) *mtype.AnyValue {
37 | return a.config.GetConfig(args...)
38 | }
39 |
40 | // Get Logger.
41 | func (a *Application) GetLogger() *core.Logger {
42 | return a.logger
43 | }
44 |
45 | // Get Exception
46 | func (a *Application) GetException() *core.Exception {
47 | return a.exception
48 | }
49 |
50 | // Get application config.
51 | func (a *Application) GetRouter() *base.RouterStorage {
52 | return a.router
53 | }
54 |
--------------------------------------------------------------------------------
/app/service/init.go:
--------------------------------------------------------------------------------
1 | package service
2 |
3 | import (
4 | "os"
5 | "path/filepath"
6 | "strings"
7 | )
8 |
9 | // Init Application.
10 | func (a *Application) init() {
11 | // Run Mode Include: dev、test、prod
12 | if a.attribute["RunMode"] = os.Getenv("REGIN_RUNMODE"); a.attribute["RunMode"] == "" {
13 | a.attribute["RunMode"] = "dev"
14 | }
15 |
16 | // Application Path ... flag get param yet
17 | if a.attribute["AppPath"], a.err = os.Getwd(); a.err != nil {
18 | panic(a.err)
19 | }
20 |
21 | // Batch Init System Path.
22 | a.BatchInitPath(map[string]string{
23 | "ConfigPath": "config." + a.attribute["RunMode"],
24 | "RuntimePath": "runtime",
25 | "RuntimeLogPath": "runtime.log",
26 | })
27 | }
28 |
29 | // Batch Init System Path.
30 | func (a *Application) BatchInitPath(pathMap map[string]string) {
31 | for key, value := range pathMap {
32 | a.attribute[key] = a.joinPath(a.attribute["AppPath"], a.joinPath(strings.Split(value, ".")...))
33 | // 不存在则创建
34 | if a.err = a.DirExists(a.attribute[key]); a.err != nil {
35 | if err := os.MkdirAll(a.attribute[key], os.ModePerm); err != nil {
36 | panic(a.err)
37 | }
38 | }
39 | }
40 | }
41 |
42 | // Judge dir is exist.
43 | func (a *Application) DirExists(path string) (err error) {
44 | _, err = os.Stat(path)
45 | return err
46 | }
47 |
48 | // Get system attribute.
49 | func (a *Application) GetAttribute(key string) string {
50 | if attribute, ok := a.attribute[key]; ok {
51 | return attribute
52 | }
53 | return ""
54 | }
55 |
56 | // Join path by file Separator.
57 | func (a *Application) joinPath(path ...string) string {
58 | return strings.Join(path, string(filepath.Separator))
59 | }
--------------------------------------------------------------------------------
/app/service/init_core.go:
--------------------------------------------------------------------------------
1 | package service
2 |
3 | // Init system component.
4 | func (a *Application) initCore() {
5 | // Init Config
6 | a.config.Init(a.GetAttribute("ConfigPath"))
7 |
8 | // Init logger.
9 | pattern := ""
10 | if pattern = a.GetConfig("server.error.pattern").ToString(); pattern == "" {
11 | pattern = "local"
12 | }
13 | a.logger.Init(pattern, a.GetAttribute("RuntimeLogPath"))
14 | }
--------------------------------------------------------------------------------
/app/service/init_expand.go:
--------------------------------------------------------------------------------
1 | package service
2 |
3 | import (
4 | "github.com/go-touch/regin/app/cache"
5 | "github.com/go-touch/regin/app/core"
6 | "github.com/go-touch/regin/app/db"
7 | )
8 |
9 | // 初始化扩展包
10 | func (a *Application) initExpand() {
11 | cache.Redis.Init(a.GetConfig("redis").ToAnyMap()) // 初始化Redis
12 | db.Config.Init(a.GetConfig("database").ToAnyMap()) // 初始化Database
13 | db.Config.InitLogWriter(func(anyMap map[string]interface{}) { // 数据库运行日志
14 | _ = a.logger.Local(core.Info, anyMap) // SQL执行日志
15 | })
16 | }
--------------------------------------------------------------------------------
/base/any_value.go:
--------------------------------------------------------------------------------
1 | package base
2 |
3 | import (
4 | "github.com/go-touch/regin/utils"
5 | )
6 |
7 | // 用于转换数据类型
8 | type AnyValue struct {
9 | value interface{}
10 | }
11 |
12 | // 声明一个存储任意类型数据的结构体,然后可以进行类型转换
13 | func Eval(value interface{}) *AnyValue {
14 | return &AnyValue{value: value}
15 | }
16 |
17 | // 返回错误信息
18 | func (av *AnyValue) ToError() error {
19 | switch utils.Convert.GetType(av.value) {
20 | case utils.Error:
21 | return av.value.(error)
22 | }
23 | return nil
24 | }
25 |
26 | // 返回原值
27 | func (av *AnyValue) ToValue() interface{} {
28 | return av.value
29 | }
30 |
31 | // 转成int类型
32 | func (av *AnyValue) ToInt() int {
33 | return utils.Convert.ToTargetType(av.value, utils.Int).(int)
34 | }
35 |
36 | // 转成byte类型
37 | func (av *AnyValue) ToByte() byte {
38 | return utils.Convert.ToTargetType(av.value, utils.Byte).(byte)
39 | }
40 |
41 | // 转成string类型
42 | func (av *AnyValue) ToString() string {
43 | return utils.Convert.ToTargetType(av.value, utils.String).(string)
44 | }
45 |
46 | // 转成bool类型
47 | func (av *AnyValue) ToBool() bool {
48 | return utils.Convert.ToTargetType(av.value, utils.Bool).(bool)
49 | }
50 |
51 | // 转成[]int类型
52 | func (av *AnyValue) ToIntSlice() []int {
53 | value := make([]int, 0)
54 | v := utils.Convert.ToTargetType(av.value, utils.IntSlice)
55 | if v != nil {
56 | value = v.([]int)
57 | }
58 | return value
59 | }
60 |
61 | // 转成[]byte类型
62 | func (av *AnyValue) ToByteSlice() []byte {
63 | value := make([]byte, 0)
64 | v := utils.Convert.ToTargetType(av.value, utils.ByteSlice)
65 | if v != nil {
66 | value = v.([]byte)
67 | }
68 | return value
69 | }
70 |
71 | // 转成[]string类型
72 | func (av *AnyValue) ToStringSlice() []string {
73 | value := make([]string, 0)
74 | v := utils.Convert.ToTargetType(av.value, utils.StringSlice)
75 | if v != nil {
76 | value = v.([]string)
77 | }
78 | return value
79 | }
80 |
81 | // 转成map[string]string类型
82 | func (av *AnyValue) ToStringMap() map[string]string {
83 | value := map[string]string{}
84 | v := utils.Convert.ToTargetType(av.value, utils.StringMap)
85 | if v != nil {
86 | value = v.(map[string]string)
87 | }
88 | return value
89 | }
90 |
91 | // 转成map[string]interface{}类型
92 | func (av *AnyValue) ToAnyMap() map[string]interface{} {
93 | value := map[string]interface{}{}
94 | v := utils.Convert.ToTargetType(av.value, utils.AnyMap)
95 | if v != nil {
96 | value = v.(map[string]interface{})
97 | }
98 | return value
99 | }
100 |
101 | // 转成[]map[string]string类型
102 | func (av *AnyValue) ToStringMapSlice() []map[string]string {
103 | switch utils.Convert.GetType(av.value) {
104 | case utils.StringMapSlice:
105 | return av.value.([]map[string]string)
106 | case utils.AnyMapSlice:
107 | value := make([]map[string]string, 0)
108 | for k, v := range av.value.([]map[string]interface{}) {
109 | value[k] = utils.Convert.ToTargetType(v, utils.StringMap).(map[string]string)
110 | }
111 | return value
112 | }
113 | return nil
114 | }
115 |
--------------------------------------------------------------------------------
/base/app.go:
--------------------------------------------------------------------------------
1 | package base
2 |
3 | import "github.com/go-touch/regin/utils"
4 |
5 | // 获取json
6 | func JsonResult() *Result {
7 | return ResultInvoker.CreateJson(200, "")
8 | }
9 |
10 | /**************************************** 结构体ConfigValue ****************************************/
11 | // Define Data
12 | type ConfigValue struct {
13 | Key string
14 | Value interface{}
15 | }
16 |
17 | // Convert to int.
18 | func (cv *ConfigValue) ToInt() int {
19 | return utils.Convert.ToTargetType(cv.Value, utils.Int).(int)
20 | }
21 |
22 | // Convert to string.
23 | func (cv *ConfigValue) ToString() string {
24 | return utils.Convert.ToTargetType(cv.Value, utils.String).(string)
25 | }
26 |
27 | // Convert to stringMap.
28 | func (cv *ConfigValue) ToStringMap() map[string]string {
29 | return utils.Convert.ToTargetType(cv.Value, utils.StringMap).(map[string]string)
30 | }
31 |
32 | // Convert to StringSlice.
33 | func (cv *ConfigValue) ToStringSlice() []string {
34 | return utils.Convert.ToTargetType(cv.Value, utils.StringSlice).([]string)
35 | }
36 |
37 | // Convert to AnyMap.
38 | func (cv *ConfigValue) ToAnyMap() map[string]interface{} {
39 | return utils.Convert.ToTargetType(cv.Value, utils.AnyMap).(map[string]interface{})
40 | }
41 |
--------------------------------------------------------------------------------
/base/app_action.go:
--------------------------------------------------------------------------------
1 | package base
2 |
3 | type AppAction interface {
4 | //Factory(request *Request) AppAction
5 | //Request() *Request
6 | //Result() *Result
7 | BeforeExec(request *Request) (result *Result)
8 | Exec(request *Request) (result *Result)
9 | }
10 |
11 | type Action struct {
12 | AppAction
13 | request *Request
14 | result *Result
15 | }
16 |
17 | // Get Request.
18 | func (a *Action) Request() *Request {
19 | return a.request
20 | }
21 |
22 | // Get Request.
23 | func (a *Action) Result() *Result {
24 | return a.result
25 | }
26 |
27 | // Before action method.
28 | func (a *Action) BeforeExec(request *Request) (result *Result) {
29 | return
30 | }
31 |
32 | // Action method.
33 | func (a *Action) Exec(request *Request) (result *Result) {
34 | return
35 | }
36 |
--------------------------------------------------------------------------------
/base/app_data.go:
--------------------------------------------------------------------------------
1 | package base
2 |
3 | type Data struct {
4 | Code int
5 | Msg string
6 | Data interface{}
7 | }
8 |
9 | // 创建Data
10 | func MakeData() *Data {
11 | return &Data{Code: 0, Msg: "", Data: ""}
12 | }
13 |
14 | // 设置code
15 | func (d *Data) SetCode(code int) {
16 | d.Code = code
17 | }
18 |
19 | // 设置code
20 | func (d *Data) SetMsg(msg string) {
21 | d.Msg = msg
22 | }
23 |
24 | // 设置code
25 | func (d *Data) SetData(data interface{}) {
26 | d.Data = data
27 | }
28 |
29 | // 读取data
30 | func (d *Data) GetData() *AnyValue {
31 | return Eval(d.Data)
32 | }
--------------------------------------------------------------------------------
/base/app_redis.go:
--------------------------------------------------------------------------------
1 | package base
2 |
3 | type RedisModel struct {
4 | conn string
5 | }
6 |
7 |
8 |
--------------------------------------------------------------------------------
/base/app_router.go:
--------------------------------------------------------------------------------
1 | package base
2 |
3 | import (
4 | "errors"
5 | "github.com/go-touch/regin/utils"
6 | )
7 |
8 | /**************************************** 数据类型 - 结构体RouterStorage ****************************************/
9 | // 路由存储器
10 | type RouterStorage struct {
11 | mode string // 路由模式: General、Restful
12 | generalMap GeneralMap // 对应路由模式: General
13 | }
14 |
15 | // 定义Router
16 | var Router *RouterStorage
17 |
18 | func init() {
19 | Router = &RouterStorage{
20 | mode: "General",
21 | generalMap: GeneralMap{},
22 | }
23 | }
24 |
25 | // 设置模式
26 | func (r *RouterStorage) setMode(mode string) error {
27 | r.mode = mode
28 | return nil
29 | }
30 |
31 | // 获取模式
32 | func (r *RouterStorage) GetMode() string {
33 | return r.mode
34 | }
35 |
36 | // 普通模式
37 | func (r *RouterStorage) General(moduleName string, generalMap GeneralMap) {
38 | // 设置模式
39 | if r.mode != "General" {
40 | r.setMode("General")
41 | }
42 | // 存储
43 | var moduleKey string
44 | for key, value := range generalMap {
45 | moduleKey = utils.StringJoinByDot(moduleName, key)
46 | r.generalMap[moduleKey] = value
47 | }
48 | }
49 |
50 | // 获取GeneralMap
51 | func (r *RouterStorage) GetGeneralMap() GeneralMap {
52 | return r.generalMap
53 | }
54 |
55 | // 获取元素
56 | func (r *RouterStorage) GetGeneral(key string) (value AppAction, err error) {
57 | if action, ok := r.generalMap[key]; ok {
58 | value = action
59 | err = nil
60 | } else {
61 | err = errors.New("获取app.Action失败")
62 | }
63 | return value, err
64 | }
65 |
--------------------------------------------------------------------------------
/base/common.go:
--------------------------------------------------------------------------------
1 | package base
2 |
3 | import "github.com/go-touch/regin/utils"
4 |
5 | /**************************************** 自定义函数类型 UserFunc ****************************************/
6 | type UserFunc func(args ...interface{}) interface{}
7 |
8 | // 转换为 string
9 | func (uf UserFunc) ToString(args ...interface{}) string {
10 | value := utils.Convert.ToTargetType(uf(args...), utils.String)
11 | return string(value.(string))
12 | }
13 |
14 | // 转换为 StringMap
15 | func (uf UserFunc) ToStringMap(args ...interface{}) map[string]string {
16 | value := utils.Convert.ToTargetType(uf(args...), utils.StringMap)
17 | return map[string]string(value.(map[string]string))
18 | }
--------------------------------------------------------------------------------
/base/data_type.go:
--------------------------------------------------------------------------------
1 | package base
2 |
3 | type DataType interface {
4 | Set(key string, value interface{})
5 | Get(key string) *AnyValue
6 | }
7 |
8 | // 预定义常见数据类型
9 | type AnyMap map[string]interface{} // [MapType] key is string,value is 任意类型
10 | type StringMap map[string]string // [MapType] key is string,value is string type
11 | type IntMap map[string]int // [MapType] key is string,value is int type
12 | type StringSliceMap map[string][]string // [MapType] key is string,value is string Slice type
13 | type GeneralMap map[string]AppAction // [MapType] key is string,value is AppAction type
14 | type AnySlice []interface{} // [SliceType] key is index,value为任意类型
15 | type StringMapSlice []map[string]string // [SliceType] key is index,value为(key为string,value为string)的map
16 | type AnyMapSlice []map[string]interface{} // [SliceType] key is index,value为(key为string,value为任意类型)的map
17 |
18 | // 设置
19 | func (am *AnyMap) Set(key string, value interface{}) {
20 | (*am)[key] = value
21 | }
22 |
23 | // 读取
24 | func (am *AnyMap) Get(key ...string) *AnyValue {
25 | if key == nil || key[0] == "" {
26 | return Eval(*am)
27 | } else if value, ok := (*am)[key[0]]; ok {
28 | return Eval(value)
29 | }
30 | return Eval("")
31 | }
--------------------------------------------------------------------------------
/base/origin.go:
--------------------------------------------------------------------------------
1 | package base
2 |
3 | /**************************************** 接口 ****************************************/
4 | type WebServer interface {
5 | Work(*Request) *Result
6 | Addr() string
7 | SSLCertPath() string
8 | ErrorCatch(error)
9 | }
10 |
--------------------------------------------------------------------------------
/base/origin_request.go:
--------------------------------------------------------------------------------
1 | package base
2 |
3 | import (
4 | "encoding/json"
5 | "encoding/xml"
6 | "github.com/gin-gonic/gin"
7 | "github.com/go-touch/mtype"
8 | "io/ioutil"
9 | "mime/multipart"
10 | "net/http"
11 | "strings"
12 | )
13 |
14 | const defaultMultipartMemory = 32 << 20 // 32 MB
15 |
16 | type Request struct {
17 | //*http.Request
18 | *gin.Context
19 | Storage *mtype.AnyMap // 运行期间的存储容器
20 | paramMap StringMap
21 | getMap StringMap
22 | cookieMap StringMap
23 | postMap *mtype.AnyMap
24 | postFileSlice []*multipart.FileHeader
25 | rawSlice []byte
26 | error error
27 | }
28 |
29 | // Define static Request
30 | var RequestInvoker *Request
31 |
32 | func init() {
33 | RequestInvoker = &Request{}
34 | }
35 |
36 | // Create an new Request.
37 | func (r *Request) Factory(c *gin.Context) *Request {
38 | request := &Request{
39 | Context: c,
40 | //Request: c.Request,
41 | Storage: &mtype.AnyMap{},
42 | cookieMap: map[string]string{},
43 | paramMap: map[string]string{},
44 | getMap: map[string]string{},
45 | postMap: &mtype.AnyMap{},
46 | postFileSlice: []*multipart.FileHeader{},
47 | rawSlice: make([]byte, 0),
48 | }
49 | _ = request.initParam(c.Params)
50 | _ = request.initGet()
51 | _ = request.initPost()
52 | return request
53 | }
54 |
55 | // Init Param data.
56 | func (r *Request) initParam(params gin.Params) error {
57 | for _, element := range params {
58 | r.paramMap[element.Key] = element.Value
59 | }
60 | return nil
61 | }
62 |
63 | // Init GET data.
64 | func (r *Request) initGet() error {
65 | params := r.Request.URL.Query()
66 | for key, value := range params {
67 | r.getMap[key] = value[len(value)-1]
68 | }
69 | return nil
70 | }
71 |
72 | // Init POST data.
73 | func (r *Request) initPost() error {
74 | // When Request method is POST then parser data.
75 | if r.Request.Method == "POST" {
76 | // Handle data by Content-Type.
77 | ct := r.Request.Header.Get("Content-Type")
78 | if strings.Contains(ct, "/x-www-form-urlencoded") || strings.Contains(ct, "/form-data") {
79 | if r.error = r.Request.ParseMultipartForm(defaultMultipartMemory); r.error != nil && r.error != http.ErrNotMultipart {
80 | return r.error
81 | }
82 | for key, value := range r.Request.PostForm {
83 | if len(value) == 1 {
84 | (*r.postMap)[key] = value[0]
85 | } else {
86 | (*r.postMap)[key] = value
87 | }
88 | }
89 | // Parser postMap data when Contains [].
90 | *r.postMap = r.parserPostMap(*r.postMap)
91 | return nil
92 | } else { // Handle data by other Content-Type.
93 | if r.rawSlice, r.error = ioutil.ReadAll(r.Request.Body); r.error != nil {
94 | return r.error
95 | }
96 | if strings.Contains(ct, "/json") { // Content-Type is Json.
97 | if r.error = json.Unmarshal(r.rawSlice, r.postMap); r.error != nil {
98 | return r.error
99 | }
100 | } else if strings.Contains(ct, "/xml") { // Content-Type is Xml.
101 | if r.error = xml.Unmarshal(r.rawSlice, r.postMap); r.error != nil {
102 | return r.error
103 | }
104 | }
105 | }
106 | }
107 | return nil
108 | }
109 |
110 | // Get Http request method
111 | func (r *Request) GetMethod() string {
112 | return r.Request.Method
113 | }
114 |
115 | // Get error info
116 | func (r *Request) GetError() error {
117 | return r.error
118 | }
119 |
120 | // Path data.
121 | func (r *Request) Param(key string, defaultValue ...string) string {
122 | val := ""
123 | if defaultValue != nil {
124 | val = defaultValue[0]
125 | }
126 | if value, ok := r.paramMap[key]; ok {
127 | return value
128 | }
129 | return val
130 | }
131 |
132 | // Get param array.
133 | func (r *Request) ParamAll() map[string]string {
134 | return r.paramMap
135 | }
136 |
137 | // Get data.
138 | func (r *Request) Get(key string, defaultValue ...string) string {
139 | val := ""
140 | if defaultValue != nil {
141 | val = defaultValue[0]
142 | }
143 | if value, ok := r.getMap[key]; ok {
144 | return value
145 | }
146 | return val
147 | }
148 |
149 | // Get param array.
150 | func (r *Request) GetAll() map[string]string {
151 | return r.getMap
152 | }
153 |
154 | // POST param.
155 | func (r *Request) Post() *mtype.AnyMap {
156 | return r.postMap
157 | }
158 |
159 | // POST file.
160 | func (r *Request) PostFile(name string) []*multipart.FileHeader {
161 | if r.Request.MultipartForm != nil && r.Request.MultipartForm.File != nil {
162 | if fileHeaders, ok := r.Request.MultipartForm.File[name]; ok {
163 | r.postFileSlice = fileHeaders
164 | }
165 | }
166 | return r.postFileSlice
167 | }
168 |
169 | // 获取元数据
170 | func (r *Request) Raw() []byte {
171 | return r.rawSlice
172 | }
173 |
174 | // Convert POST data to struct.
175 | func (r *Request) ToStruct(object interface{}, method ...string) error {
176 | byteSlice := make([]byte, 0)
177 |
178 | // Handle data by method.
179 | m := "POST"
180 | if method != nil {
181 | m = strings.ToUpper(method[0])
182 | }
183 | if m == "GET" {
184 | if data, err := json.Marshal(r.getMap); err != nil {
185 | return err
186 | } else {
187 | byteSlice = data
188 | }
189 | } else if m == "POST" {
190 | if len(r.rawSlice) > 0 {
191 | byteSlice = r.rawSlice
192 | } else if data, err := json.Marshal(r.postMap); err != nil {
193 | return err
194 | } else {
195 | byteSlice = data
196 | }
197 | }
198 |
199 | // Parse []byte to struct.
200 | err := json.Unmarshal(byteSlice, object)
201 | if err != nil {
202 | return err
203 | }
204 | return nil
205 | }
206 |
207 | // Parser postMap data.
208 | func (r *Request) parserPostMap(anyMap map[string]interface{}) map[string]interface{} {
209 | tmpMap := map[string]interface{}{}
210 | for key, value := range anyMap {
211 | i := strings.IndexByte(key, '[')
212 | j := strings.IndexByte(key, ']')
213 |
214 | if i >= 1 && j >= 1 {
215 | trimKey := strings.Trim(key, "]")
216 | k := trimKey[0:i]
217 | subK := trimKey[i+1:]
218 | if _, ok := tmpMap[k]; !ok {
219 | tmpMap[k] = map[string]interface{}{
220 | subK: value,
221 | }
222 | } else {
223 | tmpMap[k].(map[string]interface{})[subK] = value
224 | }
225 | delete(anyMap, key)
226 | }
227 | }
228 | for key, value := range tmpMap {
229 | anyMap[key] = value
230 | }
231 | return anyMap
232 | }
233 |
--------------------------------------------------------------------------------
/base/origin_result.go:
--------------------------------------------------------------------------------
1 | package base
2 |
3 | import "io"
4 |
5 | /**************************************** 数据类型 - 结构体Result ****************************************/
6 | // 用户输出函数
7 | type UserFuncOutput func(writer io.Writer)
8 |
9 | // 响应结构体
10 | type Result struct {
11 | Type string // 可选值为:String、Json、Html、Stream
12 | header map[string]string // 头信息
13 | userOutput UserFuncOutput // 用户可控制输出函数
14 | Page string // 响应页面(Type = Html时必填)
15 | Status int // 状态码 200正常状态
16 | Msg string // 提示消息
17 | Data AnyMap // 业务数据
18 | }
19 |
20 | // 定义RespResult
21 | var ResultInvoker *Result
22 |
23 | func init() {
24 | ResultInvoker = &Result{}
25 | }
26 |
27 | // 设置 header
28 | func (r *Result) SetHeader(key string, value string) {
29 | r.header[key] = value
30 | }
31 |
32 | // 获取 header
33 | func (r *Result) GetHeader() map[string]string {
34 | return r.header
35 | }
36 |
37 | // 用户自定义输出
38 | func (r *Result) SetOutput(userFunc UserFuncOutput) {
39 | r.userOutput = userFunc
40 | }
41 |
42 | // 获取用户自定义输出
43 | func (r *Result) GetOutput() UserFuncOutput {
44 | return r.userOutput
45 | }
46 |
47 | // Business data method.
48 | func (r *Result) SetData(key string, value interface{}) {
49 | r.Data[key] = value
50 | }
51 |
52 | // business data method - 获取Data
53 | func (r *Result) GetData(key string) interface{} {
54 | return r.Data[key]
55 | }
56 |
57 | // 创建Json result
58 | func (r *Result) CreateJson(status int, msg string) *Result {
59 | return &Result{
60 | Type: "Json",
61 | header: map[string]string{},
62 | Page: "",
63 | Status: status,
64 | Msg: msg,
65 | Data: AnyMap{"code": 0, "msg": "", "data": ""},
66 | }
67 | }
68 |
69 | // 创建Json result
70 | func (r *Result) CreateHtml(page string, status int, msg string) *Result {
71 | return &Result{
72 | Type: "Html",
73 | header: map[string]string{},
74 | Page: page,
75 | Status: status,
76 | Msg: msg,
77 | Data: AnyMap{},
78 | }
79 | }
80 |
81 | // 创建 Stream Result
82 | func StreamResult() *Result {
83 | return &Result{
84 | Type: "Stream",
85 | header: map[string]string{},
86 | Page: "",
87 | Status: 200,
88 | Msg: "",
89 | Data: AnyMap{"code": 0, "msg": "", "data": ""},
90 | }
91 | }
92 |
--------------------------------------------------------------------------------
/guide.go:
--------------------------------------------------------------------------------
1 | package regin
2 |
3 | import (
4 | "github.com/go-touch/regin/app"
5 | "github.com/go-touch/regin/origin"
6 | )
7 |
8 | type Guider struct{}
9 |
10 | // 定义Guider
11 | var Guide *Guider
12 |
13 | func init() {
14 | Guide = &Guider{}
15 | }
16 |
17 | // 开启http服务
18 | func (e *Guider) HttpService() {
19 | origin.Engine.HttpServer(app.NewHttp())
20 | }
21 |
--------------------------------------------------------------------------------
/origin/engine.go:
--------------------------------------------------------------------------------
1 | package origin
2 |
3 | import (
4 | "fmt"
5 | "github.com/gin-gonic/gin"
6 | "github.com/go-touch/regin/base"
7 | "net/http"
8 | )
9 |
10 | type EngineDispatcher struct {
11 | origin *gin.Engine
12 | response *ResponseHandler
13 | }
14 |
15 | // 定义RouterHandler
16 | var Engine *EngineDispatcher
17 |
18 | func init() {
19 | Engine = &EngineDispatcher{
20 | origin: gin.Default(),
21 | response: Response,
22 | }
23 | }
24 |
25 | // Run HttpServer
26 | func (ed *EngineDispatcher) HttpServer(server base.WebServer) {
27 | // 解决跨域
28 | ed.origin.Use(func(c *gin.Context) {
29 | method := c.Request.Method
30 | c.Header("Access-Control-Allow-Origin", "*")
31 | c.Header("Access-Control-Allow-Headers", "Content-Type,AccessToken,X-CSRF-Token, Authorization, Token")
32 | c.Header("Access-Control-Allow-Methods", "POST, GET, OPTIONS")
33 | c.Header("Access-Control-Expose-Headers", "Content-Length, Access-Control-Allow-Origin, Access-Control-Allow-Headers, Content-Type")
34 | c.Header("Access-Control-Allow-Credentials", "true")
35 | // 放行所有OPTIONS方法
36 | if method == "OPTIONS" {
37 | c.AbortWithStatus(http.StatusNoContent)
38 | }
39 | // 处理请求
40 | c.Next()
41 | })
42 |
43 | // 注册路由
44 | /*ed.origin.Any("/:module/:controller/:action", func(c *gin.Context) {
45 | // Error catch.
46 | defer func() {
47 | if r := recover(); r != nil {
48 | // Error catch.
49 | server.ErrorCatch(Error(r))
50 | // 打印
51 | fmt.Println(Error(r))
52 | // Exception response.
53 | result := base.ResultInvoker.CreateJson(200, "")
54 | result.SetData("code", 10000)
55 | result.SetData("msg", "There's something wrong with the server.")
56 | _ = ed.response.Output(c, result)
57 | }
58 | }()
59 | _ = ed.response.Output(c, server.Work(base.RequestInvoker.Factory(c)))
60 | })*/
61 |
62 | // 注册路由
63 | ed.origin.Any("/api/:module/:controller", func(c *gin.Context) {
64 | // Error catch.
65 | defer func() {
66 | if r := recover(); r != nil {
67 | // Error catch.
68 | server.ErrorCatch(Error(r))
69 | // 打印
70 | fmt.Println(Error(r))
71 | // Exception response.
72 | result := base.ResultInvoker.CreateJson(200, "")
73 | result.SetData("code", 10000)
74 | result.SetData("msg", "There's something wrong with the server.")
75 | _ = ed.response.Output(c, result)
76 | }
77 | }()
78 | _ = ed.response.Output(c, server.Work(base.RequestInvoker.Factory(c)))
79 | })
80 |
81 | // 静态资源
82 | ed.origin.Static("/apidoc", "./apidoc")
83 | ed.origin.LoadHTMLFiles("apidoc/index.html")
84 |
85 | _ = ed.origin.Run(server.Addr()) // Run HttpServer
86 | }
87 |
88 | // 获取key
89 | func (ed *EngineDispatcher) routerName(moduleName string, joinPathStr string) {
90 |
91 |
92 |
93 |
94 | }
95 |
96 | // 异常捕获
97 | func (ed *EngineDispatcher) errorCatch(server base.WebServer) {
98 | if r := recover(); r != nil {
99 | // Error catch.
100 | server.ErrorCatch(Error(r))
101 | // 打印
102 | fmt.Println(Error(r))
103 | // Exception response.
104 | result := base.ResultInvoker.CreateJson(200, "")
105 | result.SetData("code", 10000)
106 | result.SetData("msg", "There's something wrong with the server.")
107 | //_ = ed.response.Output(c, result)
108 | }
109 | }
110 |
--------------------------------------------------------------------------------
/origin/error.go:
--------------------------------------------------------------------------------
1 | package origin
2 |
3 | import (
4 | "errors"
5 | "fmt"
6 | "runtime"
7 | "strconv"
8 | "strings"
9 | )
10 |
11 | // Error info.
12 | func Error(recover interface{}) error {
13 | var array [4096]byte
14 | buf := array[:]
15 | runtime.Stack(buf, false)
16 | stackString := Stack(recover, buf)
17 | return errors.New(stackString)
18 | }
19 |
20 | // Handle Stack message.
21 | func Stack(err interface{}, buf []byte) string {
22 | var stackSlice []string
23 | var msg string
24 |
25 | // Filename、line
26 | if _, srcName, line, ok := runtime.Caller(3); ok {
27 | msg = fmt.Sprintf("[Error]File:%s Line:%s Msg:%s \nMethod Stack meassage:", srcName, strconv.Itoa(line), err)
28 | stackSlice = append(stackSlice, msg)
29 | } else {
30 | msg = fmt.Sprintf("[Error]Msg:%s \nMethod Stack meassage:", err)
31 | stackSlice = append(stackSlice, msg)
32 | }
33 |
34 | // Handle data.
35 | stringStack := string(buf) // Convert to string
36 | tmpStack := strings.Split(stringStack, "\n") // Split to []string by \n
37 | var receiveStack []string
38 |
39 | for _, v := range tmpStack {
40 | receiveStack = append(receiveStack, strings.TrimSpace(v))
41 | }
42 | for i, j, k := 0, 0, len(receiveStack)-1; i < k; i += 2 {
43 | stackSlice = append(stackSlice, "["+strconv.Itoa(j)+"]"+receiveStack[i]+" "+receiveStack[i+1])
44 |
45 | if j == 10 {
46 | stackSlice = append(stackSlice, "...")
47 | break
48 | }
49 | j++
50 | }
51 | return strings.Join(stackSlice, "\n")
52 | }
53 |
--------------------------------------------------------------------------------
/origin/response.go:
--------------------------------------------------------------------------------
1 | package origin
2 |
3 | import (
4 | "github.com/gin-gonic/gin"
5 | "github.com/go-touch/regin/base"
6 | )
7 |
8 | type ResponseHandler struct {
9 | page404 string
10 | page500 string
11 | }
12 |
13 | // 定义ResponseHandler
14 | var Response *ResponseHandler
15 |
16 | func init() {
17 | Response = &ResponseHandler{}
18 | }
19 |
20 | // 输出
21 | func (rh *ResponseHandler) Output(c *gin.Context, result *base.Result) error {
22 | // 响应
23 | switch result.Type {
24 | case "String":
25 | return rh.OutputString(c, result)
26 | case "Json":
27 | return rh.OutputJson(c, result)
28 | case "Html":
29 | return rh.OutputHtml(c, result)
30 | case "Stream":
31 | return rh.OutputStream(c, result)
32 | }
33 | return nil
34 | }
35 |
36 | // 输出json
37 | func (rh *ResponseHandler) OutputJson(c *gin.Context, result *base.Result) error {
38 | // 响应
39 | switch result.Status {
40 | case 200:
41 | if result.GetData("code") == 0 {
42 | result.SetData("msg", "请求成功")
43 | }
44 | case 404:
45 | result.SetData("code", 404)
46 | result.SetData("msg", result.Msg)
47 | case 500:
48 | result.SetData("code", 500)
49 | result.SetData("msg", result.Msg)
50 | default:
51 | result.SetData("code", result.Status)
52 | result.SetData("msg", result.Msg)
53 | }
54 |
55 | // 输出
56 | c.JSON(result.Status, result.Data)
57 | return nil
58 | }
59 |
60 | // 输出String
61 | func (rh *ResponseHandler) OutputString(c *gin.Context, result *base.Result) error {
62 | // 响应
63 | switch result.Status {
64 | case 404:
65 | result.SetData("code", 404)
66 | result.SetData("msg", result.Msg)
67 | case 500:
68 | result.SetData("code", 500)
69 | result.SetData("msg", result.Msg)
70 | default:
71 | result.SetData("msg", "请求成功")
72 | }
73 |
74 | // 输出
75 | c.JSON(result.Status, result.Data)
76 | return nil
77 | }
78 |
79 | // 输出Html
80 | func (rh *ResponseHandler) OutputHtml(c *gin.Context, result *base.Result) error {
81 | // 响应
82 | switch result.Status {
83 | case 404:
84 | result.SetData("code", 404)
85 | result.SetData("msg", result.Msg)
86 | case 500:
87 | result.SetData("code", 500)
88 | result.SetData("msg", result.Msg)
89 | default:
90 | result.SetData("msg", "请求成功")
91 | }
92 |
93 | // 输出
94 | c.JSON(result.Status, result.Data)
95 | return nil
96 | }
97 |
98 | // 输出Html
99 | func (rh *ResponseHandler) OutputStream(c *gin.Context, result *base.Result) error {
100 | // 响应
101 | switch result.Status {
102 | case 404:
103 | result.SetData("code", 404)
104 | result.SetData("msg", result.Msg)
105 | case 500:
106 | result.SetData("code", 500)
107 | result.SetData("msg", result.Msg)
108 | default:
109 | result.SetData("msg", "请求成功")
110 | }
111 |
112 | // 头信息
113 | if header := result.GetHeader(); len(header) > 0 {
114 | for key, value := range header {
115 | c.Header(key, value)
116 | }
117 | }
118 |
119 | // 用户自定义输出
120 | if userFunc := result.GetOutput(); userFunc != nil {
121 | userFunc(c.Writer)
122 | } else { // 默认输出
123 | c.JSON(result.Status, result.Data)
124 | }
125 | return nil
126 | }
127 |
--------------------------------------------------------------------------------
/test/test1/t1.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "fmt"
5 | "github.com/go-touch/regin/app/db"
6 | )
7 |
8 | type Base struct {
9 | }
10 |
11 | type PlusMenu2 struct {
12 | Base
13 | Id int `field:"id"`
14 | Pid int `field:"pid"`
15 | MenuName string `field:"menu_name"`
16 | }
17 |
18 | // 数据库标识(此方法可重构,用于切换数据库,默认master)
19 | func (this PlusMenu2) Identify() string {
20 | return "master"
21 | }
22 |
23 | // 数据库表名(此方法可重构,用于切换数据表)
24 | func (this PlusMenu2) TableName() string {
25 | return "plus_menu2"
26 | }
27 |
28 | func main() {
29 | db.Config.Init(map[string]interface{}{
30 | "master": map[string]string{
31 | "driverName": "mysql",
32 | "dataSourceName": "vdong:qO39eudVDA@tcp(39.106.157.226:3306)/plus_operation?charset=utf8",
33 | "maxIdleConn": "100",
34 | "maxOpenConn": "100",
35 | },
36 | })
37 | // 更新一条数据 -- 错误示例
38 | model := db.Model(&PlusMenu2{})
39 | ret := model.Update(func(dao *db.Dao) {
40 | dao.Where("id", "94")
41 | dao.Values(map[string]interface{}{
42 | "pid": "1",
43 | })
44 | //dao.Sql()
45 | })
46 | fmt.Println(ret.ToError())
47 | fmt.Println(ret.ToString())
48 | fmt.Println(ret.ToAffectedRows())
49 | }
50 |
--------------------------------------------------------------------------------
/test/test1/t2.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "fmt"
5 | "github.com/go-touch/regin/app/db"
6 | )
7 |
8 | type AdminUsers struct {
9 | Uid int `field:"uid"`
10 | Account string `field:"account"`
11 | Username string `field:"username"`
12 | }
13 |
14 | type AdminRoles struct {
15 | Id int `field:"id"`
16 | Name string `field:"name"`
17 | Desc string `field:"desc"`
18 | }
19 |
20 | // 数据库标识(此方法可重构,用于切换数据库,默认master)
21 | func (this AdminUsers) Identify() string {
22 | return "master"
23 | }
24 |
25 | // 数据库表名(此方法可重构,用于切换数据表)
26 | func (this AdminUsers) TableName() string {
27 | return "admin_users"
28 | }
29 |
30 | func main() {
31 | db.Config.Init(map[string]interface{}{
32 | "master": map[string]string{
33 | "driverName": "mysql",
34 | "dataSourceName": "vdong:qO39eudVDA@tcp(39.106.157.226:3306)/plus_operation?charset=utf8",
35 | "maxIdleConn": "10",
36 | "maxOpenConn": "100",
37 | },
38 | })
39 |
40 | // 测试
41 | model := db.Model(&AdminUsers{})
42 | model.Begin() // 开始事务
43 | ret1 := model.Update(func(dao *db.Dao) {
44 | dao.Values(map[string]interface{}{
45 | "account": "测试事务1",
46 | })
47 | dao.Where("username", "admin1")
48 | //dao.Sql()
49 | })
50 | fmt.Printf("ret1的数据:%v\n", ret1.ToAffectedRows())
51 |
52 | _ = model.Update(func(dao *db.Dao) {
53 | dao.Values(map[string]interface{}{
54 | "account": "测试事务1222",
55 | })
56 | dao.Where("username", "admin1")
57 | //dao.Sql()
58 | })
59 |
60 |
61 | // 查询
62 | ret2 := db.Model(&AdminRoles{}).FetchAll(func(dao *db.Dao) {
63 |
64 | })
65 | fmt.Printf("ret2的数据:%v\n", ret2.ToStringMapSlice())
66 |
67 | /* // 查询
68 | ret4 := db.Model(&AdminUsers{}).FetchRow(func(dao *db.Dao) {
69 | dao.Where("username", "admin2")
70 | })
71 | fmt.Printf("ret3的数据:%v\n", ret4.ToStringMap())
72 | */
73 | // 更新
74 | ret3 := db.Model(&AdminRoles{}).Update(func(dao *db.Dao) {
75 | dao.Values(map[string]interface{}{
76 | "name": "测试223",
77 | })
78 | dao.Where("id", "115")
79 | })
80 | fmt.Printf("ret3的数据:%v\n", ret3.ToAffectedRows())
81 |
82 | ret4 := db.Model(&AdminUsers{}).FetchAll(func(dao *db.Dao) {
83 | dao.Where("username", "admin2")
84 | })
85 | fmt.Printf("ret4的数据:%v\n", ret4.ToStringMapSlice())
86 |
87 | // model.Rollback()
88 |
89 | }
90 |
--------------------------------------------------------------------------------
/test/test1/t3.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "database/sql"
5 | "fmt"
6 | _ "github.com/go-sql-driver/mysql"
7 | )
8 |
9 | func main() {
10 | //var username string
11 | // 数据库连接对象
12 | db, e := sql.Open("mysql", "vdong:qO39eudVDA@tcp(39.106.157.226:3306)/plus_operation?charset=utf8")
13 | if e != nil {
14 | panic(e)
15 | }
16 | db.SetMaxOpenConns(2)
17 |
18 | // 查询1
19 | rows1, _ := db.Query("SELECT username FROM admin_users" + "")
20 | fmt.Printf("row1的值:%v\n", rows1)
21 |
22 | tx, _ := db.Begin()
23 | fmt.Printf("开启事务,tx的值:%v\n", tx)
24 |
25 | // 查询2
26 | rows2, _ := tx.Query("SELECT username FROM admin_users" + "")
27 | fmt.Printf("rows2的值:%v\n", rows2)
28 | _ = rows2.Close()
29 |
30 | fmt.Printf("tx的值:%v\n", tx)
31 |
32 |
33 | // 查询3
34 | rows3, _ := tx.Query("SELECT username FROM admin_users" + "")
35 | fmt.Printf("rows3的值:%v\n", rows3)
36 | _ = rows3.Close()
37 |
38 | _ = tx.Commit()
39 |
40 | fmt.Printf("tx的值:%v\n", tx)
41 |
42 | /*fmt.Println(rows)
43 | _ = rows.Close()
44 |
45 | tx, _ := db.Begin()
46 |
47 | tx.Exec("insert into admin_users (username) values ('测试一下')")
48 |
49 | // 查询2
50 | rows2, err2 := db.Query("SELECT * FROM admin_nodes")
51 | if err2 != nil {
52 | panic(err2)
53 | }
54 | fmt.Println(rows2)
55 | _ = rows2.Close()
56 |
57 | // 查询3
58 | rows3, err3 := db.Query("SELECT * FROM admin_roles")
59 | if err3 != nil {
60 | panic(err3)
61 | }
62 | fmt.Println(rows3)
63 | _ = rows3.Close()
64 |
65 | _ = tx.Commit()*/
66 | }
67 |
--------------------------------------------------------------------------------
/test/test1/t4.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import "fmt"
4 |
5 | type Container map[string]*Tx
6 | type Tx struct {
7 | name string
8 | }
9 |
10 | type A struct {
11 | tx *Tx
12 | }
13 |
14 | type B struct {
15 | tx *Tx
16 | }
17 |
18 | var c Container
19 |
20 | func init() {
21 | c = Container{"tx": &Tx{"张三"}}
22 | }
23 |
24 | func main() {
25 | testa := A{tx: c["tx"]}
26 | testb := B{tx: c["tx"]}
27 |
28 | fmt.Printf("testa的值为:%v\n", testa)
29 | fmt.Printf("testb的值为:%v\n", testb)
30 |
31 | fmt.Printf("c的值为:%v\n", c)
32 | fmt.Println(c)
33 |
34 | *c["tx"] = nil
35 |
36 | fmt.Printf("testa的值为:%v\n", testa.tx)
37 | fmt.Printf("testb的值为:%v\n", testb.tx)
38 |
39 | }
40 |
--------------------------------------------------------------------------------
/test/test1/t5.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "fmt"
5 | "github.com/go-touch/regin/app/db"
6 | )
7 |
8 | type BaseModel struct {
9 | }
10 |
11 | // 数据库标识(此方法可重构,用于切换数据库,默认master)
12 | func (this BaseModel) Identify() string {
13 | return "master"
14 | }
15 |
16 | type AdminUsers2 struct {
17 | BaseModel
18 | Uid int `field:"uid"`
19 | Account string `field:"account"`
20 | Username string `field:"username"`
21 | }
22 |
23 | // 数据库表名(此方法可重构,用于切换数据表)
24 | func (this AdminUsers2) TableName() string {
25 | return "admin_users"
26 | }
27 |
28 | type AdminRoles2 struct {
29 | BaseModel
30 | Id int `field:"id"`
31 | Name string `field:"name"`
32 | Desc string `field:"desc"`
33 | }
34 |
35 | // 数据库标识(此方法可重构,用于切换数据库,默认master)
36 | func (this AdminRoles2) TableName() string {
37 | return "admin_roles"
38 | }
39 |
40 | func main() {
41 | db.Config.Init(map[string]interface{}{
42 | "master": map[string]string{
43 | "driverName": "mysql",
44 | "dataSourceName": "vdong:qO39eudVDA@tcp(39.106.157.226:3306)/plus_operation?charset=utf8",
45 | "maxIdleConn": "100",
46 | "maxOpenConn": "1",
47 | },
48 | })
49 | // 查询
50 | dao := db.Model(&AdminUsers2{})
51 |
52 | ret := dao.FetchRow(func(dao *db.Dao) {
53 | dao.Where("Account like", "%15116980818%")
54 | //dao.Sql()
55 | })
56 |
57 | fmt.Println(ret.ToStringMap())
58 |
59 | dao.GetDuration()
60 | /*ret1 := dao.QueryRow("SELECT count(*) as num from admin_users")
61 | fmt.Printf("ret1的值为:%v\n", ret1)
62 |
63 | a := ret1.ToStringMap()
64 | fmt.Printf("值:%v\n", a)
65 | fmt.Printf("类型:%T\n", ret1.ToValue())*/
66 |
67 | /*dao := db.Model(&AdminUsers2{})
68 | fmt.Printf("dao的值为:%v\n", dao.GetQuery())
69 |
70 | // 开启事务
71 | dao.Begin()
72 | fmt.Printf("dao的值为:%v\n", dao.GetQuery())
73 |
74 | // 查询
75 | ret1 := dao.Query("SELECT uid,username,account FROM admin_users limit 1")
76 | fmt.Printf("ret1的值为:%v\n", ret1)
77 |
78 | // 查询
79 | ret2 := dao.FetchAll(func(dao *db.Dao) {
80 | dao.Limit(1)
81 | })
82 | fmt.Printf("ret2的值为:%v\n", ret2)
83 |
84 | // 查询
85 | dao2 := db.Model(&AdminRoles2{}).Tx(dao)
86 | fmt.Printf("dao2的值为:%v\n", dao2.GetQuery())
87 |
88 | ret3 := dao2.FetchAll(func(dao *db.Dao) {
89 | dao.Limit(1)
90 | })
91 | fmt.Printf("ret3的值为:%v\n", ret3)
92 | fmt.Printf("dao2的值为:%v\n", dao2.GetQuery())
93 |
94 | // 插入数据
95 | ret4 := dao.Insert(func(dao *db.Dao) {
96 | dao.Values(map[string]interface{}{
97 | "username": "张小三",
98 | })
99 | })
100 | fmt.Printf("ret4的值为:%v\n", ret4)
101 | fmt.Printf("dao的值为:%v\n", dao.GetQuery())
102 |
103 | // 插入数据
104 | ret5 := dao2.Tx(dao).Insert(func(dao *db.Dao) {
105 | dao.Values(map[string]interface{}{
106 | "name": "角色张小三",
107 | })
108 | })
109 | fmt.Printf("ret5的值为:%v\n", ret5)
110 | fmt.Printf("dao的值为:%v\n", dao.GetQuery())
111 |
112 | dao.Commit()
113 |
114 | fmt.Printf("dao的值为:%v\n", dao.GetQuery())*/
115 | }
116 |
--------------------------------------------------------------------------------
/test/test1/t6.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 | func main(){
10 |
11 |
12 | }
13 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/test/test1/test1.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "github.com/go-touch/regin/app/db/query"
5 | )
6 |
7 | func main() {
8 | mysql := new(query.MysqlQuery).Clone()
9 | //mysql.Field("`username`,password`,`address")
10 | //mysql.Field([]string{"a.menu_name as name", "style", "is_menu"})
11 | mysql.Table("admin_user as au")
12 | mysql.Where("id = ?", 1)
13 | mysql.Where("username = ? ","admin")
14 |
15 |
16 | mysql.FetchRow()
17 |
18 | }
19 |
--------------------------------------------------------------------------------
/test/test1/test2.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "fmt"
5 | "github.com/go-touch/regin/app/db"
6 | )
7 |
8 | type Base struct {
9 | }
10 |
11 | type AdminUsers struct {
12 | Base
13 | Uid int `field:"uid"`
14 | Account string `field:"account"`
15 | Username string `field:"username"`
16 | }
17 |
18 | // 数据库标识(此方法可重构,用于切换数据库,默认master)
19 | func (this AdminUsers) Identify() string {
20 | return "master"
21 | }
22 |
23 | // 数据库表名(此方法可重构,用于切换数据表)
24 | func (this AdminUsers) TableName() string {
25 | return "admin_users"
26 | }
27 |
28 | func main() {
29 | db.Config.Init(map[string]interface{}{
30 | "master": map[string]string{
31 | "driverName": "mysql",
32 | "dataSourceName": "vdong:qO39eudVDA@tcp(39.106.157.226:3306)/plus_operation?charset=utf8",
33 | "maxIdleConn": "100",
34 | "maxOpenConn": "100",
35 | },
36 | })
37 |
38 | // 查询单条记录
39 | /*model := db.Model(&AdminUsers{})
40 | sql := model.FetchRow(func(dao *db.Dao) {
41 | dao.Where("account", 15801690885)
42 | //dao.Where("account", 111)
43 | dao.Field("uid,account,username,avatar,")
44 | dao.Limit(0, 10)
45 | dao.Order("uid desc")
46 | //dao.Sql()
47 | }).ToStringMap()*/
48 |
49 | /*// 插入一条数据
50 | model := db.Model(&AdminUsers{})
51 | sql := model.Insert(func(dao *db.Dao) {
52 | dao.Where("account", "test1")
53 | dao.Values(map[string]interface{}{
54 | "avatar": "123",
55 | "username": "admin123",
56 | })
57 | //dao.Sql()
58 | })
59 |
60 | fmt.Println(sql.ToAffectedRows())*/
61 |
62 | // 更新一条数据 -- 错误示例
63 | /*model := db.Model(&AdminUsers{})
64 | result := model.Update(func(dao *db.Dao) {
65 | dao.Where("account", "15116980818")
66 | dao.Set(map[string]interface{}{
67 | "mobile": "123",
68 | "remark": []string{"1"},
69 | })
70 | //dao.Sql()
71 | })
72 |
73 | if result.ToError() != nil{
74 | panic(result.ToError())
75 | }
76 | fmt.Println(result.ToError())*/
77 |
78 | // 更新一条数据 -- 错误示例
79 | model := db.Model(&AdminUsers{})
80 | model.Begin() // 开始事务
81 | ret1 := model.Update(func(dao *db.Dao) {
82 | dao.Values(map[string]interface{}{
83 | "account": "测试事务1",
84 | })
85 | dao.Where("username", "admin1")
86 | //dao.Sql()
87 | })
88 | fmt.Printf("ret1的数据:%v\n", ret1.ToAffectedRows())
89 |
90 | // 查询
91 | ret2 := model.FetchAll(func(dao *db.Dao) {
92 | dao.Where("username", "admin1")
93 | })
94 | fmt.Printf("ret2的数据:%v\n", ret2.ToStringMapSlice())
95 |
96 | ret3 := db.Model(&AdminUsers{}).Update(func(dao *db.Dao) {
97 | dao.Values(map[string]interface{}{
98 | "account": "测试事务2",
99 | })
100 | dao.Where("username", "admin2")
101 | })
102 | fmt.Printf("ret3的数据:%v\n", ret3.ToAffectedRows())
103 | model.Rollback()
104 |
105 | /*model := db.Model(&AdminUsers{})
106 | model.Test()
107 | model.Begin()
108 | model.Test()
109 |
110 | db.Model(&AdminUsers{}).Test()
111 | db.Model(&AdminUsers{}).Test()
112 | db.Model(&AdminUsers{}).Test()*/
113 |
114 |
115 |
116 |
117 | }
118 |
--------------------------------------------------------------------------------
/test/test1/test3.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "fmt"
5 | "github.com/go-touch/regin/app/cache"
6 | )
7 |
8 | type RedisModel struct {
9 | }
10 |
11 | func (rm *RedisModel) Identify() string {
12 | return "plus_center.master"
13 | }
14 |
15 | func main() {
16 | cache.Redis.Init(map[string]interface{}{
17 | "plus_center": map[string]interface{}{
18 | "master": map[string]interface{}{
19 | "host": "127.0.0.1:6379",
20 | "MaxIdle": "16",
21 | "MaxActive": "32",
22 | "IdleTimeout": "120",
23 | },
24 | },
25 | })
26 |
27 | model := cache.RedisModel(new(RedisModel))
28 | ret := model.Command("incrby", "bind-phone-index_msg_limit_16619709811",20)
29 |
30 | fmt.Println(ret.Value())
31 |
32 | }
33 |
--------------------------------------------------------------------------------
/test/test1/test4.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "fmt"
5 | "github.com/go-touch/regin/utils/multitype"
6 | )
7 |
8 | type Admin struct {
9 | }
10 |
11 | func main() {
12 | any := &multitype.AnyMap{"username": "admin"}
13 |
14 | fmt.Println(any)
15 |
16 | any.Set("password", "123456")
17 |
18 | fmt.Println(any)
19 | fmt.Printf("内存地址是:%p", any)
20 |
21 | fmt.Println(any.Get("password").ToInt())
22 | fmt.Printf("类型转换成:%T\n", any.Get("password1").ToInt())
23 | fmt.Println(any.Get("password1").ToInt())
24 |
25 | any.Set("username", "张三")
26 | fmt.Println(any)
27 | fmt.Printf("内存地址是:%p\n", any)
28 | fmt.Printf("内存地址是:%T\n", any)
29 | fmt.Printf("内存地址是:%T\n", any.Get().ToStringMap())
30 | fmt.Printf("内存地址是:%v\n", any.Get().ToStringMap())
31 |
32 | c := multitype.AnyMap{"username": "admin"}
33 |
34 | fmt.Printf("转换后的类型为:%T\n", multitype.Eval(c).ToStringMap())
35 | fmt.Printf("转换后的值为:%v\n", multitype.Eval(c).ToStringMap())
36 |
37 | //d := []interface{}{"admin"}
38 |
39 | //fmt.Println(d[1])
40 |
41 | /*if 1 == "1" {
42 |
43 | }*/
44 |
45 | t()
46 |
47 | }
48 |
49 | func t(arg ...int) {
50 | //fmt.Println(arg[0])
51 | fmt.Printf("参数类型:%T", arg)
52 |
53 | if arg == nil {
54 | fmt.Println("nil")
55 | }
56 |
57 | fmt.Println(len(arg))
58 | }
59 |
--------------------------------------------------------------------------------
/test/test1/test5.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "fmt"
5 | "github.com/go-touch/regin/utils/validator"
6 | )
7 |
8 | type PlusUsers struct {
9 | UserId int `key:"user_id" require:"true" length:"0|5"`
10 | Account string `key:"account" require:"true" length:"0|20"`
11 | }
12 |
13 | func main() {
14 | validator.RegisterForm(&PlusUsers{}, "PlusUsers")
15 | dao := validator.Form("PlusUsers")
16 |
17 | for _, v := range dao.FieldMap {
18 | fmt.Println(v.Tags)
19 | }
20 |
21 | result := dao.Verify(&map[string]interface{}{
22 | "user_id": "测",
23 | })
24 |
25 | for _, v := range result {
26 | fmt.Println(v)
27 | }
28 |
29 | }
30 |
--------------------------------------------------------------------------------
/test/test1/test6.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "fmt"
5 | "strings"
6 | )
7 |
8 | func main() {
9 |
10 | fmt.Println(strings.Repeat("hello world",5))
11 |
12 |
13 | }
14 |
--------------------------------------------------------------------------------
/test/test1/test7.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "fmt"
5 | )
6 |
7 | func main() {
8 | defer func() {
9 | if r := recover(); r != nil {
10 | fmt.Printf("捕获到错误信息:%v\n",r.(string))
11 | //debug.PrintStack()
12 | //err = errors.New(r.(string))
13 | }
14 | }()
15 | action1()
16 | }
17 |
18 | func action1() {
19 | action2()
20 | }
21 |
22 | func action2() {
23 | action3()
24 | }
25 |
26 | func action3() {
27 | panic("错误")
28 | }
29 |
30 | func errorCatch(){
31 | if r := recover(); r != nil {
32 | fmt.Printf("捕获到错误信息:%v\n",r.(string))
33 | //debug.PrintStack()
34 | //err = errors.New(r.(string))
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/test/test1/test8.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "fmt"
5 | "github.com/go-touch/mtype"
6 | "github.com/go-touch/regin/utils/curl"
7 | )
8 |
9 | func main() {
10 |
11 | post := curl.Post()
12 | ret := post.Call("http://127.0.0.1:8080/demo/index",mtype.AnyMap{})
13 | fmt.Println(ret.ToAnyMap())
14 | }
15 |
--------------------------------------------------------------------------------
/test/test1/test9.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | type Link struct {
4 | value interface{}
5 | subKey string
6 | subType string
7 | subPtr *Link
8 | }
9 |
10 | // 添加链表节点
11 | func AddLink(topLink *Link, subLink *Link) {
12 | if topLink.subPtr == nil {
13 | topLink.subPtr = subLink
14 | } else {
15 | AddLink(topLink.subPtr, subLink)
16 | }
17 | }
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 | func main() {
28 |
29 | }
30 |
--------------------------------------------------------------------------------
/test/test2/t1.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "encoding/json"
5 | "fmt"
6 | )
7 |
8 | func main() {
9 | m := map[string]interface{}{
10 | "a": "admin",
11 | "b": []string{"a", "v"},
12 | }
13 |
14 | test, err := json.Marshal(&m)
15 |
16 | fmt.Println(test, "----", err)
17 |
18 | fmt.Println(string(test))
19 | }
20 |
--------------------------------------------------------------------------------
/test/test2/t2.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "fmt"
5 | "strings"
6 | )
7 |
8 | func test(any map[string]interface{}) map[string]interface{} {
9 | tmpMap := map[string]interface{}{}
10 | for key, value := range any {
11 | i := strings.IndexByte(key, '[')
12 | j := strings.IndexByte(key, ']')
13 |
14 | if i >= 1 && j >= 1 {
15 | trimKey := strings.Trim(key, "]")
16 | k := trimKey[0:i]
17 | subK := trimKey[i+1:]
18 | if _, ok := tmpMap[k]; !ok {
19 | tmpMap[k] = map[string]interface{}{
20 | subK: value,
21 | }
22 | } else {
23 | tmpMap[k].(map[string]interface{})[subK] = value
24 | }
25 | delete(any, key)
26 | }
27 | }
28 | for key, value := range tmpMap {
29 | any[key] = value
30 | }
31 | return any
32 | }
33 |
34 | func main() {
35 | data := map[string]interface{}{
36 | "username": "admin",
37 | "group[age]": 10,
38 | "group[name]": "张三",
39 | }
40 |
41 | fmt.Println(data)
42 | fmt.Println(test(data))
43 | }
44 |
--------------------------------------------------------------------------------
/test/test2/t3.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "fmt"
5 | "time"
6 | )
7 |
8 | func main() {
9 | count := 0
10 | startTime := time.Now()
11 |
12 | for {
13 | count++
14 | if count > 100 {
15 | break
16 | }
17 | fmt.Printf("输出数字:%d\n", count)
18 | }
19 |
20 | // endTime := time.Now()
21 |
22 |
23 | d := time.Since(startTime).String()
24 |
25 | fmt.Println(d)
26 |
27 |
28 | /*fmt.Println("开始时间", startTime, "\nsss")
29 | fmt.Println("结束时间", endTime, "\nsss")
30 |
31 | // rat := big.NewRat(endTime,startTime)
32 |
33 | a := big.NewInt(startTime)
34 | b := big.NewInt(endTime)
35 | z := big.NewInt(1)
36 |
37 | ret := z.Sub(b, a)
38 |
39 | fmt.Println("相减", ret, "\nsss")
40 | fmt.Printf("类型:%T\n", ret)
41 |
42 | c := big.NewInt(1000000000)
43 |
44 | fmt.Println("除法", ret.Div(ret, c), "\nsss")*/
45 | }
46 |
--------------------------------------------------------------------------------
/test/test2/t4.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "fmt"
5 | "time"
6 | )
7 |
8 | func main(){
9 |
10 | fmt.Println(time.Now().Format("2006-01-02"))
11 |
12 |
13 | }
14 |
--------------------------------------------------------------------------------
/test/test2/test3.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "fmt"
5 | "log"
6 | )
7 |
8 | type LogWriter struct {
9 | //io.Writer
10 | }
11 |
12 | func (lr *LogWriter) Write(p []byte) (n int, err error) {
13 |
14 | fmt.Println(string(p))
15 | fmt.Println("hello logging...", `\n`)
16 |
17 | return n, err
18 | }
19 |
20 | func main() {
21 | logger := log.New(&LogWriter{},"测试日志",3)
22 |
23 |
24 | logger.Printf("我在打印日志")
25 |
26 | }
27 |
--------------------------------------------------------------------------------
/utils/config_parser.go:
--------------------------------------------------------------------------------
1 | package utils
2 |
3 | import (
4 | "errors"
5 | "github.com/go-touch/regin/utils/config_parser"
6 | )
7 |
8 | type ConfigFileParser struct {
9 | Parsers map[string]config_parser.BaseParser
10 | }
11 |
12 | // 定义ConfigReader结构体
13 | var ConfigParser *ConfigFileParser
14 |
15 | func init() {
16 | ConfigParser = &ConfigFileParser{
17 | Parsers: map[string]config_parser.BaseParser{
18 | "json": new(config_parser.JsonParser).Init(),
19 | "ini": new(config_parser.IniParser).Init(),
20 | },
21 | }
22 |
23 | }
24 | // 使用解析器解析文件至map类型配置数据
25 | func (cfp *ConfigFileParser) ParserToMap(parserName string, filePath string) (map[string]interface{}, error) {
26 | parser, ok := cfp.Parsers[parserName]
27 | if !ok {
28 | return nil, errors.New("can't find the config parser" + parserName + "...")
29 | }
30 | return parser.ParserToMap(filePath)
31 | }
--------------------------------------------------------------------------------
/utils/config_parser/base.go:
--------------------------------------------------------------------------------
1 | package config_parser
2 |
3 | type BaseParser interface {
4 | Init() BaseParser
5 | ParserToMap(filePath string) (anyMap map[string]interface{}, err error)
6 | }
--------------------------------------------------------------------------------
/utils/config_parser/ini.go:
--------------------------------------------------------------------------------
1 | package config_parser
2 |
3 | import (
4 | "errors"
5 | "fmt"
6 | "gopkg.in/ini.v1"
7 | "strings"
8 | )
9 |
10 | type IniParser struct {
11 | //BaseParser
12 | goIni *ini.File
13 | options struct {
14 | LoadOptions ini.LoadOptions
15 | BlockMode bool
16 | }
17 | }
18 |
19 | // 初始化
20 | func (ip *IniParser) Init() BaseParser {
21 | ip.options.LoadOptions = ini.LoadOptions{
22 | IgnoreInlineComment: true,
23 | }
24 | ip.options.BlockMode = false
25 | return ip
26 | }
27 |
28 | // 解析配置到map[string]interface{}
29 | func (ip *IniParser) ParserToMap(filePath string) (map[string]interface{}, error) {
30 | // 使用gopkg.in包,创建iniFile
31 | iniFile, err := ini.LoadSources(ip.options.LoadOptions, filePath)
32 | if err != nil {
33 | errorMsg := fmt.Sprintf("load config conf file '"+filePath+"'failed: %s", err.Error())
34 | return nil, errors.New(errorMsg)
35 | } else {
36 | iniFile.BlockMode = ip.options.BlockMode
37 | }
38 |
39 | // 读取分区列表
40 | list := map[string]map[string]string{}
41 | SectionArray := iniFile.SectionStrings()
42 | SectionArray = SectionArray[1:]
43 | for _, value := range SectionArray {
44 | keysArray := iniFile.Section(value).KeyStrings()
45 | keyMap := map[string]string{}
46 | for _, v := range keysArray {
47 | keyMap[v] = iniFile.Section(value).Key(v).String()
48 | }
49 | list[value] = keyMap
50 | }
51 | return ip.stdMap(list), nil
52 | }
53 |
54 | // 获取处理后的map
55 | func (ip *IniParser) stdMap(list map[string]map[string]string) map[string]interface{} {
56 | rValue := map[string]interface{}{}
57 |
58 | for key, value := range list {
59 | anyMap := map[string]interface{}{}
60 | for k, v := range value {
61 | splitK := strings.Split(k, ".")
62 | if len(splitK) == 1 {
63 | anyMap[k] = v
64 | } else if len(splitK) == 2 {
65 | if _, ok := anyMap[splitK[0]]; !ok {
66 | anyMap[splitK[0]] = map[string]string{splitK[1]: v}
67 | } else {
68 | anyMap[splitK[0]].(map[string]string)[splitK[1]] = v
69 | }
70 | }
71 | }
72 | rValue[key] = anyMap
73 | }
74 | return rValue
75 | }
76 |
--------------------------------------------------------------------------------
/utils/config_parser/json.go:
--------------------------------------------------------------------------------
1 | package config_parser
2 |
3 | import (
4 | "encoding/json"
5 | "errors"
6 | "fmt"
7 | "io/ioutil"
8 | )
9 |
10 | type JsonParser struct {
11 | BaseParser
12 | }
13 |
14 | func (jp *JsonParser) Init() BaseParser {
15 | return jp
16 | }
17 |
18 | // 解析文件
19 | func (jp *JsonParser) ParserToMap(filePath string) (map[string]interface{}, error) {
20 | // 从配置文件中读取json字符串
21 | buf, err := ioutil.ReadFile(filePath)
22 | if err != nil {
23 | errorMsg := fmt.Sprintf("load config conf file '"+filePath+"'failed: %s", err.Error())
24 | return nil, errors.New(errorMsg)
25 | }
26 |
27 | // 存储map
28 | anyMap := make(map[string]interface{})
29 | err = json.Unmarshal(buf, &anyMap)
30 | if err != nil {
31 | errorMsg := fmt.Sprintf("decode config file '"+filePath+"' failed: %s", err.Error())
32 | return nil, errors.New(errorMsg)
33 | }
34 | return anyMap, nil
35 | }
36 |
--------------------------------------------------------------------------------
/utils/convert.go:
--------------------------------------------------------------------------------
1 | package utils
2 |
3 | import (
4 | "encoding/json"
5 | "strconv"
6 | )
7 |
8 | type ConvertHandler struct {
9 | }
10 |
11 | // 定义类型常量
12 | const (
13 | Int = "Int" // 类型: int
14 | Byte = "Byte" // 类型: byte
15 | String = "String" // 类型: string
16 | Bool = "Bool" // 类型: bool
17 | IntSlice = "IntSlice" // 类型: []int
18 | ByteSlice = "ByteSlice" // 类型: []byte
19 | StringSlice = "StringSlice " // 类型: []string
20 | AnySlice = "AnySlice " // 类型: []interface{}
21 | StringMapSlice = "StringMapSlice" // 类型: []map[string]string
22 | AnyMapSlice = "AnyMapSlice" // 类型: []map[string]interface{}
23 | StringMap = "StringMap" // 类型: map[string]string
24 | AnyMap = "AnyMap" // 类型: map[string]interface{}
25 | Error = "Error" // 类型: error
26 | )
27 |
28 | // 定义ConvertHandler
29 | var Convert *ConvertHandler
30 |
31 | func init() {
32 | Convert = &ConvertHandler{}
33 | }
34 |
35 | // 类型断言
36 | func (ch *ConvertHandler) GetType(object interface{}) string {
37 | switch t := object.(type) {
38 | case int:
39 | return Int
40 | case byte:
41 | return Byte
42 | case string:
43 | return String
44 | case bool:
45 | return Bool
46 | case []int:
47 | return IntSlice
48 | case []byte:
49 | return ByteSlice
50 | case []string:
51 | return StringSlice
52 | case []interface{}:
53 | return AnySlice
54 | case []map[string]string:
55 | return StringMapSlice
56 | case []map[string]interface{}:
57 | return AnyMapSlice
58 | case map[string]string:
59 | return StringMap
60 | case map[string]interface{}:
61 | return AnyMap
62 | case error:
63 | return Error
64 | default:
65 | _ = t
66 | }
67 | return ""
68 | }
69 |
70 | // 将当前对象转换为指定类型
71 | func (ch *ConvertHandler) ToTargetType(object interface{}, targetType string) interface{} {
72 | switch ch.GetType(object) {
73 | case Int:
74 | if targetType == Int { // int 转 int
75 | return object
76 | } else if targetType == Byte { // int 转 byte
77 | return byte(object.(int))
78 | } else if targetType == String { // int 转 string
79 | return strconv.Itoa(object.(int))
80 | } else if targetType == Bool { // int 转 bool
81 | if object.(int) > 0 {
82 | return true
83 | }
84 | return false
85 | }
86 | case Byte:
87 | if targetType == Int { // byte 转 int
88 | return int(object.(byte))
89 | } else if targetType == Byte { // byte 转 byte
90 | return object
91 | } else if targetType == String { // byte 转 string
92 | return string([]byte{object.(byte)})
93 | } else if targetType == Bool { // byte 转 bool
94 | if object.(byte) > 0 {
95 | return true
96 | }
97 | return false
98 | }
99 | case String:
100 | if targetType == Int { // string 转 int
101 | if v, err := strconv.Atoi(object.(string)); err != nil {
102 | return 0
103 | } else {
104 | return v
105 | }
106 | } else if targetType == String { // string 转 string
107 | return object
108 | } else if targetType == Bool { // string 转 bool
109 | if object.(string) == "true" {
110 | return true
111 | }
112 | return false
113 | } else if targetType == ByteSlice { // string 转 []Byte
114 | return []byte(object.(string))
115 | }
116 | case Bool:
117 | if targetType == Int { // bool 转 int
118 | if object == true {
119 | return 1
120 | }
121 | return 0
122 | } else if targetType == Byte { // bool 转 byte
123 | if object == true {
124 | return byte(1)
125 | }
126 | return byte(0)
127 | } else if targetType == String { // bool 转 string
128 | if object == true {
129 | return "true"
130 | }
131 | return "false"
132 | } else if targetType == Bool { // bool 转 bool
133 | return object
134 | }
135 | case IntSlice:
136 | if targetType == IntSlice { // []int 转 []int
137 | return object
138 | } else if targetType == StringSlice { // []int 转 []string
139 | var v []string
140 | for _, value := range object.([]int) {
141 | v = append(v, ch.ToTargetType(value, String).(string))
142 | }
143 | return v
144 | }
145 | case ByteSlice:
146 | if targetType == String { // []byte 转 string
147 | return string(object.([]byte))
148 | } else if targetType == Bool { // []byte 转 bool
149 | if object != nil {
150 | return true
151 | }
152 | return false
153 | } else if targetType == IntSlice { // []byte 转 []int
154 | var v []int
155 | for _, value := range object.([]byte) {
156 | v = append(v, int(value))
157 | }
158 | return v
159 | } else if targetType == StringSlice { // []byte 转 []string
160 | var v []string
161 | for _, value := range object.([]byte) {
162 | v = append(v, ch.ToTargetType(value, String).(string))
163 | }
164 | return v
165 | }
166 | case StringSlice:
167 | if targetType == IntSlice { // []string 转 []int
168 | var v []int
169 | for _, value := range object.([]int) {
170 | v = append(v, ch.ToTargetType(value, Int).(int))
171 | }
172 | return v
173 | } else if targetType == StringSlice { // []string 转 []string
174 | return object
175 | }
176 | case AnySlice:
177 | if targetType == IntSlice { // []interface{} 转 []int
178 | var v []int
179 | for _, value := range object.([]int) {
180 | v = append(v, ch.ToTargetType(value, Int).(int))
181 | }
182 | return v
183 | } else if targetType == StringSlice { // []interface{} 转 []string
184 | var v []string
185 | for _, value := range object.([]interface{}) {
186 | v = append(v, ch.ToTargetType(value, String).(string))
187 | }
188 | return v
189 | } else if targetType == AnySlice { // []interface{} 转 []interface{}
190 | return object
191 | }
192 | case StringMap:
193 | if targetType == StringSlice { // map[string]string 转 []string
194 | var v []string
195 | for _, value := range object.(map[string]string) {
196 | v = append(v, value)
197 | }
198 | return v
199 | } else if targetType == StringMap { // map[string]string 转 map[string]string
200 | return object
201 | } else if targetType == AnyMap { // map[string]string 转 map[string]interface{}
202 | v := map[string]interface{}{}
203 | for key, value := range object.(map[string]string) {
204 | v[key] = value
205 | }
206 | return v
207 | }
208 | case AnyMap:
209 | if targetType == StringMap { // map[string]interface{} 转 map[string]string
210 | value := map[string]string{}
211 | for k, v := range object.(map[string]interface{}) {
212 | value[k] = ch.ToTargetType(v, String).(string)
213 | }
214 | return value
215 | } else if targetType == AnyMap { // map[string]interface{} 转 map[string]interface{}
216 | return object
217 | }
218 | }
219 |
220 | // 其余类型转
221 | if targetType == Int {
222 | return 0
223 | } else if targetType == Byte {
224 | return byte(0)
225 | } else if targetType == String {
226 | return ""
227 | } else if targetType == Bool {
228 | return false
229 | }
230 | return nil
231 | }
232 |
233 | // 转换 []byte 到 map[string]interface{}
234 | func (ch *ConvertHandler) ByteSliceToMap(byteSliceTData []byte) (result map[string]interface{}, err error) {
235 | err = json.Unmarshal(byteSliceTData, &result)
236 | return result, err
237 | }
238 |
239 | // 转换 map[string]interface{} 到 json(string)
240 | func (ch *ConvertHandler) MapToJson(mapData map[string]interface{}) (jsonData string, err error) {
241 | result, err := json.Marshal(mapData)
242 | if err == nil {
243 | jsonData = string(result)
244 | }
245 | return jsonData, err
246 | }
247 |
248 | // 转换 json(string) 到 map[string]interface{}
249 | func (ch *ConvertHandler) JsonToMap(jsonData string) (mapData map[string]interface{}, err error) {
250 | err = json.Unmarshal([]byte(jsonData), &mapData)
251 | return mapData, err
252 | }
253 |
--------------------------------------------------------------------------------
/utils/curl/get.go:
--------------------------------------------------------------------------------
1 | package curl
2 |
3 | import (
4 | "bytes"
5 | "github.com/go-touch/mtype"
6 | "io/ioutil"
7 | "net/http"
8 | url2 "net/url"
9 | "strconv"
10 | )
11 |
12 | type GetCaller struct {
13 | method string
14 | header map[string]string
15 | }
16 |
17 | // 获取一个GetCaller
18 | func Get() *GetCaller {
19 | return &GetCaller{
20 | method: "GET",
21 | header: map[string]string{},
22 | }
23 | }
24 |
25 | // 设置头信息
26 | func (gc *GetCaller) Header(header map[string]string) {
27 | gc.header = header
28 | }
29 |
30 | // 发送Get请求
31 | func (gc *GetCaller) Call(url string, args ...map[string]interface{}) *mtype.AnyValue {
32 | // 参数处理
33 | param := url2.Values{}
34 | if args != nil {
35 | for key, value := range args[0] {
36 | if v, ok := value.(string); ok {
37 | param.Set(key, v)
38 | } else if v, ok := value.(int); ok {
39 | param.Set(key, strconv.Itoa(v))
40 | }
41 | }
42 | }
43 | parserUrl, err := url2.ParseRequestURI(url)
44 | if err != nil {
45 | return mtype.Eval(err)
46 | } else {
47 | parserUrl.RawQuery = param.Encode()
48 | url = parserUrl.String()
49 | }
50 | // 创建request
51 | request, err2 := http.NewRequest(gc.method, url, nil)
52 | if err2 != nil {
53 | return mtype.Eval(err2)
54 | }
55 | if len(gc.header) > 0 {
56 | for key, value := range gc.header {
57 | request.Header.Add(key, value)
58 | }
59 | }
60 | // 发送一个GET请求
61 | resp, err3 := http.DefaultClient.Do(request)
62 | if err3 != nil {
63 | return mtype.Eval(err3)
64 | }
65 | defer func() { _ = resp.Body.Close() }()
66 | // 响应数据处理
67 | respData, err4 := ioutil.ReadAll(resp.Body)
68 | if err4 != nil {
69 | return mtype.Eval(err4)
70 | } else {
71 | respData = bytes.TrimPrefix(respData, []byte("\xef\xbb\xbf"))
72 | }
73 | return mtype.Eval(respData)
74 | }
--------------------------------------------------------------------------------
/utils/curl/post.go:
--------------------------------------------------------------------------------
1 | package curl
2 |
3 | import (
4 | "bytes"
5 | "github.com/go-touch/mtype"
6 | "io"
7 | "io/ioutil"
8 | "net/http"
9 | "net/url"
10 | "strings"
11 | )
12 |
13 | type PostCaller struct {
14 | method string
15 | header map[string]string
16 | }
17 |
18 | // 获取一个PostCaller
19 | func Post() *PostCaller {
20 | return &PostCaller{
21 | method: "POST",
22 | header: map[string]string{},
23 | }
24 | }
25 |
26 | // Set header.
27 | func (pc *PostCaller) Header(header map[string]string) {
28 | pc.header = header
29 | }
30 |
31 | // Send a post request.
32 | func (pc *PostCaller) Call(url string, args ...interface{}) *mtype.AnyValue {
33 | // 创建request
34 | request, err := http.NewRequest(pc.method, url, pc.IoReader(args...))
35 | if err != nil {
36 | return mtype.Eval(err)
37 | }
38 | if len(pc.header) > 0 {
39 | for key, value := range pc.header {
40 | request.Header.Add(key, value)
41 | }
42 | } else {
43 | request.Header.Add("Content-Type", "application/x-www-form-urlencoded")
44 | }
45 | // 发送一个POST请求
46 | resp, err2 := http.DefaultClient.Do(request)
47 | if err2 != nil {
48 | return mtype.Eval(err2)
49 | }
50 | defer func() { _ = resp.Body.Close() }()
51 | // 响应数据处理
52 | respData, err4 := ioutil.ReadAll(resp.Body)
53 | if err4 != nil {
54 | return mtype.Eval(err4)
55 | } else {
56 | respData = bytes.TrimPrefix(respData, []byte("\xef\xbb\xbf"))
57 | }
58 | return mtype.Eval(respData)
59 | }
60 |
61 | // 获取 io.Reader.
62 | func (pc *PostCaller) IoReader(args ...interface{}) io.Reader {
63 | var ioReader io.Reader
64 | if args == nil {
65 | return nil
66 | }
67 | if mtype.GetType(args[0]) == mtype.TString {
68 | param := url.QueryEscape(args[0].(string))
69 | ioReader = strings.NewReader(param)
70 | } else {
71 | stringMap := mtype.Eval(args[0]).ToStringMap()
72 | var param []string
73 | for k, v := range stringMap {
74 | param = append(param, k+"="+url.QueryEscape(v))
75 | }
76 | ioReader = strings.NewReader(strings.Join(param, "&"))
77 | }
78 | return ioReader
79 | }
80 |
--------------------------------------------------------------------------------
/utils/encrypt/md5.go:
--------------------------------------------------------------------------------
1 | package encrypt
2 |
3 | import (
4 | "crypto/md5"
5 | "fmt"
6 | "strings"
7 | )
8 |
9 | // md5加密算法
10 | func Md5(str ...string) string {
11 | md5Ptr := md5.New()
12 | _, _ = md5Ptr.Write([]byte(strings.Join(str, "")))
13 | return fmt.Sprintf("%x", md5Ptr.Sum(nil))
14 | }
15 |
--------------------------------------------------------------------------------
/utils/encrypt/sha1.go:
--------------------------------------------------------------------------------
1 | package encrypt
2 |
3 | import (
4 | "crypto/sha1"
5 | "fmt"
6 | "strings"
7 | )
8 |
9 | // hash加密算法
10 | func Sha1(str ...string) string {
11 | Sha1Ptr := sha1.New()
12 | _, _ = Sha1Ptr.Write([]byte(strings.Join(str, "")))
13 | return fmt.Sprintf("%x", Sha1Ptr.Sum(nil))
14 | }
15 |
--------------------------------------------------------------------------------
/utils/error.go:
--------------------------------------------------------------------------------
1 | package utils
2 |
3 | import "fmt"
4 |
5 | type ErrorFormat struct {
6 | error
7 | errorMsg string
8 | }
9 |
10 | // 获取一个实现了error接口的ErrorFormat结构体
11 | func MakeError(msg string, errorMsg ...interface{}) error {
12 | return &ErrorFormat{
13 | errorMsg: fmt.Sprintf(msg, errorMsg...),
14 | }
15 | }
16 |
17 | // 重载Error方法
18 | func (ef *ErrorFormat) Error() string {
19 | return ef.errorMsg
20 | }
21 |
--------------------------------------------------------------------------------
/utils/file.go:
--------------------------------------------------------------------------------
1 | package utils
2 |
3 | import (
4 | "io"
5 | "mime/multipart"
6 | "os"
7 | "path/filepath"
8 | "strings"
9 | )
10 |
11 | type FileHandler struct {
12 | }
13 |
14 | // 定义FileHandler结构体
15 | var File *FileHandler
16 |
17 | func init() {
18 | File = &FileHandler{}
19 | }
20 |
21 | // 保存上传文件
22 | func (fh *FileHandler) SaveUploadFile(file *multipart.FileHeader, dst string) error {
23 | // 打开上传文件
24 | src, err := file.Open()
25 | if err != nil {
26 | return err
27 | }
28 | defer func() { _ = src.Close() }()
29 | // 创建目标文件
30 | out, err := os.Create(dst)
31 | if err != nil {
32 | return err
33 | }
34 | defer func() { _ = out.Close() }()
35 | _, err = io.Copy(out, src)
36 | return err
37 | }
38 |
39 | // 遍历目录
40 | func (fh *FileHandler) ScanDir(dirPath string) []os.FileInfo {
41 | // 判断目录是否存在
42 | if _, err := fh.IsExist(dirPath); err != nil {
43 | panic(err)
44 | }
45 |
46 | // 打开目录
47 | dir, err := os.Open(dirPath)
48 | if err != nil {
49 | panic(err)
50 | }
51 | defer func() { _ = dir.Close() }()
52 |
53 | // 读取目录文件
54 | files, err := dir.Readdir(-1)
55 | if err != nil {
56 | panic(err)
57 | }
58 | return files
59 | }
60 |
61 | // 判断文件夹是否存在
62 | func (fh *FileHandler) IsExist(path string) (bool, error) {
63 | // 获取文件的信息
64 | _, err := os.Stat(path)
65 | if err == nil {
66 | return true, err
67 | }
68 | return false, err
69 | }
70 |
71 | // 拼接路径
72 | func (fh *FileHandler) JoinPath(path ...string) string {
73 | return strings.Join(path, string(filepath.Separator))
74 | }
75 |
--------------------------------------------------------------------------------
/utils/handler.go:
--------------------------------------------------------------------------------
1 | package utils
2 |
3 | import (
4 | "strings"
5 | )
6 |
7 | type DataHandler struct {
8 |
9 | }
10 |
11 | // 定义DataHandler
12 | var Handler *DataHandler
13 |
14 | func init() {
15 | Handler = &DataHandler{}
16 | }
17 |
18 | func StringJoinByDot(str ...string) string {
19 | return strings.Join(str, ".")
20 | }
--------------------------------------------------------------------------------
/utils/log.go:
--------------------------------------------------------------------------------
1 | package utils
2 |
3 | import (
4 | "log"
5 | "os"
6 | "path/filepath"
7 | "strings"
8 | "time"
9 | )
10 |
11 | type Logger struct {
12 | }
13 |
14 | var Log *Logger
15 |
16 | func init() {
17 | Log = &Logger{}
18 | }
19 |
20 | // 获取文件名称
21 | func (l *Logger) GetFileName(logPath string, path ...string) string {
22 | fileName := "" // 文件名
23 | separator := string(filepath.Separator) // 分隔符
24 | datetime := time.Now().String()[0:10] // 时间戳
25 |
26 | // 拼接filename
27 | fileName += logPath + separator
28 | if path != nil {
29 | fileName += strings.Join(path, separator) + separator
30 | }
31 | fileName += datetime + ".txt"
32 | return fileName
33 | }
34 |
35 | // 写入日志
36 | func (l *Logger) Writer(fileName string, content interface{}) error {
37 | // 打开文件句柄
38 | file, err := os.OpenFile(fileName, os.O_APPEND|os.O_CREATE, os.ModePerm)
39 | if err != nil {
40 | return err
41 | }
42 | defer func() { _ = file.Close() }()
43 |
44 | // 日志文件格式:log包含时间及文件行数
45 | logger := log.New(file, "", log.LstdFlags)
46 | logger.Println(content)
47 | return nil
48 | }
--------------------------------------------------------------------------------
/utils/timer.go:
--------------------------------------------------------------------------------
1 | package utils
2 |
3 | import (
4 | time2 "time"
5 | )
6 |
7 | const TimeFormat = "2006-01-02 15:04:05"
8 |
9 | // 时间处理器
10 | type Timer struct {
11 | time2.Time
12 | }
13 |
14 | // 获取 Timer
15 | func Time(timeStr ...string) Timer {
16 | var timer *Timer
17 | if timeStr != nil {
18 | if t, err := time2.Parse(TimeFormat, timeStr[0]); err == nil {
19 | timer = &Timer{
20 | t,
21 | }
22 | }
23 | }
24 | if timer == nil {
25 | timer = &Timer{
26 | time2.Now(),
27 | }
28 | }
29 | return *timer
30 | }
31 |
32 | // 格式化输出
33 | func (t Timer) FormatStr() string {
34 | return t.Format(TimeFormat)
35 | }
36 |
--------------------------------------------------------------------------------
/utils/validator/field.go:
--------------------------------------------------------------------------------
1 | package validator
2 |
3 | import "github.com/go-touch/regin/utils/validator/tag"
4 |
5 | type Field struct {
6 | Name string
7 | Type string
8 | Tags map[string]tag.BaseTag
9 | }
10 |
11 | // 校验
12 | func (f *Field) Verify(key string, vMap *map[string]interface{}) []*tag.Result {
13 | resultGroup := make([]*tag.Result, 0)
14 | for _, tagElement := range f.Tags {
15 | resultGroup = append(resultGroup, tagElement.Verify(key, vMap))
16 | }
17 | return resultGroup
18 | }
--------------------------------------------------------------------------------
/utils/validator/form.go:
--------------------------------------------------------------------------------
1 | package validator
2 |
3 | import (
4 | "errors"
5 | "github.com/go-touch/regin/utils/validator/tag"
6 | "reflect"
7 | "strings"
8 | )
9 |
10 | // Form 字段类型限定
11 | type FieldType []string
12 |
13 | // 是否存在
14 | func (ft *FieldType) InArray(t string) bool {
15 | for _, v := range *ft {
16 | if t == v {
17 | return true
18 | }
19 | }
20 | return false
21 | }
22 |
23 | // 获取一个字段类型实例 FieldType
24 | func NewFieldType() *FieldType {
25 | return &FieldType{"int", "int8", "int16", "int32", "int64", "string"}
26 | }
27 |
28 | // Form载体
29 | type FormHandle struct {
30 | Model interface{} // 数据模型结构体指针
31 | Type reflect.Type // 反射类型
32 | Name string // 结构体名称
33 | FieldNum int // 字段数
34 | FieldMap map[string]*Field // 字段map
35 | }
36 |
37 | // 获取一个 Form实例
38 | func NewFormHandle(model interface{}) *FormHandle {
39 | formHandle := &FormHandle{
40 | Model: model,
41 | Type: reflect.TypeOf(model),
42 | }
43 | if formHandle.Type.Kind() != reflect.Ptr || formHandle.Type.Elem().Kind() != reflect.Struct {
44 | panic(errors.New("accept an pointer model"))
45 | } else {
46 | formHandle.Type = formHandle.Type.Elem()
47 | formHandle.Name = formHandle.Type.String()
48 | formHandle.FieldNum = formHandle.Type.NumField()
49 | formHandle.FieldMap = map[string]*Field{}
50 | }
51 | return formHandle
52 | }
53 |
54 | // 初始化
55 | func (mh *FormHandle) Init() {
56 | for i := 0; i < mh.FieldNum; i++ {
57 | fieldType := mh.Type.Field(i).Type.String()
58 | if NewFieldType().InArray(fieldType) {
59 | field := &Field{
60 | Name: mh.Type.Field(i).Name,
61 | Type: fieldType,
62 | Tags: map[string]tag.BaseTag{
63 | "require": tag.MakeRequire(false),
64 | "length": tag.MakeLength(false),
65 | },
66 | }
67 | // 遍历处理
68 | fieldKey := mh.Capitalize(field.Name)
69 | if value, ok := mh.Type.Field(i).Tag.Lookup("key"); ok {
70 | fieldKey = value
71 | }
72 | // 设置标签
73 | for key, tagElement := range field.Tags {
74 | if value, ok := mh.Type.Field(i).Tag.Lookup(key); ok {
75 | tagElement.SetValue(value)
76 | }
77 | }
78 | mh.FieldMap[fieldKey] = field
79 | }
80 | }
81 | }
82 |
83 | // 数据校验
84 | func (mh *FormHandle) Verify(vMap *map[string]interface{}) []*tag.Result {
85 | resultGroup := make([]*tag.Result, 0)
86 | for key, fieldElement := range mh.FieldMap {
87 | result := fieldElement.Verify(key, vMap)
88 | for _, v := range result {
89 | if v.Status == false {
90 | resultGroup = append(resultGroup, v)
91 | }
92 | }
93 | }
94 | return resultGroup
95 | }
96 |
97 | // 首字母大写转换成 _
98 | func (mh *FormHandle) Capitalize(str string) string {
99 | newStr := strings.ToLower(string(str[0]))
100 | value := []rune(str)
101 | for i := 1; i < len(value); i++ {
102 | if value[i] >= 65 && value[i] <= 96 {
103 | newStr += "_" + strings.ToLower(string(value[i]))
104 | } else {
105 | newStr += string(value[i])
106 | }
107 | }
108 | return newStr
109 | }
110 |
--------------------------------------------------------------------------------
/utils/validator/handler.go:
--------------------------------------------------------------------------------
1 | package validator
2 |
3 | import (
4 | "errors"
5 | )
6 |
7 | // Form Container
8 | type FormContainer map[string]*FormHandle
9 | var fc *FormContainer
10 |
11 | func init() {
12 | fc = &FormContainer{}
13 | }
14 |
15 | // 获取 Form
16 | func (fc *FormContainer) Get(key string) (*FormHandle, error) {
17 | if form, ok := (*fc)[key]; ok {
18 | return form, nil
19 | }
20 | return nil, errors.New("this model '" + key + "' is not registered")
21 | }
22 |
23 | // 设置 Form
24 | func (fc *FormContainer) Set(key string, form *FormHandle) {
25 | (*fc)[key] = form
26 | }
27 |
28 | // 注册 Form
29 | func RegisterForm(userModel interface{}, alias ...string) {
30 | key := ""
31 | formHandle := NewFormHandle(userModel)
32 | if alias != nil && alias[0] != "" {
33 | key = alias[0]
34 | } else {
35 | key = formHandle.Name
36 | }
37 | if _, err := fc.Get(key); err == nil {
38 | return
39 | } else {
40 | formHandle.Init()
41 | fc.Set(key, formHandle)
42 | }
43 | }
44 |
45 | // 创建 Form
46 | func Form(userModel interface{}) *FormHandle {
47 | if key, ok := userModel.(string); ok {
48 | if storage, err := fc.Get(key); err == nil {
49 | return storage
50 | } else {
51 | panic(err)
52 | }
53 | }
54 | formHandle := NewFormHandle(userModel)
55 | if storage, err := fc.Get(formHandle.Name); err == nil {
56 | return storage
57 | } else {
58 | formHandle.Init()
59 | fc.Set(formHandle.Name, formHandle)
60 | }
61 | return formHandle
62 | }
63 |
--------------------------------------------------------------------------------
/utils/validator/tag/define.go:
--------------------------------------------------------------------------------
1 | package tag
2 |
3 | // 结构体属性接口
4 | type BaseTag interface {
5 | SetValue(value string)
6 | Verify(key string, vMap *map[string]interface{}) *Result
7 | }
8 |
9 | // 校验结果
10 | type Result struct {
11 | Status bool
12 | Msg string
13 | }
14 |
--------------------------------------------------------------------------------
/utils/validator/tag/length.go:
--------------------------------------------------------------------------------
1 | package tag
2 |
3 | import (
4 | "strconv"
5 | "strings"
6 | )
7 |
8 | type Length struct {
9 | whether bool // 是否校验
10 | min int // 最小值
11 | max int // 最大值
12 | }
13 |
14 | // 创建 Length Tag
15 | func MakeLength(whether bool) *Length {
16 | return &Length{
17 | whether: whether,
18 | }
19 | }
20 |
21 | // 设置值
22 | func (l *Length) SetValue(value string) {
23 | l.whether = true
24 | rule := strings.Split(value, "|")
25 |
26 | l.min = l.toInt(rule[0]) // 最小值
27 | if len(rule) == 2 { // 最大值
28 | l.max = l.toInt(rule[1])
29 | }
30 | }
31 |
32 | // 数据校验
33 | func (l *Length) Verify(key string, vMap *map[string]interface{}) *Result {
34 | result := &Result{
35 | Status: true,
36 | Msg: "success",
37 | }
38 | if l.whether == true {
39 | if value, ok := (*vMap)[key]; ok {
40 | // 最小值
41 | if len(value.(string)) < l.min {
42 | result.Status = false
43 | result.Msg = "Param '" + key + "' value length must be greater than " + l.toString(l.min) + "."
44 | }
45 | // 最小值
46 | if l.max > l.min && len(value.(string)) > l.max {
47 | result.Status = false
48 | result.Msg = "Param '" + key + "' value length must be less than " + l.toString(l.max) + "."
49 | }
50 | }
51 | }
52 | return result
53 | }
54 |
55 | // int转字符串
56 | func (l *Length) toString(str int) string {
57 | return strconv.Itoa(str)
58 | }
59 |
60 | // 字符串转int
61 | func (l *Length) toInt(str string) int {
62 | if v, err := strconv.Atoi(str); err != nil {
63 | return 0
64 | } else {
65 | return v
66 | }
67 | }
68 |
--------------------------------------------------------------------------------
/utils/validator/tag/require.go:
--------------------------------------------------------------------------------
1 | package tag
2 |
3 | import "strings"
4 |
5 | type Require struct {
6 | value string
7 | whether bool
8 | defaultValue string
9 | }
10 |
11 | // 创建 Require
12 | func MakeRequire(whether bool) *Require {
13 | return &Require{
14 | whether: whether,
15 | defaultValue: "",
16 | }
17 | }
18 |
19 | // 设置值
20 | func (r *Require) SetValue(value string) {
21 | rule := strings.Split(value, "|")
22 | if len(rule) == 0 {
23 | return
24 | }
25 | // 是否校验
26 | if rule[0] == "true" {
27 | r.whether = true
28 | } else {
29 | r.whether = false
30 | }
31 | // 默认值
32 | if len(rule) == 2 {
33 | r.defaultValue = rule[1]
34 | }
35 | }
36 |
37 | // 数据校验
38 | func (r *Require) Verify(key string, vMap *map[string]interface{}) *Result {
39 | result := &Result{
40 | Status: true,
41 | Msg: "success",
42 | }
43 | if r.whether == true {
44 | if _, ok := (*vMap)[key]; !ok {
45 | result.Status = false
46 | result.Msg = "Param '" + key + "' is undefined."
47 | }
48 | } else {
49 | (*vMap)[key] = r.defaultValue
50 | }
51 | return result
52 | }
53 |
--------------------------------------------------------------------------------