微头条项目开发笔记|BUG修复 + 新闻详情页面完整开发记录

微头条项目开发笔记|BUG修复 + 新闻详情页面完整开发记录

前言

本次课完成两大块内容:修复两个线上功能性BUG(越权删除提示错误、发布新闻用户发布计数不增长);全新开发新闻详情页面,解决详情页作者名称不展示问题,完整梳理排错思路与前后端配套修改方案。

一、课次35:线上BUG定位与修复

Bug1:删除他人新闻仍弹出「删除成功」提示(前端判断逻辑缺失)

问题根源

后端删除接口已经做权限校验:非新闻发布者删除时,返回code≠200message="只能删除自己的新闻"标准错误结果,但前端删除接口调用后未判断返回码,无论后端成功/失败都直接弹出成功提示,造成功能逻辑错乱。

排错思路

  1. 后端接口统一返回Result封装结构,业务错误不会抛出异常,仅修改code与提示文案;
  2. 后端逻辑无漏洞,问题锁定在前端删除请求的回调判断;
  3. 前端接收后端响应后,增加res.code === 200分支判断,区分成功、失败场景分别弹窗。

修复要点

前端删除方法新增返回码判断:

const homeDeleteNews = async (id) => {
  try {
    const res = await deleteNews(id)
    if(res.code===200){
      ElMessage.success(res.message)
      loadNews() // 刷新列表
    }else{
      ElMessage.error(res.message)
    }
  } catch {
    ElMessage.error('请求失败')
  }
}

修改完成后,删除不属于自己的新闻时,正常弹出「只能删除自己的新闻」提示,越权操作拦截生效。


Bug2:发布新闻后用户表news_count发布数量不自动+1

问题根源

原始发布接口仅完成新闻插入操作,缺少同步更新用户发布计数的逻辑,用户发布文章数不会累加。

