添加首页文章页面
This commit is contained in:
@@ -4,23 +4,57 @@
|
||||
package article
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/JACKYMYPERSON/hldrCenter/config"
|
||||
"github.com/JACKYMYPERSON/hldrCenter/internal/article/internal/logic/article"
|
||||
"github.com/JACKYMYPERSON/hldrCenter/internal/article/internal/model"
|
||||
"github.com/JACKYMYPERSON/hldrCenter/internal/article/internal/types"
|
||||
"github.com/zeromicro/go-zero/core/stores/sqlx"
|
||||
"github.com/zeromicro/go-zero/rest/httpx"
|
||||
)
|
||||
|
||||
func DeleteArticleHandler(cfg *config.Config) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
var req types.DeleteArticleReq
|
||||
if err := httpx.Parse(r, &req); err != nil {
|
||||
httpx.ErrorCtx(r.Context(), w, err)
|
||||
|
||||
// 1. 从URL路径提取id(核心步骤)
|
||||
pathParts := strings.Split(r.URL.Path, "/")
|
||||
// 完整路径是 "/api/articles/12",split后应为 ["", "api", "articles", "12"]
|
||||
if len(pathParts) < 4 {
|
||||
httpx.ErrorCtx(r.Context(), w, fmt.Errorf("无效的 URL 路径"))
|
||||
return
|
||||
}
|
||||
idStr := pathParts[3]
|
||||
id, err := strconv.ParseInt(idStr, 10, 64)
|
||||
if err != nil || id <= 0 { // 增加id有效性校验
|
||||
httpx.ErrorCtx(r.Context(), w, fmt.Errorf("无效的文章ID:%s", idStr))
|
||||
return
|
||||
}
|
||||
req.Id = id // 只赋值一次,确保Id正确
|
||||
|
||||
l := article.NewDeleteArticleLogic(r.Context(), cfg)
|
||||
// 验证:打印id,确认此时是正确的(如12)
|
||||
fmt.Println("Handler中获取的文章ID:", req.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)
|
||||
articleModel := model.NewArticleModel(conn)
|
||||
|
||||
l := article.NewDeleteArticleLogic(r.Context(), cfg, articleModel)
|
||||
resp, err := l.DeleteArticle(&req)
|
||||
if err != nil {
|
||||
httpx.ErrorCtx(r.Context(), w, err)
|
||||
|
||||
@@ -33,7 +33,7 @@ func ListArticleHandler(cfg *config.Config) http.HandlerFunc {
|
||||
mysqlCfg.Database,
|
||||
mysqlCfg.Charset,
|
||||
)
|
||||
fmt.Println("接收到articlePost请求")
|
||||
fmt.Println("接收到获取文章列表请求:", req)
|
||||
|
||||
conn := sqlx.NewSqlConn("mysql", dsn)
|
||||
articleModel := model.NewArticleModel(conn)
|
||||
|
||||
@@ -4,23 +4,57 @@
|
||||
package article
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/JACKYMYPERSON/hldrCenter/config"
|
||||
"github.com/JACKYMYPERSON/hldrCenter/internal/article/internal/logic/article"
|
||||
"github.com/JACKYMYPERSON/hldrCenter/internal/article/internal/model"
|
||||
"github.com/JACKYMYPERSON/hldrCenter/internal/article/internal/types"
|
||||
"github.com/zeromicro/go-zero/core/stores/sqlx"
|
||||
"github.com/zeromicro/go-zero/rest/httpx"
|
||||
)
|
||||
|
||||
func UpdateArticleHandler(cfg *config.Config) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
var req types.UpdateArticleReq
|
||||
|
||||
pathParts := strings.Split(r.URL.Path, "/")
|
||||
// 确保路径格式正确(至少包含 4 个部分:["", "api", "articles", "12"])
|
||||
if len(pathParts) < 4 {
|
||||
httpx.ErrorCtx(r.Context(), w, fmt.Errorf("无效的 URL 路径"))
|
||||
return
|
||||
}
|
||||
idStr := pathParts[3] // 取路径中最后一个部分(如 "12")
|
||||
id, err := strconv.ParseInt(idStr, 10, 64)
|
||||
fmt.Println("访问路径:", id)
|
||||
req.Id = id
|
||||
|
||||
if err := httpx.Parse(r, &req); err != nil {
|
||||
httpx.ErrorCtx(r.Context(), w, err)
|
||||
return
|
||||
}
|
||||
|
||||
l := article.NewUpdateArticleLogic(r.Context(), cfg)
|
||||
// 新增:打印绑定后的req.Id,确认是否为12
|
||||
fmt.Println("Handler中获取的文章ID:", req.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,
|
||||
)
|
||||
|
||||
conn := sqlx.NewSqlConn("mysql", dsn)
|
||||
articleModel := model.NewArticleModel(conn)
|
||||
|
||||
l := article.NewUpdateArticleLogic(r.Context(), cfg, articleModel)
|
||||
resp, err := l.UpdateArticle(&req)
|
||||
if err != nil {
|
||||
httpx.ErrorCtx(r.Context(), w, err)
|
||||
|
||||
@@ -5,8 +5,10 @@ package article
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
|
||||
"github.com/JACKYMYPERSON/hldrCenter/config"
|
||||
"github.com/JACKYMYPERSON/hldrCenter/internal/article/internal/model"
|
||||
"github.com/JACKYMYPERSON/hldrCenter/internal/article/internal/types"
|
||||
|
||||
"github.com/zeromicro/go-zero/core/logx"
|
||||
@@ -14,20 +16,35 @@ import (
|
||||
|
||||
type DeleteArticleLogic struct {
|
||||
logx.Logger
|
||||
ctx context.Context
|
||||
cfg *config.Config
|
||||
ctx context.Context
|
||||
cfg *config.Config
|
||||
model model.ArticleModel
|
||||
}
|
||||
|
||||
func NewDeleteArticleLogic(ctx context.Context, cfg *config.Config) *DeleteArticleLogic {
|
||||
func NewDeleteArticleLogic(ctx context.Context, cfg *config.Config, model model.ArticleModel) *DeleteArticleLogic {
|
||||
return &DeleteArticleLogic{
|
||||
Logger: logx.WithContext(ctx),
|
||||
ctx: ctx,
|
||||
cfg: cfg,
|
||||
model: model,
|
||||
}
|
||||
}
|
||||
|
||||
func (l *DeleteArticleLogic) DeleteArticle(req *types.DeleteArticleReq) (resp *types.DeleteArticleResp, err error) {
|
||||
// todo: add your logic here and delete this line
|
||||
// 1. 校验参数:确保文章ID有效(大于0)
|
||||
if req.Id <= 0 {
|
||||
return nil, errors.New("无效的文章ID")
|
||||
}
|
||||
|
||||
return
|
||||
// 2. 调用Model层执行逻辑删除(更新is_delete=1)
|
||||
err = l.model.Delete(l.ctx, req.Id)
|
||||
if err != nil {
|
||||
// 可根据实际错误类型返回更具体的信息
|
||||
return nil, errors.New("删除文章失败:" + err.Error())
|
||||
}
|
||||
|
||||
// 3. 返回成功响应
|
||||
return &types.DeleteArticleResp{
|
||||
Success: true,
|
||||
}, nil
|
||||
}
|
||||
|
||||
@@ -93,11 +93,6 @@ func (l *ListArticleLogic) ListArticle(req *types.ListArticleReq) (resp *types.L
|
||||
Page: page, // 当前页码(处理后的有效值)
|
||||
Size: size, // 每页条数(处理后的有效值)
|
||||
}
|
||||
for i, item := range resp.List {
|
||||
fmt.Printf("[DEBUG] 响应第 %d 条文章的 Content:%q\n", i+1, item.Content)
|
||||
}
|
||||
|
||||
l.Infof("文章列表查询成功:topic=%s, page=%d, size=%d, 总条数=%d, 总页数=%d",
|
||||
topic, page, size, total, totalPage)
|
||||
|
||||
return resp, nil
|
||||
}
|
||||
|
||||
@@ -5,29 +5,52 @@ package article
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"github.com/JACKYMYPERSON/hldrCenter/config"
|
||||
"github.com/JACKYMYPERSON/hldrCenter/internal/article/internal/model"
|
||||
"github.com/JACKYMYPERSON/hldrCenter/internal/article/internal/types"
|
||||
"github.com/go-playground/validator/v10"
|
||||
|
||||
"github.com/zeromicro/go-zero/core/logx"
|
||||
)
|
||||
|
||||
type UpdateArticleLogic struct {
|
||||
logx.Logger
|
||||
ctx context.Context
|
||||
cfg *config.Config
|
||||
ctx context.Context
|
||||
cfg *config.Config
|
||||
model model.ArticleModel
|
||||
}
|
||||
|
||||
func NewUpdateArticleLogic(ctx context.Context, cfg *config.Config) *UpdateArticleLogic {
|
||||
func NewUpdateArticleLogic(ctx context.Context, cfg *config.Config, model model.ArticleModel) *UpdateArticleLogic {
|
||||
return &UpdateArticleLogic{
|
||||
Logger: logx.WithContext(ctx),
|
||||
ctx: ctx,
|
||||
cfg: cfg,
|
||||
model: model,
|
||||
}
|
||||
}
|
||||
|
||||
func (l *UpdateArticleLogic) UpdateArticle(req *types.UpdateArticleReq) (resp *types.UpdateArticleResp, err error) {
|
||||
// todo: add your logic here and delete this line
|
||||
validate := validator.New()
|
||||
if err := validate.Struct(req); err != nil {
|
||||
// 新增:打印校验失败原因
|
||||
fmt.Println("参数校验失败:", err)
|
||||
return nil, err
|
||||
}
|
||||
tmp := &model.ArticleUpdate{
|
||||
Id: req.Id,
|
||||
Title: req.Title,
|
||||
Excerpt: req.Excerpt,
|
||||
Cover: req.Cover,
|
||||
Content: req.Content,
|
||||
}
|
||||
|
||||
return
|
||||
fmt.Println("更改的文章信息:", tmp)
|
||||
err = l.model.Update(l.ctx, tmp)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("更新文章失败: %v", err)
|
||||
}
|
||||
|
||||
return &types.UpdateArticleResp{Success: true}, nil
|
||||
}
|
||||
|
||||
@@ -34,16 +34,28 @@ var (
|
||||
"`is_delete`", // 9. 对应 is_delete
|
||||
},
|
||||
",",
|
||||
)
|
||||
)
|
||||
articleChangeFields = func() string {
|
||||
// 获取ArticleUpdate的字段列表(假设RawFieldNames返回带`的字段名,如`title`)
|
||||
fields := stringx.Remove(builder.RawFieldNames(&ArticleUpdate{}), "`id`")
|
||||
// 拼接成 "`title`=?, `content`=?, ..." 格式
|
||||
withPlaceholders := make([]string, len(fields))
|
||||
for i, field := range fields {
|
||||
withPlaceholders[i] = field + "=?"
|
||||
}
|
||||
// 用逗号连接所有字段
|
||||
return strings.Join(withPlaceholders, ", ")
|
||||
}()
|
||||
)
|
||||
|
||||
type (
|
||||
articleModel interface {
|
||||
Insert(ctx context.Context, data *Article) (sql.Result, error)
|
||||
FindOne(ctx context.Context, id int64) (*Article, error)
|
||||
Update(ctx context.Context, data *Article) error
|
||||
Update(ctx context.Context, data *ArticleUpdate) error
|
||||
Delete(ctx context.Context, id int64) error
|
||||
List(ctx context.Context, page, size int, topic string) ([]*Article, int64, error)
|
||||
|
||||
}
|
||||
|
||||
DefaultArticleModel struct {
|
||||
@@ -75,6 +87,15 @@ type (
|
||||
IsDelete int64 `db:"is_delete"` // 与第9个字段对应
|
||||
}
|
||||
|
||||
|
||||
ArticleUpdate struct {
|
||||
Id int64 `db:"id"`
|
||||
Title string `db:"title"`
|
||||
Content string `db:"content"`
|
||||
Cover string `db:"cover"`
|
||||
Excerpt string `db:"excerpt"`
|
||||
}
|
||||
|
||||
)
|
||||
|
||||
func newArticleModel(conn sqlx.SqlConn) *DefaultArticleModel {
|
||||
@@ -85,7 +106,9 @@ func newArticleModel(conn sqlx.SqlConn) *DefaultArticleModel {
|
||||
}
|
||||
|
||||
func (m *DefaultArticleModel) Delete(ctx context.Context, id int64) error {
|
||||
query := fmt.Sprintf("delete from %s where `id` = ?", m.table)
|
||||
// 逻辑删除:更新is_delete字段为1(1表示已删除)
|
||||
query := fmt.Sprintf("update %s set `is_delete` = 1 where `id` = ?", m.table)
|
||||
// 执行更新操作,参数为文章ID(where条件)
|
||||
_, err := m.conn.ExecCtx(ctx, query, id)
|
||||
return err
|
||||
}
|
||||
@@ -110,10 +133,20 @@ func (m *DefaultArticleModel) Insert(ctx context.Context, data *Article) (sql.Re
|
||||
return ret, err
|
||||
}
|
||||
|
||||
func (m *DefaultArticleModel) Update(ctx context.Context, data *Article) error {
|
||||
query := fmt.Sprintf("update %s set %s where `id` = ?", m.table, articleRowsWithPlaceHolder)
|
||||
fmt.Println("Insert SQL 字段列表:", articleRowsExpectAutoSet)
|
||||
_, err := m.conn.ExecCtx(ctx, query, data.Title, data.Content, data.Cover, data.IsDelete, data.Topic, data.Excerpt, data.Id)
|
||||
func (m *DefaultArticleModel) Update(ctx context.Context, data *ArticleUpdate) error {
|
||||
query := fmt.Sprintf("update %s set %s where `id` = ?", m.table, articleChangeFields)
|
||||
fmt.Println("Update SQL:", query) // 打印SQL便于调试
|
||||
|
||||
// 参数顺序:与articleChangeFields中的字段顺序一致,最后跟where条件的id
|
||||
_, err := m.conn.ExecCtx(
|
||||
ctx,
|
||||
query,
|
||||
data.Title, // 对应`title`=?
|
||||
data.Content, // 对应`content`=?
|
||||
data.Cover, // 对应`cover`=?
|
||||
data.Excerpt, // 对应`excerpt`=?
|
||||
data.Id, // 对应where `id`=?
|
||||
)
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -172,9 +205,6 @@ func (m *DefaultArticleModel) List(ctx context.Context, page, size int, topic st
|
||||
articleList := make([]*Article, 0, len(tempList))
|
||||
for _, item := range tempList {
|
||||
|
||||
fmt.Printf("[DEBUG] 扫描到的文章ID:%d,Content值:%q\n", item.Id, item.Content)
|
||||
// 打印 SQL 实际查询的字段,确认 content 存在
|
||||
fmt.Printf("[DEBUG] SQL 查询字段:%s\n", articleListFields)
|
||||
articleList = append(articleList, &Article{
|
||||
Id: item.Id, // 主键
|
||||
Title: item.Title, // 标题
|
||||
@@ -187,9 +217,6 @@ func (m *DefaultArticleModel) List(ctx context.Context, page, size int, topic st
|
||||
IsDelete: item.IsDelete, // 软删除状态
|
||||
})
|
||||
}
|
||||
for i, item := range articleList {
|
||||
fmt.Printf("[DEBUG] 响应第 %d 条文章的 Content:%q\n", i+1, item.Content)
|
||||
}
|
||||
|
||||
|
||||
// 5. 返回结果(Article 切片+总条数+无错误)
|
||||
|
||||
@@ -36,7 +36,7 @@ type DeleteArticleResp struct {
|
||||
}
|
||||
|
||||
type DetailArticleReq struct {
|
||||
Id int64 `path:"id"` // 从路径参数取 ID,如 /api/articles/:id
|
||||
Id int64 `uri:"id" binding:"required,min=1"` // 从路径参数取 ID,如 /api/articles/:id
|
||||
}
|
||||
|
||||
type DetailArticleResp struct {
|
||||
@@ -59,11 +59,10 @@ type ListArticleResp struct {
|
||||
}
|
||||
|
||||
type UpdateArticleReq struct {
|
||||
Id int64 `path:"id"` // 要更新的文章 ID
|
||||
Id int64 `uri:"id" binding:"required,min=1"` // 要更新的文章 ID
|
||||
Title string `json:"title,optional"`
|
||||
Content string `json:"content,optional"`
|
||||
Cover string `json:"cover,optional"`
|
||||
Topic string `json:"topic,optional"`
|
||||
Excerpt string `json:"excerpt,optional"`
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user