feat: 目录及代码优化调整

This commit is contained in:
meilin.huang
2021-03-24 17:18:39 +08:00
parent 4c2e6b6155
commit 39e9f15def
116 changed files with 2964 additions and 310 deletions

View File

@@ -1,7 +1,8 @@
package model
package biz
import (
"fmt"
"reflect"
)
@@ -23,6 +24,12 @@ func IsTrue(exp bool, msg string, params ...interface{}) {
}
}
func IsTrueBy(exp bool, err BizError) {
if !exp {
panic(err)
}
}
func NotEmpty(str string, msg string, params ...interface{}) {
if str == "" {
panic(NewBizErr(fmt.Sprintf(msg, params...)))

41
base/biz/bizerror.go Normal file
View File

@@ -0,0 +1,41 @@
package biz
// 业务错误
type BizError struct {
code int16
err string
}
const (
SuccessCode = 200
SuccessMsg = "success"
BizErrorCode = 400
BizErrorMsg = "error"
ServerErrorCode = 500
ServerErrorMsg = "server error"
TokenErrorCode = 501
TokenErrorMsg = "token error"
)
// 错误消息
func (e *BizError) Error() string {
return e.err
}
// 错误码
func (e *BizError) Code() int16 {
return e.code
}
// 创建业务逻辑错误结构体,默认为业务逻辑错误
func NewBizErr(msg string) *BizError {
return &BizError{code: BizErrorCode, err: msg}
}
// 创建业务逻辑错误结构体可设置指定错误code
func NewBizErrCode(code int16, msg string) *BizError {
return &BizError{code: code, err: msg}
}

View File

@@ -2,12 +2,11 @@ package base
import (
"encoding/json"
"fmt"
"mayfly-go/base/biz"
"mayfly-go/base/ctx"
"mayfly-go/base/mlog"
"mayfly-go/base/model"
"mayfly-go/base/token"
"github.com/beego/beego/v2/core/logs"
"github.com/beego/beego/v2/core/validation"
"github.com/beego/beego/v2/server/web"
)
@@ -25,7 +24,7 @@ type operationFunc func(loginAccount *ctx.LoginAccount)
// 将请求体的json赋值给指定的结构体
func (c *Controller) UnmarshalBody(data interface{}) {
err := json.Unmarshal(c.Ctx.Input.RequestBody, data)
model.BizErrIsNil(err, "request body解析错误")
biz.BizErrIsNil(err, "request body解析错误")
}
// 校验表单数据
@@ -37,7 +36,7 @@ func (c *Controller) validForm(form interface{}) {
}
if !b {
e := valid.Errors[0]
panic(model.NewBizErr(e.Field + " " + e.Message))
panic(biz.NewBizErr(e.Field + " " + e.Message))
}
}
@@ -48,72 +47,61 @@ func (c *Controller) UnmarshalBodyAndValid(data interface{}) {
}
// 返回数据
// @param checkToken 是否校验token
// @param reqCtx 请求上下文
// @param getData 获取数据的回调函数
func (c *Controller) ReturnData(checkToken bool, getData getDataFunc) {
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)
}
}()
var loginAccount *ctx.LoginAccount
if checkToken {
loginAccount = c.CheckToken()
reqCtx.Req = c.Ctx.Request
// 调用请求前所有处理器
err := ctx.ApplyBeforeHandler(reqCtx)
if err != nil {
panic(err)
}
c.Success(getData(loginAccount))
}
// 返回数据
// @param checkToken 是否校验token
// @param getData 获取数据的回调函数
func (c *Controller) ReturnDataWithPermisison(permission ctx.Permission, getData getDataFunc) {
defer func() {
if err := recover(); err != nil {
c.parseErr(err)
}
}()
var logMsg string
var loginAccount *ctx.LoginAccount
if permission.CheckToken {
loginAccount = c.CheckToken()
logMsg = fmt.Sprintf("[uid=%d, uname=%s]\n", loginAccount.Id, loginAccount.Username)
}
c.Success(getData(loginAccount))
logs.Info(logMsg)
resp := getData(reqCtx.LoginAccount)
c.Success(resp)
reqCtx.RespObj = resp
}
// 无返回数据的操作,如新增修改等无需返回数据的操作
// @param checkToken 是否校验token
func (c *Controller) Operation(checkToken bool, operation operationFunc) {
// @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)
}
}()
var loginAccount *ctx.LoginAccount
if checkToken {
loginAccount = c.CheckToken()
reqCtx.Req = c.Ctx.Request
// 调用请求前所有处理器
err := ctx.ApplyBeforeHandler(reqCtx)
if err != nil {
panic(err)
}
operation(loginAccount)
c.SuccessNoData()
}
// 校验token并返回登录者账号信息
func (c *Controller) CheckToken() *ctx.LoginAccount {
tokenStr := c.Ctx.Input.Header("Authorization")
loginAccount, err := token.ParseToken(tokenStr)
if err != nil || loginAccount == nil {
panic(model.NewBizErrCode(model.TokenErrorCode, model.TokenErrorMsg))
}
return loginAccount
operation(reqCtx.LoginAccount)
c.SuccessNoData()
// 不记录返回结果
reqCtx.RespObj = 0
}
// 获取分页参数
func (c *Controller) GetPageParam() *model.PageParam {
pn, err := c.GetInt("pageNum", 1)
model.BizErrIsNil(err, "pageNum参数错误")
biz.BizErrIsNil(err, "pageNum参数错误")
ps, serr := c.GetInt("pageSize", 10)
model.BizErrIsNil(serr, "pageSize参数错误")
biz.BizErrIsNil(serr, "pageSize参数错误")
return &model.PageParam{PageNum: pn, PageSize: ps}
}
@@ -134,7 +122,7 @@ func (c *Controller) SuccessNoData() {
}
// 返回业务错误
func (c *Controller) BizError(bizError model.BizError) {
func (c *Controller) BizError(bizError *biz.BizError) {
c.Result(model.Error(bizError.Code(), bizError.Error()))
}
@@ -146,20 +134,20 @@ func (c *Controller) ServerError() {
// 解析error并对不同error返回不同result
func (c *Controller) parseErr(err interface{}) {
switch t := err.(type) {
case model.BizError:
case *biz.BizError:
c.BizError(t)
break
case error:
c.ServerError()
logs.Error(t)
mlog.Log.Error(t)
panic(err)
//break
case string:
c.ServerError()
logs.Error(t)
mlog.Log.Error(t)
panic(err)
//break
default:
logs.Error(t)
mlog.Log.Error(t)
}
}

View File

@@ -1,5 +1,8 @@
package ctx
type AppContext struct {
}
type LoginAccount struct {
Id uint64
Username string

62
base/ctx/req_ctx.go Normal file
View File

@@ -0,0 +1,62 @@
package ctx
import (
"net/http"
)
type ReqCtx struct {
Req *http.Request
NeedToken bool // 是否需要token
LoginAccount *LoginAccount // 登录账号信息
// 日志相关信息
NeedLog bool // 是否需要记录日志
LogResp bool // 是否记录返回结果
Description string // 请求描述
ReqParam interface{} // 请求参数
RespObj interface{} // 响应结果
}
// 请求前置处理器
type BeforeHandler interface {
Handler(rc *ReqCtx) error
}
// 请求后置处理器
type AfterHandler interface {
Handler(rc *ReqCtx, err error)
}
var (
BeforeHandlers []BeforeHandler
AfterHandlers []AfterHandler
)
// 应用所有请求前置处理器
func ApplyBeforeHandler(rc *ReqCtx) error {
for _, e := range BeforeHandlers {
err := e.Handler(rc)
if err != nil {
return err
}
}
return nil
}
// 应用所有后置处理器
func ApplyAfterHandler(rc *ReqCtx, err error) {
for _, e := range AfterHandlers {
e.Handler(rc, err)
}
}
// 新建请求上下文,默认为需要记录日志
// @param needToken 是否需要token才可访问
// @param description 请求描述
func NewReqCtx(needToken bool, description string) *ReqCtx {
return &ReqCtx{NeedToken: needToken, Description: description, NeedLog: true}
}
func NewNoLogReqCtx(needToken bool) *ReqCtx {
return &ReqCtx{NeedToken: needToken, NeedLog: false}
}

View File

@@ -0,0 +1,86 @@
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)
}

View File

@@ -0,0 +1,29 @@
package ctx
import (
"mayfly-go/base/biz"
)
func init() {
BeforeHandlers = append(BeforeHandlers, new(PermissionHandler))
}
var permissionError = biz.NewBizErrCode(501, "token error")
type PermissionHandler struct{}
func (p *PermissionHandler) Handler(rc *ReqCtx) error {
if !rc.NeedToken {
return nil
}
tokenStr := rc.Req.Header.Get("Authorization")
if tokenStr == "" {
return permissionError
}
loginAccount, err := ParseToken(tokenStr)
if err != nil || loginAccount == nil {
return permissionError
}
rc.LoginAccount = loginAccount
return nil
}

View File

@@ -1,9 +1,9 @@
package token
package ctx
import (
"errors"
"mayfly-go/base/ctx"
"mayfly-go/base/model"
"mayfly-go/base/biz"
"time"
"github.com/dgrijalva/jwt-go"
@@ -26,12 +26,12 @@ func CreateToken(userId uint64, username string) string {
// 使用自定义字符串加密 and get the complete encoded token as a string
tokenString, err := token.SignedString([]byte(JwtKey))
model.BizErrIsNil(err, "token创建失败")
biz.BizErrIsNil(err, "token创建失败")
return tokenString
}
// 解析token并返回登录者账号信息
func ParseToken(tokenStr string) (*ctx.LoginAccount, error) {
func ParseToken(tokenStr string) (*LoginAccount, error) {
if tokenStr == "" {
return nil, errors.New("token error")
}
@@ -43,5 +43,5 @@ func ParseToken(tokenStr string) (*ctx.LoginAccount, error) {
return nil, err
}
i := token.Claims.(jwt.MapClaims)
return &ctx.LoginAccount{Id: uint64(i["id"].(float64)), Username: i["username"].(string)}, nil
return &LoginAccount{Id: uint64(i["id"].(float64)), Username: i["username"].(string)}, nil
}

37
base/mlog/mlog.go Normal file
View File

@@ -0,0 +1,37 @@
package mlog
import (
"fmt"
"strings"
"time"
"github.com/sirupsen/logrus"
)
var Log = logrus.New()
func init() {
// customFormatter := new(logrus.TextFormatter)
// customFormatter.TimestampFormat = "2006-01-02 15:04:05.000"
// customFormatter.FullTimestamp = true
Log.SetFormatter(new(LogFormatter))
Log.SetReportCaller(true)
}
type LogFormatter struct{}
func (l *LogFormatter) Format(entry *logrus.Entry) ([]byte, error) {
timestamp := time.Now().Local().Format("2006-01-02 15:04:05.000")
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)
}
for k, v := range entry.Data {
logMsg = logMsg + fmt.Sprintf(" [%s=%v]", k, v)
}
logMsg = logMsg + fmt.Sprintf(" : %s\n", entry.Message)
return []byte(logMsg), nil
}

View File

@@ -1,27 +0,0 @@
package model
// 业务错误
type BizError struct {
code int16
err string
}
// 错误消息
func (e *BizError) Error() string {
return e.err
}
// 错误码
func (e *BizError) Code() int16 {
return e.code
}
// 创建业务逻辑错误结构体,默认为业务逻辑错误
func NewBizErr(msg string) BizError {
return BizError{code: BizErrorCode, err: msg}
}
// 创建业务逻辑错误结构体可设置指定错误code
func NewBizErrCode(code int16, msg string) BizError {
return BizError{code: code, err: msg}
}

View File

@@ -2,6 +2,7 @@ package model
import (
"errors"
"mayfly-go/base/biz"
"mayfly-go/base/ctx"
"mayfly-go/base/utils"
"reflect"
@@ -125,9 +126,9 @@ func GetPage(seter orm.QuerySeter, pageParam *PageParam, models interface{}, toM
return PageResult{Total: 0, List: nil}
}
_, qerr := seter.Limit(pageParam.PageSize, pageParam.PageNum-1).All(models, getFieldNames(toModels)...)
BizErrIsNil(qerr, "查询错误")
biz.BizErrIsNil(qerr, "查询错误")
err := utils.Copy(toModels, models)
BizErrIsNil(err, "实体转换错误")
biz.BizErrIsNil(err, "实体转换错误")
return PageResult{Total: count, List: toModels}
}
@@ -176,7 +177,7 @@ func GetListBySql(sql string, params ...interface{}) *[]orm.Params {
func GetList(seter orm.QuerySeter, model interface{}, toModel interface{}) {
_, _ = seter.All(model, getFieldNames(toModel)...)
err := utils.Copy(toModel, model)
BizErrIsNil(err, "实体转换错误")
biz.BizErrIsNil(err, "实体转换错误")
}
// 根据toModel结构体字段查询单条记录并将值赋值给toModel
@@ -186,7 +187,7 @@ func GetOne(seter orm.QuerySeter, model interface{}, toModel interface{}) error
return err
}
cerr := utils.Copy(toModel, model)
BizErrIsNil(cerr, "实体转换错误")
biz.BizErrIsNil(cerr, "实体转换错误")
return nil
}

