Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[14주차] 임현우 학습 PR 제출합니다. #2

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
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
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
package com.example.jpa.comment.controller;

import com.example.jpa.comment.dto.request.CommentCreateRequest;
import com.example.jpa.comment.dto.request.CommentUpdateRequest;
import com.example.jpa.comment.dto.response.CommentResponse;
import com.example.jpa.comment.service.CommentService;
import lombok.RequiredArgsConstructor;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;

import java.util.List;

@RestController
@RequestMapping("api/comments")
@RequiredArgsConstructor
public class CommentController {

private final CommentService commentService;

@PostMapping
public ResponseEntity<Void> create(@RequestBody CommentCreateRequest commentCreateRequest) {

commentService.create(commentCreateRequest);

return ResponseEntity.ok().build();
}

@GetMapping("/{id}")
public ResponseEntity<CommentResponse> findOne(@PathVariable("id") Long id) {

CommentResponse commentResponse = commentService.findOne(id);

return ResponseEntity.ok(commentResponse);
}

@PatchMapping("/{id}")
public ResponseEntity<Void> update(@PathVariable("id") Long id, @RequestBody CommentUpdateRequest commentUpdateRequest) {

commentService.update(id, commentUpdateRequest);

return ResponseEntity.ok().build();
}

@DeleteMapping("/{id}")
public ResponseEntity<Void> delete(@PathVariable("id") Long id) {

commentService.delete(id);

return ResponseEntity.ok().build();
}

@GetMapping
public ResponseEntity<List> findAll() {

List<CommentResponse> commentResponses = commentService.findAll();

return ResponseEntity.ok(commentResponses);
}
}
44 changes: 44 additions & 0 deletions src/main/java/com/example/jpa/comment/domain/Comment.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
package com.example.jpa.comment.domain;

import com.example.jpa.member.domain.Member;
import com.example.jpa.post.domain.Post;
import jakarta.persistence.*;
import lombok.AccessLevel;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;

