Explorar o código

初始化项目

kobe6258 hai 8 meses
achega
96c92548cd

+ 23 - 0
.gitignore

@@ -0,0 +1,23 @@
+/*.exe
+/*.tmp
+/.idea
+/routers/.DS_Store
+/rdlucklog
+/etalogs
+/conf/*.conf
+/conf/*.json
+/binlog/*
+/*.pdf
+/eta_api.tar.gz
+/eta_api
+/static/searchKeywordCount.xlsx
+/static/images/*
+.DS_Store
+/doc/
+*.DS_Store
+/static/images/*.svg
+eta_api.exe
+eta_api.exe~
+/static/tmpFile/*
+etalogs/
+/.vscode

+ 75 - 0
common/client/http_client.go

@@ -0,0 +1,75 @@
+package client
+
+import (
+	"context"
+	"fmt"
+	"io/ioutil"
+	"log"
+	"net/http"
+	"time"
+)
+
+type HttpClient struct {
+	client     *http.Client
+	maxRetries int
+	retryDelay time.Duration
+}
+
+func GetInstance(timeout time.Duration, maxRetries int) *HttpClient {
+	return &HttpClient{
+		client:     &http.Client{Timeout: timeout},
+		maxRetries: maxRetries,
+	}
+}
+
+type RetryDelayFunc func(attempt int) time.Duration
+
+// DoWithRetry 发送带有重试机制的HTTP请求,允许用户自定义重试延迟逻辑
+func (hc *HttpClient) DoWithRetry(ctx context.Context, req *http.Request, retryDelayFunc RetryDelayFunc) (*http.Response, error) {
+	attempt := 0
+	for {
+		resp, err := hc.client.Do(req.WithContext(ctx))
+		if err != nil {
+			if attempt >= hc.maxRetries {
+				return nil, fmt.Errorf("请求失败: %w", err)
+			}
+			attempt++
+			delay := retryDelayFunc(attempt)
+			time.Sleep(delay)
+			continue
+		}
+		return resp, nil
+	}
+}
+func main() {
+	client := GetInstance(10*time.Second, 3) // 超时10秒,最多重试3次
+
+	// 自定义重试延迟逻辑
+	customRetryDelay := func(attempt int) time.Duration {
+		// 示例:首次重试立即进行,之后每次重试等待时间加倍
+		delay := time.Duration(attempt) * time.Second
+		if attempt > 0 {
+			delay *= 2
+		}
+		return delay
+	}
+
+	url := "http://example.com/api/data"
+	req, err := http.NewRequestWithContext(context.Background(), http.MethodGet, url, nil)
+	if err != nil {
+		log.Fatalf("创建请求失败: %v", err)
+	}
+
+	resp, err := client.DoWithRetry(req.Context(), req, customRetryDelay)
+	if err != nil {
+		log.Fatalf("%v,请求失败", err)
+	}
+	defer resp.Body.Close()
+
+	body, readErr := ioutil.ReadAll(resp.Body)
+	if readErr != nil {
+		log.Fatalf("解析应答失败: %v", readErr)
+	}
+
+	fmt.Printf("应答结果为: %s\n", body)
+}

+ 40 - 0
common/exception/panic_recover/panic_advice.go

@@ -0,0 +1,40 @@
+package panic_recover
+
+import (
+	"fmt"
+	"github.com/beego/beego/v2/core/logs"
+	"github.com/beego/beego/v2/server/web"
+	"github.com/beego/beego/v2/server/web/context"
+	"runtime"
+)
+
+func PanicAdvice(ctx *context.Context, conf *web.Config) {
+	if err := recover(); err != nil {
+		if err == web.ErrAbort {
+			return
+		}
+
+		stack := ""
+		msg := fmt.Sprintf("The request url is  %v", ctx.Input.URL())
+		stack += msg + "</br>"
+		logs.Critical(msg)
+		msg = fmt.Sprintf("The request data is %v", string(ctx.Input.RequestBody))
+		stack += msg + "</br>"
+		logs.Critical(msg)
+		msg = fmt.Sprintf("Handler crashed with error %v", err)
+		stack += msg + "</br>"
+		logs.Critical(msg)
+		for i := 1; ; i++ {
+			_, file, line, ok := runtime.Caller(i)
+			if !ok {
+				break
+			}
+			logs.Critical(fmt.Sprintf("%s:%d", file, line))
+			stack = stack + fmt.Sprintln(fmt.Sprintf("%s:%d</br>", file, line))
+		}
+		//go utils.SendEmail(utils.APP_NAME_CN+"崩了"+time.Now().Format("2006-01-02 15:04:05"), stack, utils.EmailSendToUsers)
+		//go alarm_msg.SendAlarmMsg(utils.APP_NAME_CN+"崩了"+time.Now().Format("2006-01-02 15:04:05")+"<br/>"+stack, 3)
+	}
+
+	return
+}

+ 20 - 0
common/redis/redis_client.go

@@ -0,0 +1,20 @@
+package redis
+
+import (
+	"context"
+	"time"
+)
+
+// redis接口
+type RedisClient interface {
+	GetString(key string) string
+	GetStringWithContext(ctx context.Context, key string) string
+	SetString(key string, val string, timeout time.Duration) error
+	SetStringWithContext(ctx context.Context, key string, val string, timeout time.Duration) error
+	Delete(key string) error
+	DeleteWithContext(ctx context.Context, key string) error
+	IsExist(key string) bool
+	IsExistWithContext(ctx context.Context, key string) bool
+	Do(commandName string, args ...interface{}) (reply interface{}, err error)
+	DoWithContext(ctx context.Context, commandName string, args ...interface{}) (reply interface{}, err error)
+}

+ 10 - 0
common/utils/string_utils.go

@@ -0,0 +1,10 @@
+package stringUtils
+
+import "strings"
+
+func IsEmptyOrNil(s string) bool {
+	return &s == nil || len(s) == 0
+}
+func IsBlank(s string) bool {
+	return strings.TrimSpace(s) == ""
+}

+ 112 - 0
component/cache/redis.go

@@ -0,0 +1,112 @@
+package cache
+
+import (
+	"context"
+	"github.com/go-redis/redis/v8"
+	"log"
+	"strings"
+	"time"
+	logger "wechat/component/log"
+	redisConfig "wechat/config"
+)
+
+func GetInstance(config string) (redisCache *RedisCache, err error) {
+	if config == "" {
+		log.Fatalf("创建redis失败")
+	}
+	//	redisCache = NewRedis(redisCommon.ParseFromStr(""))
+	return
+}
+
+// RedisCache
+// @Description: redis缓存
+type RedisCache struct {
+	redisTemplate redis.UniversalClient
+}
+
+// Get 获取一个值
+func (r *RedisCache) GetString(key string) string {
+	return r.GetStringWithContext(context.Background(), key)
+
+}
+func (r *RedisCache) GetStringWithContext(ctx context.Context, key string) (value string) {
+	value, _ = r.redisTemplate.Get(ctx, key).Result()
+	return
+}
+
+// SetContext 设置一个值
+func (r *RedisCache) SetString(key string, val string, timeout time.Duration) error {
+	return r.redisTemplate.SetEX(context.Background(), key, val, timeout).Err()
+}
+
+// SetContext 设置一个值
+func (r *RedisCache) SetStringWithContext(ctx context.Context, key string, val string, timeout time.Duration) error {
+	return r.redisTemplate.SetEX(ctx, key, val, timeout).Err()
+}
+
+// IsExist 判断key是否存在
+func (r *RedisCache) IsExist(key string) bool {
+	return r.IsExistWithContext(context.Background(), key)
+}
+
+// IsExistContext 判断key是否存在
+func (r *RedisCache) IsExistWithContext(ctx context.Context, key string) bool {
+	result, _ := r.redisTemplate.Exists(ctx, key).Result()
+	return result > 0
+}
+
+// Delete 删除
+func (r *RedisCache) Delete(key string) error {
+	return r.DeleteWithContext(context.Background(), key)
+}
+
+// DeleteContext 删除
+func (r *RedisCache) DeleteWithContext(ctx context.Context, key string) error {
+	return r.redisTemplate.Del(ctx, key).Err()
+}
+func (r *RedisCache) Do(commandName string, args ...interface{}) (reply interface{}, err error) {
+	return r.DoWithContext(context.Background(), commandName, args...)
+}
+
+func (r *RedisCache) DoWithContext(ctx context.Context, commandName string, args ...interface{}) (reply interface{}, err error) {
+	newArgs := []interface{}{commandName}
+	newArgs = append(newArgs, args...)
+	return r.redisTemplate.Do(ctx, newArgs...).Result()
+}
+
+func NewRedis(opts redisConfig.RedisOpts) *RedisCache {
+	if &opts == nil || opts.Host == "" {
+		log.Fatalf("redis 连接失败")
+	}
+	redisTemplate := redis.NewUniversalClient(&redis.UniversalOptions{
+		Addrs:        strings.Split(opts.Host, ";"),
+		DB:           opts.Database,
+		Password:     opts.Password,
+		IdleTimeout:  time.Second * time.Duration(opts.IdleTimeout),
+		MinIdleConns: opts.MaxIdle,
+	})
+	return &RedisCache{redisTemplate: redisTemplate}
+}
+
+func init() {
+	config := redisConfig.GetConfig("redis")
+	// 检查是否成功获取到RedisConfig实例
+	redisInstance, ok := config.(*redisConfig.RedisConfig)
+	if !ok {
+		// 处理错误情况,比如记录日志或返回错误信息
+		logger.Info("Failed to get RedisConfig instance")
+		return // 或者采取其他适当的错误处理措施
+	}
+
+	// 获取Redis配置选项,这里假设GetConfig方法返回(*RedisOpts, error),需要检查错误
+	opts := redisInstance.GetConfig().(redisConfig.RedisOpts)
+
+	// 检查Host是否已设置,然后初始化或执行相应操作
+	if opts.Host != "" {
+		logger.Info("初始化redis")
+		// 这里可以添加初始化Redis的逻辑
+		NewRedis(opts)
+	} else {
+		logger.Info("Redis configuration is incomplete: Host is missing")
+	}
+}

+ 6 - 0
component/component.go

@@ -0,0 +1,6 @@
+package component
+
+import (
+	_ "wechat/component/cache"
+	_ "wechat/component/log"
+)

+ 177 - 0
component/log/log_plugin.go

@@ -0,0 +1,177 @@
+package logger
+
+import (
+	"encoding/json"
+	"fmt"
+	"github.com/beego/beego/v2/core/logs"
+	"log"
+	"os"
+	"path"
+	stringUtils "wechat/common/utils"
+)
+
+const (
+	DefalutLogFilePath = "./etalogs"
+	LogChannelLen      = 10000
+)
+
+var (
+	loggerHandler *WechatLogger
+)
+
+type logger struct {
+	*logs.BeeLogger
+	filter string
+}
+type WechatLogger struct {
+	logs []*logger
+}
+
+func Info(msg string) {
+	for _, appender := range loggerHandler.logs {
+		if appender.GetLevel() > logs.LevelInfo {
+			appender.Info(msg)
+		}
+
+	}
+}
+
+func Error(msg string) {
+	for _, logger := range loggerHandler.logs {
+		if logger.GetLevel() > logs.LevelError {
+			logger.Error(msg)
+		}
+	}
+}
+
+func init() {
+	var logCfg logConfig
+	configFile, err := os.ReadFile("conf/log/log_config.json")
+	if err != nil {
+		log.Fatalf("Failed to read log config: %v", err)
+	}
+	err = json.Unmarshal(configFile, &logCfg)
+	if err != nil {
+		log.Fatalf("Failed to parse log config: %v", err)
+	}
+	initLogger(logCfg)
+}
+
+var levelTrans = map[string]int{
+	"emergency": logs.LevelEmergency,
+	"alert":     logs.LevelAlert,
+	"critical":  logs.LevelCritical,
+	"error":     logs.LevelError,
+	"warn":      logs.LevelWarning,
+	"notice":    logs.LevelNotice,
+	"info":      logs.LevelInformational,
+	"debug":     logs.LevelDebug,
+}
+
+var terminalType = map[string]string{
+	"console": logs.AdapterConsole,
+	"file":    logs.AdapterFile,
+}
+
+func initLogger(logCfg logConfig) {
+	if loggerHandler == nil {
+		loggerHandler = new(WechatLogger)
+	}
+	if stringUtils.IsEmptyOrNil(logCfg.FilePath) {
+		logCfg.FilePath = DefalutLogFilePath
+	}
+	for _, appender := range logCfg.Appenders {
+		terminalType, ok := terminalType[appender.Type]
+		if !ok {
+			fmt.Println("初始化日志执行器失败:{%s},终端类型不支持{type:%s}", appender.FileName, appender.Type)
+			continue
+		}
+		var beeLogger *logs.BeeLogger
+		if terminalType == logs.AdapterConsole {
+			beeLogger = logs.NewLogger(LogChannelLen)
+			err := beeLogger.SetLogger(logs.AdapterConsole)
+			if err != nil {
+				fmt.Println("创建日志执行器失败:{%s} %v", appender.FileName, err)
+				continue
+			}
+		} else {
+			logFile := appender.FileName
+			os.MkdirAll(logCfg.FilePath, os.ModePerm)
+			// 打开文件
+			appender.FileName = path.Join(logCfg.FilePath, logFile)
+			logProps, err := ConvertAppenderToLog(&appender)
+			if err != nil {
+				fmt.Println("初始化日志执行器失败:{%s} %v", appender.FileName, err)
+				continue
+			}
+			b, _ := json.Marshal(logProps)
+			beeLogger = logs.NewLogger(LogChannelLen)
+			err = beeLogger.SetLogger(logs.AdapterFile, string(b))
+			if err != nil {
+				fmt.Println("设置日志执行器失败:{%s} %v", appender.FileName, err)
+				continue
+			}
+			beeLogger.EnableFuncCallDepth(true)
+		}
+		loggerHandler.logs = append(loggerHandler.logs, &logger{BeeLogger: beeLogger,
+			filter: appender.Filter})
+	}
+}
+
+func initFileLogger() {
+
+}
+
+// ConvertAppenderToLog 将 appender 结构体转换为 log 结构体
+func ConvertAppenderToLog(a *appender) (*logProps, error) {
+	lvl, ok := levelTrans[a.Level]
+	if !ok {
+		return nil, fmt.Errorf("unknown log level: %s", a.Level)
+	}
+
+	return &logProps{
+		Prefix:   a.Prefix,
+		FileName: a.FileName,
+		MaxLines: a.MaxLines,
+		MaxSize:  a.MaxSize,
+		Daily:    a.Daily,
+		MaxDays:  a.MaxDays,
+		Rotate:   a.Rotate,
+		Level:    lvl,
+		Color:    a.Color,
+		//Perm:     a.Perm,
+	}, nil
+}
+
+type logConfig struct {
+	FilePath  string     `json:"filepath" description:"日志路径"`
+	Appenders []appender `json:"appenders" description:"日志记录"`
+}
+
+type appender struct {
+	Filter   string `json:"filter"`
+	Prefix   string `json:"perfix" description:"日志前缀"`
+	Type     string `json:"type" description:"终端类型"`
+	FileName string `json:"filename" description:"保存的文件名"`
+	MaxLines int    `json:"maxlines"  description:"每个文件保存的最大行数,默认值 1000000"`
+	MaxSize  int    `json:"maxsize" description:"每个文件保存的最大尺寸,默认值是 1 << 28, //256 MB"`
+	Daily    bool   `json:"daily" description:"是否按照每天 logrotate,默认是 true"`
+	MaxDays  int    `json:"maxdays" description:"文件最多保存多少天,默认保存 7 天"`
+	Rotate   bool   `json:"rotate" description:"是否开启 logrotate,默认是 true"`
+	Level    string `json:"level" description:"日志保存的时候的级别,默认是 Trace 级别"`
+	Color    bool   `json:"color" description:"日志是否输出颜色"`
+	//Perm     string `json:"perm" description:"日志文件权限"`
+}
+
+type logProps struct {
+	Prefix   string `json:"perfix" description:"日志前缀"`
+	FileName string `json:"filename" description:"保存的文件名"`
+	MaxLines int    `json:"maxlines"  description:"每个文件保存的最大行数,默认值 1000000"`
+	MaxSize  int    `json:"maxsize" description:"每个文件保存的最大尺寸,默认值是 1 << 28, //256 MB"`
+	Daily    bool   `json:"daily" description:"是否按照每天 logrotate,默认是 true"`
+	MaxDays  int    `json:"maxdays" description:"文件最多保存多少天,默认保存 7 天"`
+	Rotate   bool   `json:"rotate" description:"是否开启 logrotate,默认是 true"`
+	Level    int    `json:"level" description:"日志保存的时候的级别,默认是 Trace 级别"`
+	Color    bool   `json:"color" description:"日志是否输出颜色"`
+	//Perm     string `json:"perm" description:"日志文件权限"`
+}

+ 15 - 0
component/wechat/wechat_client.go

@@ -0,0 +1,15 @@
+package wechat
+
+import (
+	"github.com/medivhzhan/weapp/v3"
+)
+
+type WechatClient struct {
+	sdk *weapp.Client
+}
+
+func GetInstance() *WechatClient {
+	return &WechatClient{
+		sdk: weapp.NewClient("", ""),
+	}
+}

+ 45 - 0
conf/log/log_config.json

@@ -0,0 +1,45 @@
+{
+  "filepath": "",
+  "appenders": [
+    {
+      "type": "console",
+      "rotate": true,
+      "level": "info",
+      "color": true
+    },
+    {
+      "type": "file",
+      "filename": "file/error.log",
+      "maxlines": 10000,
+      "maxsize": 100,
+      "daily": true,
+      "maxdays": 7,
+      "rotate": true,
+      "level": "error",
+      "color": true
+    },
+    {
+      "type": "file",
+      "filename": "file/info.log",
+      "maxlines": 50000,
+      "maxsize": 200,
+      "daily": true,
+      "maxdays": 30,
+      "rotate": true,
+      "level": "info",
+      "color": true
+    },
+    {
+      "filter": "coin,orm....*",
+      "type": "file",
+      "filename": "db/db.log",
+      "maxlines": 50000,
+      "maxsize": 200,
+      "daily": false,
+      "maxdays": 30,
+      "rotate": true,
+      "level": "info",
+      "color": true
+    }
+  ]
+}

+ 53 - 0
config/config.go

@@ -0,0 +1,53 @@
+package config
+
+import (
+	"fmt"
+	"github.com/beego/beego/v2/core/logs"
+	"github.com/beego/beego/v2/server/web"
+)
+
+const (
+	SPLIT = "."
+)
+
+type Config interface {
+	GetConfig() interface{}
+	InitConfig()
+}
+
+type BaseConfig struct {
+	prefix string
+	config map[string]string
+}
+
+func (b *BaseConfig) GetString(key string) string {
+	value, err := web.AppConfig.String(fmt.Sprintf("%s%s%s", b.prefix, SPLIT, key))
+	if err != nil {
+		return ""
+	}
+	return value
+}
+
+type Instance func() Config
+
+var configs = make(map[string]Instance)
+
+func GetConfig(name string) (config Config) {
+	instanceFunc, ok := configs[name]
+	if !ok {
+		logs.Error("cache: unknown adapter name %q (forgot to import?)", name)
+		return nil
+	}
+	config = instanceFunc()
+	config.InitConfig()
+	return config
+}
+func Register(name string, adapter Instance) {
+	if adapter == nil {
+		panic("cache: Register adapter is nil")
+	}
+	if _, ok := configs[name]; ok {
+		panic("cache: Register called twice for adapter " + name)
+	}
+	configs[name] = adapter
+}

+ 46 - 0
config/redis_config.go

@@ -0,0 +1,46 @@
+package config
+
+// RedisOpts redis 连接属性
+type RedisOpts struct {
+	Host        string
+	Username    string
+	Password    string
+	Database    int
+	MaxIdle     int
+	MaxActive   int
+	IdleTimeout int
+	DB          int
+	MaxRetries  int
+}
+type RedisConfig struct {
+	BaseConfig
+	opts RedisOpts
+}
+
+func (r *RedisConfig) GetConfig() interface{} {
+	return r.opts
+}
+func (r *RedisConfig) InitConfig() {
+	opts := RedisOpts{
+		Host:        r.GetString("host"),
+		Username:    "",
+		Password:    "",
+		Database:    0,
+		MaxIdle:     10,
+		MaxActive:   100,
+		IdleTimeout: 10,
+		DB:          0,
+		MaxRetries:  3,
+	}
+	r.opts = opts
+}
+func NewRedis() Config {
+	return &RedisConfig{
+		BaseConfig: BaseConfig{prefix: "redis"},
+		opts:       RedisOpts{},
+	}
+}
+
+func init() {
+	Register("redis", NewRedis)
+}

+ 40 - 0
controllers/base_controller.go

@@ -0,0 +1,40 @@
+package controllers
+
+import "github.com/beego/beego/v2/server/web"
+
+type BaseController struct {
+	web.Controller
+}
+
+type RetData struct {
+	ErrMsg  string      `json:"errMsg"`
+	ErrCode string      `json:"errCode"`
+	Data    interface{} `json:"data"`
+}
+
+func (b *BaseController) FailResponse() {
+
+}
+
+/*
+* Ajax	返回Json数据
+ */
+func (b *BaseController) JsonResult(status int, errCode int, errMsg string, data ...interface{}) {
+	retData := RetData{ErrMsg: "",
+		ErrCode: "0",
+		Data:    nil}
+
+	if len(data) > 0 && data[0] != nil {
+		retData.Data = data[0]
+	}
+	b.Ctx.Output.SetStatus(status)
+	b.Data["json"] = retData
+	err := b.ServeJSON()
+	if err != nil {
+		return
+	}
+}
+
+func (b *BaseController) Forbidden() {
+
+}

