Skip to content
项目
群组
代码片段
帮助
当前项目
正在载入...
登录 / 注册
切换导航面板
X
xpkg
项目
项目
详情
活动
周期分析
仓库
仓库
文件
提交
分支
标签
贡献者
图表
比较
统计图
议题
0
议题
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
CI / CD
CI / CD
流水线
作业
日程
统计图
Wiki
Wiki
代码片段
代码片段
成员
成员
折叠边栏
关闭边栏
活动
图像
聊天
创建新问题
作业
提交
问题看板
Open sidebar
屠思豪
xpkg
Commits
183e061b
提交
183e061b
authored
5月 16, 2025
作者:
mooncake9527
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
update
上级
62016f9a
隐藏空白字符变更
内嵌
并排
正在显示
13 个修改的文件
包含
378 行增加
和
58 行删除
+378
-58
logging.go
gin/middleware/logging.go
+6
-6
logging_test.go
gin/middleware/logging_test.go
+1
-1
recovery.go
gin/middleware/recovery.go
+3
-2
requstid.go
gin/middleware/requstid.go
+8
-7
requstid_test.go
gin/middleware/requstid_test.go
+4
-4
response.go
gin/response/response.go
+2
-2
ctx.go
gin/xctx/ctx.go
+64
-20
httpcli.go
httpcli/httpcli.go
+18
-15
logger.go
logger/logger.go
+10
-1
xjson.go
utils/xjson/xjson.go
+10
-0
xslice.go
utils/xslice/xslice.go
+29
-0
xstring.go
utils/xstring/xstring.go
+11
-0
xtime.go
utils/xtime/xtime.go
+212
-0
没有找到文件。
gin/middleware/logging.go
浏览文件 @
183e061b
...
...
@@ -175,15 +175,15 @@ func Logging(opts ...Option) gin.HandlerFunc {
reqID
:=
""
if
o
.
requestIDFrom
==
1
{
if
v
,
isExist
:=
c
.
Get
(
ctxUtil
.
Context
Request
IDKey
);
isExist
{
if
v
,
isExist
:=
c
.
Get
(
ctxUtil
.
Context
Trace
IDKey
);
isExist
{
if
requestID
,
ok
:=
v
.
(
string
);
ok
{
reqID
=
requestID
fields
=
append
(
fields
,
zap
.
String
(
ctxUtil
.
Context
Request
IDKey
,
reqID
))
fields
=
append
(
fields
,
zap
.
String
(
ctxUtil
.
Context
Trace
IDKey
,
reqID
))
}
}
}
else
if
o
.
requestIDFrom
==
2
{
reqID
=
c
.
Request
.
Header
.
Get
(
ctxUtil
.
HeaderXRequestIDKey
)
fields
=
append
(
fields
,
zap
.
String
(
ctxUtil
.
Context
Request
IDKey
,
reqID
))
fields
=
append
(
fields
,
zap
.
String
(
ctxUtil
.
Context
Trace
IDKey
,
reqID
))
}
o
.
log
.
Info
(
"<<<<<<<<<req"
,
fields
...
)
...
...
@@ -211,7 +211,7 @@ func Logging(opts ...Option) gin.HandlerFunc {
zap
.
ByteString
(
"body"
,
getResponseBody
(
newWriter
.
body
,
o
.
maxLength
)),
}
if
reqID
!=
""
{
fields
=
append
(
fields
,
zap
.
String
(
ctxUtil
.
Context
Request
IDKey
,
reqID
))
fields
=
append
(
fields
,
zap
.
String
(
ctxUtil
.
Context
Trace
IDKey
,
reqID
))
}
o
.
log
.
Info
(
">>>>>>>>>rsp"
,
fields
...
)
}
...
...
@@ -233,7 +233,7 @@ func SimpleLog(opts ...Option) gin.HandlerFunc {
reqID
:=
""
if
o
.
requestIDFrom
==
1
{
if
v
,
isExist
:=
c
.
Get
(
ctxUtil
.
Context
Request
IDKey
);
isExist
{
if
v
,
isExist
:=
c
.
Get
(
ctxUtil
.
Context
Trace
IDKey
);
isExist
{
if
requestID
,
ok
:=
v
.
(
string
);
ok
{
reqID
=
requestID
}
...
...
@@ -254,7 +254,7 @@ func SimpleLog(opts ...Option) gin.HandlerFunc {
zap
.
Int
(
"size"
,
c
.
Writer
.
Size
()),
}
if
reqID
!=
""
{
fields
=
append
(
fields
,
zap
.
String
(
ctxUtil
.
Context
Request
IDKey
,
reqID
))
fields
=
append
(
fields
,
zap
.
String
(
ctxUtil
.
Context
Trace
IDKey
,
reqID
))
}
o
.
log
.
Info
(
"Gin msg"
,
fields
...
)
}
...
...
gin/middleware/logging_test.go
浏览文件 @
183e061b
...
...
@@ -44,7 +44,7 @@ func runLogHTTPServer() string {
//))
helloFun
:=
func
(
c
*
gin
.
Context
)
{
logger
.
Info
(
"test request id"
,
ctxUtil
.
G
CtxRequest
IDField
(
c
))
logger
.
Info
(
"test request id"
,
ctxUtil
.
G
inTrace
IDField
(
c
))
response
.
Success
(
c
,
"hello world"
)
}
...
...
gin/middleware/recovery.go
浏览文件 @
183e061b
package
middleware
import
(
ctxUtil
"gitlab.wanzhuangkj.com/tush/xpkg/gin/xctx"
"net/http"
ctxUtil
"gitlab.wanzhuangkj.com/tush/xpkg/gin/xctx"
"github.com/gin-gonic/gin"
"go.uber.org/zap"
)
...
...
@@ -16,7 +17,7 @@ func CustomRecoveryWithLogger(logger *zap.Logger) gin.HandlerFunc {
zap
.
String
(
"client_ip"
,
c
.
ClientIP
()),
zap
.
Any
(
"error"
,
err
),
zap
.
Stack
(
"stack"
),
ctxUtil
.
G
CtxRequest
IDField
(
c
),
ctxUtil
.
G
inTrace
IDField
(
c
),
)
c
.
AbortWithStatusJSON
(
http
.
StatusInternalServerError
,
gin
.
H
{
"code"
:
500
,
...
...
gin/middleware/requstid.go
浏览文件 @
183e061b
...
...
@@ -2,9 +2,10 @@ package middleware
import
(
"context"
ctxUtil
"gitlab.wanzhuangkj.com/tush/xpkg/gin/xctx"
"net/http"
ctxUtil
"gitlab.wanzhuangkj.com/tush/xpkg/gin/xctx"
"github.com/gin-gonic/gin"
"go.uber.org/zap"
)
...
...
@@ -19,7 +20,7 @@ type requestIDOptions struct {
func
defaultRequestIDOptions
()
*
requestIDOptions
{
return
&
requestIDOptions
{
contextRequestIDKey
:
ctxUtil
.
Context
Request
IDKey
,
contextRequestIDKey
:
ctxUtil
.
Context
Trace
IDKey
,
headerXRequestIDKey
:
ctxUtil
.
HeaderXRequestIDKey
,
}
}
...
...
@@ -31,8 +32,8 @@ func (o *requestIDOptions) apply(opts ...RequestIDOption) {
}
func
(
o
*
requestIDOptions
)
setRequestIDKey
()
{
if
o
.
contextRequestIDKey
!=
ctxUtil
.
Context
Request
IDKey
{
ctxUtil
.
Context
Request
IDKey
=
o
.
contextRequestIDKey
if
o
.
contextRequestIDKey
!=
ctxUtil
.
Context
Trace
IDKey
{
ctxUtil
.
Context
Trace
IDKey
=
o
.
contextRequestIDKey
}
if
o
.
headerXRequestIDKey
!=
ctxUtil
.
HeaderXRequestIDKey
{
ctxUtil
.
HeaderXRequestIDKey
=
o
.
headerXRequestIDKey
...
...
@@ -63,7 +64,7 @@ func WithHeaderRequestIDKey(key string) RequestIDOption {
type
CtxKeyString
string
// RequestIDKey request_id
var
RequestIDKey
=
CtxKeyString
(
ctxUtil
.
Context
Request
IDKey
)
var
RequestIDKey
=
CtxKeyString
(
ctxUtil
.
Context
Trace
IDKey
)
// -------------------------------------------------------------------------------------------
...
...
@@ -85,7 +86,7 @@ func RequestID(opts ...RequestIDOption) gin.HandlerFunc {
}
// Expose it for use in the application
c
.
Set
(
ctxUtil
.
Context
Request
IDKey
,
requestID
)
c
.
Set
(
ctxUtil
.
Context
Trace
IDKey
,
requestID
)
// Set X-Request-Id header
c
.
Writer
.
Header
()
.
Set
(
ctxUtil
.
HeaderXRequestIDKey
,
requestID
)
...
...
@@ -111,7 +112,7 @@ var RequestHeaderKey = "request_header_key"
// WrapCtx wrap context, put the Keys and Header of gin.Context into context
func
WrapCtx
(
c
*
gin
.
Context
)
context
.
Context
{
ctx
:=
context
.
WithValue
(
c
.
Request
.
Context
(),
ctxUtil
.
Context
RequestIDKey
,
c
.
GetString
(
ctxUtil
.
ContextRequest
IDKey
))
//nolint
ctx
:=
context
.
WithValue
(
c
.
Request
.
Context
(),
ctxUtil
.
Context
TraceIDKey
,
c
.
GetString
(
ctxUtil
.
ContextTrace
IDKey
))
//nolint
for
k
,
v
:=
range
c
.
Keys
{
ctx
=
context
.
WithValue
(
ctx
,
k
,
v
)
//nolint
}
...
...
gin/middleware/requstid_test.go
浏览文件 @
183e061b
...
...
@@ -58,7 +58,7 @@ func TestFieldRequestIDFromContext(t *testing.T) {
c
.
Set
(
"foo"
,
"bar"
)
ctx
:=
WrapCtx
(
c
)
t
.
Log
(
ctx
.
Value
(
ctxUtil
.
Context
Request
IDKey
))
t
.
Log
(
ctx
.
Value
(
ctxUtil
.
Context
Trace
IDKey
))
t
.
Log
(
GetFromCtx
(
ctx
,
"foo"
))
t
.
Log
(
ctxUtil
.
CtxTraceIDField
(
ctx
))
t
.
Log
(
GetFromCtx
(
ctx
,
"not-exist"
))
...
...
@@ -71,7 +71,7 @@ func TestFieldRequestIDFromContext(t *testing.T) {
cctx
:=
c
c2
,
ctx2
:=
AdaptCtx
(
cctx
)
t
.
Log
(
ctxUtil
.
CtxRequestID
(
c2
))
t
.
Log
(
ctx2
.
Value
(
ctxUtil
.
Context
Request
IDKey
))
t
.
Log
(
ctx2
.
Value
(
ctxUtil
.
Context
Trace
IDKey
))
})
_
,
err
:=
http
.
Get
(
requestAddr
+
"/ping"
)
...
...
@@ -106,8 +106,8 @@ func TestRequestIDKeyOptions(t *testing.T) {
o
.
apply
(
opts
...
)
o
.
setRequestIDKey
()
t
.
Log
(
ctxUtil
.
Context
Request
IDKey
,
ctxUtil
.
HeaderXRequestIDKey
)
t
.
Log
(
ctxUtil
.
Context
Trace
IDKey
,
ctxUtil
.
HeaderXRequestIDKey
)
assert
.
Equal
(
t
,
"my_req_id"
,
ctxUtil
.
Context
Request
IDKey
)
assert
.
Equal
(
t
,
"my_req_id"
,
ctxUtil
.
Context
Trace
IDKey
)
assert
.
Equal
(
t
,
"My-X-Req-Id"
,
ctxUtil
.
HeaderXRequestIDKey
)
}
gin/response/response.go
浏览文件 @
183e061b
...
...
@@ -178,10 +178,10 @@ func Error(c *gin.Context, err error) {
msg
=
err
.
Error
()
if
xerr
,
ok
:=
err
.
(
*
xerror
.
Error
);
ok
{
if
!
errcode
.
IsSysDefinedError
(
xerr
.
Code
())
{
logger
.
Error
(
"api failed."
,
logger
.
Err
(
err
),
ctxUtil
.
G
CtxRequest
IDField
(
c
))
logger
.
Error
(
"api failed."
,
logger
.
Err
(
err
),
ctxUtil
.
G
inTrace
IDField
(
c
))
}
}
else
{
logger
.
Error
(
"api failed."
,
logger
.
Err
(
err
),
ctxUtil
.
G
CtxRequest
IDField
(
c
))
logger
.
Error
(
"api failed."
,
logger
.
Err
(
err
),
ctxUtil
.
G
inTrace
IDField
(
c
))
}
}
// 使用respJSONWith200函数返回错误信息。
...
...
gin/xctx/ctx.go
浏览文件 @
183e061b
...
...
@@ -2,6 +2,7 @@ package xctx
import
(
"context"
"errors"
xsf
"gitlab.wanzhuangkj.com/tush/xpkg/utils/xsf"
...
...
@@ -13,26 +14,31 @@ import (
var
(
GinContextKey
=
"gin_context"
// ContextRequestIDKey request id for context
ContextRequestIDKey
=
"traceID"
KeyConfigFile
=
"config_file"
KeyConfigCenter
=
"config_center"
ContextTraceIDKey
=
"traceID"
KeyConfigFile
=
"config_file"
KeyConfigCenter
=
"config_center"
// HeaderXRequestIDKey header request id key
HeaderXRequestIDKey
=
"X-Request-ID"
KeyTid
=
"tid"
KeyIP
=
"ip"
KeyUID
=
"uid"
KeyShopID
=
"shopID"
KeyUName
=
"uname"
KeyToken
=
"token"
KeyUser
=
"user"
KeyTid
=
"tid"
KeyIP
=
"IP"
KeyUID
=
"userId"
KeyUType
=
"userType"
KeyCompanyID
=
"companyId"
KeyShopID
=
"shopID"
KeyUName
=
"uname"
KeyToken
=
"token"
KeyUser
=
"user"
)
// GCtxRequestID get request id from gin.Context
func
GCtxRequestID
(
c
*
gin
.
Context
)
string
{
if
v
,
isExist
:=
c
.
Get
(
ContextRequestIDKey
);
isExist
{
var
(
ErrorGinContextNotFound
=
errors
.
New
(
"gin context not found"
)
)
// GetGinCtxTraceID get request id from gin.Context
func
GetGinCtxTraceID
(
c
*
gin
.
Context
)
string
{
if
v
,
isExist
:=
c
.
Get
(
ContextTraceIDKey
);
isExist
{
if
requestID
,
ok
:=
v
.
(
string
);
ok
{
return
requestID
}
...
...
@@ -40,14 +46,14 @@ func GCtxRequestID(c *gin.Context) string {
return
""
}
// G
CtxRequest
IDField get request id field from gin.Context
func
G
CtxRequest
IDField
(
c
*
gin
.
Context
)
zap
.
Field
{
return
zap
.
String
(
Context
RequestIDKey
,
GCtxRequest
ID
(
c
))
// G
inTrace
IDField get request id field from gin.Context
func
G
inTrace
IDField
(
c
*
gin
.
Context
)
zap
.
Field
{
return
zap
.
String
(
Context
TraceIDKey
,
GetGinCtxTrace
ID
(
c
))
}
// CtxRequestID get request id from context.Context
func
CtxRequestID
(
c
context
.
Context
)
string
{
v
:=
c
.
Value
(
Context
Request
IDKey
)
v
:=
c
.
Value
(
Context
Trace
IDKey
)
if
str
,
ok
:=
v
.
(
string
);
ok
{
return
str
}
...
...
@@ -72,7 +78,7 @@ func CtxGetGinCtx(c context.Context) *gin.Context {
// CtxTraceIDField get request id field from context.Context
func
CtxTraceIDField
(
c
context
.
Context
)
zap
.
Field
{
return
zap
.
String
(
Context
Request
IDKey
,
CtxRequestID
(
c
))
return
zap
.
String
(
Context
Trace
IDKey
,
CtxRequestID
(
c
))
}
func
GetGinUserID
(
c
*
gin
.
Context
)
xsf
.
ID
{
...
...
@@ -162,10 +168,48 @@ func GetIP(ctx context.Context) string {
}
func
WrapCtx
(
c
*
gin
.
Context
)
context
.
Context
{
ctx
:=
context
.
WithValue
(
c
.
Request
.
Context
(),
Context
RequestIDKey
,
c
.
GetString
(
ContextRequest
IDKey
))
//nolint
ctx
:=
context
.
WithValue
(
c
.
Request
.
Context
(),
Context
TraceIDKey
,
c
.
GetString
(
ContextTrace
IDKey
))
//nolint
for
k
,
v
:=
range
c
.
Keys
{
ctx
=
context
.
WithValue
(
ctx
,
k
,
v
)
//nolint
}
ctx
=
context
.
WithValue
(
ctx
,
GinContextKey
,
c
)
//nolint
return
ctx
}
func
ToGinCtx
(
ctx
context
.
Context
)
(
*
gin
.
Context
,
error
)
{
if
c
,
ok
:=
ctx
.
Value
(
GinContextKey
)
.
(
*
gin
.
Context
);
ok
{
return
c
,
nil
}
return
nil
,
ErrorGinContextNotFound
}
func
GetCtxUID
(
c
context
.
Context
)
uint
{
uid
:=
c
.
Value
(
KeyUID
)
if
uid
!=
nil
{
if
v
,
ok
:=
uid
.
(
string
);
ok
{
return
cast
.
ToUint
(
v
)
}
}
return
0
}
func
GetCtxUType
(
c
context
.
Context
)
int
{
val
:=
c
.
Value
(
KeyUType
)
if
val
!=
nil
{
if
v
,
ok
:=
val
.
(
string
);
ok
{
return
cast
.
ToInt
(
v
)
}
}
return
0
}
func
GetCtxCompanyID
(
c
context
.
Context
)
uint
{
val
:=
c
.
Value
(
KeyCompanyID
)
if
val
!=
nil
{
v
,
ok
:=
val
.
(
string
)
if
ok
{
return
cast
.
ToUint
(
v
)
}
}
return
0
}
httpcli/httpcli.go
浏览文件 @
183e061b
...
...
@@ -13,9 +13,9 @@ import (
"strings"
"time"
ctxUtil
"gitlab.wanzhuangkj.com/tush/xpkg/gin/xctx"
"gitlab.wanzhuangkj.com/tush/xpkg/logger"
"gitlab.wanzhuangkj.com/tush/xpkg/gin/xctx"
"gitlab.wanzhuangkj.com/tush/xpkg/utils/xjson"
"gitlab.wanzhuangkj.com/tush/xpkg/logger"
"gitlab.wanzhuangkj.com/tush/xpkg/xerrors/xerror"
"github.com/duke-git/lancet/v2/retry"
...
...
@@ -250,6 +250,7 @@ func (req *Request) push(ctx context.Context) (*Response, error) {
buf
=
bytes
.
NewBufferString
(
req
.
body
)
}
logger
.
Info
(
"httpcli req"
,
logger
.
String
(
"body"
,
buf
.
String
()),
xctx
.
CtxTraceIDField
(
ctx
))
return
req
.
send
(
ctx
,
buf
,
buf
)
}
...
...
@@ -285,6 +286,7 @@ func getRequestBody(buf *bytes.Buffer, maxLen int) []byte {
}
func
(
req
*
Request
)
send
(
ctx
context
.
Context
,
body
io
.
Reader
,
buf
*
bytes
.
Buffer
)
(
*
Response
,
error
)
{
logger
.
Info
(
"httpcli req"
,
logger
.
String
(
"url"
,
req
.
url
),
xctx
.
CtxTraceIDField
(
ctx
))
req
.
request
,
req
.
err
=
http
.
NewRequest
(
req
.
method
,
req
.
url
,
body
)
if
req
.
err
!=
nil
{
return
nil
,
req
.
err
...
...
@@ -300,7 +302,7 @@ func (req *Request) send(ctx context.Context, body io.Reader, buf *bytes.Buffer)
}
}
req
.
request
.
Header
.
Add
(
ctxUtil
.
HeaderXRequestIDKey
,
ctxUtil
.
CtxRequestID
(
ctx
))
req
.
request
.
Header
.
Add
(
xctx
.
HeaderXRequestIDKey
,
xctx
.
CtxRequestID
(
ctx
))
if
req
.
timeout
<
1
{
req
.
timeout
=
defaultTimeout
...
...
@@ -313,34 +315,28 @@ func (req *Request) send(ctx context.Context, body io.Reader, buf *bytes.Buffer)
ctx
,
cancel
:=
context
.
WithTimeout
(
ctx
,
time
.
Second
*
20
)
defer
cancel
()
err
:=
retry
.
Retry
(
func
()
error
{
logger
.
Info
(
"http call req"
,
logger
.
String
(
"req"
,
req
.
ReqString
(
ctx
)),
ctxUtil
.
CtxTraceIDField
(
ctx
))
var
response
*
http
.
Response
response
,
resp
.
err
=
client
.
Do
(
req
.
request
)
if
resp
.
err
!=
nil
{
return
xerror
.
New
(
resp
.
err
.
Error
())
response
,
err
:=
client
.
Do
(
req
.
request
)
if
err
!=
nil
{
logger
.
Info
(
"httpcli fail"
,
logger
.
Any
(
"err"
,
err
),
xctx
.
CtxTraceIDField
(
ctx
))
return
xerror
.
New
(
err
.
Error
())
}
resp
.
Status
=
response
.
Status
resp
.
StatusCode
=
response
.
StatusCode
for
k
,
v
:=
range
response
.
Header
{
resp
.
Header
[
k
]
=
v
}
logger
.
Info
(
"http call rsp"
,
logger
.
Any
(
"status"
,
resp
.
Status
),
logger
.
Any
(
"statusCode"
,
resp
.
StatusCode
),
logger
.
Any
(
"header"
,
response
.
Header
),
ctxUtil
.
CtxTraceIDField
(
ctx
))
if
resp
.
err
!=
nil
{
logger
.
Info
(
"http call"
,
logger
.
Any
(
"err"
,
resp
.
err
),
ctxUtil
.
CtxTraceIDField
(
ctx
))
return
resp
.
err
}
defer
response
.
Body
.
Close
()
body
,
err
:=
io
.
ReadAll
(
response
.
Body
)
if
err
!=
nil
{
return
xerror
.
New
(
err
.
Error
())
}
logger
.
Info
(
"http
call rsp"
,
logger
.
Any
(
"rsp body"
,
bytes
.
NewBuffer
(
body
)
.
String
()),
ctxUtil
.
CtxTraceIDField
(
ctx
))
logger
.
Info
(
"http
cli rsp"
,
logger
.
Any
(
"body"
,
bytes
.
NewBuffer
(
body
)
.
String
()),
xctx
.
CtxTraceIDField
(
ctx
))
resp
.
Body
=
io
.
NopCloser
(
bytes
.
NewBuffer
(
body
))
return
nil
},
retry
.
RetryWithLinearBackoff
(
time
.
Second
),
retry
.
Context
(
ctx
))
if
err
!=
nil
{
err
=
xerror
.
New
(
err
.
Error
())
logger
.
Error
(
"http
fail"
,
logger
.
Any
(
"err"
,
err
),
ctxUtil
.
CtxTraceIDField
(
ctx
))
logger
.
Error
(
"http
cli fail"
,
logger
.
Any
(
"err"
,
err
),
xctx
.
CtxTraceIDField
(
ctx
))
}
req
.
response
=
resp
...
...
@@ -590,5 +586,12 @@ type StdResult struct {
Data
interface
{}
`json:"data,omitempty"`
}
// StdResult standard return data
type
StdResult2
struct
{
Code
int
`json:"code"`
Msg
string
`json:"message"`
Data
interface
{}
`json:"data,omitempty"`
}
// KV string:interface{}
type
KV
=
map
[
string
]
interface
{}
logger/logger.go
浏览文件 @
183e061b
...
...
@@ -14,9 +14,9 @@ import (
"strings"
"time"
"gopkg.in/natefinch/lumberjack.v2"
"go.uber.org/zap"
"go.uber.org/zap/zapcore"
"gopkg.in/natefinch/lumberjack.v2"
)
const
(
...
...
@@ -213,3 +213,12 @@ func (w *ZapWriter) Write(p []byte) (n int, err error) {
}
return
len
(
p
),
nil
}
type
ConfLog
struct
{
Level
string
Path
string
Max_size
int
Max_backups
int
Max_days
int
Compress
bool
}
utils/xjson/xjson.go
浏览文件 @
183e061b
...
...
@@ -2,6 +2,8 @@ package xjson
import
(
"encoding/json"
"gitlab.wanzhuangkj.com/tush/xpkg/xerrors/xerror"
)
func
ToJsonString
(
v
any
)
string
{
...
...
@@ -15,3 +17,11 @@ func ToJsonBytes(v any) []byte {
bytes
,
_
:=
json
.
Marshal
(
v
)
return
bytes
}
func
Unmarshal
(
data
[]
byte
,
v
any
)
error
{
err
:=
json
.
Unmarshal
(
data
,
v
)
if
err
!=
nil
{
return
xerror
.
New
(
err
.
Error
())
}
return
nil
}
utils/xslice/xslice.go
浏览文件 @
183e061b
...
...
@@ -247,3 +247,32 @@ func CompareSlice[T IIDTable, BizSlice ~[]*T](ids []xsf.ID, bizSlice BizSlice, e
}
return
nil
}
func
ArrayUnique
[
T
comparable
](
array
[]
T
)
[]
T
{
mp
:=
make
(
map
[
T
]
struct
{})
idx
:=
0
for
_
,
value
:=
range
array
{
if
_
,
ok
:=
mp
[
value
];
ok
{
continue
}
array
[
idx
]
=
value
idx
=
idx
+
1
mp
[
value
]
=
struct
{}{}
}
return
array
[
:
idx
]
}
type
IId
interface
{
GetID
()
uint
}
func
GetIds
[
T
IId
](
rs
[]
*
T
)
[]
uint
{
if
len
(
rs
)
==
0
{
return
nil
}
set
:=
xset
.
NewSet
[
uint
]()
for
_
,
r
:=
range
rs
{
set
.
Add
((
*
r
)
.
GetID
())
}
return
set
.
ToList
()
}
utils/xstring/xstring.go
浏览文件 @
183e061b
...
...
@@ -4,6 +4,17 @@ import (
"strings"
)
func
CamelToUnderscore
(
s
string
)
string
{
var
builder
strings
.
Builder
for
i
,
c
:=
range
s
{
if
i
>
0
&&
c
>=
'A'
&&
c
<=
'Z'
{
builder
.
WriteByte
(
'_'
)
}
builder
.
WriteRune
(
c
)
}
return
strings
.
ToLower
(
builder
.
String
())
}
func
UnderscoreToCamel
(
s
string
,
isUpperFirst
bool
)
string
{
var
builder
strings
.
Builder
words
:=
strings
.
Split
(
s
,
"_"
)
...
...
utils/xtime/xtime.go
浏览文件 @
183e061b
...
...
@@ -163,3 +163,215 @@ func ParseExtendedDuration(s string) (time.Duration, error) {
return
total
,
nil
}
const
(
Layout_YYYY
=
"2006"
Layout_YYYYMM
=
"2006-01"
Layout_YYYYMMDD
=
"2006-01-02"
Layout_YYYYMMDD2
=
"2006/01/02"
Layout_YYYYMMDD3
=
"20060102"
Layout_YYYYMMDDHHmmSS
=
"2006-01-02 15:04:05"
)
var
(
LocBeiJing
,
_
=
time
.
LoadLocation
(
"Asia/Shanghai"
)
)
func
(
x
DateTime
)
Format
(
layout
string
)
string
{
return
x
.
Time
()
.
Format
(
layout
)
}
func
(
x
DateTime
)
FormatYYYYMMDDHHmmSS
()
string
{
return
x
.
Time
()
.
Format
(
Layout_YYYYMMDDHHmmSS
)
}
// const TimeFormat = "2006-01-02 15:04:05"
// // Value insert timestamp into mysql need this function.
// func (t DateTime) Value() (driver.Value, error) {
// var zeroTime time.Time
// if time.Time(t).UnixNano() == zeroTime.UnixNano() {
// return nil, nil
// }
// return time.Time(t), nil
// }
// // Scan value of time.Time
// func (t *DateTime) Scan(v interface{}) error {
// value, ok := v.(time.Time)
// if ok {
// *t = DateTime(value)
// return nil
// }
// return fmt.Errorf("can not convert %v to timestamp", v)
// }
func
(
x
DateTime
)
Date
()
DateTime
{
y
,
m
,
d
:=
x
.
Time
()
.
Date
()
trimmedTime
:=
time
.
Date
(
y
,
m
,
d
,
0
,
0
,
0
,
0
,
x
.
Time
()
.
Location
())
return
NewDateTime
(
trimmedTime
)
}
func
(
x
DateTime
)
WeekStart
()
DateTime
{
return
x
.
WeekEnd
()
.
AddDate
(
0
,
0
,
-
6
)
}
func
(
x
DateTime
)
WeekEnd
()
DateTime
{
weekday
:=
int
(
x
.
Time
()
.
Weekday
())
if
weekday
==
0
{
weekday
=
7
}
return
x
.
AddDate
(
0
,
0
,
+
7
-
weekday
)
}
func
(
t0
DateTime
)
MonthStart
()
DateTime
{
year
,
month
,
_
:=
t0
.
Time
()
.
Date
()
t1
:=
time
.
Date
(
year
,
month
,
1
,
0
,
0
,
0
,
0
,
t0
.
Time
()
.
Location
())
return
DateTime
(
t1
)
}
func
(
t0
DateTime
)
MonthEnd
()
DateTime
{
year
,
month
,
_
:=
t0
.
Time
()
.
Date
()
t1
:=
time
.
Date
(
year
,
month
+
1
,
0
,
0
,
0
,
0
,
0
,
t0
.
Time
()
.
Location
())
return
DateTime
(
t1
)
}
func
(
t
DateTime
)
AddDate
(
y
,
m
,
d
int
)
DateTime
{
return
DateTime
(
t
.
Time
()
.
AddDate
(
y
,
m
,
d
))
}
// WeekDay 1-7 周一到周日
func
(
x
DateTime
)
WeekDay
()
int
{
return
((
int
(
x
.
Time
()
.
Weekday
())
+
6
)
%
7
)
+
1
}
// 1-31 1号到31号
func
(
x
DateTime
)
Day
()
int
{
return
int
(
x
.
Time
()
.
Day
())
}
// 1-12 1月到12月
func
(
x
DateTime
)
Month
()
int
{
return
int
(
x
.
Time
()
.
Month
())
}
// 1970年到现在第几年
func
(
x
DateTime
)
Year
()
int
{
return
int
(
x
.
Time
()
.
Year
())
}
func
(
x
DateTime
)
After
(
t1
DateTime
)
bool
{
return
x
.
Time
()
.
After
(
t1
.
Time
())
}
// 转为北京时间
func
(
x
DateTime
)
LocalBeiJing
()
DateTime
{
return
DateTime
(
x
.
Time
()
.
In
(
LocBeiJing
))
}
func
(
x
DateTime
)
Local
()
DateTime
{
return
DateTime
(
x
.
Time
()
.
In
(
time
.
Local
))
}
func
(
x
DateTime
)
Quarter
()
int
{
return
(
int
(
x
.
Time
()
.
Month
())
-
1
)
/
3
+
1
}
func
ParseYYYYMMDD
(
value
string
)
DateTime
{
t
,
err
:=
time
.
Parse
(
Layout_YYYYMMDD
,
value
)
if
err
!=
nil
{
return
DateTime
{}
}
return
DateTime
(
t
)
}
func
ParseYYYYMMDDHHmmSS
(
value
string
)
DateTime
{
t
,
err
:=
time
.
Parse
(
Layout_YYYYMMDDHHmmSS
,
value
)
if
err
!=
nil
{
return
DateTime
{}
}
return
DateTime
(
t
)
}
func
ParseTime
(
layout
,
value
string
)
(
DateTime
,
error
)
{
t
,
err
:=
time
.
Parse
(
layout
,
value
)
if
err
!=
nil
{
return
DateTime
{},
err
}
return
DateTime
(
t
),
nil
}
func
IsSameDay
(
t1
,
t2
DateTime
)
bool
{
t1Local
:=
t1
.
Local
()
t2Local
:=
t2
.
Local
()
return
t1Local
.
Year
()
==
t2Local
.
Year
()
&&
t1Local
.
Month
()
==
t2Local
.
Month
()
&&
t1Local
.
Day
()
==
t2Local
.
Day
()
}
// 是否同一周
func
IsSameWeek
(
t0
,
t1
DateTime
)
bool
{
y1
,
w1
:=
t0
.
Time
()
.
Local
()
.
ISOWeek
()
y2
,
w2
:=
t1
.
Time
()
.
Local
()
.
ISOWeek
()
return
y1
==
y2
&&
w1
==
w2
}
func
NotSameWeek
(
t0
,
t1
DateTime
)
bool
{
return
!
IsSameWeek
(
t0
,
t1
)
}
// 是否同一个月
func
IsSameMonth
(
t0
,
t1
DateTime
)
bool
{
return
t0
.
Month
()
==
t1
.
Month
()
}
func
NotSameMonth
(
t0
,
t1
DateTime
)
bool
{
return
!
IsSameMonth
(
t0
,
t1
)
}
// 是否同一季度
func
IsSameQuarter
(
t0
,
t1
DateTime
)
bool
{
return
t0
.
Quarter
()
==
t1
.
Quarter
()
}
func
NotSameSeason
(
t0
,
t1
DateTime
)
bool
{
return
!
IsSameQuarter
(
t0
,
t1
)
}
// 是否同一年
func
IsSameYear
(
t0
,
t1
DateTime
)
bool
{
return
t0
.
Time
()
.
Year
()
==
t1
.
Time
()
.
Year
()
}
func
NotSameYear
(
t0
,
t1
DateTime
)
bool
{
return
!
IsSameYear
(
t0
,
t1
)
}
func
DayBeforeYesterday
()
DateTime
{
return
DateTime
(
time
.
Now
()
.
AddDate
(
0
,
0
,
-
2
))
}
func
Yesterday
()
DateTime
{
return
DateTime
(
time
.
Now
()
.
AddDate
(
0
,
0
,
-
1
))
}
func
Today
()
DateTime
{
return
DateTime
(
time
.
Now
())
}
func
(
t0
DateTime
)
PreviousQuarter
(
n
int
)
DateTime
{
month
:=
t0
.
Month
()
quarterStartMonth
:=
time
.
Month
((
int
(
month
)
-
1
)
/
3
*
3
+
1
)
currentQuarterStart
:=
time
.
Date
(
t0
.
Year
(),
quarterStartMonth
,
1
,
0
,
0
,
0
,
0
,
t0
.
Time
()
.
Location
(),
)
return
DateTime
(
currentQuarterStart
.
AddDate
(
0
,
-
3
*
n
,
0
))
}
func
(
t0
DateTime
)
FormatYYYYQT
()
string
{
month
:=
t0
.
Month
()
quarter
:=
(
int
(
month
)
-
1
)
/
3
+
1
return
fmt
.
Sprintf
(
"%s_%d"
,
t0
.
Format
(
Layout_YYYY
),
quarter
)
}
func
DaysBetween
(
t0
,
t1
DateTime
)
int
{
t2
:=
time
.
Date
(
t0
.
Year
(),
t0
.
Time
()
.
Month
(),
t0
.
Day
(),
0
,
0
,
0
,
0
,
t0
.
Time
()
.
Location
())
t3
:=
time
.
Date
(
t1
.
Year
(),
t1
.
Time
()
.
Month
(),
t1
.
Day
(),
0
,
0
,
0
,
0
,
t1
.
Time
()
.
Location
())
diff
:=
t2
.
Sub
(
t3
)
days
:=
int
(
diff
.
Hours
()
/
24
)
return
days
}
编写
预览
Markdown
格式
0%
重试
或
添加新文件
添加附件
取消
您添加了
0
人
到此讨论。请谨慎行事。
请先完成此评论的编辑!
取消
请
注册
或者
登录
后发表评论