后端代码改造(NewsController#addNews)

  1. 注入UserService用于操作用户表;
  2. 新闻插入成功后,使用LambdaUpdateWrapper执行SQL自增,更新对应用户news_count = news_count + 1
  3. 双重判断:新闻保存、用户计数更新全部成功,才返回发布成功;任一失败则提示发布失败;
  4. 添加打印日志输出当前登录用户ID,方便调试校验token解析的用户身份。
@Autowired
private UserService userService;

@PostMapping("/add")
public Result<?> addNews(@RequestBody NewsAddDTO dto) {
    // 1. 插入新闻
    Integer userId = UserContext.getCurrentUserId();
    System.out.println("当前用户ID:" + userId);
    if (userId == null) return Result.error("请先登录");
    News news = new News();
    news.setUserId(userId);
    news.setTitle(dto.getTitle());
    news.setContent(dto.getContent());
    news.setViewCount(0);
    boolean saved = newsService.save(news);
    // 2. 更新用户的 news_count + 1
    LambdaUpdateWrapper<User> wrapper = new LambdaUpdateWrapper<>();
    wrapper.eq(User::getId, userId)
            .setSql("news_count = news_count + 1");
    boolean updated = userService.update(wrapper);

    if (saved && updated) {
        return Result.success("发布成功");
    } else {
        return Result.error("发布失败");
    }
}

前端配套问题排查

原始前端发布代码写死userId:1,怀疑身份传递异常;通过后端打印日志验证:用户ID由JWT拦截器解析存入UserContext,前端无需手动传递userId,写死ID仅为本地测试冗余代码,不影响线上逻辑。

验证方案

使用id≠1的测试账号登录发布新闻,查看后端控制台打印正确userId,刷新数据库user表,对应用户news_count数值自动+1,BUG修复完成。

二、课次37:新闻详情页面完整开发 + 作者名不展示BUG修复

开发目标

  1. 根据路由传参新闻id,请求后端/news/{id}接口渲染新闻详情;
  2. 展示标题、作者、发布时间、浏览量、正文;
  3. 权限控制:仅新闻发布者可见「编辑、删除」按钮;
  4. 新增返回首页、编辑、删除交互弹窗。

步骤1:新建Detail.vue详情页面完整代码

页面使用Vue3 script setup语法,集成路由参数读取、页面加载请求、登录用户鉴权、删除弹窗确认逻辑:

<!-- src/views/Detail.vue -->
<template>
  <div class="detail-container">
    <el-card v-loading="loading">
      <template v-if="news">
        <h2>{{ news.title }}</h2>
        <div class="info">
          <span>作者:{{ news.username || '匿名' }}</span>
          <span>发布时间:{{ news.publishTime }}</span>
          <span>浏览量:{{ news.viewCount }}</span>
        </div>
        <div class="content">{{ news.content }}</div>
        <div class="actions">
          <el-button @click="$router.back()">返回首页</el-button>
          <el-button type="primary" @click="goToEdit" v-if="isOwner">编辑</el-button>
          <el-button type="danger" @click="handleDelete" v-if="isOwner">删除</el-button>
        </div>
      </template>
    </el-card>
  </div>
</template>

<script setup>
import { ref, onMounted, computed } from 'vue'
import { useRoute, useRouter } from 'vue-router'
import { getNewsDetail, deleteNews } from '../api/news'
import { useUserStore } from '../stores/user'
import { ElMessage, ElMessageBox } from 'element-plus'

const route = useRoute()
const router = useRouter()
const userStore = useUserStore()
const news = ref(null)
const loading = ref(false)

const isOwner = computed(() => {
  return news.value && userStore.username && news.value.username === userStore.username
})

const loadDetail = async () => {
  loading.value = true
  try {
    const res = await getNewsDetail(route.params.id)
    if (res.code === 200) {
      news.value = res.data
    } else {
      ElMessage.error(res.message)
    }
  } finally {
    loading.value = false
  }
}

const goToEdit = () => {
  router.push(`/edit/${news.value.id}`)
}

const handleDelete = async () => {
  try {
    await ElMessageBox.confirm('确定删除该新闻吗?', '提示', { type: 'warning' })
    const res = await deleteNews(news.value.id)
    if (res.code === 200) {
      ElMessage.success('删除成功')
      router.push('/home')
    } else {
      ElMessage.error(res.message)
    }
  } catch {}
}

onMounted(loadDetail)
</script>

<style scoped>
.detail-container { max-width: 800px; margin: 40px auto; }
.info { color: #909399; font-size: 14px; margin: 16px 0; }
.info span { margin-right: 20px; }
.content { font-size: 16px; line-height: 1.8; margin: 20px 0; }
.actions { margin-top: 20px; }
</style>

核心功能说明:

  1. route.params.id 获取路由传递的新闻主键;
  2. computed 计算属性isOwner对比登录用户名与新闻作者,控制编辑/删除按钮显示;
  3. 删除操作增加二次确认弹窗,防止误操作;
  4. 请求增加loading加载状态、错误提示统一捕获。

页面BUG:详情页无法显示作者名称

问题原因

  1. News实体类仅存储userId数字,无用户名字段;
  2. 原始getNewsDetail仅返回新闻表数据,未关联查询用户表获取用户名;
  3. 前端模板绑定authorName,后端无此字段,渲染为空。

后端修复:改造详情接口

修改getNewsDetail方法,查询新闻后根据userId关联查询用户,把用户名存入新闻实体返回给前端:

@GetMapping("/{id}")
public Result<News> getNewsDetail(@PathVariable Integer id) {
    News news = newsService.getById(id);
    if (news != null) {
        // 增加浏览量
        news.setViewCount(news.getViewCount() + 1);
        newsService.updateById(news);
        // 关联用户表查询作者名
        User user = userService.getById(news.getUserId());
        news.setUserName(user.getUsername());
        return Result.success(news);
    } else {
        return Result.error("新闻不存在");
    }
}

配套:News实体新增username属性,提供get/set方法。

前端批量替换字段

使用VSCode全局替换快捷键Ctrl+H,将页面中所有authorName批量替换为username,和后端返回字段保持一致。

验证

重启前后端,点击新闻进入详情页,作者名称正常渲染,编辑、删除按钮仅本人可见,浏览量自动累加,全部功能正常。

今日整体复盘

  1. BUG排查思路标准化:先区分前后端责任,后端校验正常则定位前端回调判断缺失;打印日志、数据库校验双重验证数据流转;
  2. 掌握MyBatis-Plus自更新语法setSql,实现发布计数自动累加,业务数据同步更新;
  3. 完成完整详情页开发,实现路由传参、鉴权按钮、二次确认删除、加载状态等交互;
  4. 学会实体类多表关联临时赋值方案,无需新建DTO即可携带关联用户信息返回前端;
  5. 优化前端请求健壮性:所有接口统一判断code===200,区分业务成功/失败场景提示。

c5112552-05aa-4ce9-af60-3aa892cc1f8b

posted @ 2026-06-24 09:14  橙糯CiiiiiX  阅读(4)  评论(0)    收藏  举报