2일차에는 기능과 ERD, API명세서등을 마저 기획하였다.
3일차부터는 기능들을 구현하게 되었는데, 엔티티 기준으로 역할을 나누게 되었다.
댓글, 좋아요, 게시물, 쓰레드 등이 있었는데, 나는 그 중에서 게시물을 맡게 되었다.
게시물의 기능은 일단 CRUD랑.. 페이징 조회도 R에 해당하는건가.
다음과 같이 구현했다.
주석들은 생각해 볼 것들로, 블로그 작성하면서 덧붙인 것이다.
Entity
@Entity
@Getter
@NoArgsConstructor
public class Post extends BaseEntity {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "account_id")
private Account account;
@Column(nullable = false)
private String title;
@Column
private String image;
// 이미지는 Multipart를 쓸 예정
@Column(nullable = false)
private String content;
@Builder
public Post(Account account, String title, String content) {
this.account = account;
this.title = title;
this.content = content;
}
public void modifyPost(PostRequestDto postRequestDto) {
this.title = postRequestDto.getTitle();
this.content = postRequestDto.getContent();
}
}
// Builder와 Constructor의 차이점
Controller
@RestController
@RequiredArgsConstructor
@RequestMapping("/api/posts")
public class PostController {
private final PostService postService;
@PostMapping
public ResponseEntity<PostResponseDto> newPost(@RequestBody PostRequestDto postRequestDto,
@AuthenticationPrincipal MemberDetails memberDetails) {
return ResponseEntity.status(200).body(postService.newPost(postRequestDto, memberDetails));
}
@GetMapping("/page={pageChoice}")
public List<PostResponseDto> getPosts(@PathVariable int pageChoice) {
return postService.getPosts(pageChoice);
}
@GetMapping("/{postId}")
public ResponseEntity<PostResponseDto> getPost(@PathVariable Long postId) {
return ResponseEntity.status(200).body(postService.getPost(postId));
}
@PutMapping("/{postId}")
public ResponseEntity<PostResponseDto> modifyPost(@PathVariable Long postId,
@RequestBody PostRequestDto postRequestDto,
@AuthenticationPrincipal MemberDetails memberDetails) {
return ResponseEntity.status(200)
.body(postService.modifyPost(postId, postRequestDto, memberDetails));
}
@DeleteMapping("/{postId}")
public ResponseEntity<String> deletePost(@PathVariable Long postId,
@AuthenticationPrincipal MemberDetails memberDetails) {
postService.deletePost(postId, memberDetails);
return ResponseEntity.status(200).body("삭제 완료");
}
}
Service
public interface PostService {
PostResponseDto getPost(Long postId);
List<PostResponseDto> getPosts(int pageChoice);
PostResponseDto newPost(PostRequestDto postRequestDto, MemberDetails memberDetails);
PostResponseDto modifyPost(Long postId, PostRequestDto postRequestDto,
MemberDetails memberDetails);
void deletePost(Long postId, MemberDetails memberDetails);
}
// interface를 사용하는 이유
// 개발 표준화
// 다형성 지원
// 유연성
// 런타임 개선
// 객체 구조 개선
@Service
@RequiredArgsConstructor
public class PostServiceImpl implements PostService {
private final PostRepository postRepository;
@Override
@Transactional
public PostResponseDto newPost(PostRequestDto postRequestDto, MemberDetails memberDetails) {
Post post = Post.builder()
.account(memberDetails.getMember())
.title(postRequestDto.getTitle())
.content(postRequestDto.getContent())
.build();
postRepository.save(post);
return new PostResponseDto(post);
}
@Override
@Transactional
public List<PostResponseDto> getPosts(int pageChoice) {
Page<Post> posts = postRepository.findAll(pageableSetting(pageChoice));
if (posts.isEmpty()) {
throw new CustomException(ExceptionStatus.POST_IS_NOT_EXIST);
}
List<PostResponseDto> PostResponseDtoList = posts.stream().map(PostResponseDto::new).collect(
Collectors.toList());
return PostResponseDtoList;
}
private Pageable pageableSetting(int pageChoice) {
Sort.Direction direction = Sort.Direction.DESC;
Sort sort = Sort.by(direction, "id");
Pageable pageable = PageRequest.of(pageChoice - 1, 4, sort);
return pageable;
}
// 페이징을 하는 방법은 여러가지
@Override
@Transactional
public PostResponseDto getPost(Long postId) {
Post post = postRepository.findById(postId).orElseThrow(
() -> new CustomException(ExceptionStatus.POST_IS_NOT_EXIST)
);
return new PostResponseDto(post);
}
@Override
@Transactional
public PostResponseDto modifyPost(Long postId, PostRequestDto postRequestDto,
MemberDetails memberDetails) {
Post post = postRepository.findById(postId).orElseThrow(
() -> new CustomException(ExceptionStatus.POST_IS_NOT_EXIST)
);
post.modifyPost(postRequestDto);
postRepository.save(post);
return new PostResponseDto(post);
}
@Override
@Transactional
public void deletePost(Long postId, MemberDetails memberDetails) {
Post post = postRepository.findById(postId).orElseThrow(
() -> new CustomException(ExceptionStatus.POST_IS_NOT_EXIST)
);
postRepository.delete(post);
}
}
Dto
@Getter
public class PostRequestDto {
private final String title;
private final String content;
public PostRequestDto(String title, String content) {
this.title = title;
this.content = content;
}
// private final 필드는 객체가 생성된 후에도 값이 변경되지 않기 때문에
// private final 필드를 갖는 경우, 해당 필드는 생성자에서 초기화하여야 한다.
}
@Getter
public class PostResponseDto {
private final Long postId;
private final String title;
private final String nickname;
private final String image;
private final String content;
private final LocalDateTime createDate;
private final LocalDateTime modifiedDate;
public PostResponseDto(Post post) {
this.postId = post.getId();
this.nickname = post.getAccount().getNickname();
this.title = post.getTitle();
this.image = post.getImage();
this.content = post.getContent();
this.createDate = post.getCreateDate();
this.modifiedDate = post.getModDate();
}
}
Repository
public interface PostRepository extends JpaRepository<Post, Long> {
@Override
Page<Post> findAll(Pageable pageable);
}
'개발일지 > 일간회고 (TIL)' 카테고리의 다른 글
CI / CD란 (0) | 2023.02.27 |
---|---|
20230220 (0) | 2023.02.21 |
최종 프로젝트 시작 - 1일차 (0) | 2023.02.06 |
devtools에 대해 (0) | 2023.02.04 |
정적, 동적 메서드란? (0) | 2023.02.04 |