Compare commits

..

2 Commits

Author SHA1 Message Date
Eg
2d467c710f Merge remote-tracking branch 'origin/master' 2022-05-26 00:39:47 +08:00
Eg
326118eefb 完善基础架构,新增部分问题接口 2022-05-26 00:39:39 +08:00
16 changed files with 251 additions and 4 deletions

33
api/problem.go Normal file
View 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})
}

View File

@ -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
View File

@ -0,0 +1,6 @@
package define
var (
DefaultCurrent = "1"
DefaultSize = "10"
)

5
go.mod
View File

@ -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

View File

@ -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
View 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
View 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
}

View File

@ -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
View 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
View File

@ -0,0 +1,6 @@
package param
type GetProblemList struct {
page
Keyword string `json:"keyword" form:"keyword"` // 问题关键字
}

19
repository/base.go Normal file
View 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
View 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
View 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
View 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
View 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
View 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
}