├── 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 | --------------------------------------------------------------------------------