Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 34 additions & 2 deletions src/main/java/com/handongapp/cms/dto/v1/CommentDto.java
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package com.handongapp.cms.dto.v1;

import com.handongapp.cms.domain.TbComment;
import com.handongapp.cms.domain.TbCommentOfCategory;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.Size;
import lombok.*;
Expand All @@ -23,18 +24,27 @@ public static class Response {
private final String content;
private final LocalDateTime createdAt;
private final LocalDateTime updatedAt;
private final String categorySlug;
private final String categoryLabel;
private final String categoryEmoji;

// Constructor for final fields
public Response(String id, String targetId, String userId, String categoryId, String content, LocalDateTime createdAt, LocalDateTime updatedAt) {
public Response(String id, String targetId, String userId, String categoryId, String content, LocalDateTime createdAt, LocalDateTime updatedAt, String categorySlug, String categoryLabel, String categoryEmoji) {
this.id = id;
this.targetId = targetId;
this.userId = userId;
this.categoryId = categoryId;
this.content = content;
this.createdAt = createdAt;
this.updatedAt = updatedAt;
this.categorySlug = categorySlug;
this.categoryLabel = categoryLabel;
this.categoryEmoji = categoryEmoji;
}

/**
* TbComment ์—”ํ‹ฐํ‹ฐ๋งŒ ์‚ฌ์šฉํ•˜์—ฌ Response ๊ฐ์ฒด ์ƒ์„ฑ
*/
public static Response from(TbComment entity) {
if (entity == null) return null;
return new Response(
Expand All @@ -44,7 +54,29 @@ public static Response from(TbComment entity) {
entity.getCategoryId(),
entity.getContent(),
entity.getCreatedAt(),
entity.getUpdatedAt()
entity.getUpdatedAt(),
null, // categorySlug
null, // categoryLabel
null // categoryEmoji
);
}

/**
* TbComment ์—”ํ‹ฐํ‹ฐ์™€ TbCommentOfCategory ์—”ํ‹ฐํ‹ฐ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ Response ๊ฐ์ฒด ์ƒ์„ฑ
*/
public static Response from(TbComment entity, TbCommentOfCategory category) {
if (entity == null) return null;
return new Response(
entity.getId(),
entity.getTargetId(),
entity.getUserId(),
entity.getCategoryId(),
entity.getContent(),
entity.getCreatedAt(),
entity.getUpdatedAt(),
category != null ? category.getSlug() : null,
category != null ? category.getLabel() : null,
category != null ? category.getEmoji() : null
);
}
}
Expand Down
16 changes: 16 additions & 0 deletions src/main/java/com/handongapp/cms/repository/CommentRepository.java
Original file line number Diff line number Diff line change
Expand Up @@ -26,4 +26,20 @@ List<TbComment> findCommentsByCriteria(
@Param("userId") String userId,
@Param("deletedStatus") String deletedStatus
);

/**
* ์ฝ”๋ฉ˜ํŠธ๋ฅผ ์กฐํšŒํ•˜๋ฉด์„œ ์ฝ”๋ฉ˜ํŠธ ์นดํ…Œ๊ณ ๋ฆฌ ์ •๋ณด๋ฅผ LEFT JOINํ•˜์—ฌ ํ•จ๊ป˜ ๊ฐ€์ ธ์˜ค๋Š” ์ฟผ๋ฆฌ
* ์นดํ…Œ๊ณ ๋ฆฌ๊ฐ€ ์—†๋Š” ๊ฒฝ์šฐ์—๋„ ์ฝ”๋ฉ˜ํŠธ๋Š” ์กฐํšŒ๋˜์–ด์•ผ ํ•˜๊ธฐ ๋•Œ๋ฌธ์— LEFT JOIN ์‚ฌ์šฉ
*/
@Query("SELECT c, cat FROM TbComment c " +
"LEFT JOIN TbCommentOfCategory cat ON c.categoryId = cat.id " +
"WHERE ((:targetIds) IS NULL OR c.targetId IN (:targetIds)) AND " +
"(:userId IS NULL OR c.userId = :userId) AND " +
"c.deleted = :deletedStatus " +
"ORDER BY c.createdAt DESC")
List<Object[]> findCommentsWithCategoriesByCriteria(
@Param("targetIds") List<String> targetIds,
@Param("userId") String userId,
@Param("deletedStatus") String deletedStatus
);
}
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
package com.handongapp.cms.service.impl;

import com.handongapp.cms.domain.TbComment;
import com.handongapp.cms.domain.TbCommentOfCategory;
import com.handongapp.cms.dto.v1.CommentDto;
import com.handongapp.cms.repository.CommentRepository;
import com.handongapp.cms.repository.CommentOfCategoryRepository;
import com.handongapp.cms.mapper.CustomQueryMapper;
import com.handongapp.cms.service.CommentService;
import com.handongapp.cms.exception.data.NotFoundException;
Expand All @@ -24,6 +26,7 @@ public class CommentServiceImpl implements CommentService {
private final CustomQueryMapper customQueryMapper;

private final CommentRepository commentRepository;
private final CommentOfCategoryRepository commentOfCategoryRepository;
private static final String DELETED_STATUS_NO = "N";
private static final String DELETED_STATUS_YES = "Y";

Expand All @@ -34,7 +37,14 @@ public CommentDto.Response create(String userId, CommentDto.CreateRequest req) {

TbComment entity = req.toEntity(userId);
TbComment savedComment = commentRepository.save(entity);
return CommentDto.Response.from(savedComment);

// ์นดํ…Œ๊ณ ๋ฆฌ ์ •๋ณด๋ฅผ ํ•จ๊ป˜ ๋ฐ˜ํ™˜ํ•˜๊ธฐ ์œ„ํ•ด ์นดํ…Œ๊ณ ๋ฆฌ ์กฐํšŒ
TbCommentOfCategory category = null;
if (savedComment.getCategoryId() != null) {
category = commentOfCategoryRepository.findById(savedComment.getCategoryId()).orElse(null);
}
Comment on lines +42 to +45
Copy link
Contributor

@coderabbitai coderabbitai bot Jun 3, 2025

Choose a reason for hiding this comment

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

๐Ÿ› ๏ธ Refactor suggestion

์นดํ…Œ๊ณ ๋ฆฌ ์กด์žฌ์„ฑ ๊ฒ€์ฆ ์ถ”๊ฐ€๋ฅผ ๊ณ ๋ คํ•ด๋ณด์„ธ์š”.

ํ˜„์žฌ ๊ตฌํ˜„์€ categoryId๊ฐ€ ์กด์žฌํ•˜์ง€๋งŒ ํ•ด๋‹น ์นดํ…Œ๊ณ ๋ฆฌ๊ฐ€ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์— ์—†๋Š” ๊ฒฝ์šฐ๋ฅผ ์ฒ˜๋ฆฌํ•˜์ง€๋งŒ, ์‚ฌ์šฉ์ž์—๊ฒŒ ๋ช…ํ™•ํ•œ ํ”ผ๋“œ๋ฐฑ์„ ์ œ๊ณตํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

์นดํ…Œ๊ณ ๋ฆฌ๊ฐ€ ํ•„์ˆ˜์ธ ๊ฒฝ์šฐ ๊ฒ€์ฆ ๋กœ์ง์„ ์ถ”๊ฐ€ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค:

// ์นดํ…Œ๊ณ ๋ฆฌ ์ •๋ณด๋ฅผ ํ•จ๊ป˜ ๋ฐ˜ํ™˜ํ•˜๊ธฐ ์œ„ํ•ด ์นดํ…Œ๊ณ ๋ฆฌ ์กฐํšŒ
TbCommentOfCategory category = null;
if (savedComment.getCategoryId() != null) {
-    category = commentOfCategoryRepository.findById(savedComment.getCategoryId()).orElse(null);
+    category = commentOfCategoryRepository.findById(savedComment.getCategoryId())
+            .orElseThrow(() -> new NotFoundException("์ง€์ •๋œ ์นดํ…Œ๊ณ ๋ฆฌ๋ฅผ ์ฐพ์„ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค. ID: " + savedComment.getCategoryId()));
}

Also applies to: 63-66

๐Ÿค– Prompt for AI Agents
In src/main/java/com/handongapp/cms/service/impl/CommentServiceImpl.java around
lines 42 to 45 and similarly at lines 63 to 66, the code fetches a category by
ID but does not handle the case where the category ID exists but the category is
not found in the database. Add validation to check if the category is null after
fetching; if the category is mandatory, throw an appropriate exception or return
a clear error message to inform the user that the category does not exist.

Copy link
Member

Choose a reason for hiding this comment

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

๋ฐ˜์˜ํ•ด์ฃผ์„ธ์š”

Copy link
Contributor

Choose a reason for hiding this comment

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

@Callein, ์นดํ…Œ๊ณ ๋ฆฌ ์กด์žฌ์„ฑ ๊ฒ€์ฆ์„ ์ถ”๊ฐ€ํ•˜๋Š” ์ฝ”๋“œ ๋ณ€๊ฒฝ์„ ๊ณ„ํšํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค.

graph TB
  A["Task: ์นดํ…Œ๊ณ ๋ฆฌ ์กด์žฌ์„ฑ ๊ฒ€์ฆ ์ถ”๊ฐ€"]
  A --> B["create ๋ฉ”์„œ๋“œ์˜ ์นดํ…Œ๊ณ ๋ฆฌ ์กฐํšŒ ๋กœ์ง ์ˆ˜์ •"]
  A --> C["update ๋ฉ”์„œ๋“œ์˜ ์นดํ…Œ๊ณ ๋ฆฌ ์กฐํšŒ ๋กœ์ง ์ˆ˜์ •"]
  B --> D["orElse(null)์„ orElseThrow()๋กœ ๋ณ€๊ฒฝ"]
  C --> E["orElse(null)์„ orElseThrow()๋กœ ๋ณ€๊ฒฝ"]
  D --> F["NotFoundException์œผ๋กœ ๋ช…ํ™•ํ•œ ์—๋Ÿฌ ๋ฉ”์‹œ์ง€ ์ œ๊ณต"]
  E --> G["NotFoundException์œผ๋กœ ๋ช…ํ™•ํ•œ ์—๋Ÿฌ ๋ฉ”์‹œ์ง€ ์ œ๊ณต"]
Loading

๋‹ค๋ฅธ ์—์ด์ „ํŠธ๊ฐ€ ์ด ๋ณ€๊ฒฝ์‚ฌํ•ญ๋“ค์„ ์‹ค์ œ๋กœ ๊ตฌํ˜„ํ•  ์˜ˆ์ •์ž…๋‹ˆ๋‹ค. ์ด ๋ณ€๊ฒฝ์œผ๋กœ ์นดํ…Œ๊ณ ๋ฆฌ ID๊ฐ€ ์กด์žฌํ•˜์ง€๋งŒ ํ•ด๋‹น ์นดํ…Œ๊ณ ๋ฆฌ๊ฐ€ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์— ์—†๋Š” ๊ฒฝ์šฐ ๋ช…ํ™•ํ•œ ์—๋Ÿฌ ๋ฉ”์‹œ์ง€์™€ ํ•จ๊ป˜ ์˜ˆ์™ธ๊ฐ€ ๋ฐœ์ƒํ•˜๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.


โณ Preparing changes...

Copy link
Contributor

Choose a reason for hiding this comment

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

A summary of the edits CodeRabbit can apply:

CommentServiceImpl.java์˜ create ๋ฐ update ๋ฉ”์„œ๋“œ์— ์นดํ…Œ๊ณ ๋ฆฌ ์กด์žฌ์„ฑ ๊ฒ€์ฆ ๋กœ์ง์ด ์ถ”๊ฐ€๋  ์˜ˆ์ •์ž…๋‹ˆ๋‹ค.

A plan of each step that CodeRabbit will take in order to execute the edits for each file (with inline rough draft snippets):

โœ๏ธ src/main/java/com/handongapp/cms/service/impl/CommentServiceImpl.java

create ๋ฉ”์„œ๋“œ ๋‚ด๋ถ€์—์„œ ์นดํ…Œ๊ณ ๋ฆฌ ์กฐํšŒ ๋ถ€๋ถ„์„ ์ฐพ์Šต๋‹ˆ๋‹ค (๋Œ€๋žต 42~45ํ–‰):
TbCommentOfCategory category = null; if (savedComment.getCategoryId() != null) { category = commentOfCategoryRepository.findById(savedComment.getCategoryId()).orElse(null); }


์œ„ ์ฝ”๋“œ์—์„œ orElse(null) ํ˜ธ์ถœ์„ ๋‹ค์Œ๊ณผ ๊ฐ™์ด ๊ต์ฒดํ•ฉ๋‹ˆ๋‹ค. NotFoundException์„ ๋˜์ ธ์„œ ์กด์žฌํ•˜์ง€ ์•Š๋Š” ์นดํ…Œ๊ณ ๋ฆฌ์— ๋Œ€ํ•œ ๋ช…ํ™•ํ•œ ์˜ค๋ฅ˜ ๋ฉ”์‹œ์ง€๋ฅผ ์ œ๊ณตํ•˜๋„๋ก ํ•ฉ๋‹ˆ๋‹ค:
diff - category = commentOfCategoryRepository.findById(savedComment.getCategoryId()).orElse(null); + category = commentOfCategoryRepository.findById(savedComment.getCategoryId()) + .orElseThrow(() -> new NotFoundException("์ง€์ •๋œ ์นดํ…Œ๊ณ ๋ฆฌ๋ฅผ ์ฐพ์„ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค. ID: " + savedComment.getCategoryId()));


update ๋ฉ”์„œ๋“œ ๋‚ด๋ถ€์—์„œ ์นดํ…Œ๊ณ ๋ฆฌ ์กฐํšŒ ๋ถ€๋ถ„์„ ์ฐพ์Šต๋‹ˆ๋‹ค (๋Œ€๋žต 63~66ํ–‰):
TbCommentOfCategory category = null; if (entity.getCategoryId() != null) { category = commentOfCategoryRepository.findById(entity.getCategoryId()).orElse(null); }


์œ„ ์ฝ”๋“œ์—์„œ orElse(null) ํ˜ธ์ถœ์„ ๋‹ค์Œ๊ณผ ๊ฐ™์ด ๊ต์ฒดํ•ฉ๋‹ˆ๋‹ค. NotFoundException์„ ๋˜์ ธ์„œ ์กด์žฌํ•˜์ง€ ์•Š๋Š” ์นดํ…Œ๊ณ ๋ฆฌ์— ๋Œ€ํ•œ ๋ช…ํ™•ํ•œ ์˜ค๋ฅ˜ ๋ฉ”์‹œ์ง€๋ฅผ ์ œ๊ณตํ•˜๋„๋ก ํ•ฉ๋‹ˆ๋‹ค:
diff - category = commentOfCategoryRepository.findById(entity.getCategoryId()).orElse(null); + category = commentOfCategoryRepository.findById(entity.getCategoryId()) + .orElseThrow(() -> new NotFoundException("์ง€์ •๋œ ์นดํ…Œ๊ณ ๋ฆฌ๋ฅผ ์ฐพ์„ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค. ID: " + entity.getCategoryId()));


ํŒŒ์ผ ์ƒ๋‹จ์— NotFoundException import๊ฐ€ ์žˆ๋Š”์ง€ ํ™•์ธํ•ฉ๋‹ˆ๋‹ค.
java import com.handongapp.cms.exception.data.NotFoundException;
๋ˆ„๋ฝ๋˜์–ด ์žˆ๋‹ค๋ฉด ์ถ”๊ฐ€ํ•ฉ๋‹ˆ๋‹ค.


๋‹จ์œ„ ํ…Œ์ŠคํŠธ๋‚˜ ํ†ตํ•ฉ ํ…Œ์ŠคํŠธ๋ฅผ ์‹คํ–‰ํ•˜์—ฌ, categoryId๊ฐ€ ์กด์žฌํ•˜์ง€ ์•Š์„ ๋•Œ NotFoundException์ด ๋ฐœ์ƒํ•˜๋ฉฐ ๋ฉ”์‹œ์ง€๊ฐ€ ์˜ฌ๋ฐ”๋ฅธ์ง€ ๊ฒ€์ฆํ•ฉ๋‹ˆ๋‹ค.

  • โœ… Create PR with these edits
  • ๐Ÿ“Œ Create commit in current branch
  • ๐Ÿ“‹ Get copyable edits

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@Callein ์ด๊ฑฐ ๋ฐ์ดํ„ฐ ์ค‘์—์„œ ๋Œ“๊ธ€์€ ์žˆ๋Š”๋ฐ ๋Œ“๊ธ€ ์นดํ…Œ๊ณ ๋ฆฌ์— ํ•ด๋‹นํ•˜๋Š” ์นดํ…Œ๊ณ ๋ฆฌ๊ฐ€ ์—†๋Š” ๋Œ“๊ธ€์ด ํ˜น์‹œ๋‚˜ ์ƒ๊ธฐ๋Š” ๊ฒฝ์šฐ์— ํ•ด๋‹น ๋Œ“๊ธ€์„ ์ •์ƒ์ ์œผ๋กœ ๋ณด์ „ํ•˜๊ธฐ ์œ„ํ•ด ์ผ๋ถ€๋กœ left join์„ ์‚ฌ์šฉํ•˜๋ฉด์„œ null์ด ๊ฐ€๋Šฅํ•˜๋„๋ก ํ•ด๋‘” ๊ฒ๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด ๋™์•„๋ฆฌ ๊ด€๋ฆฌ์ž๊ฐ€ ์นดํ…Œ๊ณ ๋ฆฌ ์ •๋ณด๋ฅผ ์ž„์˜๋กœ ์‚ญ์ œํ•˜์˜€์„ ๋•Œ ํ•ด๋‹น ์นดํ…Œ๊ณ ๋ฆฌ์— ์†ํ•œ ๋Œ“๊ธ€๋“ค์„ ๋ฐ์ดํ„ฐ๋ฅผ ์ •์ƒ์ ์œผ๋กœ ํ‘œ๊ธฐํ•˜๊ธฐ ์œ„ํ•ด ์žˆ์Šต๋‹ˆ๋‹ค.

Copy link
Contributor

Choose a reason for hiding this comment

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

Seems like the humans are having a chat. I'll hop back into my burrow for now. If you need me again, just tag @coderabbitai in a new comment, and I'll come hopping out!

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@junglesub ์ด๊ฑฐ ์ผ€์ด์Šค ์–ด๋–ป๊ฒŒ ํ• ์ง€ ๋ด์ฃผ์„ธ์š”


return CommentDto.Response.from(savedComment, category);
}

@Override
Expand All @@ -48,7 +58,14 @@ public CommentDto.Response update(String commentId, String userId, CommentDto.Up
}

req.applyTo(entity);
return CommentDto.Response.from(entity);

// ์นดํ…Œ๊ณ ๋ฆฌ ์ •๋ณด๋ฅผ ํ•จ๊ป˜ ๋ฐ˜ํ™˜ํ•˜๊ธฐ ์œ„ํ•ด ์นดํ…Œ๊ณ ๋ฆฌ ์กฐํšŒ
TbCommentOfCategory category = null;
if (entity.getCategoryId() != null) {
category = commentOfCategoryRepository.findById(entity.getCategoryId()).orElse(null);
}

return CommentDto.Response.from(entity, category);
}

@Override
Expand Down Expand Up @@ -86,10 +103,16 @@ public List<CommentDto.Response> searchComments(
targetIdsForQuery = resolveTargetIds(resolvedCourseId);
}

List<TbComment> comments = commentRepository.findCommentsByCriteria(targetIdsForQuery, resolvedUserId, DELETED_STATUS_NO);
// ์นดํ…Œ๊ณ ๋ฆฌ ์ •๋ณด๋ฅผ ํ•จ๊ป˜ ์กฐํšŒํ•˜๋Š” ์กฐ์ธ ์ฟผ๋ฆฌ ์‚ฌ์šฉ
List<Object[]> commentsWithCategories = commentRepository.findCommentsWithCategoriesByCriteria(
targetIdsForQuery, resolvedUserId, DELETED_STATUS_NO);

return comments.stream()
.map(CommentDto.Response::from)
return commentsWithCategories.stream()
.<CommentDto.Response>map(result -> {
TbComment comment = (TbComment) result[0];
TbCommentOfCategory category = result.length > 1 ? (TbCommentOfCategory) result[1] : null;
return CommentDto.Response.from(comment, category);
})
.collect(Collectors.toList());
}

Expand Down Expand Up @@ -182,6 +205,4 @@ private List<String> resolveTargetIds(String courseId) {
private List<String> resolveTargetIdsByNodeGroup(String nodeGroupId) {
return isNotEmpty(nodeGroupId) ? customQueryMapper.findTargetIdsByNodeGroupId(nodeGroupId) : null;
}


}