添加course的业务层和实现层
This commit is contained in:
50
server/internal/course/handler/course/createcoursehandler.go
Normal file
50
server/internal/course/handler/course/createcoursehandler.go
Normal file
@@ -0,0 +1,50 @@
|
||||
// Code scaffolded by goctl. Safe to edit.
|
||||
// goctl 1.9.2
|
||||
|
||||
package course
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
|
||||
"github.com/JACKYMYPERSON/hldrCenter/config"
|
||||
"github.com/JACKYMYPERSON/hldrCenter/internal/course/internal/logic/course"
|
||||
"github.com/JACKYMYPERSON/hldrCenter/internal/course/internal/model"
|
||||
"github.com/JACKYMYPERSON/hldrCenter/internal/course/internal/types"
|
||||
"github.com/zeromicro/go-zero/core/stores/sqlx"
|
||||
"github.com/zeromicro/go-zero/rest/httpx"
|
||||
)
|
||||
|
||||
func CreateCourseHandler(cfg *config.Config) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
var req types.CreateCourseReq
|
||||
if err := httpx.Parse(r, &req); err != nil {
|
||||
httpx.ErrorCtx(r.Context(), w, err)
|
||||
return
|
||||
}
|
||||
|
||||
mysqlCfg := cfg.MySQL
|
||||
dsn := fmt.Sprintf(
|
||||
"%s:%s@tcp(%s:%d)/%s?charset=%s&parseTime=true&loc=Local",
|
||||
mysqlCfg.Username,
|
||||
mysqlCfg.Password,
|
||||
mysqlCfg.Host,
|
||||
mysqlCfg.Port,
|
||||
mysqlCfg.Database,
|
||||
mysqlCfg.Charset,
|
||||
)
|
||||
fmt.Println("接收到articlePost请求")
|
||||
|
||||
conn := sqlx.NewSqlConn("mysql", dsn)
|
||||
|
||||
baseModel := model.NewCourseModel(conn)
|
||||
|
||||
l := course.NewCreateCourseLogic(r.Context(), cfg, baseModel)
|
||||
resp, err := l.CreateCourse(&req)
|
||||
if err != nil {
|
||||
httpx.ErrorCtx(r.Context(), w, err)
|
||||
} else {
|
||||
httpx.OkJsonCtx(r.Context(), w, resp)
|
||||
}
|
||||
}
|
||||
}
|
||||
61
server/internal/course/handler/course/deletecoursehandler.go
Normal file
61
server/internal/course/handler/course/deletecoursehandler.go
Normal file
@@ -0,0 +1,61 @@
|
||||
// Code scaffolded by goctl. Safe to edit.
|
||||
// goctl 1.9.2
|
||||
|
||||
package course
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/JACKYMYPERSON/hldrCenter/config"
|
||||
"github.com/JACKYMYPERSON/hldrCenter/internal/course/internal/logic/course"
|
||||
"github.com/JACKYMYPERSON/hldrCenter/internal/course/internal/model"
|
||||
"github.com/JACKYMYPERSON/hldrCenter/internal/course/internal/types"
|
||||
"github.com/zeromicro/go-zero/core/stores/sqlx"
|
||||
"github.com/zeromicro/go-zero/rest/httpx"
|
||||
)
|
||||
|
||||
func DeleteCourseHandler(cfg *config.Config) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
var req types.DeleteCourseReq
|
||||
pathParts := strings.Split(r.URL.Path, "/")
|
||||
if len(pathParts) < 3 { // 确保路径格式正确
|
||||
httpx.ErrorCtx(r.Context(), w, fmt.Errorf("invalid path format"))
|
||||
return
|
||||
}
|
||||
idStr := pathParts[3]
|
||||
id, err := strconv.ParseInt(idStr, 10, 64)
|
||||
if err != nil {
|
||||
httpx.ErrorCtx(r.Context(), w, fmt.Errorf("invalid meeting ID"))
|
||||
return
|
||||
}
|
||||
fmt.Println("idStr:", idStr)
|
||||
req.Id = id
|
||||
|
||||
mysqlCfg := cfg.MySQL
|
||||
dsn := fmt.Sprintf(
|
||||
"%s:%s@tcp(%s:%d)/%s?charset=%s&parseTime=true&loc=Local",
|
||||
mysqlCfg.Username,
|
||||
mysqlCfg.Password,
|
||||
mysqlCfg.Host,
|
||||
mysqlCfg.Port,
|
||||
mysqlCfg.Database,
|
||||
mysqlCfg.Charset,
|
||||
)
|
||||
fmt.Println("接收到articlePost请求")
|
||||
|
||||
conn := sqlx.NewSqlConn("mysql", dsn)
|
||||
|
||||
baseModel := model.NewCourseModel(conn)
|
||||
|
||||
l := course.NewDeleteCourseLogic(r.Context(), cfg, baseModel)
|
||||
resp, err := l.DeleteCourse(&req)
|
||||
if err != nil {
|
||||
httpx.ErrorCtx(r.Context(), w, err)
|
||||
} else {
|
||||
httpx.OkJsonCtx(r.Context(), w, resp)
|
||||
}
|
||||
}
|
||||
}
|
||||
61
server/internal/course/handler/course/getcoursehandler.go
Normal file
61
server/internal/course/handler/course/getcoursehandler.go
Normal file
@@ -0,0 +1,61 @@
|
||||
// Code scaffolded by goctl. Safe to edit.
|
||||
// goctl 1.9.2
|
||||
|
||||
package course
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/JACKYMYPERSON/hldrCenter/config"
|
||||
"github.com/JACKYMYPERSON/hldrCenter/internal/course/internal/logic/course"
|
||||
"github.com/JACKYMYPERSON/hldrCenter/internal/course/internal/model"
|
||||
"github.com/JACKYMYPERSON/hldrCenter/internal/course/internal/types"
|
||||
"github.com/zeromicro/go-zero/core/stores/sqlx"
|
||||
"github.com/zeromicro/go-zero/rest/httpx"
|
||||
)
|
||||
|
||||
func GetCourseHandler(cfg *config.Config) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
var req types.GetCourseReq
|
||||
pathParts := strings.Split(r.URL.Path, "/")
|
||||
if len(pathParts) < 3 { // 确保路径格式正确
|
||||
httpx.ErrorCtx(r.Context(), w, fmt.Errorf("invalid path format"))
|
||||
return
|
||||
}
|
||||
idStr := pathParts[3]
|
||||
id, err := strconv.ParseInt(idStr, 10, 64)
|
||||
if err != nil {
|
||||
httpx.ErrorCtx(r.Context(), w, fmt.Errorf("invalid meeting ID"))
|
||||
return
|
||||
}
|
||||
fmt.Println("idStr:", idStr)
|
||||
req.Id = id
|
||||
|
||||
mysqlCfg := cfg.MySQL
|
||||
dsn := fmt.Sprintf(
|
||||
"%s:%s@tcp(%s:%d)/%s?charset=%s&parseTime=true&loc=Local",
|
||||
mysqlCfg.Username,
|
||||
mysqlCfg.Password,
|
||||
mysqlCfg.Host,
|
||||
mysqlCfg.Port,
|
||||
mysqlCfg.Database,
|
||||
mysqlCfg.Charset,
|
||||
)
|
||||
fmt.Println("接收到articlePost请求")
|
||||
|
||||
conn := sqlx.NewSqlConn("mysql", dsn)
|
||||
|
||||
baseModel := model.NewCourseModel(conn)
|
||||
|
||||
l := course.NewGetCourseLogic(r.Context(), cfg, baseModel)
|
||||
resp, err := l.GetCourse(&req)
|
||||
if err != nil {
|
||||
httpx.ErrorCtx(r.Context(), w, err)
|
||||
} else {
|
||||
httpx.OkJsonCtx(r.Context(), w, resp)
|
||||
}
|
||||
}
|
||||
}
|
||||
50
server/internal/course/handler/course/listcoursehandler.go
Normal file
50
server/internal/course/handler/course/listcoursehandler.go
Normal file
@@ -0,0 +1,50 @@
|
||||
// Code scaffolded by goctl. Safe to edit.
|
||||
// goctl 1.9.2
|
||||
|
||||
package course
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
|
||||
"github.com/JACKYMYPERSON/hldrCenter/config"
|
||||
"github.com/JACKYMYPERSON/hldrCenter/internal/course/internal/logic/course"
|
||||
"github.com/JACKYMYPERSON/hldrCenter/internal/course/internal/model"
|
||||
"github.com/JACKYMYPERSON/hldrCenter/internal/course/internal/types"
|
||||
"github.com/zeromicro/go-zero/core/stores/sqlx"
|
||||
"github.com/zeromicro/go-zero/rest/httpx"
|
||||
)
|
||||
|
||||
func ListCourseHandler(cfg *config.Config) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
var req types.ListCourseReq
|
||||
if err := httpx.Parse(r, &req); err != nil {
|
||||
httpx.ErrorCtx(r.Context(), w, err)
|
||||
return
|
||||
}
|
||||
|
||||
mysqlCfg := cfg.MySQL
|
||||
dsn := fmt.Sprintf(
|
||||
"%s:%s@tcp(%s:%d)/%s?charset=%s&parseTime=true&loc=Local",
|
||||
mysqlCfg.Username,
|
||||
mysqlCfg.Password,
|
||||
mysqlCfg.Host,
|
||||
mysqlCfg.Port,
|
||||
mysqlCfg.Database,
|
||||
mysqlCfg.Charset,
|
||||
)
|
||||
fmt.Println("接收到articlePost请求")
|
||||
|
||||
conn := sqlx.NewSqlConn("mysql", dsn)
|
||||
|
||||
baseModel := model.NewCourseModel(conn)
|
||||
|
||||
l := course.NewListCourseLogic(r.Context(), cfg, baseModel)
|
||||
resp, err := l.ListCourse(&req)
|
||||
if err != nil {
|
||||
httpx.ErrorCtx(r.Context(), w, err)
|
||||
} else {
|
||||
httpx.OkJsonCtx(r.Context(), w, resp)
|
||||
}
|
||||
}
|
||||
}
|
||||
50
server/internal/course/handler/course/updatecoursehandler.go
Normal file
50
server/internal/course/handler/course/updatecoursehandler.go
Normal file
@@ -0,0 +1,50 @@
|
||||
// Code scaffolded by goctl. Safe to edit.
|
||||
// goctl 1.9.2
|
||||
|
||||
package course
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
|
||||
"github.com/JACKYMYPERSON/hldrCenter/config"
|
||||
"github.com/JACKYMYPERSON/hldrCenter/internal/course/internal/logic/course"
|
||||
"github.com/JACKYMYPERSON/hldrCenter/internal/course/internal/model"
|
||||
"github.com/JACKYMYPERSON/hldrCenter/internal/course/internal/types"
|
||||
"github.com/zeromicro/go-zero/core/stores/sqlx"
|
||||
"github.com/zeromicro/go-zero/rest/httpx"
|
||||
)
|
||||
|
||||
func UpdateCourseHandler(cfg *config.Config) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
var req types.UpdateCourseReq
|
||||
if err := httpx.Parse(r, &req); err != nil {
|
||||
httpx.ErrorCtx(r.Context(), w, err)
|
||||
return
|
||||
}
|
||||
|
||||
mysqlCfg := cfg.MySQL
|
||||
dsn := fmt.Sprintf(
|
||||
"%s:%s@tcp(%s:%d)/%s?charset=%s&parseTime=true&loc=Local",
|
||||
mysqlCfg.Username,
|
||||
mysqlCfg.Password,
|
||||
mysqlCfg.Host,
|
||||
mysqlCfg.Port,
|
||||
mysqlCfg.Database,
|
||||
mysqlCfg.Charset,
|
||||
)
|
||||
fmt.Println("接收到articlePost请求")
|
||||
|
||||
conn := sqlx.NewSqlConn("mysql", dsn)
|
||||
|
||||
baseModel := model.NewCourseModel(conn)
|
||||
|
||||
l := course.NewUpdateCourseLogic(r.Context(), cfg, baseModel)
|
||||
resp, err := l.UpdateCourse(&req)
|
||||
if err != nil {
|
||||
httpx.ErrorCtx(r.Context(), w, err)
|
||||
} else {
|
||||
httpx.OkJsonCtx(r.Context(), w, resp)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,94 @@
|
||||
// Code scaffolded by goctl. Safe to edit.
|
||||
// goctl 1.9.2
|
||||
|
||||
package course
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
"fmt"
|
||||
|
||||
"github.com/JACKYMYPERSON/hldrCenter/config"
|
||||
"github.com/JACKYMYPERSON/hldrCenter/internal/course/internal/model"
|
||||
"github.com/JACKYMYPERSON/hldrCenter/internal/course/internal/types"
|
||||
"github.com/go-playground/validator/v10"
|
||||
|
||||
"github.com/zeromicro/go-zero/core/logx"
|
||||
)
|
||||
|
||||
type CreateCourseLogic struct {
|
||||
logx.Logger
|
||||
ctx context.Context
|
||||
cfg *config.Config
|
||||
model model.CourseModel
|
||||
}
|
||||
|
||||
func NewCreateCourseLogic(ctx context.Context, cfg *config.Config, model model.CourseModel) *CreateCourseLogic {
|
||||
return &CreateCourseLogic{
|
||||
Logger: logx.WithContext(ctx),
|
||||
ctx: ctx,
|
||||
cfg: cfg,
|
||||
model: model,
|
||||
}
|
||||
}
|
||||
|
||||
func (l *CreateCourseLogic) CreateCourse(req *types.CreateCourseReq) (resp *types.BaseResp, err error) {
|
||||
// 初始化验证器
|
||||
validate := validator.New()
|
||||
|
||||
// 验证请求参数
|
||||
if err := validate.Struct(req); err != nil {
|
||||
// 收集所有验证错误
|
||||
var errMsg string
|
||||
for _, e := range err.(validator.ValidationErrors) {
|
||||
errMsg += fmt.Sprintf("参数 %s 验证失败: %s; ", e.Field(), e.Tag())
|
||||
}
|
||||
return &types.BaseResp{
|
||||
Code: 400, // 非0表示失败
|
||||
Msg: "参数验证失败: " + errMsg,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// 构造课程数据对象
|
||||
course := &model.Course{
|
||||
Title: req.Title,
|
||||
Subtitle: req.Subtitle,
|
||||
CoverUrl: req.CoverUrl,
|
||||
Intro: stringToNullString(req.Intro),
|
||||
Status: int64(req.Status),
|
||||
}
|
||||
|
||||
// 调用模型层插入数据
|
||||
result, err := l.model.Insert(l.ctx, course)
|
||||
if err != nil {
|
||||
return &types.BaseResp{
|
||||
Code: 500, // 非0表示失败
|
||||
Msg: "创建课程失败: " + err.Error(),
|
||||
}, nil
|
||||
}
|
||||
|
||||
// 获取插入的课程ID
|
||||
courseId, err := result.LastInsertId()
|
||||
if err != nil {
|
||||
return &types.BaseResp{
|
||||
Code: 500, // 非0表示失败
|
||||
Msg: "获取课程ID失败: " + err.Error(),
|
||||
}, nil
|
||||
}
|
||||
|
||||
// 返回成功响应(0表示成功)
|
||||
return &types.BaseResp{
|
||||
Code: 0,
|
||||
Msg: fmt.Sprintf("课程创建成功,ID: %d", courseId),
|
||||
}, nil
|
||||
}
|
||||
|
||||
func stringToNullString(s string) sql.NullString {
|
||||
if s == "" {
|
||||
return sql.NullString{Valid: false}
|
||||
}
|
||||
return sql.NullString{
|
||||
String: s,
|
||||
Valid: true,
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,78 @@
|
||||
// Code scaffolded by goctl. Safe to edit.
|
||||
// goctl 1.9.2
|
||||
|
||||
package course
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"github.com/JACKYMYPERSON/hldrCenter/config"
|
||||
"github.com/JACKYMYPERSON/hldrCenter/internal/course/internal/model"
|
||||
"github.com/JACKYMYPERSON/hldrCenter/internal/course/internal/types"
|
||||
"github.com/go-playground/validator/v10"
|
||||
|
||||
"github.com/zeromicro/go-zero/core/logx"
|
||||
)
|
||||
|
||||
type DeleteCourseLogic struct {
|
||||
logx.Logger
|
||||
ctx context.Context
|
||||
cfg *config.Config
|
||||
model model.CourseModel
|
||||
}
|
||||
|
||||
func NewDeleteCourseLogic(ctx context.Context, cfg *config.Config, model model.CourseModel) *DeleteCourseLogic {
|
||||
return &DeleteCourseLogic{
|
||||
Logger: logx.WithContext(ctx),
|
||||
ctx: ctx,
|
||||
cfg: cfg,
|
||||
model: model,
|
||||
}
|
||||
}
|
||||
|
||||
func (l *DeleteCourseLogic) DeleteCourse(req *types.DeleteCourseReq) (resp *types.BaseResp, err error) {
|
||||
// 1. 参数验证
|
||||
validate := validator.New()
|
||||
if err := validate.Struct(req); err != nil {
|
||||
var errMsg string
|
||||
for _, e := range err.(validator.ValidationErrors) {
|
||||
errMsg += fmt.Sprintf("参数 %s 验证失败: %s; ", e.Field(), e.Tag())
|
||||
}
|
||||
return &types.BaseResp{
|
||||
Code: 400,
|
||||
Msg: "参数验证失败: " + errMsg,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// 2. 复用FindOne方法检查课程是否存在
|
||||
_, err = l.model.FindOne(l.ctx, req.Id)
|
||||
if err != nil {
|
||||
if err == model.ErrNotFound { // 注意:这里需要匹配你实际的ErrNotFound定义
|
||||
return &types.BaseResp{
|
||||
Code: 404,
|
||||
Msg: fmt.Sprintf("课程ID=%d不存在", req.Id),
|
||||
}, nil
|
||||
}
|
||||
// 其他查询错误
|
||||
return &types.BaseResp{
|
||||
Code: 500,
|
||||
Msg: "查询课程信息失败: " + err.Error(),
|
||||
}, nil
|
||||
}
|
||||
|
||||
// 3. 执行逻辑删除(更新is_delete为1)
|
||||
err = l.model.Delete(l.ctx, req.Id)
|
||||
if err != nil {
|
||||
return &types.BaseResp{
|
||||
Code: 500,
|
||||
Msg: "删除课程失败: " + err.Error(),
|
||||
}, nil
|
||||
}
|
||||
|
||||
// 4. 返回成功响应
|
||||
return &types.BaseResp{
|
||||
Code: 0,
|
||||
Msg: fmt.Sprintf("课程ID=%d删除成功", req.Id),
|
||||
}, nil
|
||||
}
|
||||
@@ -0,0 +1,85 @@
|
||||
// Code scaffolded by goctl. Safe to edit.
|
||||
// goctl 1.9.2
|
||||
|
||||
package course
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/JACKYMYPERSON/hldrCenter/config"
|
||||
"github.com/JACKYMYPERSON/hldrCenter/internal/course/internal/model"
|
||||
"github.com/JACKYMYPERSON/hldrCenter/internal/course/internal/types"
|
||||
"github.com/go-playground/validator/v10"
|
||||
|
||||
"github.com/zeromicro/go-zero/core/logx"
|
||||
)
|
||||
|
||||
type GetCourseLogic struct {
|
||||
logx.Logger
|
||||
ctx context.Context
|
||||
cfg *config.Config
|
||||
model model.CourseModel
|
||||
}
|
||||
|
||||
func NewGetCourseLogic(ctx context.Context, cfg *config.Config, model model.CourseModel) *GetCourseLogic {
|
||||
return &GetCourseLogic{
|
||||
Logger: logx.WithContext(ctx),
|
||||
ctx: ctx,
|
||||
cfg: cfg,
|
||||
model: model,
|
||||
}
|
||||
}
|
||||
|
||||
func (l *GetCourseLogic) GetCourse(req *types.GetCourseReq) (resp *types.CourseResp, err error) {
|
||||
// 1. 参数验证(匹配结构体中的validate标签)
|
||||
validate := validator.New()
|
||||
if err := validate.Struct(req); err != nil {
|
||||
var errMsg string
|
||||
for _, e := range err.(validator.ValidationErrors) {
|
||||
errMsg += fmt.Sprintf("参数 %s 验证失败: %s; ", e.Field(), e.Tag())
|
||||
}
|
||||
return nil, fmt.Errorf("参数验证失败: %s", errMsg)
|
||||
}
|
||||
|
||||
// 2. 调用模型层查询课程
|
||||
course, err := l.model.FindOne(l.ctx, req.Id)
|
||||
if err != nil {
|
||||
if err == model.ErrNotFound {
|
||||
return nil, fmt.Errorf("课程不存在")
|
||||
}
|
||||
return nil, fmt.Errorf("查询课程失败: %w", err)
|
||||
}
|
||||
|
||||
// 3. 转换模型数据到响应结构体
|
||||
resp = &types.CourseResp{
|
||||
Id: course.Id,
|
||||
Title: course.Title,
|
||||
Subtitle: course.Subtitle,
|
||||
CoverUrl: course.CoverUrl,
|
||||
Intro: nullStringToString(course.Intro),
|
||||
Status: int8(course.Status),
|
||||
CreateTime: formatTime(course.CreateTime),
|
||||
UpdateTime: formatTime(course.UpdateTime),
|
||||
}
|
||||
|
||||
return resp, nil
|
||||
}
|
||||
|
||||
// 辅助函数:将sql.NullString转换为string(处理数据库NULL值)
|
||||
func nullStringToString(ns sql.NullString) string {
|
||||
if ns.Valid {
|
||||
return ns.String
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
// 辅助函数:格式化时间为字符串(处理可能的零值时间)
|
||||
func formatTime(t time.Time) string {
|
||||
if t.IsZero() {
|
||||
return ""
|
||||
}
|
||||
return t.Format("2006-01-02 15:04:05")
|
||||
}
|
||||
107
server/internal/course/internal/logic/course/listcourselogic.go
Normal file
107
server/internal/course/internal/logic/course/listcourselogic.go
Normal file
@@ -0,0 +1,107 @@
|
||||
// Code scaffolded by goctl. Safe to edit.
|
||||
// goctl 1.9.2
|
||||
|
||||
package course
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"github.com/JACKYMYPERSON/hldrCenter/config"
|
||||
"github.com/JACKYMYPERSON/hldrCenter/internal/course/internal/model"
|
||||
"github.com/JACKYMYPERSON/hldrCenter/internal/course/internal/types"
|
||||
"github.com/zeromicro/go-zero/core/logx"
|
||||
)
|
||||
|
||||
type ListCourseLogic struct {
|
||||
logx.Logger
|
||||
ctx context.Context
|
||||
cfg *config.Config
|
||||
model model.CourseModel
|
||||
}
|
||||
|
||||
func NewListCourseLogic(ctx context.Context, cfg *config.Config, model model.CourseModel) *ListCourseLogic {
|
||||
return &ListCourseLogic{
|
||||
Logger: logx.WithContext(ctx),
|
||||
ctx: ctx,
|
||||
cfg: cfg,
|
||||
model: model,
|
||||
}
|
||||
}
|
||||
|
||||
func (l *ListCourseLogic) ListCourse(req *types.ListCourseReq) (resp *types.ListCourseResp, err error) {
|
||||
// 1. 参数验证与默认值处理
|
||||
if err := validateListCourseReq(req); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// 处理分页默认值(根据结构体tag的default定义)
|
||||
page := req.Page
|
||||
size := req.Size
|
||||
if page <= 0 {
|
||||
page = 1 // 默认第一页
|
||||
}
|
||||
if size <= 0 {
|
||||
size = 10 // 默认每页10条
|
||||
}
|
||||
offset := (page - 1) * size
|
||||
|
||||
// 2. 构建查询条件
|
||||
filter := model.CourseFilter{
|
||||
Status: req.Status,
|
||||
Keyword: req.Keyword,
|
||||
Offset: offset,
|
||||
Limit: size,
|
||||
}
|
||||
|
||||
// 3. 查询课程列表数据
|
||||
courses, err := l.model.List(l.ctx, filter)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("查询课程列表失败: %w", err)
|
||||
}
|
||||
|
||||
// 4. 查询符合条件的总条数
|
||||
total, err := l.model.Count(l.ctx, filter)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("查询课程总数失败: %w", err)
|
||||
}
|
||||
|
||||
// 5. 转换数据格式(model -> types)
|
||||
var courseList []types.CourseResp
|
||||
for _, course := range courses {
|
||||
courseList = append(courseList, types.CourseResp{
|
||||
Id: course.Id,
|
||||
Title: course.Title,
|
||||
Subtitle: course.Subtitle,
|
||||
CoverUrl: course.CoverUrl,
|
||||
Intro: nullStringToString(course.Intro), // 包含简介信息
|
||||
Status: int8(course.Status),
|
||||
CreateTime: formatTime(course.CreateTime),
|
||||
UpdateTime: formatTime(course.UpdateTime), // 包含更新时间
|
||||
})
|
||||
}
|
||||
|
||||
// 6. 组装响应数据
|
||||
resp = &types.ListCourseResp{
|
||||
Total: total,
|
||||
List: courseList,
|
||||
}
|
||||
|
||||
return resp, nil
|
||||
}
|
||||
|
||||
// 参数验证函数
|
||||
func validateListCourseReq(req *types.ListCourseReq) error {
|
||||
// 自定义验证规则:页码和每页数量不能为负数
|
||||
if req.Page < 0 {
|
||||
return fmt.Errorf("页码不能为负数")
|
||||
}
|
||||
if req.Size < 0 {
|
||||
return fmt.Errorf("每页数量不能为负数")
|
||||
}
|
||||
// 状态值验证(根据业务实际允许的状态值调整)
|
||||
if req.Status < 0 && req.Status != -1 { // 假设-1表示不筛选状态
|
||||
return fmt.Errorf("无效的状态值")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -0,0 +1,89 @@
|
||||
// Code scaffolded by goctl. Safe to edit.
|
||||
// goctl 1.9.2
|
||||
|
||||
package course
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"github.com/JACKYMYPERSON/hldrCenter/config"
|
||||
"github.com/JACKYMYPERSON/hldrCenter/internal/course/internal/model"
|
||||
"github.com/JACKYMYPERSON/hldrCenter/internal/course/internal/types"
|
||||
"github.com/go-playground/validator/v10"
|
||||
|
||||
"github.com/zeromicro/go-zero/core/logx"
|
||||
)
|
||||
|
||||
type UpdateCourseLogic struct {
|
||||
logx.Logger
|
||||
ctx context.Context
|
||||
cfg *config.Config
|
||||
model model.CourseModel
|
||||
}
|
||||
|
||||
func NewUpdateCourseLogic(ctx context.Context, cfg *config.Config, model model.CourseModel) *UpdateCourseLogic {
|
||||
return &UpdateCourseLogic{
|
||||
Logger: logx.WithContext(ctx),
|
||||
ctx: ctx,
|
||||
cfg: cfg,
|
||||
model: model,
|
||||
}
|
||||
}
|
||||
|
||||
func (l *UpdateCourseLogic) UpdateCourse(req *types.UpdateCourseReq) (resp *types.BaseResp, err error) {
|
||||
// 1. 参数验证
|
||||
validate := validator.New()
|
||||
if err := validate.Struct(req); err != nil {
|
||||
var errMsg string
|
||||
for _, e := range err.(validator.ValidationErrors) {
|
||||
errMsg += fmt.Sprintf("参数 %s 验证失败: %s; ", e.Field(), e.Tag())
|
||||
}
|
||||
return &types.BaseResp{
|
||||
Code: 400,
|
||||
Msg: "参数验证失败: " + errMsg,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// 2. 检查课程是否存在
|
||||
existingCourse, err := l.model.FindOne(l.ctx, req.Id)
|
||||
if err != nil {
|
||||
if err == model.ErrNotFound {
|
||||
return &types.BaseResp{
|
||||
Code: 404,
|
||||
Msg: fmt.Sprintf("课程ID=%d不存在", req.Id),
|
||||
}, nil
|
||||
}
|
||||
return &types.BaseResp{
|
||||
Code: 500,
|
||||
Msg: "查询课程信息失败: " + err.Error(),
|
||||
}, nil
|
||||
}
|
||||
|
||||
// 3. 构造更新数据(保留原有字段,仅更新请求中提供的字段)
|
||||
updatedCourse := &model.Course{
|
||||
Id: req.Id, // 必须指定更新的课程ID
|
||||
Title: req.Title, // 标题(如果为空会覆盖原有值,根据业务需求调整)
|
||||
Subtitle: req.Subtitle, // 副标题
|
||||
CoverUrl: req.CoverUrl, // 封面图URL
|
||||
Intro: stringToNullString(req.Intro), // 课程简介
|
||||
Status: int64(req.Status), // 课程状态
|
||||
CreateTime: existingCourse.CreateTime, // 保留原始创建时间
|
||||
UpdateTime: existingCourse.UpdateTime, // 可由数据库自动更新,这里暂用原有值
|
||||
}
|
||||
|
||||
// 4. 执行更新操作
|
||||
err = l.model.Update(l.ctx, updatedCourse)
|
||||
if err != nil {
|
||||
return &types.BaseResp{
|
||||
Code: 500,
|
||||
Msg: "更新课程失败: " + err.Error(),
|
||||
}, nil
|
||||
}
|
||||
|
||||
// 5. 返回成功响应
|
||||
return &types.BaseResp{
|
||||
Code: 0,
|
||||
Msg: fmt.Sprintf("课程ID=%d更新成功", req.Id),
|
||||
}, nil
|
||||
}
|
||||
29
server/internal/course/internal/model/coursemodel.go
Normal file
29
server/internal/course/internal/model/coursemodel.go
Normal file
@@ -0,0 +1,29 @@
|
||||
package model
|
||||
|
||||
import "github.com/zeromicro/go-zero/core/stores/sqlx"
|
||||
|
||||
var _ CourseModel = (*customCourseModel)(nil)
|
||||
|
||||
type (
|
||||
// CourseModel is an interface to be customized, add more methods here,
|
||||
// and implement the added methods in customCourseModel.
|
||||
CourseModel interface {
|
||||
courseModel
|
||||
withSession(session sqlx.Session) CourseModel
|
||||
}
|
||||
|
||||
customCourseModel struct {
|
||||
*defaultCourseModel
|
||||
}
|
||||
)
|
||||
|
||||
// NewCourseModel returns a model for the database table.
|
||||
func NewCourseModel(conn sqlx.SqlConn) CourseModel {
|
||||
return &customCourseModel{
|
||||
defaultCourseModel: newCourseModel(conn),
|
||||
}
|
||||
}
|
||||
|
||||
func (m *customCourseModel) withSession(session sqlx.Session) CourseModel {
|
||||
return NewCourseModel(sqlx.NewSqlConnFromSession(session))
|
||||
}
|
||||
157
server/internal/course/internal/model/coursemodel_gen.go
Normal file
157
server/internal/course/internal/model/coursemodel_gen.go
Normal file
@@ -0,0 +1,157 @@
|
||||
// Code generated by goctl. DO NOT EDIT.
|
||||
// versions:
|
||||
// goctl version: 1.9.2
|
||||
|
||||
package model
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
"fmt"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/zeromicro/go-zero/core/stores/builder"
|
||||
"github.com/zeromicro/go-zero/core/stores/sqlx"
|
||||
"github.com/zeromicro/go-zero/core/stringx"
|
||||
)
|
||||
|
||||
var (
|
||||
courseFieldNames = builder.RawFieldNames(&Course{})
|
||||
courseRows = strings.Join(courseFieldNames, ",")
|
||||
courseRowsExpectAutoSet = strings.Join(stringx.Remove(courseFieldNames, "`id`", "`create_at`", "`create_time`", "`created_at`", "`update_at`", "`update_time`", "`updated_at`"), ",")
|
||||
courseRowsWithPlaceHolder = strings.Join(stringx.Remove(courseFieldNames, "`id`", "`create_at`", "`create_time`", "`created_at`", "`update_at`", "`update_time`", "`updated_at`"), "=?,") + "=?"
|
||||
)
|
||||
|
||||
type (
|
||||
courseModel interface {
|
||||
Insert(ctx context.Context, data *Course) (sql.Result, error)
|
||||
FindOne(ctx context.Context, id int64) (*Course, error)
|
||||
Update(ctx context.Context, data *Course) error
|
||||
Delete(ctx context.Context, id int64) error
|
||||
List(ctx context.Context, filter CourseFilter) ([]*Course, error)
|
||||
Count(ctx context.Context, filter CourseFilter) (int64, error)
|
||||
}
|
||||
|
||||
defaultCourseModel struct {
|
||||
conn sqlx.SqlConn
|
||||
table string
|
||||
}
|
||||
|
||||
Course struct {
|
||||
Id int64 `db:"id"` // 课程ID(主键)
|
||||
Title string `db:"title"` // 课程标题
|
||||
Subtitle string `db:"subtitle"` // 课程副标题
|
||||
CoverUrl string `db:"cover_url"` // 课程封面图URL
|
||||
Intro sql.NullString `db:"intro"` // 课程简介(对应“课程简介”模块)
|
||||
Status int64 `db:"status"` // 课程状态(0删除,1-已发布)
|
||||
CreateTime time.Time `db:"create_time"` // 创建时间
|
||||
UpdateTime time.Time `db:"update_time"` // 更新时间
|
||||
}
|
||||
|
||||
CourseFilter struct {
|
||||
Status int8 // 状态筛选
|
||||
Keyword string // 关键词搜索
|
||||
Offset int // 分页偏移量
|
||||
Limit int // 分页数量
|
||||
}
|
||||
)
|
||||
|
||||
func newCourseModel(conn sqlx.SqlConn) *defaultCourseModel {
|
||||
return &defaultCourseModel{
|
||||
conn: conn,
|
||||
table: "`course`",
|
||||
}
|
||||
}
|
||||
|
||||
func (m *defaultCourseModel) Delete(ctx context.Context, id int64) error {
|
||||
query := fmt.Sprintf("update %s set `status` = 0, `update_time` = CURRENT_TIMESTAMP where `id` = ?", m.table)
|
||||
_, err := m.conn.ExecCtx(ctx, query, id)
|
||||
return err
|
||||
}
|
||||
|
||||
func (m *defaultCourseModel) FindOne(ctx context.Context, id int64) (*Course, error) {
|
||||
query := fmt.Sprintf("select %s from %s where `id` = ? limit 1", courseRows, m.table)
|
||||
var resp Course
|
||||
err := m.conn.QueryRowCtx(ctx, &resp, query, id)
|
||||
switch err {
|
||||
case nil:
|
||||
return &resp, nil
|
||||
case sqlx.ErrNotFound:
|
||||
return nil, ErrNotFound
|
||||
default:
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
func (m *defaultCourseModel) Insert(ctx context.Context, data *Course) (sql.Result, error) {
|
||||
query := fmt.Sprintf("insert into %s (%s) values (?, ?, ?, ?, ?)", m.table, courseRowsExpectAutoSet)
|
||||
ret, err := m.conn.ExecCtx(ctx, query, data.Title, data.Subtitle, data.CoverUrl, data.Intro, data.Status)
|
||||
return ret, err
|
||||
}
|
||||
|
||||
func (m *defaultCourseModel) Update(ctx context.Context, data *Course) error {
|
||||
query := fmt.Sprintf("update %s set %s where `id` = ?", m.table, courseRowsWithPlaceHolder)
|
||||
_, err := m.conn.ExecCtx(ctx, query, data.Title, data.Subtitle, data.CoverUrl, data.Intro, data.Status, data.Id)
|
||||
return err
|
||||
}
|
||||
|
||||
func (m *defaultCourseModel) List(ctx context.Context, filter CourseFilter) ([]*Course, error) {
|
||||
query := fmt.Sprintf("select %s from %s where 1=1", courseRows, m.table)
|
||||
args := []interface{}{}
|
||||
|
||||
// 状态筛选逻辑:
|
||||
// - 如果未指定filter.Status(默认值),默认只查询"已发布"(status=1)
|
||||
// - 如果指定了filter.Status(0或1),则按指定值筛选(支持查询已删除的课程)
|
||||
if filter.Status == -1 {
|
||||
// 默认筛选:只查已发布(status=1)
|
||||
query += " and `status` = 1"
|
||||
} else {
|
||||
// 按指定status筛选(0=删除,1=发布)
|
||||
query += " and `status` = ?"
|
||||
args = append(args, filter.Status)
|
||||
}
|
||||
|
||||
// 关键词搜索(标题和副标题模糊匹配)
|
||||
if filter.Keyword != "" {
|
||||
query += " and (`title` like ? or `subtitle` like ?)"
|
||||
args = append(args, "%"+filter.Keyword+"%", "%"+filter.Keyword+"%")
|
||||
}
|
||||
|
||||
// 分页处理
|
||||
query += " limit ?, ?"
|
||||
args = append(args, filter.Offset, filter.Limit)
|
||||
|
||||
// 执行查询
|
||||
var courses []*Course
|
||||
err := m.conn.QueryRowsCtx(ctx, &courses, query, args...)
|
||||
return courses, err
|
||||
}
|
||||
|
||||
// 配套的Count方法也需要同步修改(确保总数计算正确)
|
||||
func (m *defaultCourseModel) Count(ctx context.Context, filter CourseFilter) (int64, error) {
|
||||
query := fmt.Sprintf("select count(1) from %s where 1=1", m.table)
|
||||
args := []interface{}{}
|
||||
|
||||
// 与List方法保持一致的status筛选逻辑
|
||||
if filter.Status == -1 {
|
||||
query += " and `status` = 1"
|
||||
} else {
|
||||
query += " and `status` = ?"
|
||||
args = append(args, filter.Status)
|
||||
}
|
||||
|
||||
// 关键词搜索条件
|
||||
if filter.Keyword != "" {
|
||||
query += " and (`title` like ? or `subtitle` like ?)"
|
||||
args = append(args, "%"+filter.Keyword+"%", "%"+filter.Keyword+"%")
|
||||
}
|
||||
|
||||
var total int64
|
||||
err := m.conn.QueryRowCtx(ctx, &total, query, args...)
|
||||
return total, err
|
||||
}
|
||||
|
||||
func (m *defaultCourseModel) tableName() string {
|
||||
return m.table
|
||||
}
|
||||
5
server/internal/course/internal/model/vars.go
Normal file
5
server/internal/course/internal/model/vars.go
Normal file
@@ -0,0 +1,5 @@
|
||||
package model
|
||||
|
||||
import "github.com/zeromicro/go-zero/core/stores/sqlx"
|
||||
|
||||
var ErrNotFound = sqlx.ErrNotFound
|
||||
57
server/internal/course/internal/types/types.go
Normal file
57
server/internal/course/internal/types/types.go
Normal file
@@ -0,0 +1,57 @@
|
||||
// Code generated by goctl. DO NOT EDIT.
|
||||
// goctl 1.9.2
|
||||
|
||||
package types
|
||||
|
||||
type BaseResp struct {
|
||||
Code int `json:"code"` // 状态码(0成功,非0失败)
|
||||
Msg string `json:"msg"` // 提示信息
|
||||
}
|
||||
|
||||
type CourseResp struct {
|
||||
Id int64 `json:"id"` // 课程ID
|
||||
Title string `json:"title"` // 课程标题
|
||||
Subtitle string `json:"subtitle"` // 课程副标题
|
||||
CoverUrl string `json:"cover_url"` // 课程封面图URL
|
||||
Intro string `json:"intro"` // 课程简介
|
||||
Status int8 `json:"status"` // 课程状态
|
||||
CreateTime string `json:"create_time"` // 创建时间
|
||||
UpdateTime string `json:"update_time"` // 更新时间
|
||||
}
|
||||
|
||||
type CreateCourseReq struct {
|
||||
Title string `json:"title" validate:"required"` // 课程标题
|
||||
Subtitle string `json:"subtitle"` // 课程副标题
|
||||
CoverUrl string `json:"cover_url"` // 课程封面图URL
|
||||
Intro string `json:"intro"` // 课程简介
|
||||
Status int8 `json:"status" default:"1"` // 课程状态(0删除,1-已发布)
|
||||
}
|
||||
|
||||
type DeleteCourseReq struct {
|
||||
Id int64 `json:"id" validate:"required"` // 课程ID
|
||||
}
|
||||
|
||||
type GetCourseReq struct {
|
||||
Id int64 `json:"id" path:"id" validate:"required"` // 课程ID
|
||||
}
|
||||
|
||||
type ListCourseReq struct {
|
||||
Page int `json:"page" default:"1"` // 页码
|
||||
Size int `json:"size" default:"10"` // 每页数量
|
||||
Status int8 `json:"status"` // 课程状态筛选
|
||||
Keyword string `json:"keyword"` // 搜索关键词(标题/副标题)
|
||||
}
|
||||
|
||||
type ListCourseResp struct {
|
||||
Total int64 `json:"total"` // 总条数
|
||||
List []CourseResp `json:"list"` // 课程列表
|
||||
}
|
||||
|
||||
type UpdateCourseReq struct {
|
||||
Id int64 `json:"id" validate:"required"` // 课程ID
|
||||
Title string `json:"title"` // 课程标题
|
||||
Subtitle string `json:"subtitle"` // 课程副标题
|
||||
CoverUrl string `json:"cover_url"` // 课程封面图URL
|
||||
Intro string `json:"intro"` // 课程简介
|
||||
Status int8 `json:"status"` // 课程状态(0删除,1-已发布)
|
||||
}
|
||||
Reference in New Issue
Block a user