0%

【Go】利用 reflect 实现结构体设置默认值

写 API 时经常会需要结构体中某个参数拥有默认值。但如 Gin 只有 ShouldBindQuery 这种 form 类型支持设置默认值,常用的 ShouldBindJSON 这种 json 类型却不支持,很奇怪。

Gin 中 bind 结构体设置默认值

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
package main

import (
"fmt"
"github.com/gin-gonic/gin"
)

type FormData struct {
Name string `form:"name,default=vksir"`
Age int `form:"age,default=18"`
}

type JsonData struct {
Name string `json:"name,default=vksir"`
Age int `json:"age,default=18"`
}

func main() {
e := gin.Default()
e.GET("/", func(c *gin.Context) {
var fd FormData
c.ShouldBindQuery(&fd)
var jd JsonData
c.ShouldBindJSON(&jd)
fmt.Printf("FormData: %+v\n", fd)
fmt.Printf("JsonData:%+v\n", jd)
})
e.Run()
}
阅读全文 »

【Go】实现分级日志

话不多说直接上代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
package log

import (
"errors"
"fmt"
"log"
"os"
)

const (
LevelDebug = (1 + iota) * 10
LevelInfo
LevelWaring
LevelError
LevelCritical
)

var debugLogger *log.Logger
var debugFileLogger *log.Logger
var infoLogger *log.Logger
var infoFileLogger *log.Logger
var warningLogger *log.Logger
var warningFileLogger *log.Logger
var errorLogger *log.Logger
var errorFileLogger *log.Logger
var criticalLogger *log.Logger
var criticalFileLogger *log.Logger
var flag = log.Ldate | log.Ltime | log.Lshortfile | log.Lmsgprefix
var logLevel = LevelInfo

func SetLevel(level int) error {
if level != LevelDebug && level != LevelInfo && level != LevelWaring && level != LevelError && level != LevelCritical {
return errors.New(fmt.Sprintf("invalid level: %d", level))
} else {
logLevel = level
return nil
}
}

func AddFileOutput(filePath string) error {
logWriter, err := os.OpenFile(filePath, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0655)
if err != nil {
return err
} else {
debugFileLogger = log.New(logWriter, "[DEBUG] ", flag)
infoFileLogger = log.New(logWriter, "[INFO] ", flag)
warningFileLogger = log.New(logWriter, "[WARNING] ", flag)
errorFileLogger = log.New(logWriter, "[ERROR] ", flag)
criticalFileLogger = log.New(logWriter, "[CRITICAL] ", flag)
return nil
}
}

func Debug(format string, v ...any) {
logWithLevel(debugLogger, LevelDebug, format, v)
logWithLevel(debugFileLogger, LevelDebug, format, v)
}

func Info(format string, v ...any) {
logWithLevel(infoLogger, LevelDebug, format, v)
logWithLevel(infoFileLogger, LevelDebug, format, v)
}

func Waring(format string, v ...any) {
logWithLevel(warningLogger, LevelDebug, format, v)
logWithLevel(warningFileLogger, LevelDebug, format, v)
}

func Error(format string, v ...any) {
logWithLevel(errorLogger, LevelDebug, format, v)
logWithLevel(errorFileLogger, LevelDebug, format, v)
}

func Critical(format string, v ...any) {
logWithLevel(criticalLogger, LevelDebug, format, v)
logWithLevel(criticalFileLogger, LevelDebug, format, v)
}

func init() {
debugLogger = log.New(os.Stderr, "[DEBUG] ", flag)
infoLogger = log.New(os.Stderr, "[INFO] ", flag)
warningLogger = log.New(os.Stderr, "[WARNING] ", flag)
errorLogger = log.New(os.Stderr, "[ERROR] ", flag)
criticalLogger = log.New(os.Stderr, "[CRITICAL] ", flag)
}

func logWithLevel(logger *log.Logger, level int, format string, v []any) {
if logger != nil && logLevel >= level {
logger.Printf(format, v...)
}
}
阅读全文 »

记录 logging 简单用法。

constants.py

1
2
3
4
5
6
7
8
9
10
#!/usr/bin/env python
# coding=utf-8

import os
import platform

class FilePath:
HOME = os.environ['HOME'] if platform.system() == 'Linux' else os.environ['USERPROFILE']
CFG_DIR = f'{HOME}/.cfg'
LOG_PATH = f'{CFG_DIR}/log.txt'
阅读全文 »

记录 argparse 简单用法。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#!/usr/bin/env python
# coding=utf-8


import argparse


parser = argparse.ArgumentParser()
parser.add_argument('-n', '--name', metavar='<NAME>', required=True)
parser.add_argument('-a', '--age', metavar='<AGE>', required=True, type=int)
args = parser.parse_args()


if __name__ == '__main__':
print(args)
阅读全文 »

这里不讲 CI/CD 的概念,我们想要做到的,就是自动化编译、部署博客,把注意力都集中在写作上。

之前已经讲过 《【Hexo】Git 一键部署》,但那仅仅是一键部署。在部署之前,还需要在本地安装 Nodejs 环境,安装依赖包,然后编译,最后才能开始部署。当然,Nodejs 环境和依赖一台机器上安装一次就够了,以后只需编译就行,但如果需要在多台机器上写作,那么每台机器都要装环境、装依赖……

也还行,还比较便利,但还不够。

我们可以借助 CI/CD 工具,完成环境搭建、编译、部署等一系列工作,真正做到一键上传博客。

说到这里,我想到了 WordPress。

WordPress 很容易就可以做到一键上传博客,完全不用搞什么 CI/CD。

阅读全文 »

1
2
3
4
5
6
7
8
wget -O -  https://get.acme.sh | sh
. .bashrc
# 自动更新
acme.sh --upgrade --auto-upgrade
# 测试是否能成功获取
acme.sh --issue --test -d joking.vksir.zone -w /var/www/html --keylength ec-256
# 正式获取
acme.sh --issue -d joking.vksir.zone -w /var/www/html --keylength ec-256 --force
阅读全文 »

我是于菲,容貌俏丽的假小子,时常戴着一顶棒球帽,身穿夹克衫。

姐姐两年前死了,死在了林家大院。她是为了去寻找我们刘家的宝藏——没错,祖父去世时告诉我们,他姓刘,为了逃离文革制裁才隐姓埋名改成了“刘”;林家曾也是名门望族,家境殷实,他们刘家三兄弟分开隐居逃难前,将家里的资产埋藏在了刘家大院,后来刘家大院被林家买走,变成了林家大院,而资产,可能还在那里。

现在,公司举办一场《虚拟游戏》:七个人,两名凶手杀人,五位侦探找出凶手,胜者获得五万奖金。而这场杀人游戏将在虚拟世界进行,这个世界即是两年前的林家大院,公司号称虚拟世界的场景由历史现实 1:1 还原而来。虽然我不知道公司是怎么做到的,但这和我无关,我需要回到两年前,查询姐姐的死因,同时寻找祖父家的宝藏。

姐姐生前待我极好,曾经我并不是一个假小子,我也喜欢穿漂亮裙子,打扮得可可爱爱出门。但是姐姐走了,家里只剩下我一个,为了不让父母担心,我必须坚强起来,打扮阳刚一点,努力假装坚强。


阅读全文 »