[feat] 여행 정보 community 게시물 및 댓글 관련 서비스 구현 #104
[feat] 여행 정보 community 게시물 및 댓글 관련 서비스 구현 #104LEEDONGH00N merged 7 commits intowith-travel:developfrom
Conversation
There was a problem hiding this comment.
Pull Request Overview
Implements a comprehensive community feature for travel information with CRUD operations for posts and comments. The PR adds the ability for users to create, read, update, and delete community posts with search functionality, along with comment management and a like system.
Key changes include:
- Community post management with dynamic search filtering using JPA Specifications
- Comment system with infinite scroll pagination using Slice-based queries
- Like functionality for comments with duplicate prevention
Reviewed Changes
Copilot reviewed 21 out of 21 changed files in this pull request and generated 5 comments.
Show a summary per file
| File | Description |
|---|---|
| SecurityUtils.java | Utility class for extracting current authenticated member ID from security context |
| ErrorCode.java | Added error codes for community and reply validation scenarios |
| Image.java | Added methods to attach/detach images from community posts |
| CommunityService.java | Core business logic for community CRUD operations with search functionality |
| CommunityRepository.java | JPA repository with custom queries for community data access |
| Community.java | Enhanced entity with builder pattern and business methods |
| CommunityReplyService.java | Service layer for comment CRUD operations and like functionality |
| CommunityReply.java | Enhanced entity with builder pattern and content modification |
| CommunityReplyLike.java | New entity representing comment likes |
| Various DTOs and Controllers | Request/response objects and REST endpoints for the community features |
Tip: Customize your code reviews with copilot-instructions.md. Create the file or learn how to get started.
src/main/java/com/arom/with_travel/domain/community/dto/CommunityDetailResponse.java
Outdated
Show resolved
Hide resolved
src/main/java/com/arom/with_travel/domain/community/service/CommunityService.java
Outdated
Show resolved
Hide resolved
| @RequestParam(defaultValue = "50") int size) { | ||
|
|
||
| Long me = null; | ||
| try { me = SecurityUtils.currentMemberIdOrThrow(); } catch (Exception ignore) {} |
There was a problem hiding this comment.
Catching all exceptions with an empty catch block is a poor practice. Consider catching only the specific expected exception (IllegalStateException) or use a more explicit approach to handle optional authentication.
| try { me = SecurityUtils.currentMemberIdOrThrow(); } catch (Exception ignore) {} | |
| try { me = SecurityUtils.currentMemberIdOrThrow(); } catch (IllegalStateException ignore) {} |
| public interface CommunityReplyRepository extends JpaRepository<CommunityReply, Long> { | ||
|
|
||
| @EntityGraph(attributePaths = {"member"}) | ||
| Page<CommunityReply> findByCommunity(Community community, Pageable pageable); |
There was a problem hiding this comment.
This method is not used in the service layer. The service uses findByCommunityOrderByCreatedAtAsc which returns a Slice. Consider removing this unused method or documenting its intended use.
| Page<CommunityReply> findByCommunity(Community community, Pageable pageable); |
| c.update(req.getTitle(), req.getContent(), req.getContinent(), req.getCountry(), req.getCity()); | ||
|
|
||
| if (req.getImages() != null) { | ||
| c.getImages().forEach(Image::detachFromCommunity); |
There was a problem hiding this comment.
This operation may cause an N+1 query problem if images are not eagerly loaded. Consider using a bulk delete query or ensure the images are fetched in a single query before this operation.
| c.getImages().forEach(Image::detachFromCommunity); | |
| List<Image> images = c.getImages().stream().collect(Collectors.toList()); // Force initialization to avoid N+1 | |
| images.forEach(Image::detachFromCommunity); |
…ityDetailResponse.java Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
| public class CommunitySpecs { | ||
| private CommunitySpecs() {} | ||
|
|
There was a problem hiding this comment.
JPA Specification 모아 둔 유틸 클래스인데 대륙/국가/도시/검색 키워드 조건을 동적으로 조합해서 커뮤니티 게시글 검색할 때 사용하려고 만든 거예요
| public static Community create(Member writer, String title, String content, | ||
| String continent, String country, String city) { | ||
| Community c = Community.builder() | ||
| .member(writer) | ||
| .title(title) | ||
| .content(content) | ||
| .continent(continent) | ||
| .country(country) | ||
| .city(city) | ||
| .build(); | ||
| return c; | ||
| } |
| public void update(String title, String content, String continent, String country, String city) { | ||
| if (title != null) this.title = title; | ||
| if (content != null) this.content = content; | ||
| if (continent != null) this.continent = continent; | ||
| if (country != null) this.country = country; | ||
| if (city != null) this.city = city; | ||
| } |
There was a problem hiding this comment.
null 여부를 확인하지 말고 그냥 값을 초기화하면 될것 같습니다. 게시글 수정 시 수정된 부분만 받는것이 아닌 전체 수정으로 받을 것 같기 때문입니다.
| communityRepository.increaseViewCount(id); | ||
| Community c = communityRepository.findDetailById(id); | ||
| if (c == null) throw BaseException.from(ErrorCode.COMMUNITY_NOT_FOUND); |
There was a problem hiding this comment.
조회 수를 늘리기 전에 먼저 게시글을 DB에서 조회해오고 나서 조회수를 증가시켜주세요
| Specification<Community> spec = Specification | ||
| .where(continentEq(continent)) | ||
| .and(countryEq(country)) | ||
| .and(cityEq(city)) | ||
| .and(keywordLike(q)); |
There was a problem hiding this comment.
Specification 클래스가 어떤 의미로 쓰이나요?
There was a problem hiding this comment.
국가·도시 등 검색 파라미터 중 값이 설정된 항목만 조건으로 추가하고, 값이 없는 필드는 자동으로 무시되도록 하여 필요한 조건만 AND로 조합하여 필터링에 유연성을 두기위해 사용했습니다
| .community(community) | ||
| .member(writer) | ||
| .content(content) | ||
| .build(); |
| public static CommunityReplyLike of(CommunityReply reply, Member member) { | ||
| return CommunityReplyLike.builder().reply(reply).member(member).build(); | ||
| } |
| public Page<CommunityListItemResponse> search(String continent, String country, String city, String q, | ||
| Pageable pageable) { |
There was a problem hiding this comment.
어느 곳에선 Slice를 반환하고, 어느곳에선 Page를 반환하던데, 이유가 있을까요?
There was a problem hiding this comment.
Page 는 게시물들 리스트를 불러올때 검색 조건에 맞는 게시물이 몇개인지 페이지 수랑 그런거 ui에 필요할 것 같아서 게시물에 쓰였고, Slice 는 게시물의 댓글 리스트 불러올때 사용했습니다
…mmunityService.java Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
이슈
구현 기능
커뮤니티 게시글 CRUD
커뮤니티 댓글 CRUD
댓글 좋아요 기능
구현 근거
검색 기능 (Specification)
게시글 조회 (Page)
댓글 조회 (Slice)
좋아요 기능