Skip to content

fix(posts): Copilot CR 6 条健壮性修复(N+1/404/409/slug) - #36

Merged
longsizhuo merged 1 commit into
mainfrom
fix/posts-cr
May 24, 2026
Merged

fix(posts): Copilot CR 6 条健壮性修复(N+1/404/409/slug)#36
longsizhuo merged 1 commit into
mainfrom
fix/posts-cr

Conversation

@longsizhuo

Copy link
Copy Markdown
Member

背景

针对 #35 合并后 Copilot 提出的 6 条 CR,逐条修复。

修复清单

#问题修复方式
1listFeed N+1:每篇 post 单独查 user_accountsfindFeedWithAuthor 改用 LEFT JOIN user_accounts 一次取回作者字段
2update() slug 未 sanitize前端传入 slug 统一经 sanitizeSlug()(小写/连字符/长度限制),与 create 行为一致
3requirePost()IllegalArgumentException → 400新增 ResourceNotFoundException,GlobalExceptionHandler 映射为 404
4create() 未 catch DuplicateKeyException → 500controller 层 catch,返回 409
5update() 同上controller 层 catch,返回 409
6update() 并发删除后 IllegalStateException → 400repository.update 返回 int affected rows;0 行抛 404

验证

./mvnw -q -DskipTests package 编译通过,无输出。

Co-authored-by: copilot-pull-request-reviewer[bot] <198982749+copilot-pull-request-reviewer[bot]@users.noreply.github.com>

- N+1:findFeedWithAuthor 改 JOIN 一次取回作者字段,消除 service 层逐行 findById
- update() slug 规范化:前端传入的 slug 统一经 sanitizeSlug(),与 create 行为一致
- requirePost() 改抛 ResourceNotFoundException(404),GlobalExceptionHandler 单独处理
- create() / update() 捕获 DuplicateKeyException 返回 409(参考 SharedLinkController)
- repository.update() 返回 int(affected rows);0 行时 service 抛 404 而非 IllegalStateException
Co-authored-by: copilot-pull-request-reviewer[bot] <198982749+copilot-pull-request-reviewer[bot]@users.noreply.github.com>
CopilotAI review requested due to automatic review settings May 24, 2026 17:20

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

该 PR 针对 posts 模块在 #35 合并后提出的健壮性问题做集中修复,目标是改进 feed 查询性能、规范 slug 处理,并将若干异常场景从 400/500 调整为更合理的 404/409 响应语义。

Changes:

  • listFeed 去除 service 层 N+1 查询,改为 repository JOIN 一次取回作者字段
  • update 统一对传入 slug 做 sanitizeSlug(),并用受影响行数判断并发删除场景返回 404
  • 新增 ResourceNotFoundException 并在 GlobalExceptionHandler 中映射为 404;create/update 捕获 DuplicateKeyException 返回 409

Reviewed changes

Copilot reviewed 6 out of 6 changed files in this pull request and generated 5 comments.

Show a summary per file
FileDescription
src/main/java/com/involutionhell/backend/posts/service/PostService.javaupdate slug 规范化、并发删除 404、feed 改走 JOIN 查询
src/main/java/com/involutionhell/backend/posts/repository/PostRepository.javarepository 接口调整:feed 改为返回带作者信息的结果;update 返回受影响行数
src/main/java/com/involutionhell/backend/posts/repository/JdbcPostRepository.java实现 JOIN 查询的 feed 方法;update 改返回 int
src/main/java/com/involutionhell/backend/posts/controller/PostController.javacreate/update 捕获重复键异常并返回 409
src/main/java/com/involutionhell/backend/common/error/ResourceNotFoundException.java新增 404 语义业务异常类型
src/main/java/com/involutionhell/backend/common/error/GlobalExceptionHandler.java新增 ResourceNotFoundException → 404 映射

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +119 to +133
public List<PostSummaryView> findFeedWithAuthor(int limit, int offset) {
// JOIN user_accounts 一次拿回作者字段,消除 service 层 N+1 查询
String sql = "SELECT p.id, p.author_id, p.slug, p.title, p.description, p.tags, "
+ "p.cover_url, p.visibility, p.status, p.promoted_pr_url, "
+ "p.view_count, p.created_at, p.updated_at, "
+ "u.username AS author_username, "
+ "u.display_name AS author_display_name, "
+ "u.avatar_url AS author_avatar_url "
+ "FROM posts p "
+ "LEFT JOIN user_accounts u ON u.id = p.author_id "
+ "WHERE p.status = ? AND p.visibility = ? "
+ "ORDER BY p.created_at DESC LIMIT ? OFFSET ?";
return jdbc.query(sql, (rs, rowNum) -> {
Post p = rowMapper.mapRow(rs, rowNum);
String username = rs.getString("author_username");
Comment on lines 29 to 35
/**
* 公开 feed 列表:status=PUBLISHED + visibility=PUBLIC,按 created_at DESC 分页。
* JOIN user_accounts 一次取回作者信息,避免 service 层 N+1 查询。
* limit 上限由 Service 层限定,避免超大 offset 拖垮 DB。
*/
List<Post> findFeed(int limit, int offset);
List<PostSummaryView> findFeedWithAuthor(int limit, int offset);

Comment on lines +56 to +59
} catch (DuplicateKeyException e) {
return ResponseEntity.status(HttpStatus.CONFLICT)
.body(new ApiResponse<>(false, "slug 已被占用,请修改文件名后重试", null));
}
Comment on lines +74 to +77
} catch (DuplicateKeyException e) {
return ResponseEntity.status(HttpStatus.CONFLICT)
.body(new ApiResponse<>(false, "slug 已被占用,请修改文件名后重试", null));
}
Comment on lines +97 to +101
@ExceptionHandler(ResourceNotFoundException.class)
public ResponseEntity<ApiResponse<Void>> handleResourceNotFound(ResourceNotFoundException e) {
return ResponseEntity.status(HttpStatus.NOT_FOUND)
.body(ApiResponse.fail(e.getMessage()));
}
@longsizhuo
longsizhuo merged commit 5a93a4a into mainMay 24, 2026
1 check passed
longsizhuo added a commit that referenced this pull request May 24, 2026
#36 的 JOIN SQL 只 SELECT 了部分列,rowMapper 读 content_md 时
PSQLException: column not found。改 SELECT p.* 保留全列,
author_* 别名列追加在后,rowMapper 正常工作。
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@longsizhuo