+ 22 - 0
controllers/user.go

@@ -0,0 +1,22 @@
+package controllers
+
+import (
+	"wechat/models"
+
+	beego "github.com/beego/beego/v2/server/web"
+)
+
+// Operations about Users
+type UserController struct {
+	beego.Controller
+}
+
+// @Title GetAll
+// @Description get all Users
+// @Success 200 {object} models.User
+// @router / [get]
+func (u *UserController) GetAll() {
+	users := models.GetAllUsers()
+	u.Data["json"] = users
+	u.ServeJSON()
+}

+ 32 - 0
go.mod

@@ -0,0 +1,32 @@
+module wechat
+
+go 1.21
+
+require (
+	github.com/beego/beego/v2 v2.2.2
+	github.com/go-redis/redis/v8 v8.11.5
+	github.com/medivhzhan/weapp/v3 v3.8.1
+)
+
+require (
+	github.com/beorn7/perks v1.0.1 // indirect
+	github.com/cespare/xxhash/v2 v2.2.0 // indirect
+	github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect
+	github.com/fatih/color v1.16.0 // indirect
+	github.com/hashicorp/golang-lru v0.5.4 // indirect
+	github.com/kr/text v0.2.0 // indirect
+	github.com/mattn/go-colorable v0.1.13 // indirect
+	github.com/mattn/go-isatty v0.0.20 // indirect
+	github.com/mitchellh/mapstructure v1.5.0 // indirect
+	github.com/prometheus/client_golang v1.19.0 // indirect
+	github.com/prometheus/client_model v0.5.0 // indirect
+	github.com/prometheus/common v0.48.0 // indirect
+	github.com/prometheus/procfs v0.12.0 // indirect
+	github.com/shiena/ansicolor v0.0.0-20200904210342-c7312218db18 // indirect
+	golang.org/x/crypto v0.23.0 // indirect
+	golang.org/x/net v0.23.0 // indirect
+	golang.org/x/sys v0.20.0 // indirect
+	golang.org/x/text v0.15.0 // indirect
+	google.golang.org/protobuf v1.34.1 // indirect
+	gopkg.in/yaml.v3 v3.0.1 // indirect
+)