@Entity
@Getter
@NoArgsConstructor(access = AccessLevel.PROTECTED)
public class Comment {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;

@ManyToOne
@JoinColumn(name = "member")
private Member member;

@ManyToOne
@JoinColumn(name = "post")
private Post post;

private String content;

@Builder
public Comment(Member member, Post post, String content) {
this.member = member;
this.post = post;
this.content = content;
}

public Comment(Member member, String content) {
this.member = member;
this.content = content;
}

public void update(String content) {
this.content = content;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package com.example.jpa.comment.dto.request;

import com.example.jpa.comment.domain.Comment;
import com.example.jpa.member.domain.Member;
import com.example.jpa.post.domain.Post;
import lombok.Getter;

@Getter
public class CommentCreateRequest {

private Long member;
private Long post;
private String content;
Comment on lines +11 to +13
Copy link
Member

Choose a reason for hiding this comment

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

제약조건 걸어주기! 당장 member필드 post필드 content필드에 null이라 빈 값이 들어올 경우도 생각해주세요.
NotNull, NotEmpty, NotBlank의 차이점에 대해 공부해보면 좋습니다!


public Comment toEntity(Member member, Post post) {
return Comment.builder()
.member(member)
.post(post)
.content(this.content)
.build();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package com.example.jpa.comment.dto.request;

import lombok.Getter;

@Getter
public class CommentUpdateRequest {

private String content;

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package com.example.jpa.comment.dto.response;

import com.example.jpa.comment.domain.Comment;
import lombok.Getter;

@Getter
public class CommentResponse {

private Long id;
private String content;

public CommentResponse(Long id, String content) {
this.id = id;
this.content = content;
}

public static CommentResponse from(Comment comment) {
return new CommentResponse(comment.getId(), comment.getContent());
}
}
61 changes: 61 additions & 0 deletions src/main/java/com/example/jpa/comment/service/CommentService.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
package com.example.jpa.comment.service;

import com.example.jpa.comment.domain.Comment;
import com.example.jpa.comment.dto.request.CommentCreateRequest;
import com.example.jpa.comment.dto.request.CommentUpdateRequest;
import com.example.jpa.comment.dto.response.CommentResponse;
import com.example.jpa.member.domain.Member;
import com.example.jpa.post.domain.Post;
import com.example.jpa.repository.CommentRepository;
import com.example.jpa.repository.MemberRepository;
import com.example.jpa.repository.PostRepository;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;
import java.util.NoSuchElementException;
import java.util.stream.Collectors;

@Service
@RequiredArgsConstructor
public class CommentService {

private final CommentRepository commentRepository;
private final MemberRepository memberRepository;
private final PostRepository postRepository;

@Transactional
public void create(CommentCreateRequest commentCreateRequest) {
Member member = memberRepository.findById(commentCreateRequest.getMember()).get();
Post post = postRepository.findById(commentCreateRequest.getPost()).get();
commentRepository.save(commentCreateRequest.toEntity(member, post));
}

@Transactional(readOnly = true)
public CommentResponse findOne(Long id) {
Comment comment = commentRepository.findById(id)
.orElseThrow(() -> new NoSuchElementException("댓글이 존재하지 않습니다."));

return CommentResponse.from(comment);
}

@Transactional
public void update(Long id, CommentUpdateRequest commentUpdateRequest) {
Comment comment = commentRepository.findById(id)
.orElseThrow(() -> new NoSuchElementException("댓글이 존재하지 않습니다."));
comment.update(commentUpdateRequest.getContent());
}

@Transactional
public void delete(Long id) {
commentRepository.deleteById(id);
}

@Transactional(readOnly = true)
public List<CommentResponse> findAll() {
return commentRepository.findAll().stream()
.map(CommentResponse::from)
.collect(Collectors.toList());
}
}
Original file line number Diff line number Diff line change
@@ -1,17 +1,15 @@
package com.example.jpa.member.controller;

import com.example.jpa.member.dto.request.MemberCreateRequest;
import com.example.jpa.member.dto.request.MemberUpdateRequest;
import com.example.jpa.member.dto.response.MemberResponse;
import com.example.jpa.member.service.MemberService;
import lombok.RequiredArgsConstructor;

import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.bind.annotation.*;

import java.util.List;

@RestController
@RequestMapping("api/members")
Expand All @@ -35,4 +33,28 @@ public ResponseEntity<MemberResponse> findOne(@PathVariable("id") Long id) {

return ResponseEntity.ok(memberResponse);
}

@PatchMapping("/{id}")
public ResponseEntity<Void> update(@PathVariable("id") Long id, @RequestBody MemberUpdateRequest memberUpdateRequest) {

memberService.update(id, memberUpdateRequest);

return ResponseEntity.ok().build();
}

@DeleteMapping("/{id}")
public ResponseEntity<Void> delete(@PathVariable("id") Long id) {

memberService.delete(id);

return ResponseEntity.ok().build();
}

@GetMapping
public ResponseEntity<List> findAll() {

List<MemberResponse> memberResponses = memberService.findAll();

return ResponseEntity.ok(memberResponses);
}
}
18 changes: 13 additions & 5 deletions src/main/java/com/example/jpa/member/domain/Member.java
Original file line number Diff line number Diff line change
@@ -1,14 +1,16 @@
package com.example.jpa.member.domain;

import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import com.example.jpa.comment.domain.Comment;
import com.example.jpa.post.domain.Post;
import jakarta.persistence.*;
import lombok.AccessLevel;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;

import java.util.ArrayList;
import java.util.List;

@Entity
@Getter
@NoArgsConstructor(access = AccessLevel.PROTECTED)
Expand All @@ -20,12 +22,18 @@ public class Member {

private String name;

@OneToMany(mappedBy = "member", cascade = CascadeType.ALL, orphanRemoval = true)
private List<Post> posts = new ArrayList<>();

@OneToMany(mappedBy = "member", cascade = CascadeType.ALL, orphanRemoval = true)
Copy link
Member

Choose a reason for hiding this comment

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

CascadeType.DELETE와 orphanRemoval 차이에 대해서도 학습하시면 좋을 것 같아요!

private List<Comment> comments = new ArrayList<>();

Comment on lines +25 to +30
Copy link
Member

Choose a reason for hiding this comment

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

간단한 토이프로젝트라서 큰 상관은 없지만 양방향 매핑은 지양하는게 좋습니다!
왜 양방향 매핑을 지양해야 할까요? 특히 Jpa엔티티와 도메인이 같은 객체일 경우에는 일어날 수 있는 문제점이 정말 많습니다.
객체간 순환참조가 될 뿐만 아니라, 조금만 도메인이 많아져도 양방향 지옥에 빠져 어려움을 겪을 확률이 너무너무 큽니다... 관리도 안될 뿐더러 의도치 않는 쿼리가 나갈 수도 있고요.
정말 두 객체가 서로 알고 있어야하는지 고민해볼 필요가 있을 것 같아요.

@Builder
public Member(String name) {
this.name = name;
}

void update(String name) {
public void update(String name) {
this.name = name;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package com.example.jpa.member.dto.request;

import lombok.Getter;

@Getter
public class MemberUpdateRequest {

private String name;

}
23 changes: 22 additions & 1 deletion src/main/java/com/example/jpa/member/service/MemberService.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,14 @@

import com.example.jpa.member.domain.Member;
import com.example.jpa.member.dto.request.MemberCreateRequest;
import com.example.jpa.member.dto.request.MemberUpdateRequest;
import com.example.jpa.member.dto.response.MemberResponse;
import com.example.jpa.repository.MemberRepository;

import java.util.List;
import java.util.NoSuchElementException;
import java.util.Optional;
import java.util.stream.Collectors;

import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
Expand All @@ -29,5 +33,22 @@ public MemberResponse findOne(Long id) {
return MemberResponse.from(member);
}

@Transactional
public void update(Long id, MemberUpdateRequest memberUpdateRequest) {
Member member = memberRepository.findById(id)
.orElseThrow(() -> new NoSuchElementException("게시글이 존재하지 않습니다."));
member.update(memberUpdateRequest.getName());
}

@Transactional
public void delete(Long id) {
memberRepository.deleteById(id);
}

@Transactional(readOnly = true)
public List<MemberResponse> findAll() {
return memberRepository.findAll().stream()
.map(MemberResponse::from)
.collect(Collectors.toList());
}
}
Loading