Conversation
- PostRequestDTO โ Post ๋ณํ ๋ก์ง toEntity(User)๋ก ์์ - ๋ชจ์ง๊ธ ๋ฑ๋ก ์ Skill ์กด์ฌ ์ฌ๋ถ ํ์ธ ํ ์์ผ๋ฉด ์์ฑ - PostResponseDTO, PostDetailDTO ์๋ต ๊ตฌ์กฐ ํต์ผ - ๋ชจ์ง๊ธ ๋ฑ๋ก/์กฐํ ์ Post โ Skill ๋ฆฌ์คํธ ์ฐ๊ฒฐ ์ฒ๋ฆฌ - ํ์ฌ ์ฐธ์ฌ์ ์(currentCount)๋ TODO๋ก ์ถํ ๊ตฌํ ์์
- ๋ชจ์ง๊ธ ์์ฑ ๋ฐ ์กฐํ ๊ธฐ๋ฅ ๊ด๋ จ ๊ตฌํ ํ์ผ ์ถ๊ฐ ์ ๋ก๋
- PostRepository์ ์ฟผ๋ฆฌ ๊ธฐ๋ฐ fetch join ๋ฉ์๋ ์ถ๊ฐ - Post ๊ฒ์๊ธ ์กฐํ ์ ๋ฐ์ํ๋ N+1 ๋ฌธ์ ํด๊ฒฐ - Repository ํจํค์ง๋ช ์คํ ์์
- findByWithSkills() ์ฟผ๋ฆฌ์ WHERE p.id = :id ์กฐ๊ฑด ๋๋ฝ - ๊ฐ์ ๊ฒ์๋ฌผ๋ง ๋ฐํ๋๋ ๋ฌธ์ ํด๊ฒฐ
|
@coderabbitai review |
There was a problem hiding this comment.
Actionable comments posted: 12
๐ญ Outside diff range comments (2)
src/main/java/aibe/hosik/apply/controller/ApplyController.java (1)
1-15:โ ๏ธ Potential issue์ปจํธ๋กค๋ฌ์ ์๋ํฌ์ธํธ ๋ฉ์๋ ์ถ๊ฐ ํ์
ํ์ฌApplyController๊ฐ ์์ฑ๋ง ๋์ด ์๊ณ , ์ค์ ์ง์(Apply) ๋ฑ๋ก/์กฐํ ๋ฑ์ REST API ๋ฉ์๋๊ฐ ๊ตฌํ๋์ด ์์ง ์์ต๋๋ค. ์ด๋๋ก ๋ฐฐํฌํ๋ฉด ๊ธฐ๋ฅ์ด ์ ๊ณต๋์ง ์์ผ๋ฏ๋ก, CRUD ๊ด๋ จ ํธ๋ค๋ฌ ๋ฉ์๋๋ฅผ ์ถ๊ฐํด ์ฃผ์ธ์.src/main/java/aibe/hosik/apply/service/ApplyService.java (1)
1-13: ๐ก Verification agent๐งฉ Analysis chain
์๋น์ค ํด๋์ค์ ๋น์ฆ๋์ค ๋ก์ง์ด ๊ตฌํ๋์ด ์์ง ์์ต๋๋ค
ApplyService ํด๋์ค๊ฐ ์ฌ๋ฐ๋ฅด๊ฒ ์ค์ ๋์ด ์์ง๋ง, ํ์ฌ ๋น์ฆ๋์ค ๋ก์ง์ด ๊ตฌํ๋์ด ์์ง ์์ต๋๋ค. ๋ชจ์ง๊ธ ๊ด๋ จ ๊ธฐ๋ฅ์ด ์ถ๊ฐ๋์๋ค๋ฉด ์ง์์(Apply) ๊ด๋ จ ์ฒ๋ฆฌ ๋ก์ง๋ ํ์ํ ๊ฒ์ผ๋ก ์์๋ฉ๋๋ค.
์๋ฅผ ๋ค์ด, ์ง์์ ์ ์ถ, ์ง์์ ์กฐํ, ์ง์ ์ํ ๋ณ๊ฒฝ ๋ฑ์ ๋ฉ์๋๊ฐ ๊ตฌํ๋๋ฉด ์ข์ ๊ฒ ๊ฐ์ต๋๋ค.
๐ Script executed:
#!/bin/bash # ApplyController์์ ApplyService๋ฅผ ์ด๋ป๊ฒ ์ฌ์ฉํ๋์ง ํ์ธ echo "Checking how ApplyService is used in ApplyController..." fd -t f ApplyController.java | xargs catLength of output: 603
ApplyService์ ๋น์ฆ๋์ค ๋ก์ง์ด ๊ตฌํ๋์ด ์์ง ์์ต๋๋ค
ํ์ฌ
ApplyService๋ApplyRepository๋ง ์ฃผ์ ๋ฐ๊ณ ์์ผ๋ฉฐ, ์ค์ CRUD๋ ์ํ ๋ณ๊ฒฝ ๋ก์ง์ ์ํํ๋ ๋ฉ์๋๊ฐ ์์ต๋๋ค. ์ด๋ก ์ธํดApplyController์์๋ ํธ์ถ ๊ฐ๋ฅํ ์๋ํฌ์ธํธ๊ฐ ์ ํ ๊ตฌํ๋์ง ์์ ์ํ์ ๋๋ค. ์๋์ ๊ฐ์ ํต์ฌ ๊ธฐ๋ฅ์ ์๋น์ค ๋ ์ด์ด์ ์ถ๊ฐํด์ฃผ์ธ์:
- ์ง์์ ์ ์ถ ๋ฉ์๋ (์:
createApply(...))- ์ง์์ ๋จ๊ฑด ์กฐํ ๋ฉ์๋ (์:
getApplyById(...))- ์ง์์ ๋ชฉ๋ก ์กฐํ ๋ฉ์๋ (์:
listApplies(...))- ์ง์ ์ํ ๋ณ๊ฒฝ ๋ฉ์๋ (์:
updateApplyStatus(...))
๐งน Nitpick comments (15)
src/main/java/aibe/hosik/post/dto/MatchedUserDTO.java (1)
3-5: ๋ฏธ์ฌ์ฉ import ์ ๊ฑฐ ๊ถ์ฅ
Post์List๊ฐ ํด๋น DTO์์ ์ฌ์ฉ๋์ง ์๊ณ ์์ด ์ฝ๋ ๊ฐ๋ ์ฑ๊ณผ ์ ์ง๋ณด์๋ฅผ ์ํด ์ ๊ฑฐํ๋ ๊ฒ์ด ์ข์ต๋๋ค.src/main/java/aibe/hosik/apply/entity/Apply.java (1)
28-32: ๊ด๊ณ ๋งคํ์ @joincolumn ์ถ๊ฐ ๊ถ์ฅ
@ManyToOneํ๋์ ๋ช ์์ ์ธ@JoinColumn(name = "...")์ ์ถ๊ฐํ๋ฉด DB ์ปฌ๋ผ ์ด๋ฆ์ด ๋ช ํํด์ง๊ณ , ํฅํ ๋ฆฌํฉํ ๋ง ์ ์ค์๋ฅผ ์ค์ผ ์ ์์ต๋๋ค.src/main/java/aibe/hosik/analysis/Analysis.java (1)
29-30: ๊ด๊ณ ๋งคํ์ @joincolumn ์ถ๊ฐ ๊ถ์ฅ
@ManyToOne(fetch = FetchType.LAZY)ํ๋์๋@JoinColumn(name = "apply_id")์ ๊ฐ์ ๋ช ์์ ์ค์ ์ ์ถ๊ฐํ๋ฉด ์คํค๋ง ์ดํด๋๊ฐ ๋์์ง๋๋ค.src/main/java/aibe/hosik/skill/cotnroller/SkillController.java (1)
3-15: ์ปจํธ๋กค๋ฌ์ ์๋ํฌ์ธํธ๊ฐ ๊ตฌํ๋์ด ์์ง ์์ต๋๋คSkillController ํด๋์ค๊ฐ ์ฌ๋ฐ๋ฅด๊ฒ ์ค์ ๋์ด ์์ง๋ง, ํ์ฌ ์ด๋ค ์๋ํฌ์ธํธ๋ ๊ตฌํ๋์ด ์์ง ์์ต๋๋ค. ํ๋ก์ ํธ ์ค๋ช ์ ๋ฐ๋ฅด๋ฉด ๋ชจ์ง๊ธ ๊ด๋ จ ๊ธฐ๋ฅ์ด ์ถ๊ฐ๋๋ค๊ณ ํ๋๋ฐ, ์คํฌ ๊ด๋ จ API๊ฐ ํ์ํ์ง ์์๊น์?
์๋ฅผ ๋ค์ด, ์คํฌ ๋ชฉ๋ก์ ์กฐํํ๋ API๋ ํน์ ์คํฌ์ ๊ฒ์ํ๋ API ๋ฑ์ด ๊ตฌํ๋๋ฉด ์ข์ ๊ฒ ๊ฐ์ต๋๋ค.
ํ์ํ์๋ค๋ฉด ๊ธฐ๋ณธ์ ์ธ CRUD ์๋ํฌ์ธํธ ๊ตฌํ์ ์ ์ํด ๋๋ฆด ์ ์์ต๋๋ค.
src/main/java/aibe/hosik/skill/service/SkillService.java (1)
1-13: ์๋น์ค ํด๋์ค์ ๋น์ฆ๋์ค ๋ก์ง์ด ๊ตฌํ๋์ด ์์ง ์์ต๋๋คSkillService ํด๋์ค๊ฐ ์ฌ๋ฐ๋ฅด๊ฒ ์ค์ ๋์ด ์์ง๋ง, ํ์ฌ ๋น์ฆ๋์ค ๋ก์ง์ด ๊ตฌํ๋์ด ์์ง ์์ต๋๋ค. ๋ชจ์ง๊ธ ๊ด๋ จ ๊ธฐ๋ฅ์์ ์คํฌ ์ ๋ณด๋ฅผ ์ฒ๋ฆฌํ๋ ค๋ฉด ์ ์ด๋ ๊ธฐ๋ณธ์ ์ธ ์คํฌ CRUD ๋ก์ง์ด ๊ตฌํ๋์ด์ผ ํฉ๋๋ค.
์คํฌ ๋ฑ๋ก, ์กฐํ, ์์ , ์ญ์ ๋ฑ์ ๋ฉ์๋๋ฅผ ์ถ๊ฐํ๋ ๊ฒ์ด ์ข์ ๊ฒ ๊ฐ์ต๋๋ค. ํนํ
SkillRepository์ ์๋ก ์ถ๊ฐ๋findByName๋ฉ์๋๋ฅผ ํ์ฉํ๋ ์๋น์ค ๋ฉ์๋๊ฐ ํ์ํฉ๋๋ค.public class SkillService { private final SkillRepository skillRepository; + public List<Skill> getAllSkills() { + return skillRepository.findAll(); + } + + public Optional<Skill> getSkillByName(String name) { + return skillRepository.findByName(name); + } + + public Skill saveSkill(Skill skill) { + return skillRepository.save(skill); + } }src/main/java/aibe/hosik/skill/repository/SkillRepository.java (1)
9-9: ์คํฌ ์ด๋ฆ์ผ๋ก ์กฐํํ๋ ๋ฉ์๋๊ฐ ์ ์ถ๊ฐ๋์์ต๋๋ค
findByName๋ฉ์๋๊ฐ ์ถ๊ฐ๋ ๊ฒ์ ์ข์ ๋ณ๊ฒฝ์ ๋๋ค.Optional์ ๋ฐํ ํ์ ์ผ๋ก ์ฌ์ฉํ ๊ฒ๋ ์ ์ ํฉ๋๋ค. ์ด ๋ฉ์๋๋ ๋ชจ์ง๊ธ์ ์ฐ๊ฒฐ๋ ์คํฌ์ ์กฐํํ ๋ ์ ์ฉํ๊ฒ ์ฌ์ฉ๋ ๊ฒ์ผ๋ก ๋ณด์ ๋๋ค.ํ ๊ฐ์ง ์ ์์ผ๋ก, ์ฌ๋ฌ ์คํฌ ์ด๋ฆ์ผ๋ก ํ๊บผ๋ฒ์ ์คํฌ์ ์กฐํํ๋ ๋ฉ์๋๋ ์ถ๊ฐํ๋ฉด ์ข์ ๊ฒ ๊ฐ์ต๋๋ค. ๋ชจ์ง๊ธ์ ๋ฑ๋กํ ๋ ์ฌ๋ฌ ์คํฌ์ ํ๋ฒ์ ์ฒ๋ฆฌํด์ผ ํ ์ํฉ์ด ์์ ์ ์๊ธฐ ๋๋ฌธ์ ๋๋ค.
public interface SkillRepository extends JpaRepository<Skill, Long> { Optional<Skill> findByName(String skillName); + + @Query("SELECT s FROM Skill s WHERE s.name IN :skillNames") + List<Skill> findByNameIn(List<String> skillNames); }src/main/java/aibe/hosik/skill/repository/PostSkillRepository.java (1)
16-17: ์คํ ์์ ์ ์์ฃผ์์ ์์ ์คํ๊ฐ ์์ต๋๋ค.
- // Post ID๋ก ํด๋น ๊ธ๊ณผ ์ฐ๊ด๋ ๋ชจ๋ ์คํฌ ์ด๋ฅด ์ง์ ์กฐํ + // Post ID๋ก ํด๋น ๊ธ๊ณผ ์ฐ๊ด๋ ๋ชจ๋ ์คํฌ ์ด๋ฆ ์ง์ ์กฐํsrc/main/java/aibe/hosik/post/service/PostService.java (1)
13-13: ๋ฐํ ํ์ ๊ฒํ ์ ์
createPost๋ฉ์๋๊ฐ ํ์ฌ Entity ๊ฐ์ฒด๋ฅผ ์ง์ ๋ฐํํ๊ณ ์์ต๋๋ค. ์ผ๋ฐ์ ์ผ๋ก ์๋น์ค ๊ณ์ธต์์๋ Entity ๋์ DTO๋ฅผ ๋ฐํํ๋ ๊ฒ์ด ์ข์ ๊ดํ์ ๋๋ค. ์ด๋ ๊ฒ ํ๋ฉด ๊ณ์ธต ๊ฐ ๊ฒฐํฉ๋๋ฅผ ๋ฎ์ถ๊ณ API ์๋ต์ด ๋ด๋ถ ๋ฐ์ดํฐ ๋ชจ๋ธ ๋ณ๊ฒฝ์ ์ํฅ์ ๋ฐ์ง ์๊ฒ ๋ฉ๋๋ค.- Post createPost(PostRequestDTO dto, User user); + PostResponseDTO createPost(PostRequestDTO dto, User user);src/main/java/aibe/hosik/post/dto/PostResponseDTO.java (1)
18-28: ํฉํ ๋ฆฌ ๋ฉ์๋ ๊ฐ์ ์ ์๋ฉ์๋ ํ๋ผ๋ฏธํฐ์์
List<String> skills์Integer currentCount์ฌ์ด์ ๊ณต๋ฐฑ์ด ๋๋ฝ๋์ด ์์ต๋๋ค. ๋ํ null ์ฒดํฌ๋ฅผ ์ถ๊ฐํ์ฌ ๋ ๊ฒฌ๊ณ ํ ์ฝ๋๋ฅผ ๊ตฌํํ ์ ์์ต๋๋ค.- public static PostResponseDTO from(Post post,List<String> skills, Integer currentCount) { + public static PostResponseDTO from(Post post, List<String> skills, Integer currentCount) { + if (post == null) { + throw new IllegalArgumentException("Post cannot be null"); + } return new PostResponseDTO(post.getId(), post.getImage(), post.getTitle(), post.getContent(), post.getCategory().toString(), - skills, + skills != null ? skills : List.of(), post.getHeadCount(), - currentCount + currentCount != null ? currentCount : 0 ); }src/main/java/aibe/hosik/post/repository/PostRepository.java (1)
15-16: ์ฃผ์ ์ฝ๋ ์ ๋ฆฌ ์ ์์ฃผ์ ์ฒ๋ฆฌ๋
@EntityGraph์ฝ๋๊ฐ ๋จ์์์ต๋๋ค. ์ด ์ฝ๋๋ ํ์ฌ ์ฌ์ฉ๋์ง ์๊ณ ์์ผ๋ฉฐ, ๋ฏธ๋์ ๋์์ผ๋ก ์ฌ์ฉํ ๊ณํ์ด ์๋ค๋ฉด ์ ๊ฑฐํ๋ ๊ฒ์ด ์ฝ๋ ๊ฐ๋ ์ฑ์ ๋์ผ ์ ์์ต๋๋ค.- // Post ์กฐํ ์ postSkills, skill ์ํฐํฐ ์ฆ์ ๋ก๋ฉ ์ง์ - //@EntityGraph(attributePaths = {"postSkills", "postSkills.skill"}) + // Post ์กฐํ ์ postSkills, skill ์ํฐํฐ ์ฆ์ ๋ก๋ฉ- // PostDetail ์กฐํ ์ ์ฆ์ ๋ก๋ฉ ์ง์ - //@EntityGraph(attributePaths = {"postSkills", "postSkills.skill"}) + // PostDetail ์กฐํ ์ ์ฆ์ ๋ก๋ฉAlso applies to: 20-21
src/main/java/aibe/hosik/post/dto/PostRequestDTO.java (1)
24-36: toEntity ๋ฉ์๋์์ ์คํฌ ๋งคํ ์ฒ๋ฆฌ ํ์ํ์ฌ
toEntity๋ฉ์๋๋ ์ฌ์ฉ์ ์ ๋ณด๋ง ์ค์ ํ๊ณ ์คํฌ ์ ๋ณด๋ ์ค์ ํ์ง ์์ต๋๋ค. ์คํฌ ๋งคํ์ ์๋น์ค ๊ณ์ธต์์ ๋ณ๋๋ก ์ฒ๋ฆฌ๋๊ณ ์์ต๋๋ค. ์ด ์ฑ ์์ DTO ๋ด๋ถ๋ก ๊ฐ์ ธ์์ ์บก์ํํ๋ ๊ฒ์ด ๋ ์ข์ ์ค๊ณ์ผ ์ ์์ต๋๋ค.๋ํ ํ์ฌ User ๋งค๊ฐ๋ณ์๊ฐ ํ์ํ๋ฐ, ์ด๋ก ์ธํด ํ ์คํธํ๊ธฐ ์ด๋ ค์ธ ์ ์์ต๋๋ค. ํฉํ ๋ฆฌ ๋ฉ์๋ ํจํด์ ์ฌ์ฉํ์ฌ ๋ถ๋ฆฌํ๋ ๊ฒ์ด ์ข์ ์ ์์ต๋๋ค.
public Post toEntity(User user) { return Post.builder() .title(title()) .content(content()) .headCount(headCount()) .image(image()) .requirementPersonality(requirementPersonality()) .endedAt(endedAt()) .category(category()) .type(type()) .user(user) .build(); } + + // ์คํฌ ์ํฐํฐ ๋งคํ์ ์ํ ๋ฉ์๋ ์ถ๊ฐ + public List<PostSkill> createPostSkills(Post post, List<Skill> skills) { + return skills.stream() + .map(skill -> PostSkill.builder() + .post(post) + .skill(skill) + .build()) + .collect(Collectors.toList()); + }src/main/java/aibe/hosik/post/dto/PostDetailDTO.java (1)
10-26: ํ๋ ์ค๋ช ์ ์ํ JavaDoc ์ถ๊ฐ ํ์
PostDetailDTO์ ๊ฐ ํ๋์ ๋ํ ์ค๋ช ์ด ๋ถ์กฑํฉ๋๋ค. ํนํmatchedUsers์ ๋ํ ์ฃผ์์ด ์์ง๋ง ๋ค๋ฅธ ํ๋์ ๋ํ ์ค๋ช ์ ์์ต๋๋ค. ๊ฐ ํ๋์ ๋ชฉ์ ๊ณผ ์๋ฏธ๋ฅผ ๋ช ํํ ํ๊ธฐ ์ํด JavaDoc ์ฃผ์์ ์ถ๊ฐํ๋ ๊ฒ์ด ์ข์ต๋๋ค./** + * ๊ฒ์๊ธ ์์ธ ์ ๋ณด๋ฅผ ๋ํ๋ด๋ DTO + * ๊ฒ์๊ธ์ ๊ธฐ๋ณธ ์ ๋ณด, ์นดํ ๊ณ ๋ฆฌ, ํ์ , ์คํฌ ๋ชฉ๋ก, ๋งค์นญ๋ ์ฌ์ฉ์ ๋ชฉ๋ก์ ํฌํจํฉ๋๋ค. + */ public record PostDetailDTO( + /** ๊ฒ์๊ธ ID */ Long id, + /** ๊ฒ์๊ธ ์ ๋ชฉ */ String title, + /** ๊ฒ์๊ธ ๋ด์ฉ */ String content, + /** ๋ชจ์ง ์ธ์ ์ */ Integer headCount, + /** ์ด๋ฏธ์ง URL */ String image, + /** ํ์ํ ์ฑ๊ฒฉ ํน์ฑ */ String requirementPersonality, + /** ๋ชจ์ง ์ข ๋ฃ์ผ */ LocalDate endedAt, + /** ๊ฒ์๊ธ ์นดํ ๊ณ ๋ฆฌ (๋ฌธ์์ด๋ก ๋ณํ๋จ) */ String category, + /** ๊ฒ์๊ธ ํ์ (๋ฌธ์์ด๋ก ๋ณํ๋จ) */ String type, + /** ์๊ตฌ๋๋ ์คํฌ ๋ชฉ๋ก */ List<String> skills, // ํ์ฌ ์ ํ๋ ๋ชฉ๋ก ๋ณด์ฌ์ฃผ๊ธฐ + /** ๋งค์นญ๋ ์ฌ์ฉ์ ๋ชฉ๋ก */ List<MatchedUserDTO> matchedUsers ) {src/main/java/aibe/hosik/post/service/PostServiceImpl.java (1)
28-47: getAllPosts ๋ฉ์๋ ์ต์ ํ ๋ฐ ์ฃผ์ ๊ฐ์ํ์ฌ
getAllPosts๋ฉ์๋์๋ ๋ช ๊ฐ์ง ๊ฐ์ ์ด ํ์ํฉ๋๋ค:
- TODO ์ฃผ์์ด ์๋๋ฐ, ํ์ฌ ์ฐธ์ฌ์ ์๋ฅผ ๊ณ์ฐํ๋ ๊ตฌํ์ด ํ์ํฉ๋๋ค.
- ์คํธ๋ฆผ ์ฐ์ฐ ์ฒด์ธ์์
.collect(Collectors.toList())๋ Java 16๋ถํฐtoList()๋ก ๋์ฒดํ ์ ์์ต๋๋ค.- ๋ฉ์๋ ์ค๋ช ์ฃผ์์ด ์์ง๋ง, JavaDoc ํ์์ผ๋ก ๊ฐ์ ํ ์ ์์ต๋๋ค.
- // PostResponseDTO๋ฅผ ํตํด ์ ์ฒด ๊ฒ์๊ธ(Post)๋ฅผ ์กฐํํฉ๋๋ค + /** + * PostResponseDTO๋ฅผ ํตํด ์ ์ฒด ๊ฒ์๊ธ(Post)๋ฅผ ์กฐํํฉ๋๋ค. + * ํ ๋ฒ์ ์ฟผ๋ฆฌ๋ก ๊ฒ์๊ธ๊ณผ ๊ด๋ จ ์คํฌ์ ํจ๊ป ์กฐํํฉ๋๋ค. + * + * @return ๋ชจ๋ ๊ฒ์๊ธ ์ ๋ณด๊ฐ ๋ด๊ธด PostResponseDTO ๋ชฉ๋ก + */ @Override public List<PostResponseDTO> getAllPosts() { // findAllWithSkills๋ก ํ ๋ฒ์ fetch(post, postSkills, skill) List<Post> posts = postRepository.findAllWithSkills(); return posts.stream() .map(post -> { // fetch๋ postSkills์์ skill ์ถ์ถ List<String> skills = post.getPostSkills().stream() .map(s -> s.getSkill().getName()) - .collect(Collectors.toList()); + .toList(); // TODO : ํ์ฌ ์ฐธ์ฌ์ ์ ๊ณ์ฐ + // ์ฐธ์ฌ์ ์ ๊ณ์ฐ ๋ก์ง ๊ตฌํ ํ์ Integer currentCount = 0; // DTO ์ ์ ํฉํ ๋ฆฌ ๋ฉ์๋ ํ์ฉ return PostResponseDTO.from(post, skills, currentCount); - }).collect(Collectors.toList()); + }).toList(); }src/main/java/aibe/hosik/post/controller/PostController.java (2)
22-22: ๋ถํ์ํ ์ฃผ์์ ์ ๊ฑฐํ์ธ์."ํ ์คํธ"๋ผ๋ ์ฃผ์์ ์ฝ๋์ ํน๋ณํ ์ ๋ณด๋ฅผ ์ ๊ณตํ์ง ์์ผ๋ฉฐ ๋ถํ์ํฉ๋๋ค. ๋ช ํํ ๋ด์ฉ์ด ์๋ ์ฃผ์์ ์ ๊ฑฐํ๋ ๊ฒ์ด ์ข์ต๋๋ค.
- // ํ ์คํธ
1-28: API ๋ฌธ์ํ ๊ฐํ๊ฐ ํ์ํฉ๋๋ค.Swagger ํ๊ทธ์ ๊ธฐ๋ณธ์ ์ธ API ๋ฌธ์ํ๊ฐ ๊ตฌํ๋์ด ์์ง๋ง, ์์ฒญ ๋ฐ ์๋ต์ ๋ํ ๋ ์์ธํ ๋ฌธ์ํ๊ฐ ํ์ํฉ๋๋ค. ํนํ ์์ฒญ ํ๋ผ๋ฏธํฐ์ ์๋ต ํ๋์ ๋ํ ์ค๋ช ์ด ๋๋ฝ๋์ด ์์ต๋๋ค.
Swagger ์ ๋ ธํ ์ด์ ์ ํ์ฅํ์ฌ API ๋ฌธ์ํ๋ฅผ ๊ฐํํ์ธ์:
@Operation(summary="๋ชจ์ง๊ธ ๋ฑ๋ก", description="๋ชจ์ง๊ธ์ ๋ฑ๋กํฉ๋๋ค.") + @ApiResponses(value = { + @ApiResponse(responseCode = "200", description = "๋ชจ์ง๊ธ ๋ฑ๋ก ์ฑ๊ณต", + content = { @Content(mediaType = "application/json", + schema = @Schema(implementation = PostResponseDTO.class)) }), + @ApiResponse(responseCode = "400", description = "์๋ชป๋ ์์ฒญ"), + @ApiResponse(responseCode = "401", description = "์ธ์ฆ ์คํจ") + }) @PostMapping
๐ Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
๐ Files selected for processing (22)
build.gradle(1 hunks)src/main/java/aibe/hosik/analysis/Analysis.java(1 hunks)src/main/java/aibe/hosik/apply/controller/ApplyController.java(1 hunks)src/main/java/aibe/hosik/apply/entity/Apply.java(1 hunks)src/main/java/aibe/hosik/apply/repository/ApplyRepository.java(1 hunks)src/main/java/aibe/hosik/apply/service/ApplyService.java(1 hunks)src/main/java/aibe/hosik/post/PostController.java(0 hunks)src/main/java/aibe/hosik/post/PostRepository.java(0 hunks)src/main/java/aibe/hosik/post/PostService.java(0 hunks)src/main/java/aibe/hosik/post/controller/PostController.java(1 hunks)src/main/java/aibe/hosik/post/dto/MatchedUserDTO.java(1 hunks)src/main/java/aibe/hosik/post/dto/PostDetailDTO.java(1 hunks)src/main/java/aibe/hosik/post/dto/PostRequestDTO.java(1 hunks)src/main/java/aibe/hosik/post/dto/PostResponseDTO.java(1 hunks)src/main/java/aibe/hosik/post/entity/Post.java(3 hunks)src/main/java/aibe/hosik/post/repository/PostRepository.java(1 hunks)src/main/java/aibe/hosik/post/service/PostService.java(1 hunks)src/main/java/aibe/hosik/post/service/PostServiceImpl.java(1 hunks)src/main/java/aibe/hosik/skill/cotnroller/SkillController.java(1 hunks)src/main/java/aibe/hosik/skill/repository/PostSkillRepository.java(1 hunks)src/main/java/aibe/hosik/skill/repository/SkillRepository.java(1 hunks)src/main/java/aibe/hosik/skill/service/SkillService.java(1 hunks)
๐ค Files with no reviewable changes (3)
- src/main/java/aibe/hosik/post/PostRepository.java
- src/main/java/aibe/hosik/post/PostController.java
- src/main/java/aibe/hosik/post/PostService.java
๐งฐ Additional context used
๐งฌ Code Graph Analysis (1)
src/main/java/aibe/hosik/post/controller/PostController.java (4)
src/main/java/aibe/hosik/apply/controller/ApplyController.java (1)
Slf4j(9-15)src/main/java/aibe/hosik/apply/service/ApplyService.java (1)
Slf4j(8-13)src/main/java/aibe/hosik/skill/service/SkillService.java (1)
Slf4j(8-13)src/main/java/aibe/hosik/skill/cotnroller/SkillController.java (1)
Slf4j(9-15)
๐ Additional comments (9)
src/main/java/aibe/hosik/post/dto/MatchedUserDTO.java (1)
7-13: DTO ์ ์๊ฐ ์ ์ ํฉ๋๋ค
๋ ์ฝ๋๋ฅผ ์ด์ฉํด ๋ถ๋ณ ๊ฐ์ฒด๋ฅผ ๊น๋ํ๊ฒ ์ ์ํ ์ ์ด ์ข์ต๋๋ค.src/main/java/aibe/hosik/apply/entity/Apply.java (1)
1-1: ํจํค์ง ๊ตฌ์กฐ ๋ณ๊ฒฝ ํ์ธ๋จ
Apply์ํฐํฐ๊ฐaibe.hosik.apply.entity๋ก ์ด๋ํ ๊ฒ์ด ์ ์ ํฉ๋๋ค.src/main/java/aibe/hosik/analysis/Analysis.java (1)
3-3: import ํจํค์ง ๊ฒฝ๋ก ์ ๋ฐ์ดํธ ํ์ธ๋จ
Apply์ ํจํค์ง ๊ฒฝ๋ก ๋ณ๊ฒฝ์ ๋ง์ถฐ import๋ฅผ ์์ ํ ๊ฒ์ด ์ฌ๋ฐ๋ฆ ๋๋ค.build.gradle (1)
27-29: Spring Security ์์กด์ฑ ํ์ฑํ ์ ์
spring-boot-starter-security๋ฅผ ํ์ฑํํ์ฌ@AuthenticationPrincipal์ ์ฌ์ฉํ๋ ์ปจํธ๋กค๋ฌ ์ธ์ฆ ๊ธฐ๋ฅ์ ์ง์ํ๋๋ก ํ ๊ฒ์ด ํ๋นํฉ๋๋ค.src/main/java/aibe/hosik/skill/repository/PostSkillRepository.java (1)
1-19: Repository ๊ตฌํ์ด ์ ๋์์ต๋๋ค!PostSkill ์ํฐํฐ์ ๋ํ ๋ฆฌํฌ์งํ ๋ฆฌ ๊ตฌํ์ด ์ ์ ํ๊ฒ ์์ฑ๋์์ต๋๋ค. ๋ ๊ฐ์ง ์ฟผ๋ฆฌ ๋ฉ์๋๊ฐ ์ ๊ณต๋๋ฉฐ:
findByPost- ํน์ Post ์ํฐํฐ์ ์ฐ๊ด๋ ๋ชจ๋ PostSkill ์กฐํfindSkillByPostId- Post ID๋ก ์ฐ๊ด๋ ์คํฌ ์ด๋ฆ๋ค์ ์ง์ ์กฐํํ๋ JPQL ์ฟผ๋ฆฌ์ด๋ Post์ Skill ๊ฐ์ ๊ด๊ณ๋ฅผ ํจ๊ณผ์ ์ผ๋ก ๊ด๋ฆฌํ๋ ๋ฐ ๋์์ด ๋ฉ๋๋ค.
src/main/java/aibe/hosik/post/service/PostService.java (1)
1-15: ์๋น์ค ์ธํฐํ์ด์ค ์ค๊ณ๊ฐ ๋ช ํํฉ๋๋คPostService ์ธํฐํ์ด์ค๊ฐ ๋ช ํํ๊ฒ ์ ์๋์ด ์์ผ๋ฉฐ, ํ์ํ ํต์ฌ ๊ธฐ๋ฅ๋ค(๊ฒ์๊ธ ๋ชฉ๋ก ์กฐํ, ๊ฒ์๊ธ ์์ฑ, ๊ฒ์๊ธ ์์ธ ์กฐํ)์ ํฌํจํ๊ณ ์์ต๋๋ค. DTO ๊ฐ์ฒด๋ฅผ ์ ์ถ๋ ฅ์ ์ฌ์ฉํ์ฌ ๊ณ์ธต ๊ฐ ์ฑ ์ ๋ถ๋ฆฌ๊ฐ ์ ๋์ด ์์ต๋๋ค.
src/main/java/aibe/hosik/post/dto/PostResponseDTO.java (1)
1-29: DTO ์ค๊ณ๊ฐ ์ ์ ํฉ๋๋คJava ๋ ์ฝ๋๋ฅผ ์ฌ์ฉํ์ฌ ๋ถ๋ณ ๋ฐ์ดํฐ ๊ฐ์ฒด๋ก PostResponseDTO๋ฅผ ๊ตฌํํ ๊ฒ์ ์ข์ ์ ๊ทผ ๋ฐฉ์์ ๋๋ค. ์ ์ ํฉํ ๋ฆฌ ๋ฉ์๋
from์ ์ฌ์ฉํ์ฌ ์ํฐํฐ์์ DTO๋ก์ ๋ณํ์ ๋ช ํํ๊ฒ ์ฒ๋ฆฌํ์ต๋๋ค.src/main/java/aibe/hosik/post/repository/PostRepository.java (1)
1-23: ์ฟผ๋ฆฌ ์ต์ ํ๊ฐ ์ ๊ตฌํ๋์์ต๋๋ค
JOIN FETCH๋ฅผ ์ฌ์ฉํ์ฌ N+1 ๋ฌธ์ ๋ฅผ ํด๊ฒฐํ๋ ์ต์ ํ๋ ์ฟผ๋ฆฌ๋ฅผ ๊ตฌํํ์ต๋๋ค.DISTINCT๋ฅผ ์ฌ์ฉํ์ฌ ์ค๋ณต์ ์ ๊ฑฐํ ๊ฒ๋ ์ ์ ํฉ๋๋ค. ์ํฐํฐ ๊ฐ ๊ด๊ณ๋ฅผ ํจ์จ์ ์ผ๋ก ์กฐํํ ์ ์๋๋ก ์ค๊ณ๋์์ต๋๋ค.src/main/java/aibe/hosik/post/controller/PostController.java (1)
40-41: TODO ์ฝ๋ฉํธ ํด๊ฒฐ ๋ฐ ๋ช ํํ ๋ฉ์๋ ์์ฑ์ด ํ์ํฉ๋๋ค."currentCount ๋ก์ง ๊ตฌํ ํ ๋ณํ"์ด๋ผ๋ TODO ์ฝ๋ฉํธ๊ฐ ์์ต๋๋ค. ์ด๋ ๊ธฐ๋ฅ์ด ์์ ํ ๊ตฌํ๋์ง ์์์์ ๋ํ๋ ๋๋ค. ๊ฐ๋ฅํ ๋นจ๋ฆฌ ์ด ๋ก์ง์ ๊ตฌํํ๊ฑฐ๋, ์งํ ์ค์ธ ์์ ์ด๋ผ๋ฉด ์ข ๋ ์์ธํ ์ค๋ช ๊ณผ ์์ ์๋ฃ ์์ ์ ์ฃผ์์ ์ถ๊ฐํ์ธ์.
๋ํ, 0์ ํ๋์ฝ๋ฉํ๋ ๊ฒ๋ณด๋ค ์๋ฏธ ์๋ ์์๋ ๋ฉ์๋ ํธ์ถ๋ก ๋์ฒดํ๋ ๊ฒ์ด ์ข์ต๋๋ค:
- PostResponseDTO responseDTO = PostResponseDTO.from(createPost, skills, 0); + // TODO: currentCount ๋ก์ง ๊ตฌํ - 2023-xx-xx๊น์ง ๊ตฌํ ์์ + PostResponseDTO responseDTO = PostResponseDTO.from(createPost, skills, getInitialCount()); // ํด๋์ค ๋ด์ ๋ค์ ๋ฉ์๋ ์ถ๊ฐ private int getInitialCount() { return 0; // ํฅํ ๋ก์ง์ผ๋ก ๋์ฒด ์์ }
| @@ -1,5 +1,6 @@ | |||
| package aibe.hosik.skill; | |||
| package aibe.hosik.skill.cotnroller; | |||
There was a problem hiding this comment.
ํจํค์ง ์ด๋ฆ์ ์คํ๊ฐ ์์ต๋๋ค
ํจํค์ง ์ด๋ฆ์ด aibe.hosik.skill.cotnroller๋ก ๋์ด ์๋๋ฐ, ์ ํํ ์คํ ๋ง์ aibe.hosik.skill.controller์
๋๋ค. ํจํค์ง ์ด๋ฆ์ ์คํ๋ ์ถํ์ ์ํฌํธ ๋ฌธ์ ๋ฅผ ์ผ์ผํฌ ์ ์์ผ๋ ์์ ํด์ฃผ์ธ์.
-package aibe.hosik.skill.cotnroller;
+package aibe.hosik.skill.controller;๐ Committable suggestion
โผ๏ธ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| package aibe.hosik.skill.cotnroller; | |
| package aibe.hosik.skill.controller; |
| // post id๋ก ์ง์์ ์กฐํ | ||
|
|
There was a problem hiding this comment.
๐ ๏ธ Refactor suggestion
์ฝ๋ฉํธ๋ง ์๊ณ ์ค์ ๋ฉ์๋ ๊ตฌํ์ด ์์ต๋๋ค
"post id๋ก ์ง์์ ์กฐํ"๋ผ๋ ์ฝ๋ฉํธ๊ฐ ์์ง๋ง ์ค์ ๋ฉ์๋๊ฐ ๊ตฌํ๋์ด ์์ง ์์ต๋๋ค. ๋ชจ์ง๊ธ๊ณผ ์ง์์ ๊ฐ์ ์ฐ๊ด๊ด๊ณ๋ฅผ ์ฒ๋ฆฌํ๊ธฐ ์ํด์๋ ์ด ๊ธฐ๋ฅ์ด ํ์ํ ๊ฒ์ผ๋ก ๋ณด์ ๋๋ค.
์๋์ ๊ฐ์ด ๋ฉ์๋๋ฅผ ๊ตฌํํ๋ ๊ฒ์ด ์ข์ ๊ฒ ๊ฐ์ต๋๋ค:
public interface ApplyRepository extends JpaRepository<Apply, Long> {
// post id๋ก ์ง์์ ์กฐํ
+ List<Apply> findByPostId(Long postId);
}๐ Committable suggestion
โผ๏ธ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| // post id๋ก ์ง์์ ์กฐํ | |
| public interface ApplyRepository extends JpaRepository<Apply, Long> { | |
| // post id๋ก ์ง์์ ์กฐํ | |
| List<Apply> findByPostId(Long postId); | |
| } |
| public record PostRequestDTO( | ||
| String title, | ||
| String content, | ||
| Integer headCount, | ||
| String image, | ||
| String requirementPersonality, | ||
| LocalDate endedAt, | ||
|
|
||
| PostCategory category, | ||
| PostType type, | ||
|
|
||
| List<String> skills | ||
| ) { |
There was a problem hiding this comment.
๐ ๏ธ Refactor suggestion
ํ๋ ์ ํจ์ฑ ๊ฒ์ฆ ์ถ๊ฐ ํ์
ํ์ฌ PostRequestDTO์ ํ๋๋ค์ ๋ํ ์ ํจ์ฑ ๊ฒ์ฆ์ด ์์ต๋๋ค. ์๋ฅผ ๋ค๋ฉด title์ด๋ content๊ฐ ๋น์ด์๊ฑฐ๋, headCount๊ฐ ์์์ธ ๊ฒฝ์ฐ ๋ฑ ์ ํจํ์ง ์์ ์
๋ ฅ์ด ๋ค์ด์ฌ ์ ์์ต๋๋ค. Bean Validation ์ ๋
ธํ
์ด์
(@NotBlank, @Size, @Min ๋ฑ)์ ์ฌ์ฉํ์ฌ ์ ํจ์ฑ ๊ฒ์ฆ์ ์ถ๊ฐํ๋ ๊ฒ์ด ์ข์ต๋๋ค.
์๋์ ๊ฐ์ด ์์ ํ๋ ๊ฒ์ ๊ถ์ฅํฉ๋๋ค:
public record PostRequestDTO(
+ @NotBlank(message = "์ ๋ชฉ์ ํ์ ์
๋ ฅ๊ฐ์
๋๋ค")
+ @Size(max = 100, message = "์ ๋ชฉ์ 100์ ์ด๋ด๋ก ์
๋ ฅํด์ฃผ์ธ์")
String title,
+ @NotBlank(message = "๋ด์ฉ์ ํ์ ์
๋ ฅ๊ฐ์
๋๋ค")
String content,
+ @Min(value = 1, message = "์ธ์ ์๋ ์ต์ 1๋ช
์ด์์ด์ด์ผ ํฉ๋๋ค")
Integer headCount,
String image,
String requirementPersonality,
+ @NotNull(message = "๋ชจ์ง ์ข
๋ฃ์ผ์ ํ์ ์
๋ ฅ๊ฐ์
๋๋ค")
+ @Future(message = "๋ชจ์ง ์ข
๋ฃ์ผ์ ํ์ฌ ์ดํ์ ๋ ์ง์ฌ์ผ ํฉ๋๋ค")
LocalDate endedAt,
+ @NotNull(message = "์นดํ
๊ณ ๋ฆฌ๋ ํ์ ์
๋ ฅ๊ฐ์
๋๋ค")
PostCategory category,
+ @NotNull(message = "ํ์
์ ํ์ ์
๋ ฅ๊ฐ์
๋๋ค")
PostType type,
+ @NotEmpty(message = "์ต์ ํ๋ ์ด์์ ์คํฌ์ด ํ์ํฉ๋๋ค")
List<String> skills
) {Bean Validation์ ์ํด ์๋ ์์กด์ฑ ์ถ๊ฐ๊ฐ ํ์ํฉ๋๋ค:
import jakarta.validation.constraints.*;| @Column | ||
| private String requirementPersonality; | ||
|
|
There was a problem hiding this comment.
๐ ๏ธ Refactor suggestion
requirementPersonality ํ๋์ ์ ํจ์ฑ ์ ์ฝ์กฐ๊ฑด ์ถ๊ฐ ํ์
requirementPersonality ํ๋์ ์ ํจ์ฑ ์ ์ฝ์กฐ๊ฑด์ด ์์ต๋๋ค. ์ด ํ๋์ ๋๋ฌด ๊ธด ํ
์คํธ๊ฐ ์ ์ฅ๋ ๊ฒฝ์ฐ ๋ฐ์ดํฐ๋ฒ ์ด์ค ๋ฌธ์ ๊ฐ ๋ฐ์ํ ์ ์์ต๋๋ค. @Size ์ ๋
ธํ
์ด์
์ ์ฌ์ฉํ์ฌ ๊ธธ์ด ์ ํ์ ์ถ๊ฐํ๋ ๊ฒ์ด ์ข์ต๋๋ค.
- @Column
+ @Column(length = 500)
+ @Size(max = 500)
private String requirementPersonality;๐ Committable suggestion
โผ๏ธ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| @Column | |
| private String requirementPersonality; | |
| @Column(length = 500) | |
| @Size(max = 500) | |
| private String requirementPersonality; |
| // ์๋ฐฉํฅ ๋งคํ | ||
| @OneToMany(mappedBy = "post", cascade = CascadeType.ALL, orphanRemoval = true) | ||
| @Builder.Default | ||
| private List<PostSkill> postSkills = new ArrayList<>(); |
There was a problem hiding this comment.
๐ ๏ธ Refactor suggestion
์๋ฐฉํฅ ๋งคํ์ ๋ํ ํฌํผ ๋ฉ์๋ ์ถ๊ฐ ํ์
์๋ฐฉํฅ ๋งคํ์ ์ฌ์ฉํ ๋๋ ์์ชฝ์์ ๊ด๊ณ๋ฅผ ์ค์ ํ๋ ํฌํผ ๋ฉ์๋๋ฅผ ์ถ๊ฐํ๋ ๊ฒ์ด ์ข์ต๋๋ค. ํ์ฌ๋ ๊ด๊ณ ์ค์ ์ฑ ์์ด ์๋น์ค ๊ณ์ธต์ ์์ด์ ์ผ๊ด์ฑ ๋ฌธ์ ๊ฐ ๋ฐ์ํ ์ ์์ต๋๋ค.
ํฌ์คํธ์ ์คํฌ ๊ฐ์ ์๋ฐฉํฅ ๊ด๊ณ๋ฅผ ๊ด๋ฆฌํ๋ ํฌํผ ๋ฉ์๋๋ฅผ ์ถ๊ฐํฉ๋๋ค:
@OneToMany(mappedBy = "post", cascade = CascadeType.ALL, orphanRemoval = true)
@Builder.Default
private List<PostSkill> postSkills = new ArrayList<>();
+
+ // ์๋ฐฉํฅ ๊ด๊ณ ์ ์ง๋ฅผ ์ํ ํฌํผ ๋ฉ์๋
+ public void addPostSkill(PostSkill postSkill) {
+ this.postSkills.add(postSkill);
+ if (postSkill.getPost() != this) {
+ postSkill.setPost(this);
+ }
+ }
+
+ public void removePostSkill(PostSkill postSkill) {
+ this.postSkills.remove(postSkill);
+ if (postSkill.getPost() == this) {
+ postSkill.setPost(null);
+ }
+ }๐ Committable suggestion
โผ๏ธ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| // ์๋ฐฉํฅ ๋งคํ | |
| @OneToMany(mappedBy = "post", cascade = CascadeType.ALL, orphanRemoval = true) | |
| @Builder.Default | |
| private List<PostSkill> postSkills = new ArrayList<>(); | |
| // ์๋ฐฉํฅ ๋งคํ | |
| @OneToMany(mappedBy = "post", cascade = CascadeType.ALL, orphanRemoval = true) | |
| @Builder.Default | |
| private List<PostSkill> postSkills = new ArrayList<>(); | |
| // ์๋ฐฉํฅ ๊ด๊ณ ์ ์ง๋ฅผ ์ํ ํฌํผ ๋ฉ์๋ | |
| public void addPostSkill(PostSkill postSkill) { | |
| this.postSkills.add(postSkill); | |
| if (postSkill.getPost() != this) { | |
| postSkill.setPost(this); | |
| } | |
| } | |
| public void removePostSkill(PostSkill postSkill) { | |
| this.postSkills.remove(postSkill); | |
| if (postSkill.getPost() == this) { | |
| postSkill.setPost(null); | |
| } | |
| } |
| @Override | ||
| public PostDetailDTO getPostDetail(Long postId) { | ||
| // ๊ฒ์๊ธ ์ ๋ณด ์กฐํ | ||
| Post post = postRepository.findByIdWithSkills(postId) | ||
| .orElseThrow(); | ||
|
|
||
| // ์คํฌ ์ด๋ฆ ์กฐํ | ||
| List<String> skills = post.getPostSkills().stream() | ||
| .map(s -> s.getSkill().getName()) | ||
| .collect(Collectors.toList()); | ||
|
|
||
| // ๋งค์นญ ์ฌ์ฉ์ ์ ๋ณด ์กฐํ | ||
| // TODO : ์ค์ ๋งค์นญ๋ ์ฌ์ฉ์ ์กฐํ | ||
| List<MatchedUserDTO> matchedUsers = new ArrayList<>(); | ||
|
|
||
| return PostDetailDTO.from(post,skills, matchedUsers); | ||
| } |
There was a problem hiding this comment.
๐ ๏ธ Refactor suggestion
getPostDetail ๋ฉ์๋ ์์ธ ์ฒ๋ฆฌ ๊ฐ์ ํ์
ํ์ฌ getPostDetail ๋ฉ์๋์์๋ ๊ฒ์๊ธ์ ์ฐพ์ง ๋ชปํ์ ๋ .orElseThrow()๋ฅผ ์ฌ์ฉํ๊ณ ์์ง๋ง, ๊ตฌ์ฒด์ ์ธ ์์ธ ๋ฉ์์ง๋ฅผ ์ ๊ณตํ์ง ์์ต๋๋ค. ๋ํ TODO ์ฃผ์์ด ์๋๋ฐ, ์ค์ ๋งค์นญ๋ ์ฌ์ฉ์๋ฅผ ์กฐํํ๋ ๊ตฌํ์ด ํ์ํฉ๋๋ค.
+ /**
+ * ๊ฒ์๊ธ ID๋ฅผ ๊ธฐ๋ฐ์ผ๋ก ๊ฒ์๊ธ ์์ธ ์ ๋ณด๋ฅผ ์กฐํํฉ๋๋ค.
+ * ๊ฒ์๊ธ๊ณผ ๊ด๋ จ ์คํฌ, ๋งค์นญ๋ ์ฌ์ฉ์ ์ ๋ณด๋ฅผ ํจ๊ป ๋ฐํํฉ๋๋ค.
+ *
+ * @param postId ์กฐํํ ๊ฒ์๊ธ ID
+ * @return ๊ฒ์๊ธ ์์ธ ์ ๋ณด๊ฐ ๋ด๊ธด DTO
+ * @throws NoSuchElementException ํด๋น ID์ ๊ฒ์๊ธ์ด ์กด์ฌํ์ง ์์ ๊ฒฝ์ฐ
+ */
+ @Transactional(readOnly = true)
@Override
public PostDetailDTO getPostDetail(Long postId) {
// ๊ฒ์๊ธ ์ ๋ณด ์กฐํ
Post post = postRepository.findByIdWithSkills(postId)
- .orElseThrow();
+ .orElseThrow(() -> new NoSuchElementException("ID๊ฐ " + postId + "์ธ ๊ฒ์๊ธ์ ์ฐพ์ ์ ์์ต๋๋ค"));
// ์คํฌ ์ด๋ฆ ์กฐํ
List<String> skills = post.getPostSkills().stream()
.map(s -> s.getSkill().getName())
- .collect(Collectors.toList());
+ .toList();
// ๋งค์นญ ์ฌ์ฉ์ ์ ๋ณด ์กฐํ
// TODO : ์ค์ ๋งค์นญ๋ ์ฌ์ฉ์ ์กฐํ
+ // ์ฌ์ฉ์ ๋งค์นญ ๋ก์ง ๊ตฌํ ํ์
List<MatchedUserDTO> matchedUsers = new ArrayList<>();
return PostDetailDTO.from(post,skills, matchedUsers);
}๐ Committable suggestion
โผ๏ธ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| @Override | |
| public PostDetailDTO getPostDetail(Long postId) { | |
| // ๊ฒ์๊ธ ์ ๋ณด ์กฐํ | |
| Post post = postRepository.findByIdWithSkills(postId) | |
| .orElseThrow(); | |
| // ์คํฌ ์ด๋ฆ ์กฐํ | |
| List<String> skills = post.getPostSkills().stream() | |
| .map(s -> s.getSkill().getName()) | |
| .collect(Collectors.toList()); | |
| // ๋งค์นญ ์ฌ์ฉ์ ์ ๋ณด ์กฐํ | |
| // TODO : ์ค์ ๋งค์นญ๋ ์ฌ์ฉ์ ์กฐํ | |
| List<MatchedUserDTO> matchedUsers = new ArrayList<>(); | |
| return PostDetailDTO.from(post,skills, matchedUsers); | |
| } | |
| /** | |
| * ๊ฒ์๊ธ ID๋ฅผ ๊ธฐ๋ฐ์ผ๋ก ๊ฒ์๊ธ ์์ธ ์ ๋ณด๋ฅผ ์กฐํํฉ๋๋ค. | |
| * ๊ฒ์๊ธ๊ณผ ๊ด๋ จ ์คํฌ, ๋งค์นญ๋ ์ฌ์ฉ์ ์ ๋ณด๋ฅผ ํจ๊ป ๋ฐํํฉ๋๋ค. | |
| * | |
| * @param postId ์กฐํํ ๊ฒ์๊ธ ID | |
| * @return ๊ฒ์๊ธ ์์ธ ์ ๋ณด๊ฐ ๋ด๊ธด DTO | |
| * @throws NoSuchElementException ํด๋น ID์ ๊ฒ์๊ธ์ด ์กด์ฌํ์ง ์์ ๊ฒฝ์ฐ | |
| */ | |
| @Transactional(readOnly = true) | |
| @Override | |
| public PostDetailDTO getPostDetail(Long postId) { | |
| // ๊ฒ์๊ธ ์ ๋ณด ์กฐํ | |
| Post post = postRepository.findByIdWithSkills(postId) | |
| .orElseThrow(() -> new NoSuchElementException("ID๊ฐ " + postId + "์ธ ๊ฒ์๊ธ์ ์ฐพ์ ์ ์์ต๋๋ค")); | |
| // ์คํฌ ์ด๋ฆ ์กฐํ | |
| List<String> skills = post.getPostSkills().stream() | |
| .map(s -> s.getSkill().getName()) | |
| .toList(); | |
| // ๋งค์นญ ์ฌ์ฉ์ ์ ๋ณด ์กฐํ | |
| // TODO : ์ค์ ๋งค์นญ๋ ์ฌ์ฉ์ ์กฐํ | |
| // ์ฌ์ฉ์ ๋งค์นญ ๋ก์ง ๊ตฌํ ํ์ | |
| List<MatchedUserDTO> matchedUsers = new ArrayList<>(); | |
| return PostDetailDTO.from(post, skills, matchedUsers); | |
| } |
| @GetMapping | ||
| public ResponseEntity<List<PostResponseDTO>> getAllPosts(){ | ||
| return ResponseEntity.ok(postService.getAllPosts()); | ||
| } |
There was a problem hiding this comment.
๐ ๏ธ Refactor suggestion
ํ์ด์ง๋ค์ด์ ๊ตฌํ์ด ํ์ํฉ๋๋ค.
getAllPosts() ๋ฉ์๋๋ ๋ชจ๋ ๊ฒ์๊ธ์ ํ ๋ฒ์ ๋ฐํํฉ๋๋ค. ๊ฒ์๊ธ ์๊ฐ ๋ง์์ง๋ฉด ์ฑ๋ฅ ๋ฌธ์ ๊ฐ ๋ฐ์ํ ์ ์์ต๋๋ค. ํ์ด์ง๋ค์ด์
์ ๊ตฌํํ์ฌ ํ ๋ฒ์ ๋ก๋๋๋ ๋ฐ์ดํฐ์ ์์ ์ ํํ๋ ๊ฒ์ด ์ข์ต๋๋ค.
๋ค์๊ณผ ๊ฐ์ด ํ์ด์ง๋ค์ด์ ์ ๊ตฌํํ ์ ์์ต๋๋ค:
@Operation(summary="๋ชจ์ง๊ธ ์กฐํ", description = "๋ชจ์ง๊ธ ๋ชฉ๋ก์ ์กฐํํฉ๋๋ค.")
@GetMapping
- public ResponseEntity<List<PostResponseDTO>> getAllPosts(){
- return ResponseEntity.ok(postService.getAllPosts());
+ public ResponseEntity<Page<PostResponseDTO>> getAllPosts(
+ @RequestParam(defaultValue = "0") int page,
+ @RequestParam(defaultValue = "10") int size,
+ @RequestParam(defaultValue = "id") String sortBy) {
+ Pageable pageable = PageRequest.of(page, size, Sort.by(sortBy).descending());
+ return ResponseEntity.ok(postService.getAllPosts(pageable));
}Committable suggestion skipped: line range outside the PR's diff.
| @Operation(summary="๋ชจ์ง๊ธ ์์ธ ์กฐํ", description="๋ชจ์ง๊ธ ๊ฒ์๊ธ์ ์์ธ ์กฐํํฉ๋๋ค") | ||
| @GetMapping("/{postId}") | ||
| public ResponseEntity<PostDetailDTO> getPostDetail(@PathVariable Long postId){ | ||
| return ResponseEntity.ok(postService.getPostDetail(postId)); | ||
| } |
There was a problem hiding this comment.
๐ ๏ธ Refactor suggestion
์์ธ ์ฒ๋ฆฌ๊ฐ ํ์ํฉ๋๋ค.
getPostDetail() ๋ฉ์๋๋ ์กด์ฌํ์ง ์๋ ID์ ๋ํ ์์ธ ์ฒ๋ฆฌ๊ฐ ๋ช
์์ ์ผ๋ก ๊ตฌํ๋์ด ์์ง ์์ต๋๋ค. ์๋น์ค ๊ณ์ธต์์ ์์ธ๋ฅผ ๋์ง ์ ์์ผ๋ฏ๋ก, ์ปจํธ๋กค๋ฌ์์ ์ด๋ฅผ ์ ์ ํ ์ฒ๋ฆฌํ๋ ๊ฒ์ด ์ข์ต๋๋ค.
๋ค์๊ณผ ๊ฐ์ด ์์ธ ์ฒ๋ฆฌ๋ฅผ ์ถ๊ฐํ ์ ์์ต๋๋ค:
@Operation(summary="๋ชจ์ง๊ธ ์์ธ ์กฐํ", description="๋ชจ์ง๊ธ ๊ฒ์๊ธ์ ์์ธ ์กฐํํฉ๋๋ค")
@GetMapping("/{postId}")
public ResponseEntity<PostDetailDTO> getPostDetail(@PathVariable Long postId){
+ try {
return ResponseEntity.ok(postService.getPostDetail(postId));
+ } catch (NoSuchElementException e) {
+ log.error("๊ฒ์๊ธ์ ์ฐพ์ ์ ์์ต๋๋ค. ID: {}", postId, e);
+ return ResponseEntity.notFound().build();
+ } catch (Exception e) {
+ log.error("๊ฒ์๊ธ ์กฐํ ์ค ์ค๋ฅ ๋ฐ์. ID: {}", postId, e);
+ return ResponseEntity.internalServerError().build();
+ }
}๋๋ ์ ์ญ ์์ธ ์ฒ๋ฆฌ๊ธฐ(Global Exception Handler)๋ฅผ ๊ตฌํํ์ฌ ๋ชจ๋ ์ปจํธ๋กค๋ฌ์์ ๋ฐ์ํ๋ ์์ธ๋ฅผ ์ค์์์ ์ฒ๋ฆฌํ๋ ๊ฒ์ ๊ณ ๋ คํด ๋ณด์ธ์.
๐ Committable suggestion
โผ๏ธ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| @Operation(summary="๋ชจ์ง๊ธ ์์ธ ์กฐํ", description="๋ชจ์ง๊ธ ๊ฒ์๊ธ์ ์์ธ ์กฐํํฉ๋๋ค") | |
| @GetMapping("/{postId}") | |
| public ResponseEntity<PostDetailDTO> getPostDetail(@PathVariable Long postId){ | |
| return ResponseEntity.ok(postService.getPostDetail(postId)); | |
| } | |
| @Operation(summary="๋ชจ์ง๊ธ ์์ธ ์กฐํ", description="๋ชจ์ง๊ธ ๊ฒ์๊ธ์ ์์ธ ์กฐํํฉ๋๋ค") | |
| @GetMapping("/{postId}") | |
| public ResponseEntity<PostDetailDTO> getPostDetail(@PathVariable Long postId){ | |
| try { | |
| return ResponseEntity.ok(postService.getPostDetail(postId)); | |
| } catch (NoSuchElementException e) { | |
| log.error("๊ฒ์๊ธ์ ์ฐพ์ ์ ์์ต๋๋ค. ID: {}", postId, e); | |
| return ResponseEntity.notFound().build(); | |
| } catch (Exception e) { | |
| log.error("๊ฒ์๊ธ ์กฐํ ์ค ์ค๋ฅ ๋ฐ์. ID: {}", postId, e); | |
| return ResponseEntity.internalServerError().build(); | |
| } | |
| } |
| @Operation(summary="๋ชจ์ง๊ธ ๋ฑ๋ก ํ ์คํธ", description="[TEST] ๋ชจ์ง๊ธ์ ๋ฑ๋กํฉ๋๋ค.") | ||
| @PostMapping("/mock") | ||
| public ResponseEntity<?> createPostForSwagger(@RequestBody PostRequestDTO dto){ | ||
|
|
||
| // ํ ์คํธ์ฉ userId | ||
| User mockUser = userRepository.findById(1L).orElseThrow(); | ||
| Post createPost = postService.createPost(dto, mockUser); | ||
| List<String> skills = postSkillRepository.findSkillByPostId(createPost.getId()); | ||
| PostResponseDTO responseDTO = PostResponseDTO.from(createPost, skills, 0); | ||
| return ResponseEntity.ok(responseDTO); | ||
| } |
There was a problem hiding this comment.
๐ ๏ธ Refactor suggestion
ํ ์คํธ์ฉ ์๋ํฌ์ธํธ์ ๋ํ ๋ณด์ ๋ฐ ์ค๊ณ ๊ฐ์ ์ด ํ์ํฉ๋๋ค.
ํ ์คํธ์ฉ ์๋ํฌ์ธํธ๋ ๋ค์๊ณผ ๊ฐ์ ๋ฌธ์ ์ ์ด ์์ต๋๋ค:
- ํ๋์ฝ๋ฉ๋ userId(1L)๋ ํด๋น ์ฌ์ฉ์๊ฐ ์กด์ฌํ์ง ์์ ๊ฒฝ์ฐ ์์ธ๊ฐ ๋ฐ์ํ ์ ์์ต๋๋ค.
- ํ๋ก๋์ ํ๊ฒฝ์์ ํ ์คํธ ์๋ํฌ์ธํธ๊ฐ ๋ ธ์ถ๋ ์ ์์ต๋๋ค.
- ์ ๊ท createPost ๋ฉ์๋์ ์ฝ๋ ์ค๋ณต์ด ๋ฐ์ํฉ๋๋ค.
๋ค์๊ณผ ๊ฐ์ ๋ฐฉ๋ฒ์ผ๋ก ๊ฐ์ ํ ์ ์์ต๋๋ค:
- ํ ์คํธ ์๋ํฌ์ธํธ๋ ๊ฐ๋ฐ/ํ ์คํธ ํ๊ฒฝ์์๋ง ํ์ฑํ๋๋๋ก ์ค์
- ์์ธ ์ฒ๋ฆฌ ์ถ๊ฐ
- ํ๋์ฝ๋ฉ๋ ID ๋์ ๋ ์์ ํ ๋ฐฉ๋ฒ ์ฌ์ฉ
+ @Profile({"dev", "test"}) // ๊ฐ๋ฐ ๋ฐ ํ
์คํธ ํ๊ฒฝ์์๋ง ํ์ฑํ
@Operation(summary="๋ชจ์ง๊ธ ๋ฑ๋ก ํ
์คํธ", description="[TEST] ๋ชจ์ง๊ธ์ ๋ฑ๋กํฉ๋๋ค.")
@PostMapping("/mock")
public ResponseEntity<?> createPostForSwagger(@RequestBody PostRequestDTO dto){
// ํ
์คํธ์ฉ userId
- User mockUser = userRepository.findById(1L).orElseThrow();
+ User mockUser = userRepository.findById(1L)
+ .orElseThrow(() -> new IllegalStateException("ํ
์คํธ์ฉ ์ฌ์ฉ์(ID: 1)๊ฐ ์กด์ฌํ์ง ์์ต๋๋ค."));
// createPost ๋ฉ์๋๋ฅผ ์ฌ์ฌ์ฉํ์ฌ ์ค๋ณต ์ฝ๋ ์ ๊ฑฐ
- Post createPost = postService.createPost(dto, mockUser);
- List<String> skills = postSkillRepository.findSkillByPostId(createPost.getId());
- PostResponseDTO responseDTO = PostResponseDTO.from(createPost, skills, 0);
- return ResponseEntity.ok(responseDTO);
+ return createPost(dto, mockUser);
}Committable suggestion skipped: line range outside the PR's diff.
| private final PostService postService; | ||
| private final UserRepository userRepository; | ||
| private final PostSkillRepository postSkillRepository; |
There was a problem hiding this comment.
๐ ๏ธ Refactor suggestion
์ปจํธ๋กค๋ฌ์์ ์ง์ Repository ์ ๊ทผ์ ์ง์ํ์ธ์.
์ปจํธ๋กค๋ฌ ๋ ์ด์ด์์ ์ง์ UserRepository์ PostSkillRepository๋ฅผ ์ฃผ์
๋ฐ์ ์ฌ์ฉํ๋ ๊ฒ์ ๊ณ์ธต ๊ตฌ์กฐ์ ์์น์ ์๋ฐํฉ๋๋ค. ์ด๋ฌํ ๋ฐ์ดํฐ ์ก์ธ์ค๋ ์๋น์ค ๋ ์ด์ด๋ฅผ ํตํด ์ด๋ฃจ์ด์ ธ์ผ ํฉ๋๋ค. ์ปจํธ๋กค๋ฌ๋ ์๋น์ค ๋ ์ด์ด์๋ง ์ํธ์์ฉํ๊ณ , ์๋น์ค ๋ ์ด์ด๊ฐ ๋ฆฌํฌ์งํ ๋ฆฌ์ ์ํธ์์ฉํ๋ ๊ตฌ์กฐ๊ฐ ๋ฐ๋์งํฉ๋๋ค.
๋ฆฌํฌ์งํ ๋ฆฌ ์ ๊ทผ ๋ก์ง์ ์๋น์ค ๊ณ์ธต์ผ๋ก ์ด๋ํ๋ ๊ฒ์ ๊ถ์ฅํฉ๋๋ค:
public class PostController {
private final PostService postService;
- private final UserRepository userRepository;
- private final PostSkillRepository postSkillRepository;
@PostMapping
public ResponseEntity<?> createPost(@RequestBody PostRequestDTO dto, @AuthenticationPrincipal User user){
Post createPost = postService.createPost(dto, user);
- // ์คํฌ ์กฐํ
- List<String> skills = postSkillRepository.findSkillByPostId(createPost.getId());
// dto ๋ฐํ
// TODO : currentCount ๋ก์ง ๊ตฌํ ํ ๋ณํ
- PostResponseDTO responseDTO = PostResponseDTO.from(createPost, skills, 0);
+ PostResponseDTO responseDTO = postService.getPostResponse(createPost);
return ResponseEntity.ok(responseDTO);
}๐ Committable suggestion
โผ๏ธ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| private final PostService postService; | |
| private final UserRepository userRepository; | |
| private final PostSkillRepository postSkillRepository; | |
| public class PostController { | |
| private final PostService postService; | |
| @PostMapping | |
| public ResponseEntity<?> createPost(@RequestBody PostRequestDTO dto, @AuthenticationPrincipal User user) { | |
| Post createPost = postService.createPost(dto, user); | |
| // dto ๋ฐํ | |
| // TODO : currentCount ๋ก์ง ๊ตฌํ ํ ๋ณํ | |
| PostResponseDTO responseDTO = postService.getPostResponse(createPost); | |
| return ResponseEntity.ok(responseDTO); | |
| } | |
| } |
Walkthrough์ด๋ฒ ๋ณ๊ฒฝ์์๋ ๊ฒ์๊ธ(Post) ๊ด๋ จ ๊ธฐ๋ฅ์ ํจํค์ง ๊ตฌ์กฐ๋ฅผ ์ธ๋ถํํ๊ณ , ๊ฒ์๊ธ ๋ฑ๋กยท์กฐํยท์์ธ์กฐํ API๋ฅผ ๊ตฌํํ์์ผ๋ฉฐ, ์ด๋ฅผ ์ํ DTO, ์๋น์ค, ๋ ํฌ์งํ ๋ฆฌ ๊ณ์ธต์ ์ ์คํ์์ต๋๋ค. Skill(๊ธฐ์ ) ๊ด๋ จ ๋ ํฌ์งํ ๋ฆฌ ๋ฐ ์๋น์ค, Apply(์ง์) ๊ด๋ จ ํจํค์ง ๊ตฌ์กฐ๋ ์ ๋น๋์์ต๋๋ค. ๋ํ Spring Security ์์กด์ฑ์ด ํ์ฑํ๋์๊ณ , ์ํฐํฐ ๊ด๊ณ(๊ฒ์๊ธ-๊ธฐ์ ) ๋ฐ ํ๋๊ฐ ํ์ฅ๋์์ต๋๋ค. ๊ธฐ์กด post ํจํค์ง์ ์ปจํธ๋กค๋ฌ, ์๋น์ค, ๋ ํฌ์งํ ๋ฆฌ๋ ์ญ์ ๋๊ณ , ์๋ก์ด ๊ตฌ์กฐ๋ก ์ฌ๊ตฌ์ฑ๋์์ต๋๋ค. Changes
Sequence Diagram(s)sequenceDiagram
participant Client
participant PostController
participant PostService
participant PostRepository
participant SkillRepository
participant PostSkillRepository
participant UserRepository
Client->>PostController: POST /api/posts (PostRequestDTO)
PostController->>UserRepository: ์ธ์ฆ ์ฌ์ฉ์ ์กฐํ
PostController->>PostService: createPost(dto, user)
PostService->>PostRepository: ๊ฒ์๊ธ ์ ์ฅ
loop ๊ฐ skill
PostService->>SkillRepository: findByName(skill)
alt skill ์์
PostService->>SkillRepository: skill ์์ฑ ๋ฐ ์ ์ฅ
end
PostService->>PostSkillRepository: PostSkill ์ ์ฅ
end
PostService-->>PostController: ์ ์ฅ๋ Post ๋ฐํ
PostController->>PostSkillRepository: ๊ฒ์๊ธ๋ณ ๊ธฐ์ ์กฐํ
PostController-->>Client: PostResponseDTO ๋ฐํ
sequenceDiagram
participant Client
participant PostController
participant PostService
participant PostRepository
participant PostSkillRepository
Client->>PostController: GET /api/posts
PostController->>PostService: getAllPosts()
PostService->>PostRepository: findAllWithSkills()
loop ๊ฐ Post
PostService->>PostSkillRepository: ๊ธฐ์ ๋ช
๋ฆฌ์คํธ ์กฐํ
end
PostService-->>PostController: PostResponseDTO ๋ฆฌ์คํธ ๋ฐํ
PostController-->>Client: PostResponseDTO ๋ฆฌ์คํธ ๋ฐํ
Poem
โจ Finishing Touches
๐ชง TipsChatThere are 3 ways to chat with CodeRabbit:
SupportNeed help? Create a ticket on our support page for assistance with any issues or questions. Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments. CodeRabbit Commands (Invoked using PR comments)
Other keywords and placeholders
CodeRabbit Configuration File (
|
There was a problem hiding this comment.
Actionable comments posted: 5
๐ญ Outside diff range comments (1)
src/main/java/aibe/hosik/apply/controller/ApplyController.java (1)
9-15: ๐ ๏ธ Refactor suggestion์ปจํธ๋กค๋ฌ ๋ฉ์๋ ๊ตฌํ ๋๋ฝ
ํ์ฌApplyController์ ์ค์ REST API ์๋ํฌ์ธํธ ๋ฉ์๋๊ฐ ์์ต๋๋ค.
์ง์์ ๋ฑ๋ก, ๋ชฉ๋ก ์กฐํ, ์์ธ ์กฐํ ๋ฑ์ CRUD ๋ฉ์๋๋ฅผ ์ถ๊ฐํด์ผ ํฉ๋๋ค.
โป๏ธ Duplicate comments (13)
src/main/java/aibe/hosik/apply/repository/ApplyRepository.java (1)
7-8: post ID๋ก ์ง์์ ์กฐํ ๋ฉ์๋ ๊ตฌํ ํ์
์ฃผ์์ผ๋ก๋ง ๋จ์ ์๋// post id๋ก ์ง์์ ์กฐํ๋ถ๋ถ์ ์ค์ ์ฟผ๋ฆฌ ๋ฉ์๋๋ฅผ ์ถ๊ฐํด์ผ ํฉ๋๋ค.
์:List<Apply> findByPostId(Long postId);src/main/java/aibe/hosik/skill/cotnroller/SkillController.java (1)
1-1: ํจํค์ง ์ด๋ฆ์ ์คํ๊ฐ ์์ต๋๋คํจํค์ง ์ด๋ฆ์ด
aibe.hosik.skill.cotnroller๋ก ๋์ด ์๋๋ฐ, ์ ํํ ์คํ ๋ง์aibe.hosik.skill.controller์ ๋๋ค. ํจํค์ง ์ด๋ฆ์ ์คํ๋ ์ถํ์ ์ํฌํธ ๋ฌธ์ ๋ฅผ ์ผ์ผํฌ ์ ์์ผ๋ ์์ ํด์ฃผ์ธ์.-package aibe.hosik.skill.cotnroller; +package aibe.hosik.skill.controller;src/main/java/aibe/hosik/post/entity/Post.java (2)
40-42: requirementPersonality ํ๋์ ์ ํจ์ฑ ์ ์ฝ์กฐ๊ฑด ์ถ๊ฐ ํ์
requirementPersonalityํ๋์ ์ ํจ์ฑ ์ ์ฝ์กฐ๊ฑด์ด ์์ต๋๋ค. ์ด ํ๋์ ๋๋ฌด ๊ธด ํ ์คํธ๊ฐ ์ ์ฅ๋ ๊ฒฝ์ฐ ๋ฐ์ดํฐ๋ฒ ์ด์ค ๋ฌธ์ ๊ฐ ๋ฐ์ํ ์ ์์ต๋๋ค.@Size์ ๋ ธํ ์ด์ ์ ์ฌ์ฉํ์ฌ ๊ธธ์ด ์ ํ์ ์ถ๊ฐํ๋ ๊ฒ์ด ์ข์ต๋๋ค.- @Column + @Column(length = 500) + @Size(max = 500) private String requirementPersonality;
57-60: ์๋ฐฉํฅ ๋งคํ์ ๋ํ ํฌํผ ๋ฉ์๋ ์ถ๊ฐ ํ์์๋ฐฉํฅ ๋งคํ์ ์ฌ์ฉํ ๋๋ ์์ชฝ์์ ๊ด๊ณ๋ฅผ ์ค์ ํ๋ ํฌํผ ๋ฉ์๋๋ฅผ ์ถ๊ฐํ๋ ๊ฒ์ด ์ข์ต๋๋ค. ํ์ฌ๋ ๊ด๊ณ ์ค์ ์ฑ ์์ด ์๋น์ค ๊ณ์ธต์ ์์ด์ ์ผ๊ด์ฑ ๋ฌธ์ ๊ฐ ๋ฐ์ํ ์ ์์ต๋๋ค.
ํฌ์คํธ์ ์คํฌ ๊ฐ์ ์๋ฐฉํฅ ๊ด๊ณ๋ฅผ ๊ด๋ฆฌํ๋ ํฌํผ ๋ฉ์๋๋ฅผ ์ถ๊ฐํฉ๋๋ค:
@OneToMany(mappedBy = "post", cascade = CascadeType.ALL, orphanRemoval = true) @Builder.Default private List<PostSkill> postSkills = new ArrayList<>(); + + // ์๋ฐฉํฅ ๊ด๊ณ ์ ์ง๋ฅผ ์ํ ํฌํผ ๋ฉ์๋ + public void addPostSkill(PostSkill postSkill) { + this.postSkills.add(postSkill); + if (postSkill.getPost() != this) { + postSkill.setPost(this); + } + } + + public void removePostSkill(PostSkill postSkill) { + this.postSkills.remove(postSkill); + if (postSkill.getPost() == this) { + postSkill.setPost(null); + } + }src/main/java/aibe/hosik/post/dto/PostRequestDTO.java (1)
11-23: ๋น ์ ํจ์ฑ ๊ฒ์ฆ ์ ๋ ธํ ์ด์ ์ด ๋๋ฝ๋์์ต๋๋คํ์ฌ
PostRequestDTO์ ํ๋๋ค์ ๋ํ ์ ํจ์ฑ ๊ฒ์ฆ์ด ์์ต๋๋ค. ์ฌ์ฉ์๊ฐ ์๋ชป๋ ๋ฐ์ดํฐ๋ฅผ ์ ๋ ฅํ ๊ฒฝ์ฐ ์๋ฒ์์ ์ ์ ํ ๊ฒ์ฆ ์์ด ์ฒ๋ฆฌ๋ ์ ์์ต๋๋ค.๋ค์๊ณผ ๊ฐ์ด Bean Validation ์ ๋ ธํ ์ด์ ์ ์ถ๊ฐํ๋ ๊ฒ์ ๊ถ์ฅํฉ๋๋ค:
public record PostRequestDTO( + @NotBlank(message = "์ ๋ชฉ์ ํ์ ์ ๋ ฅ๊ฐ์ ๋๋ค") + @Size(max = 100, message = "์ ๋ชฉ์ 100์ ์ด๋ด๋ก ์ ๋ ฅํด์ฃผ์ธ์") String title, + @NotBlank(message = "๋ด์ฉ์ ํ์ ์ ๋ ฅ๊ฐ์ ๋๋ค") String content, + @Min(value = 1, message = "์ธ์ ์๋ ์ต์ 1๋ช ์ด์์ด์ด์ผ ํฉ๋๋ค") Integer headCount, String image, String requirementPersonality, + @NotNull(message = "๋ชจ์ง ์ข ๋ฃ์ผ์ ํ์ ์ ๋ ฅ๊ฐ์ ๋๋ค") + @Future(message = "๋ชจ์ง ์ข ๋ฃ์ผ์ ํ์ฌ ์ดํ์ ๋ ์ง์ฌ์ผ ํฉ๋๋ค") LocalDate endedAt, + @NotNull(message = "์นดํ ๊ณ ๋ฆฌ๋ ํ์ ์ ๋ ฅ๊ฐ์ ๋๋ค") PostCategory category, + @NotNull(message = "ํ์ ์ ํ์ ์ ๋ ฅ๊ฐ์ ๋๋ค") PostType type, + @NotEmpty(message = "์ต์ ํ๋ ์ด์์ ์คํฌ์ด ํ์ํฉ๋๋ค") List<String> skills ) {Bean Validation์ ์ํด ์๋ ์์กด์ฑ ์ถ๊ฐ๊ฐ ํ์ํฉ๋๋ค:
import jakarta.validation.constraints.*;src/main/java/aibe/hosik/post/dto/PostDetailDTO.java (1)
27-41: ์ด๊ฑฐํ ํ์ ์์ ์ฑ ๊ฐ์ ๋ฐ ์ฝ๋ ํ์ ์์ ํ์
category์typeํ๋๋ ์ด๊ฑฐํ ๊ฐ์toString()๋์name()์ ์ฌ์ฉํ๋ ๊ฒ์ด ์ข์ต๋๋ค.- ํ์ผ ๋์ ์ค๊ดํธ ํ์์ ๋ฌธ์ ๊ฐ ์์ต๋๋ค (
}}โ} }).๋ค์๊ณผ ๊ฐ์ด ์์ ํ๋ ๊ฒ์ ๊ถ์ฅํฉ๋๋ค:
public static PostDetailDTO from(Post post, List<String> skills, List<MatchedUserDTO> matchedUsers) { return new PostDetailDTO( post.getId(), post.getTitle(), post.getContent(), post.getHeadCount(), post.getImage(), post.getRequirementPersonality(), post.getEndedAt(), - post.getCategory().toString(), - post.getType().toString(), + post.getCategory().name(), + post.getType().name(), skills, matchedUsers ); -}} + } +}src/main/java/aibe/hosik/post/service/PostServiceImpl.java (2)
49-73: ํธ๋์ญ์ ๊ด๋ฆฌ ๋ฐ ์ฝ๋ ๊ฐ์ ํ์ํ์ฌ
createPost๋ฉ์๋์๋ ๋ช ๊ฐ์ง ๊ฐ์ ์ด ํ์ํฉ๋๋ค:
- ํธ๋์ญ์ ๊ด๋ฆฌ๊ฐ ์์ด ์ฌ๋ฌ ์คํฌ์ ์ ์ฅํ๋ ๊ณผ์ ์์ ์์ธ ๋ฐ์ ์ ์ผ๋ถ๋ง ์ ์ฅ๋ ์ํ์ด ์์ต๋๋ค.
- ์ฃผ์์์ ์ธ๊ธํ๋๋ก for ๋ฃจํ๋ฅผ ์คํธ๋ฆผ์ผ๋ก ๋ณํํ๋ ๊ฒ์ด ์ข์ต๋๋ค.
- ๊ฒ์๊ธ๊ณผ ์คํฌ ๊ฐ์ ์ฐ๊ด๊ด๊ณ ์ค์ ๋ถ๋ถ์ ์ํฐํฐ ๋ด๋ถ ํฌํผ ๋ฉ์๋๋ก ์ด๋์ํค๋ ๊ฒ์ด ๋ฐ๋์งํฉ๋๋ค.
75-91: ์์ธ ์ฒ๋ฆฌ ๋ฐ ํธ๋์ญ์ ๊ด๋ฆฌ ๊ฐ์ ํ์
getPostDetail๋ฉ์๋์์ ๋ค์ ์ฌํญ๋ค์ ๊ฐ์ ํด์ผ ํฉ๋๋ค:
- ๊ฒ์๊ธ์ ์ฐพ์ง ๋ชปํ์ ๋ ๊ตฌ์ฒด์ ์ธ ์์ธ ๋ฉ์์ง๊ฐ ์์ต๋๋ค.
- ์ฝ๊ธฐ ์ ์ฉ ์์ ์
@Transactional(readOnly = true)์ด๋ ธํ ์ด์ ์ ์ถ๊ฐํด์ผ ํฉ๋๋ค.- ์ต์ Java ๋ฌธ๋ฒ์ ํ์ฉํ์ฌ
collect(Collectors.toList())๋์toList()๋ฅผ ์ฌ์ฉํ์ธ์.src/main/java/aibe/hosik/post/controller/PostController.java (5)
29-31: ์ปจํธ๋กค๋ฌ์์ ์ง์ Repository ์ ๊ทผ์ ์ง์ํ์ธ์์ปจํธ๋กค๋ฌ ๋ ์ด์ด์์ ์ง์
UserRepository์PostSkillRepository๋ฅผ ์ฃผ์ ๋ฐ์ ์ฌ์ฉํ๋ ๊ฒ์ ๊ณ์ธต ๊ตฌ์กฐ ์์น์ ์๋ฐํฉ๋๋ค. ๋ฐ์ดํฐ ์ก์ธ์ค๋ ์๋น์ค ๋ ์ด์ด๋ฅผ ํตํด ์ด๋ฃจ์ด์ ธ์ผ ํฉ๋๋ค. ์ปจํธ๋กค๋ฌ๋ ์๋น์ค ๋ ์ด์ด์๋ง ์ํธ์์ฉํ๊ณ , ์๋น์ค ๋ ์ด์ด๊ฐ ๋ฆฌํฌ์งํ ๋ฆฌ์ ์ํธ์์ฉํ๋ ๊ตฌ์กฐ๊ฐ ๋ฐ๋์งํฉ๋๋ค.
44-55: ํ ์คํธ์ฉ ์๋ํฌ์ธํธ ๊ฐ์ ํ์ํ ์คํธ์ฉ ์๋ํฌ์ธํธ์ ๋ค์๊ณผ ๊ฐ์ ๋ฌธ์ ์ ์ด ์์ต๋๋ค:
- ํ๋์ฝ๋ฉ๋ userId(1L)๋ ํด๋น ์ฌ์ฉ์๊ฐ ์กด์ฌํ์ง ์์ ๊ฒฝ์ฐ ์์ธ๊ฐ ๋ฐ์ํ ์ ์์ต๋๋ค.
- ํ๋ก๋์ ํ๊ฒฝ์์ ํ ์คํธ ์๋ํฌ์ธํธ๊ฐ ๋ ธ์ถ๋ ์ ์์ด ๋ณด์ ์ํ์ด ์์ต๋๋ค.
- ์ ๊ท createPost ๋ฉ์๋์ ์ฝ๋ ์ค๋ณต์ด ๋ฐ์ํฉ๋๋ค.
57-61: ํ์ด์ง๋ค์ด์ ๊ตฌํ ํ์
getAllPosts()๋ฉ์๋๋ ๋ชจ๋ ๊ฒ์๊ธ์ ํ ๋ฒ์ ๋ฐํํฉ๋๋ค. ๊ฒ์๊ธ ์๊ฐ ๋ง์์ง๋ฉด ์ฑ๋ฅ ๋ฌธ์ ๊ฐ ๋ฐ์ํ ์ ์์ต๋๋ค. ํ์ด์ง๋ค์ด์ ์ ๊ตฌํํ์ฌ ํ ๋ฒ์ ๋ก๋๋๋ ๋ฐ์ดํฐ์ ์์ ์ ํํ๋ ๊ฒ์ด ์ข์ต๋๋ค.
63-67: ์์ธ ์ฒ๋ฆฌ ์ถ๊ฐ ํ์
getPostDetail()๋ฉ์๋๋ ์กด์ฌํ์ง ์๋ ID์ ๋ํ ์์ธ ์ฒ๋ฆฌ๊ฐ ๋ช ์์ ์ผ๋ก ๊ตฌํ๋์ด ์์ง ์์ต๋๋ค. ์๋น์ค ๊ณ์ธต์์ ์์ธ๋ฅผ ๋์ง ์ ์์ผ๋ฏ๋ก, ์ปจํธ๋กค๋ฌ์์ ์ด๋ฅผ ์ ์ ํ ์ฒ๋ฆฌํ๋ ๊ฒ์ด ์ข์ต๋๋ค.
33-43: ๐ ๏ธ Refactor suggestion์๋น์ค ๊ณ์ธต์ผ๋ก ์ฑ ์ ์ด๋ ํ์
ํ์ฌ ์ปจํธ๋กค๋ฌ์์ ์ง์ ์คํฌ์ ์กฐํํ๊ณ DTO๋ฅผ ์์ฑํ๋ ๋ก์ง์ด ์์ต๋๋ค. ์ด๋ฌํ ๋ก์ง์ ์๋น์ค ๊ณ์ธต์ผ๋ก ์ด๋์์ผ์ผ ํฉ๋๋ค. ์ปจํธ๋กค๋ฌ๋ ์์ฒญ์ ๋ฐ๊ณ ์๋ต์ ๋ฐํํ๋ ์ญํ ๋ง ์ํํ๋ ๊ฒ์ด ๋ฐ๋์งํฉ๋๋ค.
@Operation(summary="๋ชจ์ง๊ธ ๋ฑ๋ก", description="๋ชจ์ง๊ธ์ ๋ฑ๋กํฉ๋๋ค.") @PostMapping public ResponseEntity<?> createPost(@RequestBody PostRequestDTO dto, @AuthenticationPrincipal User user){ - Post createPost = postService.createPost(dto, user); - // ์คํฌ ์กฐํ - List<String> skills = postSkillRepository.findSkillByPostId(createPost.getId()); - // dto ๋ฐํ - // TODO : currentCount ๋ก์ง ๊ตฌํ ํ ๋ณํ - PostResponseDTO responseDTO = PostResponseDTO.from(createPost, skills, 0); - return ResponseEntity.ok(responseDTO); + PostResponseDTO responseDTO = postService.createAndGetPostResponse(dto, user); + return ResponseEntity.ok(responseDTO); }
๐งน Nitpick comments (12)
src/main/java/aibe/hosik/apply/entity/Apply.java (1)
28-32: ๋ช ์์ JoinColumn ์ง์ ๊ถ์ฅ
@ManyToOne์ฐ๊ด๊ด๊ณ ํ๋์@JoinColumn(name = "post_id")๋ฐ@JoinColumn(name = "resume_id")๋ฅผ ์ถ๊ฐํ๋ฉด DB ์คํค๋ง์ ๋งคํ์ด ๋ช ํํด์ ธ ๊ฐ๋ ์ฑ๊ณผ ์ ์ง๋ณด์์ฑ์ด ๊ฐ์ ๋ฉ๋๋ค.src/main/java/aibe/hosik/apply/service/ApplyService.java (1)
8-13: ๋ก๊ฑฐ ๋ฏธ์ฌ์ฉ ์ ์ ๊ฑฐ ๊ณ ๋ ค
@Slf4j์ ๋ ธํ ์ด์ ์ด ์ ์ฉ๋์์ผ๋ ํ์ฌ ๋ก๊น ํธ์ถ์ด ์์ต๋๋ค. ์ถํ ๋ก๊น ๊ณํ์ด ์๋ค๋ฉด ์ ๊ฑฐํด๋ ์ข์ต๋๋ค.src/main/java/aibe/hosik/post/dto/MatchedUserDTO.java (1)
1-15: ์ ์์ฑ๋ DTO ํด๋์ค์ด์ง๋ง ๋ถํ์ํ ์ํฌํธ๊ฐ ์์ต๋๋ค.DTO ๋ ์ฝ๋๊ฐ ์ ์ค๊ณ๋์์ต๋๋ค. ํ์ํ ์ฌ์ฉ์ ์ ๋ณด ํ๋๋ค์ ๋ชจ๋ ํฌํจํ๊ณ ์์ต๋๋ค. ๊ทธ๋ฌ๋
Post์ํฐํฐ๋ฅผ ์ํฌํธํ๊ณ ์์ง๋ง ์ค์ ๋ก ์ฌ์ฉํ์ง ์๊ณ ์์ต๋๋ค.๋ค์๊ณผ ๊ฐ์ด ๋ถํ์ํ ์ํฌํธ๋ฅผ ์ ๊ฑฐํ์ธ์:
package aibe.hosik.post.dto; -import aibe.hosik.post.entity.Post; import java.util.List; public record MatchedUserDTO( Long userId, String username, String nickname, String image, String introduction ) { }src/main/java/aibe/hosik/skill/repository/PostSkillRepository.java (1)
16-18: ์ฃผ์ ์คํ ์์ ํ์์ฃผ์์ ์คํ๊ฐ ์์ต๋๋ค. "์ด๋ฅด"๋ "์ด๋ฆ"์ ์คํ๋ก ๋ณด์ ๋๋ค.
๋ค์๊ณผ ๊ฐ์ด ์์ ํ์ธ์:
- // Post ID๋ก ํด๋น ๊ธ๊ณผ ์ฐ๊ด๋ ๋ชจ๋ ์คํฌ ์ด๋ฅด ์ง์ ์กฐํ + // Post ID๋ก ํด๋น ๊ธ๊ณผ ์ฐ๊ด๋ ๋ชจ๋ ์คํฌ ์ด๋ฆ ์ง์ ์กฐํ @Query("SELECT s.skill.name FROM PostSkill s WHERE s.post.id = :postId") List<String> findSkillByPostId(@Param("postId") Long postId);src/main/java/aibe/hosik/post/service/PostService.java (1)
11-15: ์๋น์ค ์ธํฐํ์ด์ค ๋ฉ์๋์ JavaDoc ์ค๋ช ์ถ๊ฐ ๋ฐ ๋ฐํ ํ์ ์ผ๊ด์ฑ ๊ฒํ์๋น์ค ์ธํฐํ์ด์ค ๋ฉ์๋๋ค์ด ์ ์ ์๋์ด ์์ง๋ง, ๊ฐ ๋ฉ์๋์ ๋ชฉ์ ๊ณผ ๋์์ ์ค๋ช ํ๋ JavaDoc ์ฃผ์์ด ์์ต๋๋ค. ๋ํ
createPost๋ฉ์๋๋ ๋ค๋ฅธ ๋ฉ์๋๋ค๊ณผ ๋ฌ๋ฆฌ ์ํฐํฐ๋ฅผ ๋ฐํํ๊ณ ์์ด ์ผ๊ด์ฑ์ด ๋จ์ด์ง๋๋ค.๋ค์๊ณผ ๊ฐ์ด JavaDoc์ ์ถ๊ฐํ๊ณ ๋ฐํ ํ์ ์ DTO๋ก ํต์ผํ๋ ๊ฒ์ด ์ข์ต๋๋ค:
public interface PostService { + /** + * ๋ชจ๋ ๊ฒ์๊ธ ๋ชฉ๋ก์ ์กฐํํฉ๋๋ค. + * @return ๊ฒ์๊ธ ์๋ต DTO ๋ชฉ๋ก + */ List<PostResponseDTO> getAllPosts(); + + /** + * ์๋ก์ด ๊ฒ์๊ธ์ ์์ฑํฉ๋๋ค. + * @param dto ๊ฒ์๊ธ ์์ฑ ์์ฒญ DTO + * @param user ๊ฒ์๊ธ ์์ฑ์ + * @return ์์ฑ๋ ๊ฒ์๊ธ ์๋ต DTO + */ - Post createPost(PostRequestDTO dto, User user); + PostResponseDTO createPost(PostRequestDTO dto, User user); + + /** + * ํน์ ๊ฒ์๊ธ์ ์์ธ ์ ๋ณด๋ฅผ ์กฐํํฉ๋๋ค. + * @param postId ์กฐํํ ๊ฒ์๊ธ ID + * @return ๊ฒ์๊ธ ์์ธ ์ ๋ณด DTO + */ PostDetailDTO getPostDetail(Long postId); }src/main/java/aibe/hosik/post/dto/PostResponseDTO.java (1)
7-16: ์๋ต DTO ํ๋์ ๋ํ ๋ฌธ์ํ ํ์
PostResponseDTOํด๋์ค์ ๊ฐ ํ๋์ ๋ํ ์ค๋ช ์ด ์์ด ๋ค๋ฅธ ๊ฐ๋ฐ์๊ฐ ์ด DTO๋ฅผ ์ฌ์ฉํ ๋ ๊ฐ ํ๋์ ์๋ฏธ์ ์ฉ๋๋ฅผ ์ดํดํ๊ธฐ ์ด๋ ค์ธ ์ ์์ต๋๋ค.Javadoc ์ฃผ์์ ์ถ๊ฐํ์ฌ ๊ฐ ํ๋์ ์๋ฏธ์ ์ฉ๋๋ฅผ ๋ช ํํ๊ฒ ์ค๋ช ํ๋ ๊ฒ์ด ์ข์ต๋๋ค:
/** + * ๊ฒ์๊ธ ๋ชฉ๋ก ์กฐํ ์๋ต์ ์ํ DTO + */ public record PostResponseDTO( + /** ๊ฒ์๊ธ ID */ Long id, + /** ๊ฒ์๊ธ ์ด๋ฏธ์ง URL */ String image, + /** ๊ฒ์๊ธ ์ ๋ชฉ */ String title, + /** ๊ฒ์๊ธ ๋ด์ฉ */ String content, + /** ๊ฒ์๊ธ ์นดํ ๊ณ ๋ฆฌ */ String category, + /** ๊ฒ์๊ธ ๊ด๋ จ ๊ธฐ์ ๋ชฉ๋ก */ List<String> skills, + /** ์ด ๋ชจ์ง ์ธ์ */ Integer headCount, + /** ํ์ฌ ๋ชจ์ง๋ ์ธ์ */ Integer currentCount ) {src/main/java/aibe/hosik/post/repository/PostRepository.java (1)
13-17: EntityGraph์ JPQL ์ฟผ๋ฆฌ ์ฌ์ฉ ๋ฐฉ์ ์ค๋ช ํ์ํ์ฌ ์ฝ๋์์๋
@EntityGraph๊ฐ ์ฃผ์ ์ฒ๋ฆฌ๋๊ณ JPQL ์ฟผ๋ฆฌ๊ฐ ์ฌ์ฉ๋๊ณ ์์ต๋๋ค. ๋ ๋ฐฉ์ ๋ชจ๋ ๊ฐ๋ฅํ์ง๋ง ์ด๋ค ๋ฐฉ์์ ์ ํํ๋์ง์ ๊ทธ ์ด์ ์ ๋ํ ์ค๋ช ์ด ์์ต๋๋ค.๋ํ ๋๋์ ๋ฐ์ดํฐ๋ฅผ ์กฐํํ ๋
DISTINCT๋ ์ฑ๋ฅ ์ด์๋ฅผ ๋ฐ์์ํฌ ์ ์์ต๋๋ค. ํ์ด์ง ์ฒ๋ฆฌ์ ํจ๊ป ์ฌ์ฉํ๋ฉด ์ข์ ๊ฒ ๊ฐ์ต๋๋ค.public interface PostRepository extends JpaRepository<Post, Long> { - // Post ์กฐํ ์ postSkills, skill ์ํฐํฐ ์ฆ์ ๋ก๋ฉ ์ง์ + /** + * ๋ชจ๋ ๊ฒ์๊ธ์ ์ฐ๊ด๋ ์คํฌ๊ณผ ํจ๊ป ์กฐํํฉ๋๋ค. + * JPQL์ LEFT JOIN FETCH๋ฅผ ์ฌ์ฉํ์ฌ N+1 ๋ฌธ์ ๋ฅผ ๋ฐฉ์งํฉ๋๋ค. + * ์ฐธ๊ณ : EntityGraph ๋ฐฉ์๋ ๊ฐ๋ฅํ๋ JPQL ์ฟผ๋ฆฌ๊ฐ ๋ ๋ช ์์ ์ด์ด์ ์ ํํ์ต๋๋ค. + * @return ์คํฌ ์ ๋ณด๊ฐ ํฌํจ๋ ๋ชจ๋ ๊ฒ์๊ธ ๋ชฉ๋ก + */ //@EntityGraph(attributePaths = {"postSkills", "postSkills.skill"}) @Query("SELECT DISTINCT p FROM Post p LEFT JOIN FETCH p.postSkills ps LEFT JOIN FETCH ps.skill") List<Post> findAllWithSkills();src/main/java/aibe/hosik/post/dto/PostDetailDTO.java (1)
10-26: DTO ํ๋์ ๋ํ ๋ฌธ์ํ ์ถ๊ฐ ํ์
PostDetailDTOํด๋์ค์ ๊ฐ ํ๋์ ๋ํ ์ค๋ช ์ด ์์ด ๋ค๋ฅธ ๊ฐ๋ฐ์๊ฐ ์ด DTO๋ฅผ ์ฌ์ฉํ ๋ ๊ฐ ํ๋์ ์๋ฏธ์ ์ฉ๋๋ฅผ ์ดํดํ๊ธฐ ์ด๋ ค์ธ ์ ์์ต๋๋ค. ํนํ "ํ์ฌ ์ ํ๋ ๋ชฉ๋ก ๋ณด์ฌ์ฃผ๊ธฐ" ์ฃผ์์ ๊ตฌ์ฒด์ ์ธ ์ค๋ช ์ด ๋ถ์กฑํฉ๋๋ค.Javadoc ์ฃผ์์ ์ถ๊ฐํ์ฌ ๊ฐ ํ๋์ ์๋ฏธ์ ์ฉ๋๋ฅผ ๋ช ํํ๊ฒ ์ค๋ช ํ๋ ๊ฒ์ด ์ข์ต๋๋ค:
+/** + * ๊ฒ์๊ธ ์์ธ ์ ๋ณด๋ฅผ ์ํ DTO ํด๋์ค์ ๋๋ค. + */ public record PostDetailDTO( + /** ๊ฒ์๊ธ ID */ Long id, + /** ๊ฒ์๊ธ ์ ๋ชฉ */ String title, + /** ๊ฒ์๊ธ ๋ด์ฉ */ String content, + /** ๋ชจ์ง ์ธ์ ์ */ Integer headCount, + /** ๊ฒ์๊ธ ์ด๋ฏธ์ง URL */ String image, + /** ์๊ตฌ๋๋ ์ฑ๊ฒฉ ํน์ฑ */ String requirementPersonality, + /** ๋ชจ์ง ์ข ๋ฃ์ผ */ LocalDate endedAt, + /** ๊ฒ์๊ธ ์นดํ ๊ณ ๋ฆฌ */ String category, + /** ๊ฒ์๊ธ ํ์ */ String type, + /** ๊ด๋ จ ๊ธฐ์ ๋ชฉ๋ก */ List<String> skills, - // ํ์ฌ ์ ํ๋ ๋ชฉ๋ก ๋ณด์ฌ์ฃผ๊ธฐ + /** ๋งค์นญ๋ ์ฌ์ฉ์ ๋ชฉ๋ก - ํ์ฌ ์ ํ๋ ์ง์์๋ค์ ์ ๋ณด๋ฅผ ํฌํจ */ List<MatchedUserDTO> matchedUsers ) {src/main/java/aibe/hosik/post/service/PostServiceImpl.java (1)
28-47: Stream ์ฌ์ฉ ์ ์ต์ Java ๋ฉ์๋ ํ์ฉ ๊ถ์ฅ
getAllPosts()๋ฉ์๋์์ ๋ฐํ ์collect(Collectors.toList())๋ฅผ ์ฌ์ฉํ๊ณ ๊ณ์ ๋ฐ, Java 16 ์ด์์์๋ ๋ ๊ฐ๊ฒฐํ.toList()๋ฉ์๋๋ฅผ ์ฌ์ฉํ ์ ์์ต๋๋ค. ๋ํ ํ์ฌ ์ฐธ์ฌ์ ์์ ๋ํ ๊ตฌํ์ด ํ์ํฉ๋๋ค.return posts.stream() .map(post -> { // fetch๋ postSkills์์ skill ์ถ์ถ List<String> skills = post.getPostSkills().stream() .map(s -> s.getSkill().getName()) - .collect(Collectors.toList()); + .toList(); // TODO : ํ์ฌ ์ฐธ์ฌ์ ์ ๊ณ์ฐ Integer currentCount = 0; // DTO ์ ์ ํฉํ ๋ฆฌ ๋ฉ์๋ ํ์ฉ return PostResponseDTO.from(post, skills, currentCount); - }).collect(Collectors.toList()); + }).toList();src/main/java/aibe/hosik/post/controller/PostController.java (3)
15-16: ๋ถํ์ํ import ์ ๊ฑฐ
org.apache.coyote.Responseimport๋ ์ฌ์ฉ๋์ง ์๊ณ ์์ต๋๋ค. ๋ถํ์ํ import๋ ์ ๊ฑฐํ๋ ๊ฒ์ด ์ข์ต๋๋ค.import lombok.extern.slf4j.Slf4j; -import org.apache.coyote.Response; import org.springframework.http.ResponseEntity;
22-22: ๋ถํ์ํ ์ฃผ์ ์ ๊ฑฐ"ํ ์คํธ" ์ฃผ์์ ์๋ฏธ๊ฐ ๋ถ๋ถ๋ช ํ๋ฉฐ ์ฝ๋ ๊ฐ๋ ์ฑ์ ์ ํ์ํต๋๋ค. ๋ช ํํ ์ค๋ช ์ด ํ์ํ๊ฑฐ๋ ๋ถํ์ํ ์ฃผ์์ ์ ๊ฑฐํ๋ ๊ฒ์ด ์ข์ต๋๋ค.
-// ํ ์คํธ @Slf4j @RestController
1-21: ์ ์ฒด ์ปจํธ๋กค๋ฌ ๊ตฌ์กฐ ๊ฐ์ ์ ์์ปจํธ๋กค๋ฌ ์ ์ฒด์ ๋ํ ๋ช ๊ฐ์ง ๊ฐ์ ์ฌํญ์ ์ ์ํฉ๋๋ค:
- ์์ธ ์ฒ๋ฆฌ๋ฅผ ์ํ ๊ธ๋ก๋ฒ ์์ธ ํธ๋ค๋ฌ(Global Exception Handler) ๊ตฌํ์ ๊ณ ๋ คํ์ธ์.
- ๋ฆฌํฉํ ๋ง๋ ์๋น์ค ๊ณ์ธต๊ณผ ํจ๊ป ์๋ํ๋๋ก ์ปจํธ๋กค๋ฌ ์ฝ๋๋ฅผ ์กฐ์ ํ์ธ์.
- ๋ฐํ ํ์ ์ ์ผ๊ด์ฑ ์๊ฒ ์ ์งํ๊ณ , ๊ฐ๋ฅํ ๊ตฌ์ฒด์ ์ธ ํ์ ์ ์ฌ์ฉํ์ธ์(์:
ResponseEntity<?>๋ณด๋ค๋ResponseEntity<PostResponseDTO>).- ํจ๊ณผ์ ์ธ API ๋ฌธ์ํ๋ฅผ ์ํด Swagger ์ด๋ ธํ ์ด์ ์ ๋ ์์ธํ๊ฒ ํ์ฉํ์ธ์.
๋ชจ๋ฒ ์ฌ๋ก๋ก ๊ณ ๋ คํด ๋ณผ ์ ์๋ ์ํคํ ์ฒ ํจํด์ ๋ค์๊ณผ ๊ฐ์ต๋๋ค:
- ๊ณ์ธต ๋ถ๋ฆฌ: ์ปจํธ๋กค๋ฌ๋ HTTP ์์ฒญ/์๋ต ์ฒ๋ฆฌ๋ง ๋ด๋นํ๊ณ , ๋น์ฆ๋์ค ๋ก์ง์ ์๋น์ค์์ ์ฒ๋ฆฌ
- DTO ๋ณํ: ์ํฐํฐ์ DTO ๊ฐ ๋ณํ ๋ก์ง์ ์๋น์ค ๋๋ ๋งคํผ ํด๋์ค๋ก ๋ถ๋ฆฌ
- ๊ธ๋ก๋ฒ ์์ธ ์ฒ๋ฆฌ: @ControllerAdvice ๋๋ @RestControllerAdvice๋ฅผ ์ฌ์ฉํ ์ผ๊ด๋ ์์ธ ์ฒ๋ฆฌ
- ํ์ด์ง๋ค์ด์ : ๋์ฉ๋ ๋ฐ์ดํฐ ์ฒ๋ฆฌ๋ฅผ ์ํ ํ์ค ํ์ด์ง๋ค์ด์ ๊ตฌํ
๐ Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
๐ Files selected for processing (22)
build.gradle(1 hunks)src/main/java/aibe/hosik/analysis/Analysis.java(1 hunks)src/main/java/aibe/hosik/apply/controller/ApplyController.java(1 hunks)src/main/java/aibe/hosik/apply/entity/Apply.java(1 hunks)src/main/java/aibe/hosik/apply/repository/ApplyRepository.java(1 hunks)src/main/java/aibe/hosik/apply/service/ApplyService.java(1 hunks)src/main/java/aibe/hosik/post/PostController.java(0 hunks)src/main/java/aibe/hosik/post/PostRepository.java(0 hunks)src/main/java/aibe/hosik/post/PostService.java(0 hunks)src/main/java/aibe/hosik/post/controller/PostController.java(1 hunks)src/main/java/aibe/hosik/post/dto/MatchedUserDTO.java(1 hunks)src/main/java/aibe/hosik/post/dto/PostDetailDTO.java(1 hunks)src/main/java/aibe/hosik/post/dto/PostRequestDTO.java(1 hunks)src/main/java/aibe/hosik/post/dto/PostResponseDTO.java(1 hunks)src/main/java/aibe/hosik/post/entity/Post.java(3 hunks)src/main/java/aibe/hosik/post/repository/PostRepository.java(1 hunks)src/main/java/aibe/hosik/post/service/PostService.java(1 hunks)src/main/java/aibe/hosik/post/service/PostServiceImpl.java(1 hunks)src/main/java/aibe/hosik/skill/cotnroller/SkillController.java(1 hunks)src/main/java/aibe/hosik/skill/repository/PostSkillRepository.java(1 hunks)src/main/java/aibe/hosik/skill/repository/SkillRepository.java(1 hunks)src/main/java/aibe/hosik/skill/service/SkillService.java(1 hunks)
๐ค Files with no reviewable changes (3)
- src/main/java/aibe/hosik/post/PostRepository.java
- src/main/java/aibe/hosik/post/PostService.java
- src/main/java/aibe/hosik/post/PostController.java
๐ Additional comments (11)
src/main/java/aibe/hosik/apply/entity/Apply.java (1)
1-2: ํจํค์ง ๊ตฌ์กฐ ๋ณ๊ฒฝ ํ์ธ
package aibe.hosik.apply.entity;๋ก ์ํฐํฐ ํจํค์ง๊ฐ ์ธ๋ถํ๋์ด ๋ชจ๋ํ ๊ตฌ์กฐ๊ฐ ์ผ๊ด๋๊ฒ ์ ๋ฆฌ๋์์ต๋๋ค.src/main/java/aibe/hosik/analysis/Analysis.java (1)
3-3: Import ๊ฒฝ๋ก ์ ๋ฐ์ดํธ ํ์ธ
import aibe.hosik.apply.entity.Apply;๋ก ๋ณ๊ฒฝ๋์ดApply์ํฐํฐ์ ์๋ก์ด ํจํค์ง ์์น๊ฐ ์ฌ๋ฐ๋ฅด๊ฒ ๋ฐ์๋์์ต๋๋ค.src/main/java/aibe/hosik/apply/service/ApplyService.java (1)
1-3: ํจํค์ง ๋ฐ import ์ ๋ฐ์ดํธ
package aibe.hosik.apply.service;์import aibe.hosik.apply.repository.ApplyRepository;๋ก ๋ชจ๋ํ๋ ํจํค์ง ๊ตฌ์กฐ๊ฐ ์ผ๊ด๋๊ฒ ์ ๋ฆฌ๋์์ต๋๋ค.src/main/java/aibe/hosik/apply/controller/ApplyController.java (1)
1-3: ํจํค์ง ๋ฐ import ๊ฒฝ๋ก ๋ณ๊ฒฝ ํ์ธ
package aibe.hosik.apply.controller;์import aibe.hosik.apply.service.ApplyService;๋ก ๊ตฌ์กฐ๊ฐ ์ฌ๋ฐ๋ฅด๊ฒ ๋ฐ์๋์์ต๋๋ค.src/main/java/aibe/hosik/apply/repository/ApplyRepository.java (1)
1-3: ํจํค์ง ๋ฐ import ๋ณ๊ฒฝ ํ์ธ
package aibe.hosik.apply.repository;์import aibe.hosik.apply.entity.Apply;๋ก ์ด๋์ด ์ฌ๋ฐ๋ฅด๊ฒ ๋ฐ์๋์์ต๋๋ค.src/main/java/aibe/hosik/skill/cotnroller/SkillController.java (1)
3-3: ์๋น์ค ๋ ์ด์ด ์ํฌํธ ์ถ๊ฐ ๊ตฌํ ์๋ฃSkillService๋ฅผ ์ฌ๋ฐ๋ฅด๊ฒ ์ํฌํธํ์์ต๋๋ค. ๊ณ์ธต ๊ตฌ์กฐ๋ฅผ ์ ์ ํ ๋ถ๋ฆฌํ์ฌ ๊ตฌํํ์ ์ ์ด ์ข์ต๋๋ค.
src/main/java/aibe/hosik/skill/service/SkillService.java (2)
1-1: ์๋น์ค ๊ณ์ธต ํจํค์ง ๊ตฌ์กฐ ๊ฐ์์๋น์ค ํด๋์ค๋ฅผ
serviceํจํค์ง๋ก ์ด๋์ํจ ๊ฒ์ ์ข์ ๊ตฌ์กฐ ๊ฐ์ ์ ๋๋ค. ์ด๋ ํ์ค Spring ์ ํ๋ฆฌ์ผ์ด์ ๋ ์ด์ด๋ง ๊ท์น์ ๋ฐ๋ฅด๊ณ ์์ต๋๋ค.
3-3: ๋ ํฌ์งํ ๋ฆฌ ์ํฌํธ ๊ฒฝ๋ก ์์ ์๋ฃSkillRepository๋ฅผ ์ฌ๋ฐ๋ฅธ ํจํค์ง์์ ์ํฌํธํ๊ณ ์์ต๋๋ค. ๊ณ์ธต ๊ตฌ์กฐ์ ๋ง๊ฒ ์ ์ ๋ฆฌ๋์์ต๋๋ค.
src/main/java/aibe/hosik/skill/repository/SkillRepository.java (3)
1-1: ๋ ํฌ์งํ ๋ฆฌ ๊ณ์ธต ํจํค์ง ๊ตฌ์กฐ ๊ฐ์๋ ํฌ์งํ ๋ฆฌ ์ธํฐํ์ด์ค๋ฅผ
repositoryํจํค์ง๋ก ์ด๋์ํจ ๊ฒ์ ์ข์ ๊ตฌ์กฐ ๊ฐ์ ์ ๋๋ค. ์ด๋ ํ์ค Spring ์ ํ๋ฆฌ์ผ์ด์ ๋ ์ด์ด๋ง ๊ท์น์ ๋ฐ๋ฅด๊ณ ์์ต๋๋ค.
6-7: Optional ์ํฌํธ ์ถ๊ฐOptional์ ์ฌ์ฉํ์ฌ ์กด์ฌํ์ง ์์ ์ ์๋ ๊ฐ์ ์ฒ๋ฆฌํ๋ ๋ฐฉ์์ Java 8 ์ดํ์ ์ข์ ๊ดํ์ ๋๋ค. ์ ํ์ จ์ต๋๋ค.
9-9: ์ด๋ฆ์ผ๋ก ์คํฌ์ ์ฐพ๋ ๋ฉ์๋ ์ถ๊ฐ
findByName๋ฉ์๋๋ฅผ ์ถ๊ฐํ ๊ฒ์ ์ข์ ๊ตฌํ์ ๋๋ค. Spring Data JPA ๊ท์น์ ๋ฐ๋ผ ๋ฉ์๋ ์ด๋ฆ์ ํตํด ์ฟผ๋ฆฌ๊ฐ ์๋ ์์ฑ๋ฉ๋๋ค. Optional์ ๋ฐํ ํ์ ์ผ๋ก ์ฌ์ฉํ์ฌ null ์ฒดํฌ ๋์ ํจ์ํ ์ ๊ทผ ๋ฐฉ์์ ์ฌ์ฉํ ์ ์๊ฒ ํ ์ ๋ ์ข์ต๋๋ค.์ด ๋ฉ์๋๋ ๊ฒ์๊ธ ์์ฑ ๊ณผ์ ์์ ์คํฌ์ ์ด๋ฆ์ผ๋ก ์กฐํํ๋ ๋ฐ ์ ์ฉํ๊ฒ ์ฌ์ฉ๋ ๊ฒ์ ๋๋ค.
| dependencies { | ||
| implementation 'org.springframework.boot:spring-boot-starter-data-jpa' | ||
| // implementation 'org.springframework.boot:spring-boot-starter-security' | ||
| implementation 'org.springframework.boot:spring-boot-starter-security' |
There was a problem hiding this comment.
๐ก Verification agent
โ Verification inconclusive
Spring Security ์์กด์ฑ์ด ํ์ฑํ๋์์ต๋๋ค
Spring Security ์์กด์ฑ์ ํ์ฑํํ์ จ๋ค์. ์ด๋ ์ธ์ฆ ๋ฐ ๊ถํ ๋ถ์ฌ ๊ธฐ๋ฅ์ ํ๋ก์ ํธ์ ์ถ๊ฐํฉ๋๋ค. ๋ค๋ง, Spring Security๋ฅผ ํ์ฑํํ๋ฉด ๊ธฐ๋ณธ์ ์ผ๋ก ๋ชจ๋ ์๋ํฌ์ธํธ๊ฐ ์ธ์ฆ์ ํ์๋ก ํ๊ฒ ๋ฉ๋๋ค. ์ด๋ฅผ ์ํ ์ ์ ํ ๋ณด์ ๊ตฌ์ฑ์ด ํ๋ก์ ํธ์ ์ถ๊ฐ๋์๋์ง ํ์ธํด์ฃผ์ธ์.
ํ๋ก์ ํธ์ SecurityConfig ๋๋ WebSecurityConfigurerAdapter ๊ตฌํ์ฒด๊ฐ ์๋์ง ํ์ธํด๋ณด์ธ์:
๐ Script executed:
#!/bin/bash
# ๋ณด์ ์ค์ ํ์ผ ์กด์ฌ ํ์ธ
find src/main/java -type f -name "*Security*.java" -o -name "*WebSecurity*.java" | sortLength of output: 89
๋ณด์ ์ค์ ํด๋์ค ๋ฏธํ์ธ
Spring Security ์์กด์ฑ์ ์ถ๊ฐํ์
จ์ผ๋, src/main/java ๊ฒฝ๋ก์์ *Security*.java ๋๋ *WebSecurity*.java ํ์ผ์ด ๊ฒ์๋์ง ์์ต๋๋ค. ์ด ์ํ๋ผ๋ฉด ๊ธฐ๋ณธ ์ค์ ์ผ๋ก ๋ชจ๋ ์๋ํฌ์ธํธ๊ฐ ์ธ์ฆ์ ํ์๋ก ํ๋ฉฐ, ๊ธฐ๋ณธ ๋ก๊ทธ์ธ ํ์ด์ง์ ๊ธฐ๋ณธ ๊ณ์ ์ด ์์ฑ๋ ์ ์์ต๋๋ค. ๋ค์ ์ฌํญ์ ๊ฒํ ๋ฐ ์กฐ์นํด์ฃผ์ธ์:
- ์ฌ์ฉ์ ์ ์ ๋ณด์ ์ค์ ํด๋์ค(SecurityConfig)๋ฅผ ์ถ๊ฐํ์ฌ ์ธ์ฆ/์ธ๊ฐ ์ ์ฑ ์ ๋ช ์์ ์ผ๋ก ๊ตฌ์ฑ
@Configuration๊ณผ@EnableWebSecurity์ ๋ ธํ ์ด์ ์ ์ฌ์ฉํดWebSecurityConfigurerAdapter๋๋SecurityFilterChain๊ตฌํ์ฒด ์์ฑ- ์๋ํฌ์ธํธ๋ณ ์ ๊ทผ ์ ์ด(
antMatchers๋ฑ), CSRFยทCORS ์ค์ ์ฌ๋ถ ํ์ธ
์์:
@Configuration
@EnableWebSecurity
public class SecurityConfig {
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http
.authorizeRequests(auth -> auth
.antMatchers("/public/**").permitAll()
.anyRequest().authenticated()
)
.formLogin(withDefaults());
return http.build();
}
}์์ ๊ฐ์ด ๋ณด์ ์ค์ ์ ์ถ๊ฐํ์ฌ ํ๋ก์ ํธ์ ํ์ํ ์ธ์ฆยท์ธ๊ฐ ๋ก์ง์ ๊ตฌํํด์ฃผ์ธ์.
| public Post toEntity(User user) { | ||
| return Post.builder() | ||
| .title(title()) | ||
| .content(content()) | ||
| .headCount(headCount()) | ||
| .image(image()) | ||
| .requirementPersonality(requirementPersonality()) | ||
| .endedAt(endedAt()) | ||
| .category(category()) | ||
| .type(type()) | ||
| .user(user) | ||
| .build(); | ||
| } |
There was a problem hiding this comment.
๐ ๏ธ Refactor suggestion
toEntity ๋ฉ์๋์ Null ์ฒดํฌ ์ถ๊ฐ ํ์
toEntity ๋ฉ์๋์์ null ๊ฐ์ ๊ฐ์ง ํ๋๋ค์ ๋ํ ์ฒ๋ฆฌ๊ฐ ์์ต๋๋ค. ์ ํจ์ฑ ๊ฒ์ฆ์ ์ถ๊ฐํ๋๋ผ๋ ๋ฐํ์์์ ์์์น ๋ชปํ NullPointerException์ด ๋ฐ์ํ ์ ์์ต๋๋ค.
๋ค์๊ณผ ๊ฐ์ด ๋น๋ ํจํด์์ null ์ฒดํฌ ๋ก์ง์ ์ถ๊ฐํ๋ ๊ฒ์ด ์ข์ต๋๋ค:
public Post toEntity(User user) {
+ if (user == null) {
+ throw new IllegalArgumentException("์ฌ์ฉ์ ์ ๋ณด๋ ํ์์
๋๋ค");
+ }
return Post.builder()
.title(title())
.content(content())
.headCount(headCount())
.image(image())
.requirementPersonality(requirementPersonality())
.endedAt(endedAt())
.category(category())
.type(type())
.user(user)
.build();
}๐ Committable suggestion
โผ๏ธ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| public Post toEntity(User user) { | |
| return Post.builder() | |
| .title(title()) | |
| .content(content()) | |
| .headCount(headCount()) | |
| .image(image()) | |
| .requirementPersonality(requirementPersonality()) | |
| .endedAt(endedAt()) | |
| .category(category()) | |
| .type(type()) | |
| .user(user) | |
| .build(); | |
| } | |
| public Post toEntity(User user) { | |
| if (user == null) { | |
| throw new IllegalArgumentException("์ฌ์ฉ์ ์ ๋ณด๋ ํ์์ ๋๋ค"); | |
| } | |
| return Post.builder() | |
| .title(title()) | |
| .content(content()) | |
| .headCount(headCount()) | |
| .image(image()) | |
| .requirementPersonality(requirementPersonality()) | |
| .endedAt(endedAt()) | |
| .category(category()) | |
| .type(type()) | |
| .user(user) | |
| .build(); | |
| } |
| public static PostResponseDTO from(Post post,List<String> skills, Integer currentCount) { | ||
| return new PostResponseDTO(post.getId(), | ||
| post.getImage(), | ||
| post.getTitle(), | ||
| post.getContent(), | ||
| post.getCategory().toString(), | ||
| skills, | ||
| post.getHeadCount(), | ||
| currentCount | ||
| ); | ||
| } |
There was a problem hiding this comment.
๐ ๏ธ Refactor suggestion
๋ฌธ๋ฒ ๋ฐ Enum ์ฒ๋ฆฌ ๊ฐ์ ํ์
- ๋ฉ์๋ ์ธ์ ์ฌ์ด์ ๊ณต๋ฐฑ์ด ๋๋ฝ๋์์ต๋๋ค (
Post post,List<String>โPost post, List<String>). - Enum ๊ฐ์ ์ฒ๋ฆฌํ ๋
toString()๋์name()์ ์ฌ์ฉํ๋ ๊ฒ์ด ์ข์ต๋๋ค.
๋ค์๊ณผ ๊ฐ์ด ์์ ํ๋ ๊ฒ์ ๊ถ์ฅํฉ๋๋ค:
- public static PostResponseDTO from(Post post,List<String> skills, Integer currentCount) {
+ public static PostResponseDTO from(Post post, List<String> skills, Integer currentCount) {
return new PostResponseDTO(post.getId(),
post.getImage(),
post.getTitle(),
post.getContent(),
- post.getCategory().toString(),
+ post.getCategory().name(),
skills,
post.getHeadCount(),
currentCount
);
}๐ Committable suggestion
โผ๏ธ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| public static PostResponseDTO from(Post post,List<String> skills, Integer currentCount) { | |
| return new PostResponseDTO(post.getId(), | |
| post.getImage(), | |
| post.getTitle(), | |
| post.getContent(), | |
| post.getCategory().toString(), | |
| skills, | |
| post.getHeadCount(), | |
| currentCount | |
| ); | |
| } | |
| public static PostResponseDTO from(Post post, List<String> skills, Integer currentCount) { | |
| return new PostResponseDTO(post.getId(), | |
| post.getImage(), | |
| post.getTitle(), | |
| post.getContent(), | |
| post.getCategory().name(), | |
| skills, | |
| post.getHeadCount(), | |
| currentCount | |
| ); | |
| } |
| // PostDetail ์กฐํ ์ ์ฆ์ ๋ก๋ฉ ์ง์ | ||
| //@EntityGraph(attributePaths = {"postSkills", "postSkills.skill"}) | ||
| @Query("SELECT DISTINCT p FROM Post p LEFT JOIN FETCH p.postSkills ps LEFT JOIN FETCH ps.skill WHERE p.id = :id") | ||
| Optional<Post> findByIdWithSkills(@Param("id") Long id); |
There was a problem hiding this comment.
๐ ๏ธ Refactor suggestion
ํ์ด์ง ์ฒ๋ฆฌ ๋ฐ ์ฃผ์ ๊ฐ์ ํ์
๊ฒ์๊ธ ์กฐํ ์ ํ์ด์ง ์ฒ๋ฆฌ๊ฐ ๊ตฌํ๋์ด ์์ง ์์ต๋๋ค. ๋ฐ์ดํฐ๊ฐ ๋ง์์ง ๊ฒฝ์ฐ ์ฑ๋ฅ ์ด์๊ฐ ๋ฐ์ํ ์ ์์ต๋๋ค.
๋ํ ๋ฉ์๋ ์ฃผ์์ ์ถ๊ฐํ์ฌ ๋ฉ์๋์ ๋ชฉ์ ๊ณผ ์ฌ์ฉ๋ฒ์ ๋ช ํํ ์ค๋ช ํ๋ ๊ฒ์ด ์ข์ต๋๋ค.
- // PostDetail ์กฐํ ์ ์ฆ์ ๋ก๋ฉ ์ง์
+ /**
+ * ํน์ ID์ ๊ฒ์๊ธ์ ์ฐ๊ด๋ ์คํฌ๊ณผ ํจ๊ป ์กฐํํฉ๋๋ค.
+ * JPQL์ LEFT JOIN FETCH๋ฅผ ์ฌ์ฉํ์ฌ N+1 ๋ฌธ์ ๋ฅผ ๋ฐฉ์งํฉ๋๋ค.
+ * @param id ์กฐํํ ๊ฒ์๊ธ ID
+ * @return ์คํฌ ์ ๋ณด๊ฐ ํฌํจ๋ ๊ฒ์๊ธ (Optional)
+ */
//@EntityGraph(attributePaths = {"postSkills", "postSkills.skill"})
@Query("SELECT DISTINCT p FROM Post p LEFT JOIN FETCH p.postSkills ps LEFT JOIN FETCH ps.skill WHERE p.id = :id")
Optional<Post> findByIdWithSkills(@Param("id") Long id);
+
+ /**
+ * ๋ชจ๋ ๊ฒ์๊ธ์ ํ์ด์งํ์ฌ ์กฐํํฉ๋๋ค.
+ * @param pageable ํ์ด์ง ์ ๋ณด
+ * @return ํ์ด์ง๋ ๊ฒ์๊ธ ๋ชฉ๋ก
+ */
+ @Query(value = "SELECT DISTINCT p FROM Post p",
+ countQuery = "SELECT COUNT(p) FROM Post p")
+ Page<Post> findAllWithPaging(Pageable pageable);๐ Committable suggestion
โผ๏ธ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| // PostDetail ์กฐํ ์ ์ฆ์ ๋ก๋ฉ ์ง์ | |
| //@EntityGraph(attributePaths = {"postSkills", "postSkills.skill"}) | |
| @Query("SELECT DISTINCT p FROM Post p LEFT JOIN FETCH p.postSkills ps LEFT JOIN FETCH ps.skill WHERE p.id = :id") | |
| Optional<Post> findByIdWithSkills(@Param("id") Long id); | |
| /** | |
| * ํน์ ID์ ๊ฒ์๊ธ์ ์ฐ๊ด๋ ์คํฌ๊ณผ ํจ๊ป ์กฐํํฉ๋๋ค. | |
| * JPQL์ LEFT JOIN FETCH๋ฅผ ์ฌ์ฉํ์ฌ N+1 ๋ฌธ์ ๋ฅผ ๋ฐฉ์งํฉ๋๋ค. | |
| * @param id ์กฐํํ ๊ฒ์๊ธ ID | |
| * @return ์คํฌ ์ ๋ณด๊ฐ ํฌํจ๋ ๊ฒ์๊ธ (Optional) | |
| */ | |
| //@EntityGraph(attributePaths = {"postSkills", "postSkills.skill"}) | |
| @Query("SELECT DISTINCT p FROM Post p LEFT JOIN FETCH p.postSkills ps LEFT JOIN FETCH ps.skill WHERE p.id = :id") | |
| Optional<Post> findByIdWithSkills(@Param("id") Long id); | |
| /** | |
| * ๋ชจ๋ ๊ฒ์๊ธ์ ํ์ด์งํ์ฌ ์กฐํํฉ๋๋ค. | |
| * @param pageable ํ์ด์ง ์ ๋ณด | |
| * @return ํ์ด์ง๋ ๊ฒ์๊ธ ๋ชฉ๋ก | |
| */ | |
| @Query(value = "SELECT DISTINCT p FROM Post p", | |
| countQuery = "SELECT COUNT(p) FROM Post p") | |
| Page<Post> findAllWithPaging(Pageable pageable); |
| package aibe.hosik.post.service; | ||
|
|
||
| import aibe.hosik.post.dto.MatchedUserDTO; | ||
| import aibe.hosik.post.dto.PostDetailDTO; | ||
| import aibe.hosik.post.dto.PostRequestDTO; | ||
| import aibe.hosik.post.dto.PostResponseDTO; | ||
| import aibe.hosik.post.entity.Post; | ||
| import aibe.hosik.post.repository.PostRepository; | ||
| import aibe.hosik.skill.repository.PostSkillRepository; | ||
| import aibe.hosik.skill.repository.SkillRepository; | ||
| import aibe.hosik.skill.entity.PostSkill; | ||
| import aibe.hosik.skill.entity.Skill; | ||
| import aibe.hosik.user.User; | ||
| import lombok.RequiredArgsConstructor; | ||
| import org.springframework.stereotype.Service; | ||
|
|
||
| import java.util.ArrayList; | ||
| import java.util.List; | ||
| import java.util.stream.Collectors; | ||
|
|
||
| @Service | ||
| @RequiredArgsConstructor | ||
| public class PostServiceImpl implements PostService { | ||
| private final PostRepository postRepository; | ||
| private final SkillRepository skillRepository; | ||
| private final PostSkillRepository postSkillRepository; | ||
|
|
There was a problem hiding this comment.
๐ ๏ธ Refactor suggestion
์ ์ฒด ํด๋์ค ๊ตฌ์กฐ์ ๋ํ ์ ์
์๋น์ค ํด๋์ค ์ ์ฒด์ ๋ํ ๋ช ๊ฐ์ง ๊ฐ์ ์ฌํญ์ ์ ์ํฉ๋๋ค:
- ๊ฐ ๋ฉ์๋์ ๋ช ํํ JavaDoc ์ฃผ์์ ์ถ๊ฐํ์ฌ ๋ฉ์๋์ ๋ชฉ์ , ๋งค๊ฐ๋ณ์, ๋ฐํ๊ฐ, ์์ธ ๋ฑ์ ๋ฌธ์ํํ์ธ์.
- ํด๋์ค ์์ค์์ ์์ธ ์ฒ๋ฆฌ ์ ๋ต์ ๊ตฌํํ๋ ๊ฒ์ด ์ข์ต๋๋ค (์: ์ฌ์ฉ์ ์ ์ ์์ธ ํด๋์ค ์ฌ์ฉ).
- ๋๋ฒ๊ทธ ๋ฐ ์ฑ๋ฅ ๋ชจ๋ํฐ๋ง์ ์ํ ๋ก๊น ์ ์ถ๊ฐํ์ธ์.
package aibe.hosik.post.service;
import aibe.hosik.post.dto.MatchedUserDTO;
import aibe.hosik.post.dto.PostDetailDTO;
import aibe.hosik.post.dto.PostRequestDTO;
import aibe.hosik.post.dto.PostResponseDTO;
import aibe.hosik.post.entity.Post;
import aibe.hosik.post.repository.PostRepository;
import aibe.hosik.skill.repository.PostSkillRepository;
import aibe.hosik.skill.repository.SkillRepository;
import aibe.hosik.skill.entity.PostSkill;
import aibe.hosik.skill.entity.Skill;
import aibe.hosik.user.User;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+import lombok.extern.slf4j.Slf4j;
+import java.util.NoSuchElementException;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
+/**
+ * ๊ฒ์๊ธ(Post) ๊ด๋ จ ๋น์ฆ๋์ค ๋ก์ง์ ์ฒ๋ฆฌํ๋ ์๋น์ค ๊ตฌํ ํด๋์ค์
๋๋ค.
+ * ๊ฒ์๊ธ ์กฐํ, ์์ฑ, ์์ธ ์กฐํ ๋ฑ์ ๊ธฐ๋ฅ์ ์ ๊ณตํฉ๋๋ค.
+ */
@Service
@RequiredArgsConstructor
+@Slf4j
public class PostServiceImpl implements PostService {
private final PostRepository postRepository;
private final SkillRepository skillRepository;
private final PostSkillRepository postSkillRepository;๐ Committable suggestion
โผ๏ธ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| package aibe.hosik.post.service; | |
| import aibe.hosik.post.dto.MatchedUserDTO; | |
| import aibe.hosik.post.dto.PostDetailDTO; | |
| import aibe.hosik.post.dto.PostRequestDTO; | |
| import aibe.hosik.post.dto.PostResponseDTO; | |
| import aibe.hosik.post.entity.Post; | |
| import aibe.hosik.post.repository.PostRepository; | |
| import aibe.hosik.skill.repository.PostSkillRepository; | |
| import aibe.hosik.skill.repository.SkillRepository; | |
| import aibe.hosik.skill.entity.PostSkill; | |
| import aibe.hosik.skill.entity.Skill; | |
| import aibe.hosik.user.User; | |
| import lombok.RequiredArgsConstructor; | |
| import org.springframework.stereotype.Service; | |
| import java.util.ArrayList; | |
| import java.util.List; | |
| import java.util.stream.Collectors; | |
| @Service | |
| @RequiredArgsConstructor | |
| public class PostServiceImpl implements PostService { | |
| private final PostRepository postRepository; | |
| private final SkillRepository skillRepository; | |
| private final PostSkillRepository postSkillRepository; | |
| package aibe.hosik.post.service; | |
| import aibe.hosik.post.dto.MatchedUserDTO; | |
| import aibe.hosik.post.dto.PostDetailDTO; | |
| import aibe.hosik.post.dto.PostRequestDTO; | |
| import aibe.hosik.post.dto.PostResponseDTO; | |
| import aibe.hosik.post.entity.Post; | |
| import aibe.hosik.post.repository.PostRepository; | |
| import aibe.hosik.skill.repository.PostSkillRepository; | |
| import aibe.hosik.skill.repository.SkillRepository; | |
| import aibe.hosik.skill.entity.PostSkill; | |
| import aibe.hosik.skill.entity.Skill; | |
| import aibe.hosik.user.User; | |
| import lombok.RequiredArgsConstructor; | |
| import org.springframework.stereotype.Service; | |
| +import org.springframework.transaction.annotation.Transactional; | |
| +import lombok.extern.slf4j.Slf4j; | |
| +import java.util.NoSuchElementException; | |
| import java.util.ArrayList; | |
| import java.util.List; | |
| import java.util.stream.Collectors; | |
| +/** | |
| + * ๊ฒ์๊ธ(Post) ๊ด๋ จ ๋น์ฆ๋์ค ๋ก์ง์ ์ฒ๋ฆฌํ๋ ์๋น์ค ๊ตฌํ ํด๋์ค์ ๋๋ค. | |
| + * ๊ฒ์๊ธ ์กฐํ, ์์ฑ, ์์ธ ์กฐํ ๋ฑ์ ๊ธฐ๋ฅ์ ์ ๊ณตํฉ๋๋ค. | |
| + */ | |
| @Service | |
| @RequiredArgsConstructor | |
| +@Slf4j | |
| public class PostServiceImpl implements PostService { | |
| private final PostRepository postRepository; | |
| private final SkillRepository skillRepository; | |
| private final PostSkillRepository postSkillRepository; | |
| // ... rest of the implementation | |
| } |
Entity ์์ฑ ๋ฐ ํด๋ ๊ตฌ์กฐ ์์ฑ
Summary by CodeRabbit
์ ๊ท ๊ธฐ๋ฅ
๊ฐ์ ๋ฐ ๋ณ๊ฒฝ
๋ฒ๊ทธ ์์