+ 79 - 0
go.sum

@@ -0,0 +1,79 @@
+github.com/beego/beego/v2 v2.2.2 h1:h6TNybAiMPXx9RXxK71Wz+JkPE7rpsL+ctjSZpv5yB0=
+github.com/beego/beego/v2 v2.2.2/go.mod h1:A3BC73uulBnqW3O1uBEN7q+oykprxipZTYRdZtEuKyY=
+github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
+github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
+github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44=
+github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
+github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
+github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
+github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
+github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78=
+github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc=
+github.com/elazarl/go-bindata-assetfs v1.0.1 h1:m0kkaHRKEu7tUIUFVwhGGGYClXvyl4RE03qmvRTNfbw=
+github.com/elazarl/go-bindata-assetfs v1.0.1/go.mod h1:v+YaWX3bdea5J/mo8dSETolEo7R71Vk1u8bnjau5yw4=
+github.com/fatih/color v1.16.0 h1:zmkK9Ngbjj+K0yRhTVONQh1p/HknKYSlNT+vZCzyokM=
+github.com/fatih/color v1.16.0/go.mod h1:fL2Sau1YI5c0pdGEVCbKQbLXB6edEj1ZgiY4NijnWvE=
+github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4=
+github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
+github.com/go-redis/redis/v8 v8.11.5 h1:AcZZR7igkdvfVmQTPnu9WE37LRrO/YrBH5zWyjDC0oI=
+github.com/go-redis/redis/v8 v8.11.5/go.mod h1:gREzHqY1hg6oD9ngVRbLStwAWKhA0FEgq8Jd4h5lpwo=
+github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
+github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
+github.com/hashicorp/golang-lru v0.5.4 h1:YDjusn29QI/Das2iO9M0BHnIbxPeyuCHsjMW+lJfyTc=
+github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4=
+github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
+github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
+github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
+github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
+github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
+github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
+github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
+github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
+github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
+github.com/medivhzhan/weapp/v3 v3.8.1 h1:ZRYcEAU9mz73hI/X7+/qVj2ik+TPEQaI7PuiD2alF8E=
+github.com/medivhzhan/weapp/v3 v3.8.1/go.mod h1:xE4GrGv/3/eR2+GSO8L8wCmvbf261aBHJla/QmoVGQM=
+github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY=
+github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
+github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE=
+github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU=
+github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE=
+github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU=
+github.com/onsi/gomega v1.18.1 h1:M1GfJqGRrBrrGGsbxzV5dqM2U2ApXefZCQpkukxYRLE=
+github.com/onsi/gomega v1.18.1/go.mod h1:0q+aL8jAiMXy9hbwj2mr5GziHiwhAIQpFmmtT5hitRs=
+github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
+github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
+github.com/prometheus/client_golang v1.19.0 h1:ygXvpU1AoN1MhdzckN+PyD9QJOSD4x7kmXYlnfbA6JU=
+github.com/prometheus/client_golang v1.19.0/go.mod h1:ZRM9uEAypZakd+q/x7+gmsvXdURP+DABIEIjnmDdp+k=
+github.com/prometheus/client_model v0.5.0 h1:VQw1hfvPvk3Uv6Qf29VrPF32JB6rtbgI6cYPYQjL0Qw=
+github.com/prometheus/client_model v0.5.0/go.mod h1:dTiFglRmd66nLR9Pv9f0mZi7B7fk5Pm3gvsjB5tr+kI=
+github.com/prometheus/common v0.48.0 h1:QO8U2CdOzSn1BBsmXJXduaaW+dY/5QLjfB8svtSzKKE=
+github.com/prometheus/common v0.48.0/go.mod h1:0/KsvlIEfPQCQ5I2iNSAWKPZziNCvRs5EC6ILDTlAPc=
+github.com/prometheus/procfs v0.12.0 h1:jluTpSng7V9hY0O2R9DzzJHYb2xULk9VTR1V1R/k6Bo=
+github.com/prometheus/procfs v0.12.0/go.mod h1:pcuDEFsWDnvcgNzo4EEweacyhjeA9Zk3cnaOZAZEfOo=
+github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ=
+github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog=
+github.com/shiena/ansicolor v0.0.0-20200904210342-c7312218db18 h1:DAYUYH5869yV94zvCES9F51oYtN5oGlwjxJJz7ZCnik=
+github.com/shiena/ansicolor v0.0.0-20200904210342-c7312218db18/go.mod h1:nkxAfR/5quYxwPZhyDxgasBMnRtBZd0FCEpawpjMUFg=
+github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
+github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
+golang.org/x/crypto v0.23.0 h1:dIJU/v2J8Mdglj/8rJ6UUOM3Zc9zLZxVZwwxMooUSAI=
+golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8=
+golang.org/x/net v0.23.0 h1:7EYJ93RZ9vYSZAIb2x3lnuvqO5zneoD6IvWjuhfxjTs=
+golang.org/x/net v0.23.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg=
+golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.20.0 h1:Od9JTbYCk261bKm4M/mw7AklTlFYIa0bIp9BgSm1S8Y=
+golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
+golang.org/x/text v0.15.0 h1:h1V/4gjBv8v9cjcR6+AR5+/cIYK5N/WAgiv4xlsEtAk=
+golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
+google.golang.org/protobuf v1.34.1 h1:9ddQBjfCyZPOHPUiPxpYESBLc+T8P3E+Vo4IbKZgFWg=
+google.golang.org/protobuf v1.34.1/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos=
+gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
+gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
+gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
+gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=
+gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
+gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
+gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
+gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
+gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=

