mirror of
https://github.com/tiennm99/zfoo.git
synced 2026-10-16 14:14:19 +00:00
feat[golang]: 添加一些go的常用工具类
This commit is contained in:
1 parent
180906e577
commit
71cd7ccdbe
18 files changed
+1628
-4
No files matched your search
@@ -9,9 +9,11 @@
|
|||||||
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
* See the License for the specific language governing permissions and limitations under the License.
|
* See the License for the specific language governing permissions and limitations under the License.
|
||||||
*/
|
*/
|
||||||
package sliceutil
|
package arrayutil
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"math"
|
||||||
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -218,3 +220,158 @@ func DifferenceInterface(slice1, slice2 []interface{}) []interface{} {
|
|||||||
}
|
}
|
||||||
return n
|
return n
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// 合并数组
|
||||||
|
func MergeArray(dest []interface{}, src []interface{}) (result []interface{}) {
|
||||||
|
result = make([]interface{}, len(dest)+len(src))
|
||||||
|
copy(result, dest)
|
||||||
|
copy(result[len(dest):], src)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 删除数组
|
||||||
|
func DeleteArray(src []interface{}, index int) (result []interface{}) {
|
||||||
|
result = append(src[:index], src[(index+1):]...)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// []string => []int
|
||||||
|
func ArrayStr2Int(data []string) []int {
|
||||||
|
var (
|
||||||
|
arr = make([]int, 0, len(data))
|
||||||
|
)
|
||||||
|
if len(data) == 0 {
|
||||||
|
return arr
|
||||||
|
}
|
||||||
|
for i, _ := range data {
|
||||||
|
var num, _ = strconv.Atoi(data[i])
|
||||||
|
arr = append(arr, num)
|
||||||
|
}
|
||||||
|
return arr
|
||||||
|
}
|
||||||
|
|
||||||
|
// []int => []string
|
||||||
|
func ArrayInt2Str(data []int) []string {
|
||||||
|
var (
|
||||||
|
arr = make([]string, 0, len(data))
|
||||||
|
)
|
||||||
|
if len(data) == 0 {
|
||||||
|
return arr
|
||||||
|
}
|
||||||
|
for i, _ := range data {
|
||||||
|
arr = append(arr, strconv.Itoa(data[i]))
|
||||||
|
}
|
||||||
|
return arr
|
||||||
|
}
|
||||||
|
|
||||||
|
// str[TrimSpace] in string list
|
||||||
|
func TrimSpaceStrInArray(str string, data []string) bool {
|
||||||
|
if len(data) > 0 {
|
||||||
|
for _, row := range data {
|
||||||
|
if str == strings.TrimSpace(row) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// str in string list
|
||||||
|
func StrInArray(str string, data []string) bool {
|
||||||
|
if len(data) > 0 {
|
||||||
|
for _, row := range data {
|
||||||
|
if str == row {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// str in int list
|
||||||
|
func IntInArray(num int, data []int) bool {
|
||||||
|
if len(data) > 0 {
|
||||||
|
for _, row := range data {
|
||||||
|
if num == row {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
var defSep = "_"
|
||||||
|
|
||||||
|
/**
|
||||||
|
笛卡尔组合
|
||||||
|
测试用例
|
||||||
|
cart := [][]string{
|
||||||
|
{"a1", "a2"},
|
||||||
|
{"b1", "b2"},
|
||||||
|
}
|
||||||
|
CartCombine(cart)
|
||||||
|
*/
|
||||||
|
func CartCombine(data [][]string, sep string) []string {
|
||||||
|
var _sep = defSep
|
||||||
|
if sep != "" {
|
||||||
|
_sep = sep
|
||||||
|
}
|
||||||
|
var _r []string
|
||||||
|
lens := func(i int) int { return len(data[i]) }
|
||||||
|
for i := make([]int, len(data)); i[0] < lens(0); next(i, lens) {
|
||||||
|
var r []string
|
||||||
|
for j, k := range i {
|
||||||
|
r = append(r, data[j][k])
|
||||||
|
}
|
||||||
|
_r = append(_r, strings.Join(r, _sep))
|
||||||
|
}
|
||||||
|
return _r
|
||||||
|
}
|
||||||
|
|
||||||
|
func next(i []int, lens func(i int) int) {
|
||||||
|
for j := len(i) - 1; j >= 0; j-- {
|
||||||
|
i[j]++
|
||||||
|
if j == 0 || i[j] < lens(j) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
i[j] = 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const (
|
||||||
|
TOTAL_PAGE_FIELD = "total_page"
|
||||||
|
PAGE_FIELD = "page"
|
||||||
|
ROWS_FIELD = "rows"
|
||||||
|
TOTAL_RECORD_FIELD = "total_record"
|
||||||
|
)
|
||||||
|
|
||||||
|
/**
|
||||||
|
page 当前页
|
||||||
|
listRow 每页行数
|
||||||
|
total 数据总数
|
||||||
|
|
||||||
|
分页数据填充 返回
|
||||||
|
=> map[string]int
|
||||||
|
["total_page"] => 1,
|
||||||
|
["page"] => 1,
|
||||||
|
["rows"] => 20,
|
||||||
|
["total_record"] => 3,
|
||||||
|
*/
|
||||||
|
func CommaPaginator(page int, listRow int, total int) map[string]int {
|
||||||
|
totalpages := int(math.Ceil(float64(total) / float64(listRow)))
|
||||||
|
if page <= 0 {
|
||||||
|
page = 1
|
||||||
|
}
|
||||||
|
paginator := make(map[string]int)
|
||||||
|
paginator[TOTAL_PAGE_FIELD] = totalpages
|
||||||
|
paginator[PAGE_FIELD] = page
|
||||||
|
paginator[ROWS_FIELD] = listRow
|
||||||
|
paginator[TOTAL_RECORD_FIELD] = total
|
||||||
|
return paginator
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -14,7 +14,12 @@ package byteutil
|
|||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"encoding/binary"
|
"encoding/binary"
|
||||||
|
"encoding/gob"
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
"reflect"
|
"reflect"
|
||||||
|
"strconv"
|
||||||
|
"time"
|
||||||
"unsafe"
|
"unsafe"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -64,3 +69,92 @@ func Split(buf []byte, limit int) [][]byte {
|
|||||||
func Join(s [][]byte) []byte {
|
func Join(s [][]byte) []byte {
|
||||||
return bytes.Join(s, []byte(""))
|
return bytes.Join(s, []byte(""))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
type RawBytes []byte
|
||||||
|
|
||||||
|
func cloneBytes(b []byte) []byte {
|
||||||
|
if b == nil {
|
||||||
|
return nil
|
||||||
|
} else {
|
||||||
|
c := make([]byte, len(b))
|
||||||
|
copy(c, b)
|
||||||
|
return c
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func AsString(src interface{}) string {
|
||||||
|
switch v := src.(type) {
|
||||||
|
case string:
|
||||||
|
return v
|
||||||
|
case []byte:
|
||||||
|
return string(v)
|
||||||
|
case int:
|
||||||
|
return strconv.Itoa(v)
|
||||||
|
case int32:
|
||||||
|
return strconv.FormatInt(int64(v), 10)
|
||||||
|
case int64:
|
||||||
|
return strconv.FormatInt(v, 10)
|
||||||
|
case float32:
|
||||||
|
return strconv.FormatFloat(float64(v), 'f', -1, 64)
|
||||||
|
case float64:
|
||||||
|
return strconv.FormatFloat(v, 'f', -1, 64)
|
||||||
|
case time.Time:
|
||||||
|
return time.Time.Format(v, "2006-01-02 15:04:05")
|
||||||
|
case bool:
|
||||||
|
return strconv.FormatBool(v)
|
||||||
|
default:
|
||||||
|
{
|
||||||
|
b, _ := json.Marshal(v)
|
||||||
|
return string(b)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return fmt.Sprintf("%v", src)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 编码二进制
|
||||||
|
func EncodeByte(data interface{}) ([]byte, error) {
|
||||||
|
buf := bytes.NewBuffer(nil)
|
||||||
|
enc := gob.NewEncoder(buf)
|
||||||
|
err := enc.Encode(data)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return buf.Bytes(), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// 解码二进制
|
||||||
|
func DecodeByte(data []byte, to interface{}) error {
|
||||||
|
buf := bytes.NewBuffer(data)
|
||||||
|
dec := gob.NewDecoder(buf)
|
||||||
|
return dec.Decode(to)
|
||||||
|
}
|
||||||
|
|
||||||
|
// byte转16进制字符串
|
||||||
|
func ByteToHex(data []byte) string {
|
||||||
|
buffer := new(bytes.Buffer)
|
||||||
|
for _, b := range data {
|
||||||
|
|
||||||
|
s := strconv.FormatInt(int64(b&0xff), 16)
|
||||||
|
if len(s) == 1 {
|
||||||
|
buffer.WriteString("0")
|
||||||
|
}
|
||||||
|
buffer.WriteString(s)
|
||||||
|
}
|
||||||
|
|
||||||
|
return buffer.String()
|
||||||
|
}
|
||||||
|
|
||||||
|
// 16进制字符串转[]byte
|
||||||
|
func HexToBye(hex string) []byte {
|
||||||
|
length := len(hex) / 2
|
||||||
|
slice := make([]byte, length)
|
||||||
|
rs := []rune(hex)
|
||||||
|
|
||||||
|
for i := 0; i < length; i++ {
|
||||||
|
s := string(rs[i*2 : i*2+2])
|
||||||
|
value, _ := strconv.ParseInt(s, 16, 10)
|
||||||
|
slice[i] = byte(value & 0xFF)
|
||||||
|
}
|
||||||
|
return slice
|
||||||
|
}
|
||||||
@@ -164,3 +164,16 @@ func Base64Encode(src []byte) string {
|
|||||||
func Base64Decode(src string) ([]byte, error) {
|
func Base64Decode(src string) ([]byte, error) {
|
||||||
return base64.StdEncoding.DecodeString(src)
|
return base64.StdEncoding.DecodeString(src)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 四舍五入
|
||||||
|
func Float64Rand(v float64, dig int) float64 {
|
||||||
|
cDig := strconv.Itoa(dig)
|
||||||
|
val := fmt.Sprintf("%0."+cDig+"f", v)
|
||||||
|
return StringToFloat64(val)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 浮点数串化(左边是整数位置,右边是小数位,dig参数控制)
|
||||||
|
func FloatToFDig(floVal float64, dig int) string {
|
||||||
|
return fmt.Sprintf("%10."+strconv.Itoa(dig)+"f", floVal) //十位整数,8位小数
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,84 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2020 The zfoo Authors
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
|
||||||
|
* in compliance with the License. You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed
|
||||||
|
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and limitations under the License.
|
||||||
|
*/
|
||||||
|
package errors
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"os/exec"
|
||||||
|
"path/filepath"
|
||||||
|
"runtime/debug"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
/*
|
||||||
|
用于抓取错误记录打印(panic信息,不可度量的)
|
||||||
|
注意:每个 goroutine 开始部分都需要写上:defer mycatch.Dmp()
|
||||||
|
类似于
|
||||||
|
go func(){
|
||||||
|
defer mycatch.Dmp()
|
||||||
|
}()
|
||||||
|
*/
|
||||||
|
|
||||||
|
func Dmp() {
|
||||||
|
errstr := ""
|
||||||
|
if err := recover(); err != nil {
|
||||||
|
errstr += (fmt.Sprintf("%v\r\n", err)) //输出panic信息
|
||||||
|
errstr += ("--------------------------------------------\r\n")
|
||||||
|
}
|
||||||
|
|
||||||
|
errstr += (string(debug.Stack())) //输出堆栈信息
|
||||||
|
// OnWriteErrToFile(errstr)
|
||||||
|
}
|
||||||
|
|
||||||
|
func OnWriteErrToFile(errstring string) {
|
||||||
|
path := GetModelPath() + "/err"
|
||||||
|
if !PathExists(path) {
|
||||||
|
os.MkdirAll(path, os.ModePerm) //生成多级目录
|
||||||
|
}
|
||||||
|
|
||||||
|
now := time.Now() //获取当前时间
|
||||||
|
pid := os.Getpid() //获取进程ID
|
||||||
|
time_str := now.Format("2006-01-02") //设定时间格式
|
||||||
|
fname := fmt.Sprintf("%s/panic_%s-%x.log", path, time_str, pid) //保存错误信息文件名:程序名-进程ID-当前时间(年月日时分秒)
|
||||||
|
fmt.Println("panic to file ", fname)
|
||||||
|
|
||||||
|
f, err := os.OpenFile(fname, os.O_CREATE|os.O_APPEND|os.O_RDWR, 0666)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
defer f.Close()
|
||||||
|
|
||||||
|
f.WriteString("=========================" + now.Format("2006-01-02 15:04:05 ========================= \r\n"))
|
||||||
|
f.WriteString(errstring) //输出堆栈信息
|
||||||
|
f.WriteString("=========================end=========================")
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取目录地址
|
||||||
|
func GetModelPath() string {
|
||||||
|
file, _ := exec.LookPath(os.Args[0])
|
||||||
|
path := filepath.Dir(file)
|
||||||
|
path, _ = filepath.Abs(path)
|
||||||
|
|
||||||
|
return path
|
||||||
|
}
|
||||||
|
|
||||||
|
func PathExists(path string) bool {
|
||||||
|
_, err := os.Stat(path)
|
||||||
|
if err == nil {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
if os.IsNotExist(err) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2020 The zfoo Authors
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
|
||||||
|
* in compliance with the License. You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed
|
||||||
|
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and limitations under the License.
|
||||||
|
*/
|
||||||
|
package errors
|
||||||
|
|
||||||
|
import "testing"
|
||||||
|
|
||||||
|
func TestDmp(t *testing.T) {
|
||||||
|
|
||||||
|
Dmp()
|
||||||
|
panic(1)
|
||||||
|
}
|
||||||
@@ -0,0 +1,283 @@
|
|||||||
|
// from https://github.com/pkg/errors
|
||||||
|
// Package errors provides simple error handling primitives.
|
||||||
|
//
|
||||||
|
// The traditional error handling idiom in Go is roughly akin to
|
||||||
|
//
|
||||||
|
// if err != nil {
|
||||||
|
// return err
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// which when applied recursively up the call stack results in error reports
|
||||||
|
// without context or debugging information. The errors package allows
|
||||||
|
// programmers to add context to the failure path in their code in a way
|
||||||
|
// that does not destroy the original value of the error.
|
||||||
|
//
|
||||||
|
// Adding context to an error
|
||||||
|
//
|
||||||
|
// The errors.Wrap function returns a new error that adds context to the
|
||||||
|
// original error by recording a stack trace at the point Wrap is called,
|
||||||
|
// together with the supplied message. For example
|
||||||
|
//
|
||||||
|
// _, err := ioutil.ReadAll(r)
|
||||||
|
// if err != nil {
|
||||||
|
// return errors.Wrap(err, "read failed")
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// If additional control is required, the errors.WithStack and
|
||||||
|
// errors.WithMessage functions destructure errors.Wrap into its component
|
||||||
|
// operations: annotating an error with a stack trace and with a message,
|
||||||
|
// respectively.
|
||||||
|
//
|
||||||
|
// Retrieving the cause of an error
|
||||||
|
//
|
||||||
|
// Using errors.Wrap constructs a stack of errors, adding context to the
|
||||||
|
// preceding error. Depending on the nature of the error it may be necessary
|
||||||
|
// to reverse the operation of errors.Wrap to retrieve the original error
|
||||||
|
// for inspection. Any error value which implements this interface
|
||||||
|
//
|
||||||
|
// type causer interface {
|
||||||
|
// Cause() error
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// can be inspected by errors.Cause. errors.Cause will recursively retrieve
|
||||||
|
// the topmost error that does not implement causer, which is assumed to be
|
||||||
|
// the original cause. For example:
|
||||||
|
//
|
||||||
|
// switch err := errors.Cause(err).(type) {
|
||||||
|
// case *MyError:
|
||||||
|
// // handle specifically
|
||||||
|
// default:
|
||||||
|
// // unknown error
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// Although the causer interface is not exported by this package, it is
|
||||||
|
// considered a part of its stable public interface.
|
||||||
|
//
|
||||||
|
// Formatted printing of errors
|
||||||
|
//
|
||||||
|
// All error values returned from this package implement fmt.Formatter and can
|
||||||
|
// be formatted by the fmt package. The following verbs are supported:
|
||||||
|
//
|
||||||
|
// %s print the error. If the error has a Cause it will be
|
||||||
|
// printed recursively.
|
||||||
|
// %v see %s
|
||||||
|
// %+v extended format. Each Frame of the error's StackTrace will
|
||||||
|
// be printed in detail.
|
||||||
|
//
|
||||||
|
// Retrieving the stack trace of an error or wrapper
|
||||||
|
//
|
||||||
|
// New, Errorf, Wrap, and Wrapf record a stack trace at the point they are
|
||||||
|
// invoked. This information can be retrieved with the following interface:
|
||||||
|
//
|
||||||
|
// type stackTracer interface {
|
||||||
|
// StackTrace() errors.StackTrace
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// The returned errors.StackTrace type is defined as
|
||||||
|
//
|
||||||
|
// type StackTrace []Frame
|
||||||
|
//
|
||||||
|
// The Frame type represents a call site in the stack trace. Frame supports
|
||||||
|
// the fmt.Formatter interface that can be used for printing information about
|
||||||
|
// the stack trace of this error. For example:
|
||||||
|
//
|
||||||
|
// if err, ok := err.(stackTracer); ok {
|
||||||
|
// for _, f := range err.StackTrace() {
|
||||||
|
// fmt.Printf("%+s:%d", f)
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// Although the stackTracer interface is not exported by this package, it is
|
||||||
|
// considered a part of its stable public interface.
|
||||||
|
//
|
||||||
|
// See the documentation for Frame.Format for more details.
|
||||||
|
package errors
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
)
|
||||||
|
|
||||||
|
// New returns an error with the supplied message.
|
||||||
|
// New also records the stack trace at the point it was called.
|
||||||
|
func New(message string) error {
|
||||||
|
return &fundamental{
|
||||||
|
msg: message,
|
||||||
|
stack: callers(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Errorf formats according to a format specifier and returns the string
|
||||||
|
// as a value that satisfies error.
|
||||||
|
// Errorf also records the stack trace at the point it was called.
|
||||||
|
func Errorf(format string, args ...interface{}) error {
|
||||||
|
return &fundamental{
|
||||||
|
msg: fmt.Sprintf(format, args...),
|
||||||
|
stack: callers(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// fundamental is an error that has a message and a stack, but no caller.
|
||||||
|
type fundamental struct {
|
||||||
|
msg string
|
||||||
|
*stack
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *fundamental) Error() string { return f.msg }
|
||||||
|
|
||||||
|
func (f *fundamental) Format(s fmt.State, verb rune) {
|
||||||
|
switch verb {
|
||||||
|
case 'v':
|
||||||
|
if s.Flag('+') {
|
||||||
|
io.WriteString(s, f.msg)
|
||||||
|
f.stack.Format(s, verb)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
fallthrough
|
||||||
|
case 's':
|
||||||
|
io.WriteString(s, f.msg)
|
||||||
|
case 'q':
|
||||||
|
fmt.Fprintf(s, "%q", f.msg)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithStack annotates err with a stack trace at the point WithStack was called.
|
||||||
|
// If err is nil, WithStack returns nil.
|
||||||
|
func WithStack(err error) error {
|
||||||
|
if err == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return &withStack{
|
||||||
|
err,
|
||||||
|
callers(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type withStack struct {
|
||||||
|
error
|
||||||
|
*stack
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w *withStack) Cause() error { return w.error }
|
||||||
|
|
||||||
|
func (w *withStack) Format(s fmt.State, verb rune) {
|
||||||
|
switch verb {
|
||||||
|
case 'v':
|
||||||
|
if s.Flag('+') {
|
||||||
|
fmt.Fprintf(s, "%+v", w.Cause())
|
||||||
|
w.stack.Format(s, verb)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
fallthrough
|
||||||
|
case 's':
|
||||||
|
io.WriteString(s, w.Error())
|
||||||
|
case 'q':
|
||||||
|
fmt.Fprintf(s, "%q", w.Error())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Wrap returns an error annotating err with a stack trace
|
||||||
|
// at the point Wrap is called, and the supplied message.
|
||||||
|
// If err is nil, Wrap returns nil.
|
||||||
|
func Wrap(err error, message string) error {
|
||||||
|
if err == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
err = &withMessage{
|
||||||
|
cause: err,
|
||||||
|
msg: message,
|
||||||
|
}
|
||||||
|
return &withStack{
|
||||||
|
err,
|
||||||
|
callers(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Wrapf returns an error annotating err with a stack trace
|
||||||
|
// at the point Wrapf is called, and the format specifier.
|
||||||
|
// If err is nil, Wrapf returns nil.
|
||||||
|
func Wrapf(err error, format string, args ...interface{}) error {
|
||||||
|
if err == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
err = &withMessage{
|
||||||
|
cause: err,
|
||||||
|
msg: fmt.Sprintf(format, args...),
|
||||||
|
}
|
||||||
|
return &withStack{
|
||||||
|
err,
|
||||||
|
callers(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithMessage annotates err with a new message.
|
||||||
|
// If err is nil, WithMessage returns nil.
|
||||||
|
func WithMessage(err error, message string) error {
|
||||||
|
if err == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return &withMessage{
|
||||||
|
cause: err,
|
||||||
|
msg: message,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithMessagef annotates err with the format specifier.
|
||||||
|
// If err is nil, WithMessagef returns nil.
|
||||||
|
func WithMessagef(err error, format string, args ...interface{}) error {
|
||||||
|
if err == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return &withMessage{
|
||||||
|
cause: err,
|
||||||
|
msg: fmt.Sprintf(format, args...),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type withMessage struct {
|
||||||
|
cause error
|
||||||
|
msg string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w *withMessage) Error() string { return w.msg + ": " + w.cause.Error() }
|
||||||
|
func (w *withMessage) Cause() error { return w.cause }
|
||||||
|
|
||||||
|
func (w *withMessage) Format(s fmt.State, verb rune) {
|
||||||
|
switch verb {
|
||||||
|
case 'v':
|
||||||
|
if s.Flag('+') {
|
||||||
|
fmt.Fprintf(s, "%+v\n", w.Cause())
|
||||||
|
io.WriteString(s, w.msg)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
fallthrough
|
||||||
|
case 's', 'q':
|
||||||
|
io.WriteString(s, w.Error())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Cause returns the underlying cause of the error, if possible.
|
||||||
|
// An error value has a cause if it implements the following
|
||||||
|
// interface:
|
||||||
|
//
|
||||||
|
// type causer interface {
|
||||||
|
// Cause() error
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// If the error does not implement Cause, the original error will
|
||||||
|
// be returned. If the error is nil, nil will be returned without further
|
||||||
|
// investigation.
|
||||||
|
func Cause(err error) error {
|
||||||
|
type causer interface {
|
||||||
|
Cause() error
|
||||||
|
}
|
||||||
|
|
||||||
|
for err != nil {
|
||||||
|
cause, ok := err.(causer)
|
||||||
|
if !ok {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
err = cause.Cause()
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
}
|
||||||
@@ -0,0 +1,36 @@
|
|||||||
|
package errors
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func test1() error {
|
||||||
|
return test2()
|
||||||
|
}
|
||||||
|
|
||||||
|
func test2() error {
|
||||||
|
return Wrapf(New("something go wrong"), "自定义消息")
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestErr(t *testing.T) {
|
||||||
|
err := test1()
|
||||||
|
fmt.Println(fmt.Sprintf("%+v", err))
|
||||||
|
err = Cause(err) //获取原始对象
|
||||||
|
fmt.Println(fmt.Sprintf("%+v", err))
|
||||||
|
}
|
||||||
|
|
||||||
|
func test11() error {
|
||||||
|
return test21()
|
||||||
|
}
|
||||||
|
|
||||||
|
func test21() error {
|
||||||
|
return New("something go wrong")
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestErr1(t *testing.T) {
|
||||||
|
err := test11()
|
||||||
|
fmt.Println(fmt.Sprintf("%+v", err))
|
||||||
|
err = Cause(err) //获取原始对象
|
||||||
|
fmt.Println(fmt.Sprintf("%+v", err))
|
||||||
|
}
|
||||||
@@ -0,0 +1,158 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2020 The zfoo Authors
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
|
||||||
|
* in compliance with the License. You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed
|
||||||
|
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and limitations under the License.
|
||||||
|
*/
|
||||||
|
package errors
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"path"
|
||||||
|
"runtime"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Frame represents a program counter inside a stack frame.
|
||||||
|
type Frame uintptr
|
||||||
|
|
||||||
|
// pc returns the program counter for this frame;
|
||||||
|
// multiple frames may have the same PC value.
|
||||||
|
func (f Frame) pc() uintptr { return uintptr(f) - 1 }
|
||||||
|
|
||||||
|
// file returns the full path to the file that contains the
|
||||||
|
// function for this Frame's pc.
|
||||||
|
func (f Frame) file() string {
|
||||||
|
fn := runtime.FuncForPC(f.pc())
|
||||||
|
if fn == nil {
|
||||||
|
return "unknown"
|
||||||
|
}
|
||||||
|
file, _ := fn.FileLine(f.pc())
|
||||||
|
return file
|
||||||
|
}
|
||||||
|
|
||||||
|
// line returns the line number of source code of the
|
||||||
|
// function for this Frame's pc.
|
||||||
|
func (f Frame) line() int {
|
||||||
|
fn := runtime.FuncForPC(f.pc())
|
||||||
|
if fn == nil {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
_, line := fn.FileLine(f.pc())
|
||||||
|
return line
|
||||||
|
}
|
||||||
|
|
||||||
|
// Format formats the frame according to the fmt.Formatter interface.
|
||||||
|
//
|
||||||
|
// %s source file
|
||||||
|
// %d source line
|
||||||
|
// %n function name
|
||||||
|
// %v equivalent to %s:%d
|
||||||
|
//
|
||||||
|
// Format accepts flags that alter the printing of some verbs, as follows:
|
||||||
|
//
|
||||||
|
// %+s function name and path of source file relative to the compile time
|
||||||
|
// GOPATH separated by \n\t (<funcname>\n\t<path>)
|
||||||
|
// %+v equivalent to %+s:%d
|
||||||
|
func (f Frame) Format(s fmt.State, verb rune) {
|
||||||
|
switch verb {
|
||||||
|
case 's':
|
||||||
|
switch {
|
||||||
|
case s.Flag('+'):
|
||||||
|
pc := f.pc()
|
||||||
|
fn := runtime.FuncForPC(pc)
|
||||||
|
if fn == nil {
|
||||||
|
io.WriteString(s, "unknown")
|
||||||
|
} else {
|
||||||
|
file, _ := fn.FileLine(pc)
|
||||||
|
fmt.Fprintf(s, "%s\n\t%s", fn.Name(), file)
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
io.WriteString(s, path.Base(f.file()))
|
||||||
|
}
|
||||||
|
case 'd':
|
||||||
|
fmt.Fprintf(s, "%d", f.line())
|
||||||
|
case 'n':
|
||||||
|
name := runtime.FuncForPC(f.pc()).Name()
|
||||||
|
io.WriteString(s, funcname(name))
|
||||||
|
case 'v':
|
||||||
|
f.Format(s, 's')
|
||||||
|
io.WriteString(s, ":")
|
||||||
|
f.Format(s, 'd')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// StackTrace is stack of Frames from innermost (newest) to outermost (oldest).
|
||||||
|
type StackTrace []Frame
|
||||||
|
|
||||||
|
// Format formats the stack of Frames according to the fmt.Formatter interface.
|
||||||
|
//
|
||||||
|
// %s lists source files for each Frame in the stack
|
||||||
|
// %v lists the source file and line number for each Frame in the stack
|
||||||
|
//
|
||||||
|
// Format accepts flags that alter the printing of some verbs, as follows:
|
||||||
|
//
|
||||||
|
// %+v Prints filename, function, and line number for each Frame in the stack.
|
||||||
|
func (st StackTrace) Format(s fmt.State, verb rune) {
|
||||||
|
switch verb {
|
||||||
|
case 'v':
|
||||||
|
switch {
|
||||||
|
case s.Flag('+'):
|
||||||
|
for _, f := range st {
|
||||||
|
fmt.Fprintf(s, "\n%+v", f)
|
||||||
|
}
|
||||||
|
case s.Flag('#'):
|
||||||
|
fmt.Fprintf(s, "%#v", []Frame(st))
|
||||||
|
default:
|
||||||
|
fmt.Fprintf(s, "%v", []Frame(st))
|
||||||
|
}
|
||||||
|
case 's':
|
||||||
|
fmt.Fprintf(s, "%s", []Frame(st))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// stack represents a stack of program counters.
|
||||||
|
type stack []uintptr
|
||||||
|
|
||||||
|
func (s *stack) Format(st fmt.State, verb rune) {
|
||||||
|
switch verb {
|
||||||
|
case 'v':
|
||||||
|
switch {
|
||||||
|
case st.Flag('+'):
|
||||||
|
for _, pc := range *s {
|
||||||
|
f := Frame(pc)
|
||||||
|
fmt.Fprintf(st, "\n%+v", f)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *stack) StackTrace() StackTrace {
|
||||||
|
f := make([]Frame, len(*s))
|
||||||
|
for i := 0; i < len(f); i++ {
|
||||||
|
f[i] = Frame((*s)[i])
|
||||||
|
}
|
||||||
|
return f
|
||||||
|
}
|
||||||
|
|
||||||
|
func callers() *stack {
|
||||||
|
const depth = 32
|
||||||
|
var pcs [depth]uintptr
|
||||||
|
n := runtime.Callers(3, pcs[:])
|
||||||
|
var st stack = pcs[0:n]
|
||||||
|
return &st
|
||||||
|
}
|
||||||
|
|
||||||
|
// funcname removes the path prefix component of a function's name reported by func.Name().
|
||||||
|
func funcname(name string) string {
|
||||||
|
i := strings.LastIndex(name, "/")
|
||||||
|
name = name[i+1:]
|
||||||
|
i = strings.Index(name, ".")
|
||||||
|
return name[i+1:]
|
||||||
|
}
|
||||||
@@ -17,6 +17,7 @@ import (
|
|||||||
"os"
|
"os"
|
||||||
"path"
|
"path"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
// SelfPath gets compiled executable file absolute path.
|
// SelfPath gets compiled executable file absolute path.
|
||||||
@@ -117,3 +118,56 @@ func RemoveDir(dirPath string) error {
|
|||||||
}
|
}
|
||||||
return os.Remove(dirPath)
|
return os.Remove(dirPath)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func PathExists(path string) bool {
|
||||||
|
_, err := os.Stat(path)
|
||||||
|
if err == nil {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
if os.IsNotExist(err) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// 创建目录
|
||||||
|
func BuildDir(abs_dir string) error {
|
||||||
|
return os.MkdirAll(path.Dir(abs_dir), os.ModePerm) //生成多级目录
|
||||||
|
}
|
||||||
|
|
||||||
|
// 删除文件或文件夹
|
||||||
|
func DeleteFile(abs_dir string) error {
|
||||||
|
return os.RemoveAll(abs_dir)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取目录所有文件夹
|
||||||
|
func GetPathDirs(abs_dir string) (re []string) {
|
||||||
|
if PathExists(abs_dir) {
|
||||||
|
files, _ := ioutil.ReadDir(abs_dir)
|
||||||
|
for _, f := range files {
|
||||||
|
if f.IsDir() {
|
||||||
|
re = append(re, f.Name())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取目录所有文件
|
||||||
|
func GetPathFiles(abs_dir string) (re []string) {
|
||||||
|
if PathExists(abs_dir) {
|
||||||
|
files, _ := ioutil.ReadDir(abs_dir)
|
||||||
|
for _, f := range files {
|
||||||
|
if !f.IsDir() {
|
||||||
|
re = append(re, f.Name())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取程序运行路径
|
||||||
|
func GetCurrentDirectory() string {
|
||||||
|
dir, _ := filepath.Abs(filepath.Dir(os.Args[0]))
|
||||||
|
return strings.Replace(dir, "\\", "/", -1)
|
||||||
|
}
|
||||||
@@ -12,9 +12,16 @@
|
|||||||
package httputil
|
package httputil
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bytes"
|
||||||
|
"encoding/binary"
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
|
"net"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"net/url"
|
||||||
"strings"
|
"strings"
|
||||||
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
func PostWithHeader(url string, msg []byte, headers map[string]string) (string, error) {
|
func PostWithHeader(url string, msg []byte, headers map[string]string) (string, error) {
|
||||||
@@ -42,3 +49,327 @@ func PostWithAuthorization(url, authorization string, msg []byte) (string, error
|
|||||||
headers["Content-Type"] = "application/json"
|
headers["Content-Type"] = "application/json"
|
||||||
return PostWithHeader(url, msg, headers)
|
return PostWithHeader(url, msg, headers)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
const (
|
||||||
|
CONN_TIME_OUT = time.Second * 2
|
||||||
|
)
|
||||||
|
|
||||||
|
func Get(apiURL string, params url.Values) (resData string, e error) {
|
||||||
|
var (
|
||||||
|
Url *url.URL
|
||||||
|
err error
|
||||||
|
)
|
||||||
|
Url, err = url.Parse(apiURL)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
Url.RawQuery = params.Encode()
|
||||||
|
resp, err := http.Get(Url.String())
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
defer resp.Body.Close()
|
||||||
|
res, err := ioutil.ReadAll(resp.Body)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
return string(res), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Get with TimeOut
|
||||||
|
Code == 200 则返回,其他请打印错误
|
||||||
|
第三个参数设置超时 单位:秒 【0:则默认两秒】
|
||||||
|
*/
|
||||||
|
func SendGetWithTimeOut(apiUrl string, params url.Values, time_out int) (resData string, e error) {
|
||||||
|
var (
|
||||||
|
Url *url.URL
|
||||||
|
err error
|
||||||
|
b []byte
|
||||||
|
)
|
||||||
|
Url, err = url.Parse(apiUrl)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
Url.RawQuery = params.Encode()
|
||||||
|
client := _httpClient(time_out)
|
||||||
|
resp, err := client.Get(Url.String())
|
||||||
|
if err != nil || resp == nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
defer resp.Body.Close()
|
||||||
|
if resp.StatusCode != http.StatusOK {
|
||||||
|
return "", nil
|
||||||
|
}
|
||||||
|
if resp.Body != nil {
|
||||||
|
b, err = ioutil.ReadAll(resp.Body)
|
||||||
|
return string(b), nil
|
||||||
|
}
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
func _httpClient(time_out int) http.Client {
|
||||||
|
var (
|
||||||
|
_sec time.Duration
|
||||||
|
)
|
||||||
|
_sec = CONN_TIME_OUT
|
||||||
|
if time_out > 0 {
|
||||||
|
_sec = time.Second * time.Duration(time_out)
|
||||||
|
}
|
||||||
|
return http.Client{
|
||||||
|
Transport: &http.Transport{
|
||||||
|
Dial: func(netw, addr string) (net.Conn, error) {
|
||||||
|
conn, err := net.DialTimeout(netw, addr, _sec)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
conn.SetDeadline(time.Now().Add(_sec))
|
||||||
|
return conn, nil
|
||||||
|
},
|
||||||
|
ResponseHeaderTimeout: _sec,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
网络请求POST
|
||||||
|
*/
|
||||||
|
func Post(apiURL string, params url.Values) (resData string, err error) {
|
||||||
|
resp, err := http.PostForm(apiURL, params)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
defer resp.Body.Close()
|
||||||
|
res, err := ioutil.ReadAll(resp.Body)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
return string(res), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Post with TimeOut
|
||||||
|
Code == 200 则返回,其他请打印错误
|
||||||
|
第三个参数设置超时 单位:秒 【0:则默认两秒】
|
||||||
|
*/
|
||||||
|
func SendPostWithTimeOut(apiUrl string, params url.Values, time_out int) (resData string, e error) {
|
||||||
|
var (
|
||||||
|
err error
|
||||||
|
b []byte
|
||||||
|
)
|
||||||
|
client := _httpClient(time_out)
|
||||||
|
resp, err := client.PostForm(apiUrl, params)
|
||||||
|
if err != nil || resp == nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
defer resp.Body.Close()
|
||||||
|
if resp.StatusCode != http.StatusOK {
|
||||||
|
return "", nil
|
||||||
|
}
|
||||||
|
if resp.Body != nil {
|
||||||
|
b, err = ioutil.ReadAll(resp.Body)
|
||||||
|
return string(b), nil
|
||||||
|
}
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//OnPostJSON 发送修改密码
|
||||||
|
func OnPostJSON(url, jsonstr string) []byte {
|
||||||
|
//解析这个 URL 并确保解析没有出错。
|
||||||
|
body := bytes.NewBuffer([]byte(jsonstr))
|
||||||
|
resp, err := http.Post(url, "application/json;charset=utf-8", body)
|
||||||
|
if err != nil {
|
||||||
|
return []byte("")
|
||||||
|
}
|
||||||
|
defer resp.Body.Close()
|
||||||
|
body1, err1 := ioutil.ReadAll(resp.Body)
|
||||||
|
if err1 != nil {
|
||||||
|
return []byte("")
|
||||||
|
}
|
||||||
|
|
||||||
|
return body1
|
||||||
|
}
|
||||||
|
|
||||||
|
//OnGetJSON 发送get 请求
|
||||||
|
func OnGetJSON(url, params string) string {
|
||||||
|
//解析这个 URL 并确保解析没有出错。
|
||||||
|
var urls = url
|
||||||
|
if len(params) > 0 {
|
||||||
|
urls += "?" + params
|
||||||
|
}
|
||||||
|
resp, err := http.Get(urls)
|
||||||
|
if err != nil {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
defer resp.Body.Close()
|
||||||
|
body1, err1 := ioutil.ReadAll(resp.Body)
|
||||||
|
if err1 != nil {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
return string(body1)
|
||||||
|
}
|
||||||
|
|
||||||
|
//SendGet 发送get 请求 返回对象
|
||||||
|
func SendGet(url, params string, obj interface{}) bool {
|
||||||
|
//解析这个 URL 并确保解析没有出错。
|
||||||
|
var urls = url
|
||||||
|
if len(params) > 0 {
|
||||||
|
urls += "?" + params
|
||||||
|
}
|
||||||
|
resp, err := http.Get(urls)
|
||||||
|
if err != nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
defer resp.Body.Close()
|
||||||
|
body, err := ioutil.ReadAll(resp.Body)
|
||||||
|
if err != nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
//log.Println((string(body)))
|
||||||
|
err = json.Unmarshal([]byte(body), &obj)
|
||||||
|
if err != nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
//SendGetEx 发送GET请求
|
||||||
|
func SendGetEx(url string, reponse interface{}) bool {
|
||||||
|
resp, e := http.Get(url)
|
||||||
|
if e != nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
defer resp.Body.Close()
|
||||||
|
body, err := ioutil.ReadAll(resp.Body)
|
||||||
|
if err != nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
err = json.Unmarshal(body, &reponse)
|
||||||
|
if err != nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
//OnPostForm form 方式发送post请求
|
||||||
|
func OnPostForm(url string, data url.Values) (body []byte) {
|
||||||
|
resp, err := http.PostForm(url, data)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
defer resp.Body.Close()
|
||||||
|
body, err = ioutil.ReadAll(resp.Body)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
//SendPost 发送POST请求
|
||||||
|
func SendPost(requestBody interface{}, responseBody interface{}, url string) bool {
|
||||||
|
postData, err := json.Marshal(requestBody)
|
||||||
|
client := &http.Client{}
|
||||||
|
req, _ := http.NewRequest("POST", url, bytes.NewReader(postData))
|
||||||
|
req.Header.Add("Accept", "application/json")
|
||||||
|
req.Header.Add("Content-Type", "application/json;charset=utf-8")
|
||||||
|
// req.Header.Add("Authorization", authorization)
|
||||||
|
resp, e := client.Do(req)
|
||||||
|
if e != nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
defer resp.Body.Close()
|
||||||
|
|
||||||
|
body, err := ioutil.ReadAll(resp.Body)
|
||||||
|
if err != nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
// result := string(body)
|
||||||
|
|
||||||
|
err = json.Unmarshal(body, &responseBody)
|
||||||
|
if err != nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
//WriteJSON 像指定client 发送json 包
|
||||||
|
//msg message.MessageBody
|
||||||
|
func WriteJSON(w http.ResponseWriter, msg interface{}) {
|
||||||
|
w.Header().Set("Content-Type", "application/json; charset=utf-8")
|
||||||
|
js, err := json.Marshal(msg)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
fmt.Fprintf(w, string(js))
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// --------------------------------------------------------------------------------------------------------
|
||||||
|
const (
|
||||||
|
XForwardedFor = "X-Forwarded-For"
|
||||||
|
XRealIP = "X-Real-IP"
|
||||||
|
)
|
||||||
|
|
||||||
|
// RemoteIp 返回远程客户端的 IP,如 192.168.1.1
|
||||||
|
func RemoteIp(req *http.Request) string {
|
||||||
|
remoteAddr := req.RemoteAddr
|
||||||
|
if ip := req.Header.Get(XRealIP); ip != "" {
|
||||||
|
remoteAddr = ip
|
||||||
|
} else if ip = req.Header.Get(XForwardedFor); ip != "" {
|
||||||
|
remoteAddr = ip
|
||||||
|
} else {
|
||||||
|
remoteAddr, _, _ = net.SplitHostPort(remoteAddr)
|
||||||
|
}
|
||||||
|
|
||||||
|
if remoteAddr == "::1" {
|
||||||
|
remoteAddr = "127.0.0.1"
|
||||||
|
}
|
||||||
|
|
||||||
|
return remoteAddr
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ip2long 将 IPv4 字符串形式转为 uint32
|
||||||
|
func Ip2long(ipstr string) uint32 {
|
||||||
|
ip := net.ParseIP(ipstr)
|
||||||
|
if ip == nil {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
ip = ip.To4()
|
||||||
|
return binary.BigEndian.Uint32(ip)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取本机网卡IP
|
||||||
|
func GetLocalIP() (ipv4 string, err error) {
|
||||||
|
var (
|
||||||
|
addrs []net.Addr
|
||||||
|
addr net.Addr
|
||||||
|
ipNet *net.IPNet // IP地址
|
||||||
|
isIpNet bool
|
||||||
|
)
|
||||||
|
// 获取所有网卡
|
||||||
|
if addrs, err = net.InterfaceAddrs(); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// 取第一个非lo的网卡IP
|
||||||
|
for _, addr = range addrs {
|
||||||
|
// 这个网络地址是IP地址: ipv4, ipv6
|
||||||
|
if ipNet, isIpNet = addr.(*net.IPNet); isIpNet && !ipNet.IP.IsLoopback() {
|
||||||
|
// 跳过IPV6
|
||||||
|
if ipNet.IP.To4() != nil {
|
||||||
|
ipv4 = ipNet.IP.String() // 192.168.1.1
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
@@ -0,0 +1,57 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2020 The zfoo Authors
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
|
||||||
|
* in compliance with the License. You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed
|
||||||
|
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and limitations under the License.
|
||||||
|
*/
|
||||||
|
package jsonutil
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
)
|
||||||
|
|
||||||
|
/**
|
||||||
|
JSON (map转json)
|
||||||
|
*/
|
||||||
|
|
||||||
|
func ToJsonString(data map[string]interface{}) string {
|
||||||
|
jsonData, err := json.Marshal(data)
|
||||||
|
if err != nil {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
return string(jsonData)
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
泛型比较麻烦,单独做一个
|
||||||
|
*/
|
||||||
|
func Struct2Json(data interface{}) (string, error) {
|
||||||
|
jsonData, err := json.Marshal(data)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
return string(jsonData), err
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
JSON (json转map)
|
||||||
|
*/
|
||||||
|
func StringToJson(data string) map[string]interface{} {
|
||||||
|
var jsonData map[string]interface{}
|
||||||
|
json.Unmarshal([]byte(data), &jsonData)
|
||||||
|
return jsonData
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
JSONstring (json转IntList)
|
||||||
|
*/
|
||||||
|
func ToIntList(data string) []int {
|
||||||
|
var tmp = make([]int, 0)
|
||||||
|
json.Unmarshal([]byte(data), &tmp)
|
||||||
|
return tmp
|
||||||
|
}
|
||||||
@@ -11,7 +11,10 @@
|
|||||||
*/
|
*/
|
||||||
package maputil
|
package maputil
|
||||||
|
|
||||||
import "strings"
|
import (
|
||||||
|
"reflect"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
// IsEmpty ...
|
// IsEmpty ...
|
||||||
func IsEmpty(mp map[string]string) bool {
|
func IsEmpty(mp map[string]string) bool {
|
||||||
@@ -79,3 +82,16 @@ func Merge(src, dst map[string]string) map[string]string {
|
|||||||
}
|
}
|
||||||
return dst
|
return dst
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 结构体转map
|
||||||
|
func Struct2Map(obj interface{}) map[string]interface{} {
|
||||||
|
t := reflect.TypeOf(obj)
|
||||||
|
v := reflect.ValueOf(obj)
|
||||||
|
|
||||||
|
var data = make(map[string]interface{})
|
||||||
|
for i := 0; i < t.NumField(); i++ {
|
||||||
|
data[t.Field(i).Name] = v.Field(i).Interface()
|
||||||
|
}
|
||||||
|
return data
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,79 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2020 The zfoo Authors
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
|
||||||
|
* in compliance with the License. You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed
|
||||||
|
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and limitations under the License.
|
||||||
|
*/
|
||||||
|
package security
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"crypto/aes"
|
||||||
|
"crypto/cipher"
|
||||||
|
)
|
||||||
|
|
||||||
|
/**
|
||||||
|
Aes加解密
|
||||||
|
填充方式【CBC】
|
||||||
|
收集
|
||||||
|
*/
|
||||||
|
|
||||||
|
func AesEncrypt(origData, key []byte) ([]byte, error) {
|
||||||
|
block, err := aes.NewCipher(key)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
blockSize := block.BlockSize()
|
||||||
|
origData = PKCS5Padding(origData, blockSize)
|
||||||
|
// origData = ZeroPadding(origData, block.BlockSize())
|
||||||
|
blockMode := cipher.NewCBCEncrypter(block, key[:blockSize])
|
||||||
|
crypted := make([]byte, len(origData))
|
||||||
|
// crypted := origData
|
||||||
|
blockMode.CryptBlocks(crypted, origData)
|
||||||
|
return crypted, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func AesDecrypt(crypted, key []byte) ([]byte, error) {
|
||||||
|
block, err := aes.NewCipher(key)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
blockSize := block.BlockSize()
|
||||||
|
blockMode := cipher.NewCBCDecrypter(block, key[:blockSize])
|
||||||
|
origData := make([]byte, len(crypted))
|
||||||
|
// origData := crypted
|
||||||
|
blockMode.CryptBlocks(origData, crypted)
|
||||||
|
origData = PKCS5UnPadding(origData)
|
||||||
|
// origData = ZeroUnPadding(origData)
|
||||||
|
return origData, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func ZeroPadding(ciphertext []byte, blockSize int) []byte {
|
||||||
|
padding := blockSize - len(ciphertext)%blockSize
|
||||||
|
padtext := bytes.Repeat([]byte{0}, padding)
|
||||||
|
return append(ciphertext, padtext...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func ZeroUnPadding(origData []byte) []byte {
|
||||||
|
length := len(origData)
|
||||||
|
unpadding := int(origData[length-1])
|
||||||
|
return origData[:(length - unpadding)]
|
||||||
|
}
|
||||||
|
|
||||||
|
func PKCS5Padding(ciphertext []byte, blockSize int) []byte {
|
||||||
|
padding := blockSize - len(ciphertext)%blockSize
|
||||||
|
padtext := bytes.Repeat([]byte{byte(padding)}, padding)
|
||||||
|
return append(ciphertext, padtext...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func PKCS5UnPadding(origData []byte) []byte {
|
||||||
|
length := len(origData)
|
||||||
|
// 去掉最后一个字节 unpadding 次
|
||||||
|
unpadding := int(origData[length-1])
|
||||||
|
return origData[:(length - unpadding)]
|
||||||
|
}
|
||||||
@@ -9,7 +9,7 @@
|
|||||||
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
* See the License for the specific language governing permissions and limitations under the License.
|
* See the License for the specific language governing permissions and limitations under the License.
|
||||||
*/
|
*/
|
||||||
package rsautil
|
package security
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2020 The zfoo Authors
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
|
||||||
|
* in compliance with the License. You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed
|
||||||
|
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and limitations under the License.
|
||||||
|
*/
|
||||||
|
package dmd5
|
||||||
|
|
||||||
|
import (
|
||||||
|
"crypto/md5"
|
||||||
|
"encoding/hex"
|
||||||
|
)
|
||||||
|
|
||||||
|
/**
|
||||||
|
md5
|
||||||
|
*/
|
||||||
|
|
||||||
|
func Md5EnCode(string string) string {
|
||||||
|
h := md5.New()
|
||||||
|
h.Write([]byte(string)) // 需要加密的字符串为
|
||||||
|
return hex.EncodeToString(h.Sum(nil))
|
||||||
|
}
|
||||||
@@ -9,7 +9,7 @@
|
|||||||
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
* See the License for the specific language governing permissions and limitations under the License.
|
* See the License for the specific language governing permissions and limitations under the License.
|
||||||
*/
|
*/
|
||||||
package rsautil
|
package security
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"crypto/rand"
|
"crypto/rand"
|
||||||
@@ -15,8 +15,10 @@ import (
|
|||||||
"bytes"
|
"bytes"
|
||||||
"net/url"
|
"net/url"
|
||||||
"regexp"
|
"regexp"
|
||||||
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"unicode"
|
"unicode"
|
||||||
|
"unsafe"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Reverse 反转字符串
|
// Reverse 反转字符串
|
||||||
@@ -125,3 +127,126 @@ func TrimSpace(s string) string {
|
|||||||
s = strings.Trim(s, "\t")
|
s = strings.Trim(s, "\t")
|
||||||
return s
|
return s
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func CamelCase(s string) string {
|
||||||
|
if s == "" {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
t := make([]byte, 0, 32)
|
||||||
|
i := 0
|
||||||
|
if s[0] == '_' {
|
||||||
|
t = append(t, 'X')
|
||||||
|
i++
|
||||||
|
}
|
||||||
|
for ; i < len(s); i++ {
|
||||||
|
c := s[i]
|
||||||
|
if c == '_' && i+1 < len(s) && isASCIIUpper(s[i+1]) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if isASCIIDigit(c) {
|
||||||
|
t = append(t, c)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if isASCIIUpper(c) {
|
||||||
|
c ^= ' '
|
||||||
|
}
|
||||||
|
t = append(t, c)
|
||||||
|
|
||||||
|
for i+1 < len(s) && isASCIIUpper(s[i+1]) {
|
||||||
|
i++
|
||||||
|
t = append(t, '_')
|
||||||
|
t = append(t, bytes.ToLower([]byte{s[i]})[0])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return string(t)
|
||||||
|
}
|
||||||
|
func isASCIIUpper(c byte) bool {
|
||||||
|
return 'A' <= c && c <= 'Z'
|
||||||
|
}
|
||||||
|
|
||||||
|
func isASCIIDigit(c byte) bool {
|
||||||
|
return '0' <= c && c <= '9'
|
||||||
|
}
|
||||||
|
|
||||||
|
// 手机号码检测
|
||||||
|
func CheckIsMobile(mobileNum string) bool {
|
||||||
|
var regular = "^1[345789]{1}\\d{9}$"
|
||||||
|
reg := regexp.MustCompile(regular)
|
||||||
|
return reg.MatchString(mobileNum)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 判断是否是18或15位身份证
|
||||||
|
func IsIdCard(cardNo string) bool {
|
||||||
|
// 18位身份证 ^(\d{17})([0-9]|X)$
|
||||||
|
if m, _ := regexp.MatchString(`(^\d{15}$)|(^\d{18}$)|(^\d{17}(\d|X|x)$)`, cardNo); !m {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
// 字节转字符串
|
||||||
|
func BytesToString(data []byte) string {
|
||||||
|
return *(*string)(unsafe.Pointer(&data))
|
||||||
|
}
|
||||||
|
|
||||||
|
// 字符串转字节数组
|
||||||
|
func StringToBytes(data string) []byte {
|
||||||
|
return *(*[]byte)(unsafe.Pointer(&data))
|
||||||
|
}
|
||||||
|
|
||||||
|
// 判断字符串是否为中文[精确度需要反复试验]
|
||||||
|
func IsContainCN(str string) bool {
|
||||||
|
var hzRegexp = regexp.MustCompile("[\u4e00-\u9fa5]+")
|
||||||
|
return hzRegexp.MatchString(str)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Emoji表情解码
|
||||||
|
func UnicodeEmojiDecode(s string) string {
|
||||||
|
//emoji表情的数据表达式
|
||||||
|
re := regexp.MustCompile("\\[[\\\\u0-9a-zA-Z]+\\]")
|
||||||
|
// 提取emoji数据表达式
|
||||||
|
reg := regexp.MustCompile("\\[\\\\u|]")
|
||||||
|
src := re.FindAllString(s, -1)
|
||||||
|
for i := 0; i < len(src); i++ {
|
||||||
|
e := reg.ReplaceAllString(src[i], "")
|
||||||
|
p, err := strconv.ParseInt(e, 16, 32)
|
||||||
|
if err == nil {
|
||||||
|
s = strings.Replace(s, src[i], string(rune(p)), -1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
身份证手机号填充
|
||||||
|
*/
|
||||||
|
|
||||||
|
func SignIdcard(idcard string) string {
|
||||||
|
cp := idcard
|
||||||
|
leth := len(cp)
|
||||||
|
return cp[0:4] + " **** **** " + cp[leth-4:]
|
||||||
|
}
|
||||||
|
|
||||||
|
func SignMobile(mobile string) string {
|
||||||
|
cp := mobile
|
||||||
|
leth := len(cp)
|
||||||
|
return cp[0:3] + " **** " + cp[leth-4:]
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Emoji表情转换
|
||||||
|
func UnicodeEmojiCode(s string) string {
|
||||||
|
ret := ""
|
||||||
|
rs := []rune(s)
|
||||||
|
for i := 0; i < len(rs); i++ {
|
||||||
|
if len(string(rs[i])) == 4 {
|
||||||
|
u := `[\u` + strconv.FormatInt(int64(rs[i]), 16) + `]`
|
||||||
|
ret += u
|
||||||
|
|
||||||
|
} else {
|
||||||
|
ret += string(rs[i])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ret
|
||||||
|
}
|
||||||
@@ -0,0 +1,90 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2020 The zfoo Authors
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
|
||||||
|
* in compliance with the License. You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed
|
||||||
|
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and limitations under the License.
|
||||||
|
*/
|
||||||
|
package dtime
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"math/rand"
|
||||||
|
"sync"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
/**
|
||||||
|
时间获取
|
||||||
|
时间转换必须加入时区设置,请注意
|
||||||
|
*/
|
||||||
|
|
||||||
|
var (
|
||||||
|
randSeek = int64(1)
|
||||||
|
l sync.Mutex
|
||||||
|
zone = "CST" //时区
|
||||||
|
)
|
||||||
|
|
||||||
|
func TimeIntToDate(time_int int) string {
|
||||||
|
var cstZone = time.FixedZone(zone, 8*3600)
|
||||||
|
return time.Unix(int64(time_int), 0).In(cstZone).Format("2006-01-02 15:04:05")
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetNowDateTime() string {
|
||||||
|
var cstZone = time.FixedZone(zone, 8*3600)
|
||||||
|
return time.Now().In(cstZone).Format("2006-01-02 15:04:05")
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetDate() string {
|
||||||
|
var cstZone = time.FixedZone(zone, 8*3600)
|
||||||
|
return time.Now().In(cstZone).Format("2006-01-02")
|
||||||
|
}
|
||||||
|
|
||||||
|
//防时间间隔
|
||||||
|
func GetIntTime() int {
|
||||||
|
var _t = int(time.Now().Unix())
|
||||||
|
return _t
|
||||||
|
}
|
||||||
|
|
||||||
|
//暂时独立
|
||||||
|
func _getRandomSring(num int, str ...string) string {
|
||||||
|
s := "123456789"
|
||||||
|
if len(str) > 0 {
|
||||||
|
s = str[0]
|
||||||
|
}
|
||||||
|
l := len(s)
|
||||||
|
r := rand.New(rand.NewSource(getRandSeek()))
|
||||||
|
var buf bytes.Buffer
|
||||||
|
for i := 0; i < num; i++ {
|
||||||
|
x := r.Intn(l)
|
||||||
|
buf.WriteString(s[x : x+1])
|
||||||
|
}
|
||||||
|
return buf.String()
|
||||||
|
}
|
||||||
|
|
||||||
|
func getRandSeek() int64 {
|
||||||
|
l.Lock()
|
||||||
|
if randSeek >= 100000000 {
|
||||||
|
randSeek = 1
|
||||||
|
}
|
||||||
|
randSeek++
|
||||||
|
l.Unlock()
|
||||||
|
return time.Now().UnixNano() + randSeek
|
||||||
|
}
|
||||||
|
|
||||||
|
//获取今天时间戳 Today => 00:00:00
|
||||||
|
func TodayTimeUnix() int {
|
||||||
|
t := time.Now()
|
||||||
|
tm1 := int(time.Date(t.Year(), t.Month(), t.Day(), 0, 0, 0, 0, t.Location()).Unix())
|
||||||
|
return tm1
|
||||||
|
}
|
||||||
|
|
||||||
|
//获取今天时间戳 Today => 23:59:59
|
||||||
|
func TodayNightUnix() int {
|
||||||
|
tm1 := TodayTimeUnix() + 86400 - 1
|
||||||
|
return tm1
|
||||||
|
}
|
||||||
Reference in new issue
Block a user