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,逐条修复。

修复清单

# 问题 修复方式
1 listFeed N+1:每篇 post 单独查 user_accounts findFeedWithAuthor 改用 LEFT JOIN user_accounts 一次取回作者字段
2 update() slug 未 sanitize 前端传入 slug 统一经 sanitizeSlug()(小写/连字符/长度限制),与 create 行为一致
3 requirePost()IllegalArgumentException → 400 新增 ResourceNotFoundException,GlobalExceptionHandler 映射为 404
4 create() 未 catch DuplicateKeyException → 500 controller 层 catch,返回 409
5 update() 同上 controller 层 catch,返回 409
6 update() 并发删除后 IllegalStateException → 400 repository.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>
Copilot AI review requested due to automatic review settings May 24, 2026 17:20
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

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
File Description
src/main/java/com/involutionhell/backend/posts/service/PostService.java update slug 规范化、并发删除 404、feed 改走 JOIN 查询
src/main/java/com/involutionhell/backend/posts/repository/PostRepository.java repository 接口调整: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.java create/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 main May 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 free to 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