+ 22 - 0
main.go

@@ -0,0 +1,22 @@
+package main
+
+import (
+	"github.com/beego/beego/v2/server/web"
+	"wechat/common/exception/panic_recover"
+	_ "wechat/component"
+	logger "wechat/component/log"
+	"wechat/middleware"
+	_ "wechat/routers"
+)
+
+func main() {
+	if web.BConfig.RunMode == "dev" {
+		web.BConfig.WebConfig.DirectoryIndex = true
+		web.BConfig.WebConfig.StaticDir["/swagger"] = "swagger"
+	}
+	logger.Info("初始化成功")
+	//增加授权拦截
+	web.InsertFilter("*", web.BeforeRouter, middleware.AuthMiddleware())
+	web.BConfig.RecoverFunc = panic_recover.PanicAdvice
+	web.Run()
+}

+ 24 - 0
middleware/auth_middleware.go

@@ -0,0 +1,24 @@
+package middleware
+
+import (
+	"github.com/beego/beego/v2/core/logs"
+	"github.com/beego/beego/v2/server/web"
+	"github.com/beego/beego/v2/server/web/context"
+	"net/http"
+)
+
+const (
+	UNAUTHORIZED = "未授权"
+	FORBIDDEN    = "禁止访问"
+	NOTFOUND     = "未找到"
+)
+
+func AuthMiddleware() web.FilterFunc {
+	return func(ctx *context.Context) {
+		auth := ctx.Input.Header("author")
+		if auth == "" {
+			logs.Error("author is empty")
+			ctx.Abort(http.StatusForbidden, UNAUTHORIZED)
+		}
+	}
+}

