✨ 完善基础架构,新增部分问题接口
This commit is contained in:
		
							
								
								
									
										33
									
								
								api/problem.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										33
									
								
								api/problem.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,33 @@
 | 
			
		||||
package api
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"github.com/gin-gonic/gin"
 | 
			
		||||
	"online_code/core"
 | 
			
		||||
	"online_code/models/param"
 | 
			
		||||
	"online_code/repository"
 | 
			
		||||
	"online_code/utils"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type problemApi struct{}
 | 
			
		||||
 | 
			
		||||
func ProblemApi() *problemApi {
 | 
			
		||||
	return &problemApi{}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (problemApi) GetProbleList(ctx *gin.Context) {
 | 
			
		||||
	var p param.GetProblemList
 | 
			
		||||
	if err := ctx.ShouldBind(&p); err != nil {
 | 
			
		||||
		core.R(ctx).FailWithMessage("参数错误: " + err.Error())
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	records, count, err := repository.ProblemService().GetList(p)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		core.R(ctx).FailWithMessage("获取题目列表失败: " + err.Error())
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
	// 计算总页码
 | 
			
		||||
	totalPage := utils.GenTotalPage(count, p.Size)
 | 
			
		||||
	// 返回结果
 | 
			
		||||
	core.R(ctx).OkWithData(core.PageData{Current: p.Current, Size: p.Size, Total: count, TotalPage: totalPage, Records: records})
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										19
									
								
								config.yaml
									
									
									
									
									
								
							
							
						
						
									
										19
									
								
								config.yaml
									
									
									
									
									
								
							@@ -0,0 +1,19 @@
 | 
			
		||||
app:
 | 
			
		||||
  port: 8083
 | 
			
		||||
  name: online_code
 | 
			
		||||
  version: v1
 | 
			
		||||
  prefix: /api/v1
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
mysql:
 | 
			
		||||
  host: 127.0.0.1
 | 
			
		||||
  port: 3306
 | 
			
		||||
  user: root
 | 
			
		||||
  password: root
 | 
			
		||||
  db: online_code
 | 
			
		||||
 | 
			
		||||
redis:
 | 
			
		||||
  host: 127.0.0.1
 | 
			
		||||
  port: 6379
 | 
			
		||||
  password: loser123
 | 
			
		||||
  db: 0
 | 
			
		||||
							
								
								
									
										6
									
								
								define/define.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								define/define.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,6 @@
 | 
			
		||||
package define
 | 
			
		||||
 | 
			
		||||
var (
 | 
			
		||||
	DefaultCurrent = "1"
 | 
			
		||||
	DefaultSize    = "10"
 | 
			
		||||
)
 | 
			
		||||
							
								
								
									
										5
									
								
								go.mod
									
									
									
									
									
								
							
							
						
						
									
										5
									
								
								go.mod
									
									
									
									
									
								
							@@ -5,13 +5,14 @@ go 1.18
 | 
			
		||||
require (
 | 
			
		||||
	git.echol.cn/loser/logger v1.0.14
 | 
			
		||||
	git.echol.cn/loser/nacos-viper-remote v0.4.1-0.20220525104600-e38430672884
 | 
			
		||||
	gitee.ltd/lxh/logger v1.0.14
 | 
			
		||||
	github.com/caarlos0/env/v6 v6.9.2
 | 
			
		||||
	github.com/fsnotify/fsnotify v1.5.1
 | 
			
		||||
	github.com/gin-gonic/gin v1.7.7
 | 
			
		||||
	github.com/go-redis/redis/v8 v8.11.5
 | 
			
		||||
	github.com/google/uuid v1.1.2
 | 
			
		||||
	github.com/spf13/viper v1.10.1
 | 
			
		||||
	golang.org/x/crypto v0.0.0-20220214200702-86341886e292
 | 
			
		||||
	golang.org/x/sync v0.0.0-20210220032951-036812b2e83c
 | 
			
		||||
	gorm.io/driver/mysql v1.3.2
 | 
			
		||||
	gorm.io/gorm v1.23.5
 | 
			
		||||
)
 | 
			
		||||
@@ -19,6 +20,7 @@ require (
 | 
			
		||||
require (
 | 
			
		||||
	cloud.google.com/go v0.99.0 // indirect
 | 
			
		||||
	cloud.google.com/go/firestore v1.6.1 // indirect
 | 
			
		||||
	gitee.ltd/lxh/logger v1.0.14 // indirect
 | 
			
		||||
	github.com/aliyun/alibaba-cloud-sdk-go v1.61.18 // indirect
 | 
			
		||||
	github.com/armon/go-metrics v0.3.10 // indirect
 | 
			
		||||
	github.com/beorn7/perks v1.0.1 // indirect
 | 
			
		||||
@@ -96,7 +98,6 @@ require (
 | 
			
		||||
	go.uber.org/atomic v1.9.0 // indirect
 | 
			
		||||
	go.uber.org/multierr v1.8.0 // indirect
 | 
			
		||||
	go.uber.org/zap v1.21.0 // indirect
 | 
			
		||||
	golang.org/x/crypto v0.0.0-20210915214749-c084706c2272 // indirect
 | 
			
		||||
	golang.org/x/net v0.0.0-20220517181318-183a9ca12b87 // indirect
 | 
			
		||||
	golang.org/x/oauth2 v0.0.0-20220411215720-9780585627b5 // indirect
 | 
			
		||||
	golang.org/x/sys v0.0.0-20220517195934-5e4e11fc645e // indirect
 | 
			
		||||
 
 | 
			
		||||
@@ -9,7 +9,12 @@ import (
 | 
			
		||||
// 初始化数据库表
 | 
			
		||||
func databaseTable() {
 | 
			
		||||
	dbs := []any{
 | 
			
		||||
		new(entity.User), // 管理员用户
 | 
			
		||||
		new(entity.User),
 | 
			
		||||
		new(entity.Category),
 | 
			
		||||
		new(entity.Problem),
 | 
			
		||||
		new(entity.ProblemCategory),
 | 
			
		||||
		new(entity.Submit),
 | 
			
		||||
		new(entity.TestCase),
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if err := client.MySQL.AutoMigrate(dbs...); err != nil {
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										50
									
								
								main.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										50
									
								
								main.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,50 @@
 | 
			
		||||
package main
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"git.echol.cn/loser/logger/log"
 | 
			
		||||
	"github.com/gin-gonic/gin"
 | 
			
		||||
	"golang.org/x/sync/errgroup"
 | 
			
		||||
	"net/http"
 | 
			
		||||
	"online_code/config"
 | 
			
		||||
	"online_code/core"
 | 
			
		||||
	"online_code/route"
 | 
			
		||||
	"time"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
var g errgroup.Group
 | 
			
		||||
 | 
			
		||||
// 启动入口
 | 
			
		||||
func main() {
 | 
			
		||||
	// 强制日志颜色化
 | 
			
		||||
	gin.ForceConsoleColor()
 | 
			
		||||
	app := &http.Server{
 | 
			
		||||
		Addr:         fmt.Sprintf(":%d", config.Scd.Api.Port),
 | 
			
		||||
		Handler:      api(),
 | 
			
		||||
		ReadTimeout:  5 * time.Second,
 | 
			
		||||
		WriteTimeout: 1 * time.Minute,
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// 启动项目
 | 
			
		||||
	g.Go(func() error {
 | 
			
		||||
		return app.ListenAndServe()
 | 
			
		||||
	})
 | 
			
		||||
	if err := g.Wait(); err != nil {
 | 
			
		||||
		log.Panicf("启动失败,错误信息:%s", err.Error())
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// 生成接口服务
 | 
			
		||||
func api() http.Handler {
 | 
			
		||||
	app := gin.New()
 | 
			
		||||
	app.Use(gin.Recovery())
 | 
			
		||||
	// 开启自定义请求方式不允许处理函数
 | 
			
		||||
	app.HandleMethodNotAllowed = true
 | 
			
		||||
	// 处理请求方式不对
 | 
			
		||||
	app.NoMethod(core.NoMethodHandler())
 | 
			
		||||
	// 404返回数据
 | 
			
		||||
	app.NoRoute(core.NoRouteHandler())
 | 
			
		||||
	// 初始化路由
 | 
			
		||||
	route.InitRoute(app.Group(config.Scd.Api.Prefix))
 | 
			
		||||
	return app
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										18
									
								
								models/cache/user.go
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										18
									
								
								models/cache/user.go
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,18 @@
 | 
			
		||||
package cache
 | 
			
		||||
 | 
			
		||||
import "encoding/json"
 | 
			
		||||
 | 
			
		||||
// UserInfo 登录用的用户信息结构体
 | 
			
		||||
type UserInfo struct {
 | 
			
		||||
	UserType string `json:"userType"` // 用户类型
 | 
			
		||||
	UserId   string `json:"userId"`   // 用户Id
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// String 实现Stringer接口
 | 
			
		||||
func (i UserInfo) String() (string, error) {
 | 
			
		||||
	b, err := json.Marshal(i)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return "", err
 | 
			
		||||
	}
 | 
			
		||||
	return string(b), nil
 | 
			
		||||
}
 | 
			
		||||
@@ -4,7 +4,7 @@ import (
 | 
			
		||||
	"online_code/common/types"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// ProblemCategory 问题分类表
 | 
			
		||||
// ProblemCategory 问题分类关联表
 | 
			
		||||
type ProblemCategory struct {
 | 
			
		||||
	types.BaseDbModel
 | 
			
		||||
	ProblemId     uint      `json:"problem_id" gorm:"column:problem_id;type:int(11);comment:'问题的ID'" `                // 问题的ID
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										7
									
								
								models/param/base.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								models/param/base.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,7 @@
 | 
			
		||||
package param
 | 
			
		||||
 | 
			
		||||
// 分页通用参数
 | 
			
		||||
type page struct {
 | 
			
		||||
	Current int `json:"current" form:"current" binding:"required"` // 页码
 | 
			
		||||
	Size    int `json:"size" form:"size" binding:"required"`       // 每页数量
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										6
									
								
								models/param/problem.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								models/param/problem.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,6 @@
 | 
			
		||||
package param
 | 
			
		||||
 | 
			
		||||
type GetProblemList struct {
 | 
			
		||||
	page
 | 
			
		||||
	Keyword string `json:"keyword" form:"keyword"` // 问题关键字
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										19
									
								
								repository/base.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										19
									
								
								repository/base.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,19 @@
 | 
			
		||||
package repository
 | 
			
		||||
 | 
			
		||||
import "gorm.io/gorm"
 | 
			
		||||
 | 
			
		||||
// 分页组件
 | 
			
		||||
func page(current, size int) func(db *gorm.DB) *gorm.DB {
 | 
			
		||||
	return func(db *gorm.DB) *gorm.DB {
 | 
			
		||||
		if current == 0 {
 | 
			
		||||
			current = 1
 | 
			
		||||
		}
 | 
			
		||||
		if size < 1 {
 | 
			
		||||
			size = 10
 | 
			
		||||
		}
 | 
			
		||||
		// 计算偏移量
 | 
			
		||||
		offset := (current - 1) * size
 | 
			
		||||
		// 返回组装结果
 | 
			
		||||
		return db.Offset(offset).Limit(size)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										31
									
								
								repository/problem.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										31
									
								
								repository/problem.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,31 @@
 | 
			
		||||
package repository
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"online_code/client"
 | 
			
		||||
	"online_code/models/entity"
 | 
			
		||||
	"online_code/models/param"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type problemService struct{}
 | 
			
		||||
 | 
			
		||||
func ProblemService() *problemService {
 | 
			
		||||
	return &problemService{}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// GetList 获取题目列表
 | 
			
		||||
func (problemService) GetList(p param.GetProblemList) (records entity.Problem, count int64, err error) {
 | 
			
		||||
	sel := client.MySQL.Scopes(page(p.Current, p.Size))
 | 
			
		||||
 | 
			
		||||
	if p.Keyword != "" {
 | 
			
		||||
		sel.Where("title LIKE ? OR content like ?", "%"+p.Keyword+"%", "%"+p.Keyword+"%")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	err = sel.Order("updated_at DESC").Find(&records).Offset(-1).Limit(-1).Count(&count).Error
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// GetProblemInfo 获取题目详情
 | 
			
		||||
func (problemService) GetProblemInfo(id int) (problem entity.Problem, err error) {
 | 
			
		||||
	err = client.MySQL.Where("id = ?", id).Find(&problem).Error
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										10
									
								
								route/problem.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								route/problem.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,10 @@
 | 
			
		||||
package route
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"github.com/gin-gonic/gin"
 | 
			
		||||
	"online_code/api"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func problem(g *gin.RouterGroup) {
 | 
			
		||||
	g.GET("/list", api.ProblemApi().GetProbleList)
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										8
									
								
								route/router.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										8
									
								
								route/router.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,8 @@
 | 
			
		||||
package route
 | 
			
		||||
 | 
			
		||||
import "github.com/gin-gonic/gin"
 | 
			
		||||
 | 
			
		||||
func InitRoute(g *gin.RouterGroup) {
 | 
			
		||||
	api := g.Group("/api")
 | 
			
		||||
	problem(api.Group("/problem"))
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										14
									
								
								utils/page.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										14
									
								
								utils/page.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,14 @@
 | 
			
		||||
package utils
 | 
			
		||||
 | 
			
		||||
// GenTotalPage 计算总页数
 | 
			
		||||
func GenTotalPage(count int64, size int) int {
 | 
			
		||||
	totalPage := 0
 | 
			
		||||
	if count > 0 {
 | 
			
		||||
		upPage := 0
 | 
			
		||||
		if int(count)%size > 0 {
 | 
			
		||||
			upPage = 1
 | 
			
		||||
		}
 | 
			
		||||
		totalPage = (int(count) / size) + upPage
 | 
			
		||||
	}
 | 
			
		||||
	return totalPage
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										20
									
								
								utils/token.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										20
									
								
								utils/token.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,20 @@
 | 
			
		||||
package utils
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"golang.org/x/crypto/bcrypt"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// 生成Token的密钥,写死,防止乱改
 | 
			
		||||
//var jwtSecret = "qSxw4fCBBBecPsws"
 | 
			
		||||
 | 
			
		||||
// HashPassword 加密密码
 | 
			
		||||
func HashPassword(pass *string) {
 | 
			
		||||
	bytePass := []byte(*pass)
 | 
			
		||||
	hPass, _ := bcrypt.GenerateFromPassword(bytePass, bcrypt.DefaultCost)
 | 
			
		||||
	*pass = string(hPass)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// ComparePassword 校验密码
 | 
			
		||||
func ComparePassword(dbPass, pass string) bool {
 | 
			
		||||
	return bcrypt.CompareHashAndPassword([]byte(dbPass), []byte(pass)) == nil
 | 
			
		||||
}
 | 
			
		||||
		Reference in New Issue
	
	Block a user