개인적으로 시작한 개발이며, 틀린 점이나 부족한 부분이 많을 수 있으니 보완할 사항이나 질문은 댓글로 남겨주세요!
Database : mysql community Server 8.0.23
language : Java 11
Framework : Spring
IDE : IntelliJ ultimate ver.
OS : MS Win10 64bit
지난 번 리포지토리까지 개발한 데에 이어 서비스를 개발했다.
리포지토리가 Entity와 연관된 작업만을 수행한다면, 서비스는 클라이언트로부터의 요청을 받아 Entity 작업의 전까지의 과정을 수행한다.
public interface PostService {
public Long post(Long memberId, Long categoryId, String title, String contents);
public Long updatePost(Long postId, Long categoryId, String title, String contents);
public Post findOne(Long postId);
public List<Post> findAll();
public List<Post> findByMember(Member member);
public List<Post> findByCategory(Category category);
public void deletePost(Long postId);
}
Post의 대표적인 CRUD 기능에 대한 메서드가 있는 인터페이스를 생성한다.
JpaRepository에서 제공하는 기능들에 대한 메서드는
단순히 서비스에서 리포지토리로 작업을 넘기는 것이기 때문에
직접 postRepository에 접근할 수 있지만
위와 같이 구성했다.
@Service
@Transactional(readOnly = true)
@RequiredArgsConstructor
public class PostServiceImpl implements PostService{
private final PostRepository postRepository;
private final MemberRepository memberRepository;
private final CategoryRepository categoryRepository;
@Override
@Transactional
public Long post(Long memberId, Long categoryId,
String title, String contents) {
Member member = memberRepository.getOne(memberId);
Category category = categoryRepository.getOne(categoryId);
Post post = new Post();
post.createPost(member, category, title, contents);
postRepository.save(post);
return post.getId();
}
@Override
@Transactional
public Long updatePost(Long postId, Long categoryId,
String title, String contents) {
Post post = postRepository.getOne(postId);
Category category = categoryRepository.getOne(categoryId);
post.setCategory(category);
post.setTitle(title);
post.setContents(contents);
post.setUpdateDate(LocalDateTime.now());
return post.getId();
}
@Override
@Transactional
public void deletePost(Long postId) {
Post post = postRepository.getOne(postId);
post.getCategory().getPosts()
.removeIf(targetPost -> targetPost.equals(post));
post.getMember().getPosts()
.removeIf(targetPost -> targetPost.equals(post));
postRepository.deleteById(postId);
}
@Override
public Post findOne(Long postId) {
return postRepository.getOne(postId);
}
@Override
public List<Post> findAll() {
return postRepository.findAll();
}
@Override
public List<Post> findByMember(Member member) {
return postRepository.findByMember(member);
}
@Override
public List<Post> findByCategory(Category category) {
return postRepository.findByCategory(category);
}
}
post 메소드에선
updatePost 메소드에서는 update 기능을 수행하는데,
deletePost 메소드에서는 delete 기능을 수행하고,
JPA delete가 되지 않는 문제
기존에 연관관계에 대한 부분을 막연히 JPA가 해결해줄 거라 생각해 아래와 같이 코드를 짰었는데
@Override
@Transactional
public void deletePost(Long postId) {
postRepository.deleteById(postId);
}
테스트 결과 삭제가 되지 않는 문제가 발생했다.
stack overflow에서도 비슷한 문제가 있는 개발자가 있던 모양인데, 명확한 해답을 찾지 못했다.
다른 팀원이 작성한 Member에 대해 삭제를 진행해봤을 때
문제 없이 잘 되는 걸 보고 차이점을 생각하다 연관관계에 대한 문제인가 싶어
Member와 Category의 리스트에서 해당 포스트를 지워주는 로직을 추가해봤다.
@Override
@Transactional
public void deletePost(Long postId) {
Post post = postRepository.getOne(postId);
post.getCategory().getPosts()
.removeIf(targetPost -> targetPost.equals(post));
post.getMember().getPosts()
.removeIf(targetPost -> targetPost.equals(post));
postRepository.deleteById(postId);
}
그 결과 삭제 로직이 정상적으로 작동했다.
이 부분이 왜 그런지는 조금 더 공부해봐야할 것 같은데,
삭제 로직을 구현할 때에는 연관관계에 대해서 꼭 다시 살펴봐야 할 것 같다.
@SpringBootTest
@Transactional
public class PostServiceTest {
@Autowired
PostService postService;
@Autowired
PostRepository postRepository;
@Autowired
MemberRepository memberRepository;
@Autowired
CategoryRepository categoryRepository;
@Autowired
EntityManager em;
@Test
public void 포스트() throws Exception {
// given
Member member = new Member();
Category category = new Category();
member.setUsername("dd");
member.setPassword("dddd");
memberRepository.save(member);
category.setName("Anony");
categoryRepository.save(category);
Long memberId = member.getId();
Long categoryId = category.getId();
// when
Long post = postService.post(memberId, categoryId, "test", "this is test");
// then
assertThat(post).isNotNull();
}
@Test
public void 아이디로찾기() throws Exception {
// given
Member member = new Member();
Category category = new Category();
member.setUsername("dd");
member.setPassword("dddd");
memberRepository.save(member);
category.setName("Anony");
categoryRepository.save(category);
Long memberId = member.getId();
Long categoryId = category.getId();
Long postId = postService.post(memberId, categoryId, "test", "this is test");
// when
Post findPost = postService.findOne(postId);
// then
assertThat(findPost.getId()).isEqualTo(postId);
assertThat(findPost.getMember().getId()).isEqualTo(memberId);
assertThat(findPost.getCategory().getId()).isEqualTo(categoryId);
assertThat(findPost.getTitle()).isEqualTo("test");
assertThat(findPost.getContents()).isEqualTo("this is test");
}
@Test
public void 멤버로찾기() throws Exception {
// given
Member member = new Member();
Category category = new Category();
member.setUsername("dd");
member.setPassword("dddd");
memberRepository.save(member);
category.setName("Anony");
categoryRepository.save(category);
Long memberId = member.getId();
Long categoryId = category.getId();
// when
postService.post(memberId, categoryId, "test", "this is test");
postService.post(memberId,categoryId,"test2","this is 2nd test");
Member findMember = memberRepository.getOne(memberId);
List<Post> posts = postService.findByMember(findMember);
// then
assertThat(posts.size()).isEqualTo(2);
for (Post post: posts){
System.out.println("post.getTitle() = " + post.getTitle());
assertThat(post.getMember().getId()).isEqualTo(memberId);
}
}
@Test
public void 모두찾기() throws Exception {
// given
Member member = new Member();
Category category = new Category();
member.setUsername("dd");
member.setPassword("dddd");
memberRepository.save(member);
category.setName("Anony");
categoryRepository.save(category);
Long memberId = member.getId();
Long categoryId = category.getId();
// when
postService.post(memberId, categoryId, "test", "this is test");
postService.post(memberId,categoryId,"test2","this is 2nd test");
postService.post(memberId, categoryId, "test3", "this is 3nd test");
List<Post> all = postService.findAll();
// then
assertThat(all.size()).isEqualTo(3);
}
@Test
public void 카테고리로찾기() throws Exception {
Member member = new Member();
Category category = new Category();
member.setUsername("dd");
member.setPassword("dddd");
memberRepository.save(member);
category.setName("Anony");
categoryRepository.save(category);
Long memberId = member.getId();
Long categoryId = category.getId();
// when
postService.post(memberId, categoryId, "test", "this is test");
postService.post(memberId,categoryId,"test2","this is 2nd test");
postService.post(memberId, categoryId, "test3", "this is 3nd test");
Category findCategory = categoryRepository.getOne(categoryId);
List<Post> byCategory = postService.findByCategory(findCategory);
// then
assertThat(byCategory.size()).isEqualTo(3);
}
@Test
public void 업데이트() throws Exception {
// given
Member member = new Member();
Category category1 = new Category();
Category category2 = new Category();
member.setUsername("dd");
member.setPassword("dddd");
memberRepository.save(member);
category1.setName("Anony");
category2.setName("Anony2");
categoryRepository.save(category1);
categoryRepository.save(category2);
Long memberId = member.getId();
Long categoryId = category1.getId();
Long category2Id = category2.getId();
// when
Long postId = postService.post(memberId, categoryId, "test", "this is test");
Long updated = postService.updatePost(postId, category2Id, "test2", "this is updated test");
// then
assertThat(postId).isEqualTo(updated);
assertThat(postService.findOne(updated).getCategory().getId()).isEqualTo(category2Id);
assertThat(postService.findOne(updated).getCategory()).isEqualTo(category2);
assertThat(postService.findOne(updated).getTitle()).isEqualTo("test2");
assertThat(postService.findOne(updated).getContents()).isEqualTo("this is updated test");
}
@Test
public void 삭제() throws Exception {
// given
Member member = new Member();
member.setUsername("p");
member.setPassword("d");
memberRepository.save(member);
Category category = new Category();
category.setName("dd");
categoryRepository.save(category);
Long postId = postService.post(member.getId(), category.getId(), "title", "contents");
List<Post> before = postService.findAll();
System.out.println("before = " + before);
// when
postService.deletePost(postId);
List<Post> after = postService.findAll();
System.out.println("after = " + after);
// then
assertThat(after.size()).isEqualTo(before.size()-1);
}
모든 테스트가 잘 통과하는 걸 확인할 수 있다.
테스트 코드의 메소드 이름이 한글로 되어 있어 깨지는 경우가 발생할 수 있는데,
Help -> Edit Custom VM Options..
-Dfile.encoding=UTF-8 을 추가
IntelliJ를 다시 실행하면 한글이 깨지지 않고 잘 보인다.