+ 86 - 0
models/user.go

@@ -0,0 +1,86 @@
+package models
+
+import (
+	"errors"
+	"strconv"
+	"time"
+)
+
+var (
+	UserList map[string]*User
+)
+
+func init() {
+	UserList = make(map[string]*User)
+	u := User{"user_11111", "astaxie", "11111", Profile{"male", 20, "Singapore", "astaxie@gmail.com"}}
+	UserList["user_11111"] = &u
+}
+
+type User struct {
+	Id       string
+	Username string
+	Password string
+	Profile  Profile
+}
+
+type Profile struct {
+	Gender  string
+	Age     int
+	Address string
+	Email   string
+}
+
+func AddUser(u User) string {
+	u.Id = "user_" + strconv.FormatInt(time.Now().UnixNano(), 10)
+	UserList[u.Id] = &u
+	return u.Id
+}
+
+func GetUser(uid string) (u *User, err error) {
+	if u, ok := UserList[uid]; ok {
+		return u, nil
+	}
+	return nil, errors.New("User not exists")
+}
+
+func GetAllUsers() map[string]*User {
+	return UserList
+}
+
+func UpdateUser(uid string, uu *User) (a *User, err error) {
+	if u, ok := UserList[uid]; ok {
+		if uu.Username != "" {
+			u.Username = uu.Username
+		}
+		if uu.Password != "" {
+			u.Password = uu.Password
+		}
+		if uu.Profile.Age != 0 {
+			u.Profile.Age = uu.Profile.Age
+		}
+		if uu.Profile.Address != "" {
+			u.Profile.Address = uu.Profile.Address
+		}
+		if uu.Profile.Gender != "" {
+			u.Profile.Gender = uu.Profile.Gender
+		}
+		if uu.Profile.Email != "" {
+			u.Profile.Email = uu.Profile.Email
+		}
+		return u, nil
+	}
+	return nil, errors.New("User Not Exist")
+}
+
+func Login(username, password string) bool {
+	for _, u := range UserList {
+		if u.Username == username && u.Password == password {
+			return true
+		}
+	}
+	return false
+}
+
+func DeleteUser(uid string) {
+	delete(UserList, uid)
+}