View File

@@ -1,72 +0,0 @@
package model
import (
"fmt"
"mayfly-go/base/utils"
"mayfly-go/controllers/vo"
"mayfly-go/models"
"strings"
"testing"
"github.com/beego/beego/v2/client/orm"
_ "github.com/go-sql-driver/mysql"
)
type AccountDetailVO struct {
Id int64
Username string
}
func init() {
orm.RegisterDriver("mysql", orm.DRMySQL)
orm.RegisterDataBase("default", "mysql", "root:111049@tcp(localhost:3306)/mayfly-go?charset=utf8")
orm.Debug = true
}
func TestGetList(t *testing.T) {
query := QuerySetter(new(models.Account)).OrderBy("-Id")
list := new([]AccountDetailVO)
GetList(query, new([]models.Account), list)
fmt.Println(list)
}
func TestGetOne(t *testing.T) {
model := new(models.Account)
query := QuerySetter(model).Filter("Id", 2)
adv := new(AccountDetailVO)
GetOne(query, model, adv)
fmt.Println(adv)
}
func TestMap(t *testing.T) {
//o := getOrm()
//
////v := new([]Account)
//var maps []orm.Params
//_, err := o.Raw("SELECT a.Id, a.Username, r.Id AS 'Role.Id', r.Name AS 'Role.Name' FROM " +
// "t_account a JOIN t_role r ON a.id = r.account_id").Values(&maps)
//fmt.Println(err)
//////res := new([]Account)
////model := &Account{}
////o.QueryTable("t_account").Filter("id", 1).RelatedSel().One(model)
////o.LoadRelated(model, "Role")
res := new([]vo.AccountVO)
sql := "SELECT a.Id, a.Username, r.Id AS 'Role.Id', r.Name AS 'Role.Name' FROM t_account a JOIN t_role r ON a.id = r.account_id"
//limitSql := sql + " LIMIT 1, 3"
//selectIndex := strings.Index(sql, "SELECT ") + 7
//fromIndex := strings.Index(sql, " FROM")
//selectCol := sql[selectIndex:fromIndex]
//countSql := strings.Replace(sql, selectCol, "COUNT(*)", 1)
//fmt.Println(limitSql)
//fmt.Println(selectCol)
//fmt.Println(countSql)
page := GetPageBySql(sql, res, &PageParam{PageNum: 1, PageSize: 1})
fmt.Println(page)
//return res
}
func TestCase2Camel(t *testing.T) {
fmt.Println(utils.Case2Camel("create_time"))
fmt.Println(strings.Title("username"))
}

