mirror of
https://gitee.com/dromara/mayfly-go
synced 2025-11-03 16:00:25 +08:00
代码重构-基于gin,gorm
This commit is contained in:
@@ -2,6 +2,7 @@ package biz
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"mayfly-go/base/utils"
|
||||
|
||||
"reflect"
|
||||
)
|
||||
@@ -42,6 +43,18 @@ func NotNil(data interface{}, msg string) {
|
||||
}
|
||||
}
|
||||
|
||||
func NotBlank(data interface{}, msg string) {
|
||||
if utils.IsBlank(reflect.ValueOf(data)) {
|
||||
panic(NewBizErr(msg))
|
||||
}
|
||||
}
|
||||
|
||||
func IsEquals(data interface{}, data1 interface{}, msg string) {
|
||||
if data != data1 {
|
||||
panic(NewBizErr(msg))
|
||||
}
|
||||
}
|
||||
|
||||
func Nil(data interface{}, msg string) {
|
||||
if !reflect.ValueOf(data).IsNil() {
|
||||
panic(NewBizErr(msg))
|
||||
|
||||
12
base/config/app.go
Normal file
12
base/config/app.go
Normal file
@@ -0,0 +1,12 @@
|
||||
package config
|
||||
|
||||
import "fmt"
|
||||
|
||||
type App struct {
|
||||
Name string `yaml:"name"`
|
||||
Version string `yaml:"version"`
|
||||
}
|
||||
|
||||
func (a *App) GetAppInfo() string {
|
||||
return fmt.Sprintf("[%s:%s]", a.Name, a.Version)
|
||||
}
|
||||
51
base/config/config.go
Normal file
51
base/config/config.go
Normal file
@@ -0,0 +1,51 @@
|
||||
package config
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"fmt"
|
||||
"mayfly-go/base/utils"
|
||||
"path/filepath"
|
||||
)
|
||||
|
||||
func init() {
|
||||
configFilePath := flag.String("e", "./config.yml", "配置文件路径,默认为可执行文件目录")
|
||||
flag.Parse()
|
||||
// 获取启动参数中,配置文件的绝对路径
|
||||
path, _ := filepath.Abs(*configFilePath)
|
||||
startConfigParam = &CmdConfigParam{ConfigFilePath: path}
|
||||
// 读取配置文件信息
|
||||
yc := &Config{}
|
||||
if err := utils.LoadYml(startConfigParam.ConfigFilePath, yc); err != nil {
|
||||
panic(fmt.Sprintf("读取配置文件[%s]失败: %s", startConfigParam.ConfigFilePath, err.Error()))
|
||||
}
|
||||
Conf = yc
|
||||
}
|
||||
|
||||
// 启动配置参数
|
||||
type CmdConfigParam struct {
|
||||
ConfigFilePath string // -e 配置文件路径
|
||||
}
|
||||
|
||||
// 启动可执行文件时的参数
|
||||
var startConfigParam *CmdConfigParam
|
||||
|
||||
// yaml配置文件映射对象
|
||||
type Config struct {
|
||||
App *App `yaml:"app"`
|
||||
Server *Server `yaml:"server"`
|
||||
Redis *Redis `yaml:"redis"`
|
||||
Mysql *Mysql `yaml:"mysql"`
|
||||
}
|
||||
|
||||
// 配置文件映射对象
|
||||
var Conf *Config
|
||||
|
||||
// 获取执行可执行文件时,指定的启动参数
|
||||
func getStartConfig() *CmdConfigParam {
|
||||
configFilePath := flag.String("e", "./config.yml", "配置文件路径,默认为可执行文件目录")
|
||||
flag.Parse()
|
||||
// 获取配置文件绝对路径
|
||||
path, _ := filepath.Abs(*configFilePath)
|
||||
sc := &CmdConfigParam{ConfigFilePath: path}
|
||||
return sc
|
||||
}
|
||||
17
base/config/mysql.go
Normal file
17
base/config/mysql.go
Normal file
@@ -0,0 +1,17 @@
|
||||
package config
|
||||
|
||||
type Mysql struct {
|
||||
Host string `mapstructure:"path" json:"host" yaml:"host"`
|
||||
Config string `mapstructure:"config" json:"config" yaml:"config"`
|
||||
Dbname string `mapstructure:"db-name" json:"dbname" yaml:"db-name"`
|
||||
Username string `mapstructure:"username" json:"username" yaml:"username"`
|
||||
Password string `mapstructure:"password" json:"password" yaml:"password"`
|
||||
MaxIdleConns int `mapstructure:"max-idle-conns" json:"maxIdleConns" yaml:"max-idle-conns"`
|
||||
MaxOpenConns int `mapstructure:"max-open-conns" json:"maxOpenConns" yaml:"max-open-conns"`
|
||||
LogMode bool `mapstructure:"log-mode" json:"logMode" yaml:"log-mode"`
|
||||
LogZap string `mapstructure:"log-zap" json:"logZap" yaml:"log-zap"`
|
||||
}
|
||||
|
||||
func (m *Mysql) Dsn() string {
|
||||
return m.Username + ":" + m.Password + "@tcp(" + m.Host + ")/" + m.Dbname + "?" + m.Config
|
||||
}
|
||||
8
base/config/redis.go
Normal file
8
base/config/redis.go
Normal file
@@ -0,0 +1,8 @@
|
||||
package config
|
||||
|
||||
type Redis struct {
|
||||
Host string `yaml:"host"`
|
||||
Port int `yaml:"port"`
|
||||
Password string `yaml:"password"`
|
||||
Db int `yaml:"db"`
|
||||
}
|
||||
25
base/config/server.go
Normal file
25
base/config/server.go
Normal file
@@ -0,0 +1,25 @@
|
||||
package config
|
||||
|
||||
import "fmt"
|
||||
|
||||
type Server struct {
|
||||
Port int `yaml:"port"`
|
||||
Model string `yaml:"model"`
|
||||
Cors bool `yaml:"cors"`
|
||||
Static *[]*Static `yaml:"static"`
|
||||
StaticFile *[]*StaticFile `yaml:"static-file"`
|
||||
}
|
||||
|
||||
func (s *Server) GetPort() string {
|
||||
return fmt.Sprintf(":%d", s.Port)
|
||||
}
|
||||
|
||||
type Static struct {
|
||||
RelativePath string `yaml:"relative-path"`
|
||||
Root string `yaml:"root"`
|
||||
}
|
||||
|
||||
type StaticFile struct {
|
||||
RelativePath string `yaml:"relative-path"`
|
||||
Filepath string `yaml:"filepath"`
|
||||
}
|
||||
@@ -1,153 +0,0 @@
|
||||
package base
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"mayfly-go/base/biz"
|
||||
"mayfly-go/base/ctx"
|
||||
"mayfly-go/base/mlog"
|
||||
"mayfly-go/base/model"
|
||||
|
||||
"github.com/beego/beego/v2/core/validation"
|
||||
"github.com/beego/beego/v2/server/web"
|
||||
)
|
||||
|
||||
type Controller struct {
|
||||
web.Controller
|
||||
}
|
||||
|
||||
// 获取数据函数
|
||||
type getDataFunc func(loginAccount *ctx.LoginAccount) interface{}
|
||||
|
||||
// 操作函数,无返回数据
|
||||
type operationFunc func(loginAccount *ctx.LoginAccount)
|
||||
|
||||
// 将请求体的json赋值给指定的结构体
|
||||
func (c *Controller) UnmarshalBody(data interface{}) {
|
||||
err := json.Unmarshal(c.Ctx.Input.RequestBody, data)
|
||||
biz.BizErrIsNil(err, "request body解析错误")
|
||||
}
|
||||
|
||||
// 校验表单数据
|
||||
func (c *Controller) validForm(form interface{}) {
|
||||
valid := validation.Validation{}
|
||||
b, err := valid.Valid(form)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
if !b {
|
||||
e := valid.Errors[0]
|
||||
panic(biz.NewBizErr(e.Field + " " + e.Message))
|
||||
}
|
||||
}
|
||||
|
||||
// 将请求体的json赋值给指定的结构体,并校验表单数据
|
||||
func (c *Controller) UnmarshalBodyAndValid(data interface{}) {
|
||||
c.UnmarshalBody(data)
|
||||
c.validForm(data)
|
||||
}
|
||||
|
||||
// 返回数据
|
||||
// @param reqCtx 请求上下文
|
||||
// @param getData 获取数据的回调函数
|
||||
func (c *Controller) ReturnData(reqCtx *ctx.ReqCtx, getData getDataFunc) {
|
||||
defer func() {
|
||||
if err := recover(); err != nil {
|
||||
ctx.ApplyAfterHandler(reqCtx, err.(error))
|
||||
c.parseErr(err)
|
||||
} else {
|
||||
// 应用所有请求后置处理器
|
||||
ctx.ApplyAfterHandler(reqCtx, nil)
|
||||
}
|
||||
}()
|
||||
reqCtx.Req = c.Ctx.Request
|
||||
// 调用请求前所有处理器
|
||||
err := ctx.ApplyBeforeHandler(reqCtx)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
resp := getData(reqCtx.LoginAccount)
|
||||
c.Success(resp)
|
||||
reqCtx.RespObj = resp
|
||||
}
|
||||
|
||||
// 无返回数据的操作,如新增修改等无需返回数据的操作
|
||||
// @param reqCtx 请求上下文
|
||||
func (c *Controller) Operation(reqCtx *ctx.ReqCtx, operation operationFunc) {
|
||||
defer func() {
|
||||
if err := recover(); err != nil {
|
||||
ctx.ApplyAfterHandler(reqCtx, err.(error))
|
||||
c.parseErr(err)
|
||||
} else {
|
||||
ctx.ApplyAfterHandler(reqCtx, nil)
|
||||
}
|
||||
}()
|
||||
reqCtx.Req = c.Ctx.Request
|
||||
// 调用请求前所有处理器
|
||||
err := ctx.ApplyBeforeHandler(reqCtx)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
operation(reqCtx.LoginAccount)
|
||||
c.SuccessNoData()
|
||||
|
||||
// 不记录返回结果
|
||||
reqCtx.RespObj = 0
|
||||
}
|
||||
|
||||
// 获取分页参数
|
||||
func (c *Controller) GetPageParam() *model.PageParam {
|
||||
pn, err := c.GetInt("pageNum", 1)
|
||||
biz.BizErrIsNil(err, "pageNum参数错误")
|
||||
ps, serr := c.GetInt("pageSize", 10)
|
||||
biz.BizErrIsNil(serr, "pageSize参数错误")
|
||||
return &model.PageParam{PageNum: pn, PageSize: ps}
|
||||
}
|
||||
|
||||
// 统一返回Result json对象
|
||||
func (c *Controller) Result(result *model.Result) {
|
||||
c.Data["json"] = result
|
||||
c.ServeJSON()
|
||||
}
|
||||
|
||||
// 返回成功结果
|
||||
func (c *Controller) Success(data interface{}) {
|
||||
c.Result(model.Success(data))
|
||||
}
|
||||
|
||||
// 返回成功结果
|
||||
func (c *Controller) SuccessNoData() {
|
||||
c.Result(model.SuccessNoData())
|
||||
}
|
||||
|
||||
// 返回业务错误
|
||||
func (c *Controller) BizError(bizError *biz.BizError) {
|
||||
c.Result(model.Error(bizError.Code(), bizError.Error()))
|
||||
}
|
||||
|
||||
// 返回服务器错误结果
|
||||
func (c *Controller) ServerError() {
|
||||
c.Result(model.ServerError())
|
||||
}
|
||||
|
||||
// 解析error,并对不同error返回不同result
|
||||
func (c *Controller) parseErr(err interface{}) {
|
||||
switch t := err.(type) {
|
||||
case *biz.BizError:
|
||||
c.BizError(t)
|
||||
break
|
||||
case error:
|
||||
c.ServerError()
|
||||
mlog.Log.Error(t)
|
||||
panic(err)
|
||||
//break
|
||||
case string:
|
||||
c.ServerError()
|
||||
mlog.Log.Error(t)
|
||||
panic(err)
|
||||
//break
|
||||
default:
|
||||
mlog.Log.Error(t)
|
||||
}
|
||||
}
|
||||
96
base/ctx/log_handler.go
Normal file
96
base/ctx/log_handler.go
Normal file
@@ -0,0 +1,96 @@
|
||||
package ctx
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"mayfly-go/base/biz"
|
||||
"mayfly-go/base/mlog"
|
||||
"mayfly-go/base/utils"
|
||||
"reflect"
|
||||
"runtime/debug"
|
||||
|
||||
log "github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
func init() {
|
||||
// customFormatter := new(log.TextFormatter)
|
||||
// customFormatter.TimestampFormat = "2006-01-02 15:04:05.000"
|
||||
// customFormatter.FullTimestamp = true
|
||||
log.SetFormatter(new(mlog.LogFormatter))
|
||||
log.SetReportCaller(true)
|
||||
|
||||
AfterHandlers = append(AfterHandlers, new(LogInfo))
|
||||
}
|
||||
|
||||
type LogInfo struct {
|
||||
NeedLog bool // 是否需要记录日志
|
||||
LogResp bool // 是否记录返回结果
|
||||
Description string // 请求描述
|
||||
}
|
||||
|
||||
func NewLogInfo(description string) *LogInfo {
|
||||
return &LogInfo{NeedLog: true, Description: description, LogResp: false}
|
||||
}
|
||||
|
||||
func (i *LogInfo) WithLogResp(logResp bool) *LogInfo {
|
||||
i.LogResp = logResp
|
||||
return i
|
||||
}
|
||||
|
||||
func (l *LogInfo) AfterHandle(rc *ReqCtx) {
|
||||
li := rc.LogInfo
|
||||
if li == nil || !li.NeedLog {
|
||||
return
|
||||
}
|
||||
|
||||
lfs := log.Fields{}
|
||||
if la := rc.LoginAccount; la != nil {
|
||||
lfs["uid"] = la.Id
|
||||
lfs["uname"] = la.Username
|
||||
}
|
||||
|
||||
req := rc.Req
|
||||
lfs[req.Method] = req.URL.Path
|
||||
|
||||
if err := rc.err; err != nil {
|
||||
log.WithFields(lfs).Error(getErrMsg(rc, err))
|
||||
return
|
||||
}
|
||||
log.WithFields(lfs).Info(getLogMsg(rc))
|
||||
}
|
||||
|
||||
func getLogMsg(rc *ReqCtx) string {
|
||||
msg := rc.LogInfo.Description
|
||||
if !utils.IsBlank(reflect.ValueOf(rc.ReqParam)) {
|
||||
rb, _ := json.Marshal(rc.ReqParam)
|
||||
msg = msg + fmt.Sprintf("\n--> %s", string(rb))
|
||||
}
|
||||
|
||||
// 返回结果不为空,则记录返回结果
|
||||
if rc.LogInfo.LogResp && !utils.IsBlank(reflect.ValueOf(rc.ResData)) {
|
||||
respB, _ := json.Marshal(rc.ResData)
|
||||
msg = msg + fmt.Sprintf("\n<-- %s", string(respB))
|
||||
}
|
||||
return msg
|
||||
}
|
||||
|
||||
func getErrMsg(rc *ReqCtx, err interface{}) string {
|
||||
msg := rc.LogInfo.Description
|
||||
if !utils.IsBlank(reflect.ValueOf(rc.ReqParam)) {
|
||||
rb, _ := json.Marshal(rc.ReqParam)
|
||||
msg = msg + fmt.Sprintf("\n--> %s", string(rb))
|
||||
}
|
||||
|
||||
var errMsg string
|
||||
switch t := err.(type) {
|
||||
case *biz.BizError:
|
||||
errMsg = fmt.Sprintf("\n<-e errCode: %d, errMsg: %s", t.Code(), t.Error())
|
||||
break
|
||||
case error:
|
||||
errMsg = fmt.Sprintf("\n<-e errMsg: %s\n%s", t.Error(), string(debug.Stack()))
|
||||
break
|
||||
case string:
|
||||
errMsg = fmt.Sprintf("\n<-e errMsg: %s\n%s", t, string(debug.Stack()))
|
||||
}
|
||||
return (msg + errMsg)
|
||||
}
|
||||
@@ -12,7 +12,7 @@ var permissionError = biz.NewBizErrCode(501, "token error")
|
||||
|
||||
type PermissionHandler struct{}
|
||||
|
||||
func (p *PermissionHandler) Handler(rc *ReqCtx) error {
|
||||
func (p *PermissionHandler) BeforeHandle(rc *ReqCtx) error {
|
||||
if !rc.NeedToken {
|
||||
return nil
|
||||
}
|
||||
@@ -1,30 +1,73 @@
|
||||
package ctx
|
||||
|
||||
import (
|
||||
"mayfly-go/base/ginx"
|
||||
"mayfly-go/base/model"
|
||||
"net/http"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
type ReqCtx struct {
|
||||
Req *http.Request
|
||||
NeedToken bool // 是否需要token
|
||||
LoginAccount *LoginAccount // 登录账号信息
|
||||
// // 获取数据函数
|
||||
// type getDataFunc func(*ReqCtx) interface{}
|
||||
|
||||
// 日志相关信息
|
||||
NeedLog bool // 是否需要记录日志
|
||||
LogResp bool // 是否记录返回结果
|
||||
Description string // 请求描述
|
||||
ReqParam interface{} // 请求参数
|
||||
RespObj interface{} // 响应结果
|
||||
// // 操作函数,无返回数据
|
||||
// type operationFunc func(*ReqCtx)
|
||||
|
||||
// 处理函数
|
||||
type HandlerFunc func(*ReqCtx)
|
||||
|
||||
type ReqCtx struct {
|
||||
Req *http.Request // http request
|
||||
GinCtx *gin.Context // gin context
|
||||
|
||||
NeedToken bool // 是否需要token
|
||||
LoginAccount *model.LoginAccount // 登录账号信息
|
||||
|
||||
LogInfo *LogInfo // 日志相关信息
|
||||
ReqParam interface{} // 请求参数,主要用于记录日志
|
||||
ResData interface{} // 响应结果
|
||||
err interface{} // 请求错误
|
||||
}
|
||||
|
||||
// 请求前置处理器
|
||||
func (rc *ReqCtx) Handle(handler HandlerFunc) {
|
||||
ginCtx := rc.GinCtx
|
||||
defer func() {
|
||||
if err := recover(); err != nil {
|
||||
rc.err = err
|
||||
ginx.ErrorRes(ginCtx, err)
|
||||
}
|
||||
// 应用所有请求后置处理器
|
||||
ApplyAfterHandler(rc)
|
||||
}()
|
||||
if ginCtx == nil {
|
||||
panic("ginContext == nil")
|
||||
}
|
||||
|
||||
rc.Req = ginCtx.Request
|
||||
// 默认为不记录请求参数,可在handler回调函数中覆盖赋值
|
||||
rc.ReqParam = 0
|
||||
// 默认响应结果为nil,可在handler中赋值
|
||||
rc.ResData = nil
|
||||
|
||||
// 调用请求前所有处理器
|
||||
err := ApplyBeforeHandler(rc)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
handler(rc)
|
||||
ginx.SuccessRes(ginCtx, rc.ResData)
|
||||
}
|
||||
|
||||
// 请求前置处理器,返回error则停止后续逻辑
|
||||
type BeforeHandler interface {
|
||||
Handler(rc *ReqCtx) error
|
||||
BeforeHandle(rc *ReqCtx) error
|
||||
}
|
||||
|
||||
// 请求后置处理器
|
||||
type AfterHandler interface {
|
||||
Handler(rc *ReqCtx, err error)
|
||||
AfterHandle(rc *ReqCtx)
|
||||
}
|
||||
|
||||
var (
|
||||
@@ -35,8 +78,7 @@ var (
|
||||
// 应用所有请求前置处理器
|
||||
func ApplyBeforeHandler(rc *ReqCtx) error {
|
||||
for _, e := range BeforeHandlers {
|
||||
err := e.Handler(rc)
|
||||
if err != nil {
|
||||
if err := e.BeforeHandle(rc); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
@@ -44,19 +86,29 @@ func ApplyBeforeHandler(rc *ReqCtx) error {
|
||||
}
|
||||
|
||||
// 应用所有后置处理器
|
||||
func ApplyAfterHandler(rc *ReqCtx, err error) {
|
||||
func ApplyAfterHandler(rc *ReqCtx) {
|
||||
for _, e := range AfterHandlers {
|
||||
e.Handler(rc, err)
|
||||
e.AfterHandle(rc)
|
||||
}
|
||||
}
|
||||
|
||||
// 新建请求上下文,默认为需要记录日志
|
||||
// @param needToken 是否需要token才可访问
|
||||
// @param description 请求描述
|
||||
func NewReqCtx(needToken bool, description string) *ReqCtx {
|
||||
return &ReqCtx{NeedToken: needToken, Description: description, NeedLog: true}
|
||||
// 新建请求上下文,默认需要校验token
|
||||
func NewReqCtx() *ReqCtx {
|
||||
return &ReqCtx{NeedToken: true}
|
||||
}
|
||||
|
||||
func NewNoLogReqCtx(needToken bool) *ReqCtx {
|
||||
return &ReqCtx{NeedToken: needToken, NeedLog: false}
|
||||
func NewReqCtxWithGin(g *gin.Context) *ReqCtx {
|
||||
return &ReqCtx{NeedToken: true, GinCtx: g}
|
||||
}
|
||||
|
||||
// 调用该方法设置请求描述,则默认记录日志,并不记录响应结果
|
||||
func (r *ReqCtx) WithLog(li *LogInfo) *ReqCtx {
|
||||
r.LogInfo = li
|
||||
return r
|
||||
}
|
||||
|
||||
// 是否需要token
|
||||
func (r *ReqCtx) WithNeedToken(needToken bool) *ReqCtx {
|
||||
r.NeedToken = needToken
|
||||
return r
|
||||
}
|
||||
|
||||
@@ -1,86 +0,0 @@
|
||||
package ctx
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"mayfly-go/base/biz"
|
||||
"mayfly-go/base/mlog"
|
||||
"mayfly-go/base/utils"
|
||||
"reflect"
|
||||
|
||||
log "github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
func init() {
|
||||
// customFormatter := new(log.TextFormatter)
|
||||
// customFormatter.TimestampFormat = "2006-01-02 15:04:05.000"
|
||||
// customFormatter.FullTimestamp = true
|
||||
log.SetFormatter(new(mlog.LogFormatter))
|
||||
log.SetReportCaller(true)
|
||||
|
||||
AfterHandlers = append(AfterHandlers, new(LogHandler))
|
||||
}
|
||||
|
||||
type LogHandler struct{}
|
||||
|
||||
func (l *LogHandler) Handler(rc *ReqCtx, err error) {
|
||||
if !rc.NeedLog {
|
||||
return
|
||||
}
|
||||
|
||||
lfs := log.Fields{}
|
||||
if la := rc.LoginAccount; la != nil {
|
||||
lfs["uid"] = la.Id
|
||||
lfs["uname"] = la.Username
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
// lfs["errMsg"] = err.Error()
|
||||
|
||||
// switch t := err.(type) {
|
||||
// case *biz.BizError:
|
||||
// lfs["errCode"] = t.Code()
|
||||
// break
|
||||
// default:
|
||||
// }
|
||||
log.WithFields(lfs).Error(getErrMsg(rc, err))
|
||||
return
|
||||
}
|
||||
|
||||
// rb, _ := json.Marshal(rc.ReqParam)
|
||||
// lfs["req"] = string(rb)
|
||||
// // 返回结果不为空,则记录返回结果
|
||||
// if rc.LogResp && !utils.IsBlank(reflect.ValueOf(rc.RespObj)) {
|
||||
// respB, _ := json.Marshal(rc.RespObj)
|
||||
// lfs["resp"] = string(respB)
|
||||
// }
|
||||
log.WithFields(lfs).Info(getLogMsg(rc))
|
||||
}
|
||||
|
||||
func getLogMsg(rc *ReqCtx) string {
|
||||
msg := rc.Description
|
||||
rb, _ := json.Marshal(rc.ReqParam)
|
||||
msg = msg + fmt.Sprintf("\n--> %s", string(rb))
|
||||
// 返回结果不为空,则记录返回结果
|
||||
if rc.LogResp && !utils.IsBlank(reflect.ValueOf(rc.RespObj)) {
|
||||
respB, _ := json.Marshal(rc.RespObj)
|
||||
msg = msg + fmt.Sprintf("\n<-- %s", string(respB))
|
||||
}
|
||||
return msg
|
||||
}
|
||||
|
||||
func getErrMsg(rc *ReqCtx, err error) string {
|
||||
msg := rc.Description
|
||||
rb, _ := json.Marshal(rc.ReqParam)
|
||||
msg = msg + fmt.Sprintf("\n--> %s", string(rb))
|
||||
|
||||
var errMsg string
|
||||
switch t := err.(type) {
|
||||
case *biz.BizError:
|
||||
errMsg = fmt.Sprintf("\n<-e errCode: %d, errMsg: %s", t.Code(), t.Error())
|
||||
break
|
||||
default:
|
||||
errMsg = fmt.Sprintf("\n<-e errMsg: %s", t.Error())
|
||||
}
|
||||
return (msg + errMsg)
|
||||
}
|
||||
@@ -4,6 +4,7 @@ import (
|
||||
"errors"
|
||||
|
||||
"mayfly-go/base/biz"
|
||||
"mayfly-go/base/model"
|
||||
"time"
|
||||
|
||||
"github.com/dgrijalva/jwt-go"
|
||||
@@ -31,7 +32,7 @@ func CreateToken(userId uint64, username string) string {
|
||||
}
|
||||
|
||||
// 解析token,并返回登录者账号信息
|
||||
func ParseToken(tokenStr string) (*LoginAccount, error) {
|
||||
func ParseToken(tokenStr string) (*model.LoginAccount, error) {
|
||||
if tokenStr == "" {
|
||||
return nil, errors.New("token error")
|
||||
}
|
||||
@@ -43,5 +44,5 @@ func ParseToken(tokenStr string) (*LoginAccount, error) {
|
||||
return nil, err
|
||||
}
|
||||
i := token.Claims.(jwt.MapClaims)
|
||||
return &LoginAccount{Id: uint64(i["id"].(float64)), Username: i["username"].(string)}, nil
|
||||
return &model.LoginAccount{Id: uint64(i["id"].(float64)), Username: i["username"].(string)}, nil
|
||||
}
|
||||
|
||||
61
base/ginx/ginx.go
Normal file
61
base/ginx/ginx.go
Normal file
@@ -0,0 +1,61 @@
|
||||
package ginx
|
||||
|
||||
import (
|
||||
"mayfly-go/base/biz"
|
||||
"mayfly-go/base/mlog"
|
||||
"mayfly-go/base/model"
|
||||
"net/http"
|
||||
"strconv"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
// 绑定并校验请求结构体参数
|
||||
func BindJsonAndValid(g *gin.Context, data interface{}) {
|
||||
err := g.BindJSON(data)
|
||||
if err != nil {
|
||||
panic(biz.NewBizErr(err.Error()))
|
||||
}
|
||||
}
|
||||
|
||||
// 获取分页参数
|
||||
func GetPageParam(g *gin.Context) *model.PageParam {
|
||||
return &model.PageParam{PageNum: QueryInt(g, "pageNum", 1), PageSize: QueryInt(g, "pageSize", 10)}
|
||||
}
|
||||
|
||||
// 获取查询参数中指定参数值,并转为int
|
||||
func QueryInt(g *gin.Context, qm string, defaultInt int) int {
|
||||
qv := g.Query(qm)
|
||||
if qv == "" {
|
||||
return defaultInt
|
||||
}
|
||||
qvi, err := strconv.Atoi(qv)
|
||||
biz.BizErrIsNil(err, "query param not int")
|
||||
return qvi
|
||||
}
|
||||
|
||||
// 返回统一成功结果
|
||||
func SuccessRes(g *gin.Context, data interface{}) {
|
||||
g.JSON(http.StatusOK, model.Success(data))
|
||||
}
|
||||
|
||||
// 返回失败结果集
|
||||
func ErrorRes(g *gin.Context, err interface{}) {
|
||||
switch t := err.(type) {
|
||||
case *biz.BizError:
|
||||
g.JSON(http.StatusOK, model.Error(t.Code(), t.Error()))
|
||||
break
|
||||
case error:
|
||||
g.JSON(http.StatusOK, model.ServerError())
|
||||
mlog.Log.Error(t)
|
||||
// panic(err)
|
||||
break
|
||||
case string:
|
||||
g.JSON(http.StatusOK, model.ServerError())
|
||||
mlog.Log.Error(t)
|
||||
// panic(err)
|
||||
break
|
||||
default:
|
||||
mlog.Log.Error(t)
|
||||
}
|
||||
}
|
||||
17
base/global/global.go
Normal file
17
base/global/global.go
Normal file
@@ -0,0 +1,17 @@
|
||||
package global
|
||||
|
||||
import (
|
||||
"mayfly-go/base/config"
|
||||
"mayfly-go/base/mlog"
|
||||
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
// 日志
|
||||
var Log = mlog.Log
|
||||
|
||||
// config.yml配置文件映射对象
|
||||
var Config = config.Conf
|
||||
|
||||
// gorm
|
||||
var Db *gorm.DB
|
||||
39
base/initialize/gorm.go
Normal file
39
base/initialize/gorm.go
Normal file
@@ -0,0 +1,39 @@
|
||||
package initialize
|
||||
|
||||
import (
|
||||
"mayfly-go/base/global"
|
||||
|
||||
"gorm.io/driver/mysql"
|
||||
"gorm.io/gorm"
|
||||
"gorm.io/gorm/logger"
|
||||
"gorm.io/gorm/schema"
|
||||
)
|
||||
|
||||
func GormMysql() *gorm.DB {
|
||||
m := global.Config.Mysql
|
||||
if m.Dbname == "" {
|
||||
return nil
|
||||
}
|
||||
|
||||
mysqlConfig := mysql.Config{
|
||||
DSN: m.Dsn(), // DSN data source name
|
||||
DefaultStringSize: 191, // string 类型字段的默认长度
|
||||
DisableDatetimePrecision: true, // 禁用 datetime 精度,MySQL 5.6 之前的数据库不支持
|
||||
DontSupportRenameIndex: true, // 重命名索引时采用删除并新建的方式,MySQL 5.7 之前的数据库和 MariaDB 不支持重命名索引
|
||||
DontSupportRenameColumn: true, // 用 `change` 重命名列,MySQL 8 之前的数据库和 MariaDB 不支持重命名列
|
||||
SkipInitializeWithVersion: false, // 根据版本自动配置
|
||||
}
|
||||
ormConfig := &gorm.Config{NamingStrategy: schema.NamingStrategy{
|
||||
TablePrefix: "t_",
|
||||
SingularTable: true,
|
||||
}, Logger: logger.Default.LogMode(logger.Silent)}
|
||||
if db, err := gorm.Open(mysql.New(mysqlConfig), ormConfig); err != nil {
|
||||
global.Log.Panic("mysql连接失败")
|
||||
return nil
|
||||
} else {
|
||||
sqlDB, _ := db.DB()
|
||||
sqlDB.SetMaxIdleConns(m.MaxIdleConns)
|
||||
sqlDB.SetMaxOpenConns(m.MaxOpenConns)
|
||||
return db
|
||||
}
|
||||
}
|
||||
27
base/middleware/cors.go
Normal file
27
base/middleware/cors.go
Normal file
@@ -0,0 +1,27 @@
|
||||
package middleware
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
// 处理跨域请求,支持options访问
|
||||
func Cors() gin.HandlerFunc {
|
||||
return func(c *gin.Context) {
|
||||
method := c.Request.Method
|
||||
|
||||
c.Header("Access-Control-Allow-Origin", "*")
|
||||
c.Header("Access-Control-Allow-Methods", "POST, GET, OPTIONS, PUT, DELETE, UPDATE")
|
||||
c.Header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept, Authorization")
|
||||
c.Header("Access-Control-Expose-Headers", "Content-Length, Access-Control-Allow-Origin, Access-Control-Allow-Headers, Cache-Control, Content-Language, Content-Type")
|
||||
c.Header("Access-Control-Allow-Credentials", "true")
|
||||
|
||||
//放行所有OPTIONS方法
|
||||
if method == "OPTIONS" {
|
||||
c.AbortWithStatus(http.StatusNoContent)
|
||||
}
|
||||
// 处理请求
|
||||
c.Next()
|
||||
}
|
||||
}
|
||||
15
base/middleware/recover.go
Normal file
15
base/middleware/recover.go
Normal file
@@ -0,0 +1,15 @@
|
||||
package middleware
|
||||
|
||||
import "github.com/gin-gonic/gin"
|
||||
|
||||
// RecoveryMiddleware 崩溃恢复中间件
|
||||
func RecoveryMiddleware() gin.HandlerFunc {
|
||||
return func(c *gin.Context) {
|
||||
defer func() {
|
||||
if err := recover(); err != nil {
|
||||
|
||||
}
|
||||
}()
|
||||
c.Next()
|
||||
}
|
||||
}
|
||||
25
base/middleware/req_log.go
Normal file
25
base/middleware/req_log.go
Normal file
@@ -0,0 +1,25 @@
|
||||
package middleware
|
||||
|
||||
import (
|
||||
"mayfly-go/base/ctx"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
var logHandler = new(ctx.LogInfo)
|
||||
|
||||
func ReqLog() gin.HandlerFunc {
|
||||
return func(c *gin.Context) {
|
||||
|
||||
// 处理请求
|
||||
c.Next()
|
||||
|
||||
reqCtxI, exist := c.Get("reqCtx")
|
||||
if !exist {
|
||||
return
|
||||
}
|
||||
|
||||
reqCtx := reqCtxI.(*ctx.ReqCtx)
|
||||
logHandler.AfterHandle(reqCtx)
|
||||
}
|
||||
}
|
||||
@@ -2,6 +2,7 @@ package mlog
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
@@ -26,8 +27,14 @@ func (l *LogFormatter) Format(entry *logrus.Entry) ([]byte, error) {
|
||||
level := entry.Level
|
||||
logMsg := fmt.Sprintf("%s [%s]", timestamp, strings.ToUpper(level.String()))
|
||||
// 如果存在调用信息,且为error级别以上记录文件及行号
|
||||
if caller := entry.Caller; caller != nil && level <= logrus.ErrorLevel {
|
||||
logMsg = logMsg + fmt.Sprintf(" [%s:%d]", caller.File, caller.Line)
|
||||
if caller := entry.Caller; caller != nil {
|
||||
var fp string
|
||||
if level <= logrus.ErrorLevel {
|
||||
fp = caller.File
|
||||
} else {
|
||||
fp = filepath.Base(caller.File)
|
||||
}
|
||||
logMsg = logMsg + fmt.Sprintf(" [%s:%d]", fp, caller.Line)
|
||||
}
|
||||
for k, v := range entry.Data {
|
||||
logMsg = logMsg + fmt.Sprintf(" [%s=%v]", k, v)
|
||||
|
||||
15
base/model/login_account.go
Normal file
15
base/model/login_account.go
Normal file
@@ -0,0 +1,15 @@
|
||||
package model
|
||||
|
||||
type AppContext struct {
|
||||
}
|
||||
|
||||
type LoginAccount struct {
|
||||
Id uint64
|
||||
Username string
|
||||
}
|
||||
|
||||
type Permission struct {
|
||||
CheckToken bool // 是否检查token
|
||||
Code string // 权限码
|
||||
Name string // 描述
|
||||
}
|
||||
@@ -1,31 +1,25 @@
|
||||
package model
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"mayfly-go/base/biz"
|
||||
"mayfly-go/base/ctx"
|
||||
"mayfly-go/base/utils"
|
||||
"reflect"
|
||||
"mayfly-go/base/global"
|
||||
"strconv"
|
||||
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/beego/beego/v2/client/orm"
|
||||
"github.com/siddontang/go/log"
|
||||
)
|
||||
|
||||
type Model struct {
|
||||
Id uint64 `orm:"column(id);auto" json:"id"`
|
||||
CreateTime *time.Time `orm:"column(create_time);type(datetime);null" json:"createTime"`
|
||||
CreatorId uint64 `orm:"column(creator_id)" json:"creatorId"`
|
||||
Creator string `orm:"column(creator)" json:"creator"`
|
||||
UpdateTime *time.Time `orm:"column(update_time);type(datetime);null" json:"updateTime"`
|
||||
ModifierId uint64 `orm:"column(modifier_id)" json:"modifierId"`
|
||||
Modifier string `orm:"column(modifier)" json:"modifier"`
|
||||
Id uint64 `json:"id"`
|
||||
CreateTime *time.Time `json:"createTime"`
|
||||
CreatorId uint64 `json:"creatorId"`
|
||||
Creator string `json:"creator"`
|
||||
UpdateTime *time.Time `json:"updateTime"`
|
||||
ModifierId uint64 `json:"modifierId"`
|
||||
Modifier string `json:"modifier"`
|
||||
}
|
||||
|
||||
// 设置基础信息. 如创建时间,修改时间,创建者,修改者信息
|
||||
func (m *Model) SetBaseInfo(account *ctx.LoginAccount) {
|
||||
func (m *Model) SetBaseInfo(account *LoginAccount) {
|
||||
nowTime := time.Now()
|
||||
isCreate := m.Id == 0
|
||||
if isCreate {
|
||||
@@ -46,257 +40,179 @@ func (m *Model) SetBaseInfo(account *ctx.LoginAccount) {
|
||||
m.ModifierId = id
|
||||
}
|
||||
|
||||
// 获取orm querySeter
|
||||
func QuerySetter(table interface{}) orm.QuerySeter {
|
||||
return getOrm().QueryTable(table)
|
||||
}
|
||||
|
||||
// 根据id获取实体对象。model需为指针类型(需要将查询出来的值赋值给model)
|
||||
//
|
||||
// 若error不为nil则为不存在该记录
|
||||
func GetById(model interface{}, id uint64, cols ...string) error {
|
||||
return QuerySetter(model).Filter("Id", id).One(model, cols...)
|
||||
return global.Db.Debug().Select(cols).Where("id = ?", id).First(model).Error
|
||||
}
|
||||
|
||||
// 根据id更新model,更新字段为model中不为空的值,即int类型不为0,ptr类型不为nil这类字段值
|
||||
func UpdateById(model interface{}) (int64, error) {
|
||||
var id uint64
|
||||
params := orm.Params{}
|
||||
err := utils.DoWithFields(model, func(ft reflect.StructField, fv reflect.Value) error {
|
||||
if utils.IsBlank(fv) {
|
||||
return nil
|
||||
}
|
||||
if ft.Name == "Id" {
|
||||
if id = fv.Uint(); id == 0 {
|
||||
return errors.New("根据id更新model时Id不能为0")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
params[ft.Name] = fv.Interface()
|
||||
return nil
|
||||
})
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return QuerySetter(model).Filter("Id", id).Update(params)
|
||||
func UpdateById(model interface{}) error {
|
||||
return global.Db.Model(model).Updates(model).Error
|
||||
}
|
||||
|
||||
// 根据id删除model
|
||||
func DeleteById(model interface{}, id uint64) (int64, error) {
|
||||
return QuerySetter(model).Filter("Id", id).Delete()
|
||||
func DeleteById(model interface{}, id uint64) error {
|
||||
// return QuerySetter(model).Filter("Id", id).Delete()
|
||||
return global.Db.Delete(model).Error
|
||||
}
|
||||
|
||||
// 插入model
|
||||
func Insert(model interface{}) (int64, error) {
|
||||
return getOrm().Insert(model)
|
||||
func Insert(model interface{}) error {
|
||||
return global.Db.Create(model).Error
|
||||
}
|
||||
|
||||
// 获取满足model中不为空的字段值条件的所有数据.
|
||||
//
|
||||
// @param list为数组类型 如 var users []*User
|
||||
func ListByCondition(model interface{}, list interface{}) {
|
||||
qs := QuerySetter(model)
|
||||
utils.DoWithFields(model, func(ft reflect.StructField, fv reflect.Value) error {
|
||||
if !utils.IsBlank(fv) {
|
||||
qs = qs.Filter(ft.Name, fv.Interface())
|
||||
}
|
||||
return nil
|
||||
})
|
||||
qs.All(list)
|
||||
// @param list为数组类型 如 var users []*User,可指定为非model结构体,即只包含需要返回的字段结构体
|
||||
func ListBy(model interface{}, list interface{}, cols ...string) {
|
||||
global.Db.Debug().Model(model).Select(cols).Where(model).Find(list)
|
||||
}
|
||||
|
||||
// 获取满足model中不为空的字段值条件的单个对象。model需为指针类型(需要将查询出来的值赋值给model)
|
||||
//
|
||||
// 若 error不为nil,则为不存在该记录
|
||||
func GetByCondition(model interface{}, cols ...string) error {
|
||||
qs := QuerySetter(model)
|
||||
utils.DoWithFields(model, func(ft reflect.StructField, fv reflect.Value) error {
|
||||
if !utils.IsBlank(fv) {
|
||||
qs = qs.Filter(ft.Name, fv.Interface())
|
||||
}
|
||||
return nil
|
||||
})
|
||||
return qs.One(model, cols...)
|
||||
func GetBy(model interface{}, cols ...string) error {
|
||||
return global.Db.Debug().Select(cols).Where(model).First(model).Error
|
||||
}
|
||||
|
||||
// 获取满足conditionModel中不为空的字段值条件的单个对象。model需为指针类型(需要将查询出来的值赋值给model)
|
||||
// @param toModel 需要查询的字段
|
||||
// 若 error不为nil,则为不存在该记录
|
||||
func GetByConditionTo(conditionModel interface{}, toModel interface{}) error {
|
||||
return global.Db.Debug().Model(conditionModel).Where(conditionModel).First(toModel).Error
|
||||
}
|
||||
|
||||
// 获取分页结果
|
||||
func GetPage(seter orm.QuerySeter, pageParam *PageParam, models interface{}, toModels interface{}) PageResult {
|
||||
count, _ := seter.Count()
|
||||
func GetPage(pageParam *PageParam, conditionModel interface{}, toModels interface{}, orderBy ...string) PageResult {
|
||||
var count int64
|
||||
global.Db.Debug().Model(conditionModel).Where(conditionModel).Count(&count)
|
||||
if count == 0 {
|
||||
return PageResult{Total: 0, List: nil}
|
||||
return PageResult{Total: 0, List: []string{}}
|
||||
}
|
||||
_, qerr := seter.Limit(pageParam.PageSize, pageParam.PageNum-1).All(models, getFieldNames(toModels)...)
|
||||
biz.BizErrIsNil(qerr, "查询错误")
|
||||
err := utils.Copy(toModels, models)
|
||||
biz.BizErrIsNil(err, "实体转换错误")
|
||||
page := pageParam.PageNum
|
||||
pageSize := pageParam.PageSize
|
||||
var orderByStr string
|
||||
if orderBy == nil {
|
||||
orderByStr = "id desc"
|
||||
} else {
|
||||
orderByStr = strings.Join(orderBy, ",")
|
||||
}
|
||||
global.Db.Debug().Model(conditionModel).Where(conditionModel).Order(orderByStr).Limit(pageSize).Offset((page - 1) * pageSize).Find(toModels)
|
||||
return PageResult{Total: count, List: toModels}
|
||||
}
|
||||
|
||||
// 根据sql获取分页对象
|
||||
func GetPageBySql(sql string, toModel interface{}, param *PageParam, args ...interface{}) PageResult {
|
||||
func GetPageBySql(sql string, param *PageParam, toModel interface{}, args ...interface{}) PageResult {
|
||||
db := global.Db
|
||||
selectIndex := strings.Index(sql, "SELECT ") + 7
|
||||
fromIndex := strings.Index(sql, " FROM")
|
||||
selectCol := sql[selectIndex:fromIndex]
|
||||
countSql := strings.Replace(sql, selectCol, "COUNT(*) AS total ", 1)
|
||||
// 查询count
|
||||
o := getOrm()
|
||||
type TotalRes struct {
|
||||
Total int64
|
||||
}
|
||||
var totalRes TotalRes
|
||||
_ = o.Raw(countSql, args).QueryRow(&totalRes)
|
||||
total := totalRes.Total
|
||||
if total == 0 {
|
||||
return PageResult{Total: 0, List: nil}
|
||||
var count int
|
||||
db.Raw(countSql, args...).Scan(&count)
|
||||
if count == 0 {
|
||||
return PageResult{Total: 0, List: []string{}}
|
||||
}
|
||||
// 分页查询
|
||||
limitSql := sql + " LIMIT " + strconv.Itoa(param.PageNum-1) + ", " + strconv.Itoa(param.PageSize)
|
||||
var maps []orm.Params
|
||||
_, err := o.Raw(limitSql, args).Values(&maps)
|
||||
if err != nil {
|
||||
panic(errors.New("查询错误 : " + err.Error()))
|
||||
}
|
||||
e := ormParams2Struct(maps, toModel)
|
||||
if e != nil {
|
||||
panic(e)
|
||||
}
|
||||
return PageResult{Total: total, List: toModel}
|
||||
db.Raw(limitSql).Scan(toModel)
|
||||
return PageResult{Total: int64(count), List: toModel}
|
||||
}
|
||||
|
||||
func GetListBySql(sql string, params ...interface{}) *[]orm.Params {
|
||||
var maps []orm.Params
|
||||
_, err := getOrm().Raw(sql, params).Values(&maps)
|
||||
if err != nil {
|
||||
log.Error("根据sql查询数据列表失败:%s", err.Error())
|
||||
}
|
||||
return &maps
|
||||
func GetListBySql(sql string, params ...interface{}) []map[string]interface{} {
|
||||
var maps []map[string]interface{}
|
||||
global.Db.Raw(sql, params).Scan(&maps)
|
||||
return maps
|
||||
}
|
||||
|
||||
// 获取所有列表数据
|
||||
// model为数组类型 如 var users []*User
|
||||
func GetList(seter orm.QuerySeter, model interface{}, toModel interface{}) {
|
||||
_, _ = seter.All(model, getFieldNames(toModel)...)
|
||||
err := utils.Copy(toModel, model)
|
||||
biz.BizErrIsNil(err, "实体转换错误")
|
||||
}
|
||||
// func GetList(seter orm.QuerySeter, model interface{}, toModel interface{}) {
|
||||
// _, _ = seter.All(model, getFieldNames(toModel)...)
|
||||
// err := utils.Copy(toModel, model)
|
||||
// biz.BizErrIsNil(err, "实体转换错误")
|
||||
// }
|
||||
|
||||
// 根据toModel结构体字段查询单条记录,并将值赋值给toModel
|
||||
func GetOne(seter orm.QuerySeter, model interface{}, toModel interface{}) error {
|
||||
err := seter.One(model, getFieldNames(toModel)...)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
cerr := utils.Copy(toModel, model)
|
||||
biz.BizErrIsNil(cerr, "实体转换错误")
|
||||
return nil
|
||||
}
|
||||
// func getOrm() orm.Ormer {
|
||||
// return orm.NewOrm()
|
||||
// }
|
||||
|
||||
// 根据实体以及指定字段值查询实体,若字段数组为空,则默认用id查
|
||||
func GetBy(model interface{}, fs ...string) error {
|
||||
err := getOrm().Read(model, fs...)
|
||||
if err != nil {
|
||||
if err == orm.ErrNoRows {
|
||||
return errors.New("该数据不存在")
|
||||
} else {
|
||||
return errors.New("查询失败")
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
// // 结果模型缓存
|
||||
// var resultModelCache = make(map[string][]string)
|
||||
|
||||
func Update(model interface{}, fs ...string) error {
|
||||
_, err := getOrm().Update(model, fs...)
|
||||
if err != nil {
|
||||
return errors.New("数据更新失败")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
// // 获取实体对象的字段名
|
||||
// func getFieldNames(obj interface{}) []string {
|
||||
// objType := indirectType(reflect.TypeOf(obj))
|
||||
// cacheKey := objType.PkgPath() + "." + objType.Name()
|
||||
// cache := resultModelCache[cacheKey]
|
||||
// if cache != nil {
|
||||
// return cache
|
||||
// }
|
||||
// cache = getFieldNamesByType("", reflect.TypeOf(obj))
|
||||
// resultModelCache[cacheKey] = cache
|
||||
// return cache
|
||||
// }
|
||||
|
||||
func Delete(model interface{}, fs ...string) error {
|
||||
_, err := getOrm().Delete(model, fs...)
|
||||
if err != nil {
|
||||
return errors.New("数据删除失败")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
// func indirectType(reflectType reflect.Type) reflect.Type {
|
||||
// for reflectType.Kind() == reflect.Ptr || reflectType.Kind() == reflect.Slice {
|
||||
// reflectType = reflectType.Elem()
|
||||
// }
|
||||
// return reflectType
|
||||
// }
|
||||
|
||||
func getOrm() orm.Ormer {
|
||||
return orm.NewOrm()
|
||||
}
|
||||
// func getFieldNamesByType(namePrefix string, reflectType reflect.Type) []string {
|
||||
// var fieldNames []string
|
||||
|
||||
// 结果模型缓存
|
||||
var resultModelCache = make(map[string][]string)
|
||||
// if reflectType = indirectType(reflectType); reflectType.Kind() == reflect.Struct {
|
||||
// for i := 0; i < reflectType.NumField(); i++ {
|
||||
// t := reflectType.Field(i)
|
||||
// tName := t.Name
|
||||
// // 判断结构体字段是否为结构体,是的话则跳过
|
||||
// it := indirectType(t.Type)
|
||||
// if it.Kind() == reflect.Struct {
|
||||
// itName := it.Name()
|
||||
// // 如果包含Time或time则表示为time类型,无需递归该结构体字段
|
||||
// if !strings.Contains(itName, "BaseModel") && !strings.Contains(itName, "Time") &&
|
||||
// !strings.Contains(itName, "time") {
|
||||
// fieldNames = append(fieldNames, getFieldNamesByType(tName+"__", it)...)
|
||||
// continue
|
||||
// }
|
||||
// }
|
||||
|
||||
// 获取实体对象的字段名
|
||||
func getFieldNames(obj interface{}) []string {
|
||||
objType := indirectType(reflect.TypeOf(obj))
|
||||
cacheKey := objType.PkgPath() + "." + objType.Name()
|
||||
cache := resultModelCache[cacheKey]
|
||||
if cache != nil {
|
||||
return cache
|
||||
}
|
||||
cache = getFieldNamesByType("", reflect.TypeOf(obj))
|
||||
resultModelCache[cacheKey] = cache
|
||||
return cache
|
||||
}
|
||||
// if t.Anonymous {
|
||||
// fieldNames = append(fieldNames, getFieldNamesByType("", t.Type)...)
|
||||
// } else {
|
||||
// fieldNames = append(fieldNames, namePrefix+tName)
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
func indirectType(reflectType reflect.Type) reflect.Type {
|
||||
for reflectType.Kind() == reflect.Ptr || reflectType.Kind() == reflect.Slice {
|
||||
reflectType = reflectType.Elem()
|
||||
}
|
||||
return reflectType
|
||||
}
|
||||
// return fieldNames
|
||||
// }
|
||||
|
||||
func getFieldNamesByType(namePrefix string, reflectType reflect.Type) []string {
|
||||
var fieldNames []string
|
||||
// func ormParams2Struct(maps []orm.Params, structs interface{}) error {
|
||||
// structsV := reflect.Indirect(reflect.ValueOf(structs))
|
||||
// valType := structsV.Type()
|
||||
// valElemType := valType.Elem()
|
||||
// sliceType := reflect.SliceOf(valElemType)
|
||||
|
||||
if reflectType = indirectType(reflectType); reflectType.Kind() == reflect.Struct {
|
||||
for i := 0; i < reflectType.NumField(); i++ {
|
||||
t := reflectType.Field(i)
|
||||
tName := t.Name
|
||||
// 判断结构体字段是否为结构体,是的话则跳过
|
||||
it := indirectType(t.Type)
|
||||
if it.Kind() == reflect.Struct {
|
||||
itName := it.Name()
|
||||
// 如果包含Time或time则表示为time类型,无需递归该结构体字段
|
||||
if !strings.Contains(itName, "BaseModel") && !strings.Contains(itName, "Time") &&
|
||||
!strings.Contains(itName, "time") {
|
||||
fieldNames = append(fieldNames, getFieldNamesByType(tName+"__", it)...)
|
||||
continue
|
||||
}
|
||||
}
|
||||
// length := len(maps)
|
||||
|
||||
if t.Anonymous {
|
||||
fieldNames = append(fieldNames, getFieldNamesByType("", t.Type)...)
|
||||
} else {
|
||||
fieldNames = append(fieldNames, namePrefix+tName)
|
||||
}
|
||||
}
|
||||
}
|
||||
// valSlice := structsV
|
||||
// if valSlice.IsNil() {
|
||||
// // Make a new slice to hold our result, same size as the original data.
|
||||
// valSlice = reflect.MakeSlice(sliceType, length, length)
|
||||
// }
|
||||
|
||||
return fieldNames
|
||||
}
|
||||
|
||||
func ormParams2Struct(maps []orm.Params, structs interface{}) error {
|
||||
structsV := reflect.Indirect(reflect.ValueOf(structs))
|
||||
valType := structsV.Type()
|
||||
valElemType := valType.Elem()
|
||||
sliceType := reflect.SliceOf(valElemType)
|
||||
|
||||
length := len(maps)
|
||||
|
||||
valSlice := structsV
|
||||
if valSlice.IsNil() {
|
||||
// Make a new slice to hold our result, same size as the original data.
|
||||
valSlice = reflect.MakeSlice(sliceType, length, length)
|
||||
}
|
||||
|
||||
for i := 0; i < length; i++ {
|
||||
err := utils.Map2Struct(maps[i], valSlice.Index(i).Addr().Interface())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
structsV.Set(valSlice)
|
||||
return nil
|
||||
}
|
||||
// for i := 0; i < length; i++ {
|
||||
// err := utils.Map2Struct(maps[i], valSlice.Index(i).Addr().Interface())
|
||||
// if err != nil {
|
||||
// return err
|
||||
// }
|
||||
// }
|
||||
// structsV.Set(valSlice)
|
||||
// return nil
|
||||
// }
|
||||
|
||||
@@ -21,3 +21,24 @@ func GetInt4Map(m map[string]interface{}, key string) int {
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
// map构造器
|
||||
type mapBuilder struct {
|
||||
m map[string]interface{}
|
||||
}
|
||||
|
||||
func MapBuilder(key string, value interface{}) *mapBuilder {
|
||||
mb := new(mapBuilder)
|
||||
mb.m = make(map[string]interface{}, 4)
|
||||
mb.m[key] = value
|
||||
return mb
|
||||
}
|
||||
|
||||
func (mb *mapBuilder) Put(key string, value interface{}) *mapBuilder {
|
||||
mb.m[key] = value
|
||||
return mb
|
||||
}
|
||||
|
||||
func (mb *mapBuilder) ToMap() map[string]interface{} {
|
||||
return mb.m
|
||||
}
|
||||
|
||||
9
base/utils/stack_trace_utils.go
Normal file
9
base/utils/stack_trace_utils.go
Normal file
@@ -0,0 +1,9 @@
|
||||
package utils
|
||||
|
||||
import "runtime"
|
||||
|
||||
// 获取调用堆栈信息
|
||||
func GetStackTrace() string {
|
||||
var buf [2 << 10]byte
|
||||
return string(buf[:runtime.Stack(buf[:], false)])
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
package yml
|
||||
package utils
|
||||
|
||||
import (
|
||||
"errors"
|
||||
@@ -16,7 +16,7 @@ func LoadYml(path string, out interface{}) error {
|
||||
// yaml解析
|
||||
err := yaml.Unmarshal(yamlFileBytes, out)
|
||||
if err != nil {
|
||||
return errors.New("无法解析 [" + path + "]")
|
||||
return errors.New("无法解析 [" + path + "] -- " + err.Error())
|
||||
}
|
||||
return nil
|
||||
}
|
||||
Reference in New Issue
Block a user