+ 28 - 0
routers/commentsRouter.go

@@ -0,0 +1,28 @@
+package routers
+
+import (
+	beego "github.com/beego/beego/v2/server/web"
+	"github.com/beego/beego/v2/server/web/context/param"
+)
+
+func init() {
+
+    beego.GlobalControllerRouter["wechat/controllers/app:WechatController"] = append(beego.GlobalControllerRouter["wechat/controllers/app:WechatController"],
+        beego.ControllerComments{
+            Method: "GetUserInfo",
+            Router: `/getUserInfo`,
+            AllowHTTPMethods: []string{"get"},
+            MethodParams: param.Make(),
+            Filters: nil,
+            Params: nil})
+
+    beego.GlobalControllerRouter["wechat/controllers:UserController"] = append(beego.GlobalControllerRouter["wechat/controllers:UserController"],
+        beego.ControllerComments{
+            Method: "GetAll",
+            Router: `/`,
+            AllowHTTPMethods: []string{"get"},
+            MethodParams: param.Make(),
+            Filters: nil,
+            Params: nil})
+
+}

+ 17 - 0
routers/router.go

@@ -0,0 +1,17 @@
+package routers
+
+import (
+	beego "github.com/beego/beego/v2/server/web"
+	"wechat/controllers"
+)
+
+func init() {
+	ns := beego.NewNamespace("/v1",
+		beego.NSNamespace("/user",
+			beego.NSInclude(
+				&controllers.UserController{},
+			),
+		),
+	)
+	beego.AddNamespace(ns)
+}