64
base/rediscli/rediscli.go Normal file
View File

@@ -0,0 +1,64 @@
package rediscli
import (
"fmt"
"time"
"github.com/go-redis/redis"
)
var cli *redis.Client
func SetCli(client *redis.Client) {
cli = client
}
func GetCli() *redis.Client {
return cli
}
// get key value
func Get(key string) string {
val, err := cli.Get(key).Result()
switch {
case err == redis.Nil:
fmt.Println("key does not exist")
case err != nil:
fmt.Println("Get failed", err)
case val == "":
fmt.Println("value is empty")
}
return val
}
// set key value
func Set(key string, val string, expiration time.Duration) {
cli.Set(key, val, expiration)
}
func HSet(key string, field string, val interface{}) {
cli.HSet(key, field, val)
}
// hget
func HGet(key string, field string) string {
val, _ := cli.HGet(key, field).Result()
return val
}
// hget
func HExist(key string, field string) bool {
val, _ := cli.HExists(key, field).Result()
return val
}
// hgetall
func HGetAll(key string) map[string]string {
vals, _ := cli.HGetAll(key).Result()
return vals
}
// hdel
func HDel(key string, fields ...string) int {
return int(cli.HDel(key, fields...).Val())
}

22
base/utils/yml/yml.go Normal file
View File

@@ -0,0 +1,22 @@
package yml
import (
"errors"
"io/ioutil"
"gopkg.in/yaml.v3"
)
// 从指定路径加载yaml文件
func LoadYml(path string, out interface{}) error {
yamlFileBytes, readErr := ioutil.ReadFile(path)
if readErr != nil {
return readErr
}
// yaml解析
err := yaml.Unmarshal(yamlFileBytes, out)
if err != nil {
return errors.New("无法解析 [" + path + "]")
}
return nil
}