mirror of
https://gitee.com/xiangheng/x_admin.git
synced 2025-12-24 08:12:55 +08:00
226 lines
5.9 KiB
Go
226 lines
5.9 KiB
Go
package response
|
|
|
|
import (
|
|
"errors"
|
|
"net/http"
|
|
"strconv"
|
|
"x_admin/core"
|
|
|
|
"github.com/gin-gonic/gin"
|
|
"github.com/go-sql-driver/mysql"
|
|
"go.uber.org/zap"
|
|
"gorm.io/gorm"
|
|
)
|
|
|
|
// RespType 响应类型
|
|
type RespType struct {
|
|
code int
|
|
message string
|
|
data interface{}
|
|
}
|
|
|
|
// Response 响应格式结构
|
|
type Response struct {
|
|
Code int `json:"code"`
|
|
Message string `json:"message"`
|
|
Data interface{} `json:"data"`
|
|
}
|
|
|
|
var (
|
|
// code 200成功
|
|
Success = RespType{code: 200, message: "成功"}
|
|
// code 300失败
|
|
Failed = RespType{code: 300, message: "失败"}
|
|
// code 310参数校验错误
|
|
ParamsValidError = RespType{code: 310, message: "参数校验错误"}
|
|
// code 311参数类型错误
|
|
ParamsTypeError = RespType{code: 311, message: "参数类型错误"}
|
|
|
|
RequestMethodError = RespType{code: 312, message: "请求方法错误"}
|
|
AssertArgumentError = RespType{code: 313, message: "断言参数错误"}
|
|
// code 330登录账号或密码错误
|
|
LoginAccountError = RespType{code: 330, message: "登录账号或密码错误"}
|
|
// code 331登录账号已被禁用了
|
|
LoginDisableError = RespType{code: 331, message: "登录账号已被禁用了"}
|
|
// code 332 token参数为空
|
|
TokenEmpty = RespType{code: 332, message: "token参数为空"}
|
|
// code 333 登录失效
|
|
TokenInvalid = RespType{code: 333, message: "登录失效"}
|
|
// 无相关权限
|
|
NoPermission = RespType{code: 403, message: "无相关权限"}
|
|
Request404Error = RespType{code: 404, message: "请求接口不存在"}
|
|
Request405Error = RespType{code: 405, message: "请求方法不允许"}
|
|
// code 500系统错误
|
|
SystemError = RespType{code: 500, message: "系统错误"}
|
|
)
|
|
|
|
// Error 实现error方法
|
|
func (rt RespType) Error() string {
|
|
return strconv.Itoa(rt.code) + ":" + rt.message
|
|
}
|
|
|
|
// SetMessage 以响应类型生成信息
|
|
func (rt RespType) SetMessage(message string) RespType {
|
|
rt.message = message
|
|
return rt
|
|
}
|
|
|
|
// SetData 以响应类型生成数据
|
|
func (rt RespType) SetData(data interface{}) RespType {
|
|
rt.data = data
|
|
return rt
|
|
}
|
|
|
|
// Code 获取code
|
|
func (rt RespType) Code() int {
|
|
return rt.code
|
|
}
|
|
|
|
// Msg 获取msg
|
|
func (rt RespType) Msg() string {
|
|
return rt.message
|
|
}
|
|
|
|
// Data 获取data
|
|
func (rt RespType) Data() interface{} {
|
|
return rt.data
|
|
}
|
|
|
|
// Result 统一响应
|
|
func Result(c *gin.Context, resp RespType, data interface{}) {
|
|
if data == nil {
|
|
data = resp.data
|
|
}
|
|
if resp != Success {
|
|
c.Error(resp)
|
|
}
|
|
c.JSON(http.StatusOK, Response{
|
|
Code: resp.code,
|
|
Message: resp.message,
|
|
Data: data,
|
|
})
|
|
}
|
|
|
|
// Ok 正常响应
|
|
func Ok(c *gin.Context) {
|
|
Result(c, Success, nil)
|
|
}
|
|
|
|
// // OkWithMsg 正常响应附带msg
|
|
// func OkWithMsg(c *gin.Context, message string) {
|
|
// resp := Success
|
|
// resp.message = message
|
|
// Result(c, resp, nil)
|
|
// }
|
|
|
|
// OkWithData 正常响应附带data
|
|
func OkWithData(c *gin.Context, data interface{}) {
|
|
Result(c, Success, data)
|
|
}
|
|
|
|
// respLogger 打印日志
|
|
func respLogger(resp RespType, template string, args ...interface{}) {
|
|
loggerFunc := core.Logger.WithOptions(zap.AddCallerSkip(2)).Warnf
|
|
if resp.code >= 500 {
|
|
loggerFunc = core.Logger.WithOptions(zap.AddCallerSkip(1)).Errorf
|
|
}
|
|
loggerFunc(template, args...)
|
|
}
|
|
|
|
// Fail 错误响应
|
|
func Fail(c *gin.Context, resp RespType) {
|
|
respLogger(resp, "Request Fail: url=[%s], resp=[%+v]", c.Request.URL.Path, resp)
|
|
Result(c, resp, nil)
|
|
}
|
|
|
|
// FailWithMsg 错误响应附带msg
|
|
func FailWithMsg(c *gin.Context, resp RespType, message string) {
|
|
resp.message = message
|
|
respLogger(resp, "Request FailWithMsg: url=[%s], resp=[%+v]", c.Request.URL.Path, resp)
|
|
Result(c, resp, nil)
|
|
}
|
|
|
|
// FailWithData 错误响应附带data
|
|
func FailWithData(c *gin.Context, resp RespType, data interface{}) {
|
|
respLogger(resp, "Request FailWithData: url=[%s], resp=[%+v], data=[%+v]", c.Request.URL.Path, resp, data)
|
|
Result(c, resp, data)
|
|
}
|
|
|
|
// IsFailWithResp 判断是否出现错误,并追加错误返回信息
|
|
func IsFailWithResp(c *gin.Context, err error) bool {
|
|
if err == nil {
|
|
return false
|
|
}
|
|
switch v := err.(type) {
|
|
// 自定义类型
|
|
case RespType:
|
|
data := v.Data()
|
|
if data == nil {
|
|
data = nil
|
|
}
|
|
FailWithData(c, v, data)
|
|
// 其他类型
|
|
default:
|
|
Fail(c, SystemError.SetMessage(err.Error()))
|
|
}
|
|
return true
|
|
}
|
|
|
|
// CheckAndResp 判断是否出现错误,并返回对应响应
|
|
func CheckAndResp(c *gin.Context, err error) {
|
|
if IsFailWithResp(c, err) {
|
|
return
|
|
}
|
|
Ok(c)
|
|
}
|
|
|
|
// CheckAndRespWithData 判断是否出现错误,并返回对应响应(带data数据)
|
|
func CheckAndRespWithData(c *gin.Context, data interface{}, err error) {
|
|
if IsFailWithResp(c, err) {
|
|
return
|
|
}
|
|
OkWithData(c, data)
|
|
}
|
|
|
|
// CheckErr 校验未知错误并抛出
|
|
func CheckErr(err error, template string, args ...interface{}) (e error) {
|
|
prefix := ": "
|
|
if len(args) > 0 {
|
|
prefix = " ,"
|
|
}
|
|
args = append(args, err)
|
|
if err != nil {
|
|
core.Logger.WithOptions(zap.AddCallerSkip(1)).Errorf(template+prefix+"err=[%+v]", args...)
|
|
return SystemError.SetMessage(template)
|
|
}
|
|
return
|
|
}
|
|
|
|
// 插入操作违反唯一约束时,会发生此错误:
|
|
func CheckMysqlErr(err error) (e error) {
|
|
if mysqlErr, ok := err.(*mysql.MySQLError); ok {
|
|
switch mysqlErr.Number {
|
|
case 404:
|
|
core.Logger.WithOptions(zap.AddCallerSkip(1)).Errorf("record not found: err=[%+v]", err)
|
|
return SystemError.SetMessage("数据不存在")
|
|
case 1062: // MySQL中表示重复条目的代码
|
|
core.Logger.WithOptions(zap.AddCallerSkip(1)).Infof("数据已存在: err=[%+v]", err)
|
|
return SystemError.SetMessage("数据已存在")
|
|
default:
|
|
// 处理其他错误
|
|
core.Logger.WithOptions(zap.AddCallerSkip(1)).Errorf("未知错误: err=[%+v]", err)
|
|
return err
|
|
}
|
|
}
|
|
return
|
|
}
|
|
|
|
// CheckErrDBNotRecord 校验数据库记录不存在的错误
|
|
func CheckErrDBNotRecord(err error, message string) (e error) {
|
|
if err != nil && errors.Is(err, gorm.ErrRecordNotFound) {
|
|
core.Logger.WithOptions(zap.AddCallerSkip(1)).Infof("记录不存在: err=[%+v]", err)
|
|
return SystemError.SetMessage(message)
|
|
}
|
|
return
|
|
}
|