3주차 스터디입니다.
이번 주는 게시판 CRUD를 만드는 것이 목표였습니다.
Service, Repository, DTO, Entity, Controller로 구성이 되어 있습니다.
Controller
- 사용자의 요청이 진입하는 곳
- 사용자의 요청을 처리하는 곳
- 처리 후 서비스로 넘어갑니다.
service
- repository와 controller 사이 미들웨어
- controller에서 받은 데이터를 가공해서 DB를 보내거나 DB에서 가져온 데이터를 가공해서 사용자에게 보내줍니다.
- 사용자의 요구사항을 처리하는 곳 (비즈니스 로직)
repository
- 간단히 말하면 CRUD를 처리하는 클래스입니다.
dto
- Data Transfer Object
- 데이터의 저장을 담당합니다.
- 계층간에 데이터를 교환할 때 주로 사용합니다.
Entity
- DB에 접근하는 객체
Post Entity입니다. 이전과 동일하나, created_at과 updated_at을 추가하여 날짜를 확인할 수 있도록 했습니다.
추가로, CRUD에서 Update에 대응하는 메소드를 추가했습니다.
package com.example.gdsctuk.entity;
import jakarta.persistence.*;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;
import org.hibernate.annotations.CreationTimestamp;
import org.hibernate.annotations.UpdateTimestamp;
import java.time.LocalDateTime;
import java.util.List;
@Entity
@Table
@NoArgsConstructor
@Getter
public class Post {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long postId;
@Column(columnDefinition = "TEXT")
private String title;
@Column(columnDefinition = "TEXT")
private String content;
@Column
private String postWriter;
@Column
private String postPasswd;
@CreationTimestamp // INSERT 시 자동으로 값을 채워줌
@Column(name = "created_at")
private LocalDateTime createdAt;
@Column(name = "updated_at")
@UpdateTimestamp // UPDATE 시 자동으로 값을 채워줌
private LocalDateTime updatedAt;
@OneToMany(mappedBy = "post")
private List<Comment> comments;
@Builder
public Post(Long postId, String title, String content, String postWriter, String postPasswd ) {
this.postId = postId;
this.title = title;
this.content = content;
this.postWriter = postWriter;
this.postPasswd = postPasswd;
this.createdAt = LocalDateTime.now();
this.updatedAt = LocalDateTime.now();
}
public void update(String title, String content) {
this.title = title;
this.content = content;
this.updatedAt = LocalDateTime.now();
}
}
package com.example.gdsctuk.repository;
import com.example.gdsctuk.entity.Post;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
@Repository
public interface PostRepository extends JpaRepository<Post, Long> {
}
PostRequest.java
package com.example.gdsctuk.dto;
import lombok.*;
import com.example.gdsctuk.entity.Post;
@Getter
@ToString
@NoArgsConstructor
@AllArgsConstructor
public class PostRequest {
private String title;
private String content;
private String postWriter;
private String postPasswd;
public Post toEntity() {
return Post.builder()
.title(title)
.content(content)
.postWriter(postWriter)
.postPasswd(postPasswd)
.build();
}
}
PostResponse.java
package com.example.gdsctuk.dto;
import com.example.gdsctuk.entity.Post;
import lombok.*;
@Getter
@ToString
@NoArgsConstructor
public class PostResponse {
private Long postId;
private String title;
private String content;
private String postWriter;
private String postPasswd;
public PostResponse(Post post) {
this.postId = post.getPostId();
this.title = post.getTitle();
this.content = post.getContent();
this.postWriter = post.getPostWriter();
this.postPasswd = post.getPostPasswd();
}
}
중간에서 데이터를 전송해주는 계층인 DTO 계층의 코드입니다.
PostRequest는 포스트와 관련된 정보를 받아 toEntity 메소드를 통해 전달합니다. (DTO to Entity)
PostResponse는 받아온 정보들을 Entity의 정보를 DTO로 매핑합니다. (Entity to DTO)
package com.example.gdsctuk.controller;
import com.example.gdsctuk.dto.PostResponse;
import com.example.gdsctuk.dto.PostRequest;
import com.example.gdsctuk.entity.Post;
import com.example.gdsctuk.service.PostService;
import org.springframework.web.bind.annotation.*;
import java.util.List;
@RestController
@RequestMapping("/post")
public class PostController {
private final PostService postService;
public PostController(PostService postService) {
this.postService = postService;
}
@GetMapping("/{id}")
public PostResponse getPostById(@PathVariable Long id) {
return postService.getPostById(id);
}
@PostMapping
public Post createPost(@RequestBody PostRequest post) {
return postService.createPost(post);
}
@PutMapping("/{id}")
public Post updatePost(@PathVariable Long id, @RequestBody PostRequest updatedPost) {
return postService.updatePost(id, updatedPost);
}
@DeleteMapping("/{id}")
public void deletePost(@PathVariable Long id) {
postService.deletePost(id);
}
}
getPostById 메소드는 Id 번호에 맞는 포스트를 찾습니다.
createPost 메소드는 새로운 포스트를 생성합니다.
updatePost 메소드는 이전에 작성한 포스트를 수정할 수 있습니다.
deletePost 메소드는 Id 번호에 맞는 포스트를 삭제합니다.
package com.example.gdsctuk.service;
import com.example.gdsctuk.repository.PostRepository;
import com.example.gdsctuk.dto.PostRequest;
import com.example.gdsctuk.dto.PostResponse;
import com.example.gdsctuk.entity.Post;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.List;
@Service
@Transactional(readOnly = true)
public class PostService {
private final PostRepository postRepository;
public PostService(PostRepository postRepository) {
this.postRepository = postRepository;
}
@Transactional
public List<Post> getAllPost() {
return postRepository.findAll();
}
@Transactional
public PostResponse getPostById(Long id) {
Post post = postRepository.findById(id)
.orElseThrow(() -> new IllegalArgumentException("잘못된 Post ID 입니다."));
return new PostResponse(post);
}
@Transactional
public Post createPost(PostRequest post) {
return postRepository.save(post.toEntity());
}
@Transactional
public Post updatePost(Long id, PostRequest updatedPost) {
Post post = postRepository.findById(id).orElseThrow(() -> new IllegalArgumentException("잘못된 Post ID 입니다."));
post.update(updatedPost.getTitle(), post.getContent());
return postRepository.save(post);
}
@Transactional
public void deletePost(Long id) {
postRepository.deleteById(id);
}
getAllPost()와 getPostById() 메소드는 단일 포스트, 혹은 포스트 전체의 목록을 가져오는 메소드입니다.
createPost는 post를 받아와서, Repository 쪽으로 넘겨 db에 저장을 할 수 있도록 합니다.
updatePost는 findById를 통해 받아온 포스트의 내용을 수정합니다.
그 후 다시 저장합니다.
deletePost는 말 그대로 포스트 자체를 삭제합니다.
-> 현재는 Soft delete가 아닌 Hard delete로 구현이 되어있어, 이 부분에 대한 변경이 필요합니다.
Postman도 좋은데, 최근 Hoppscotch라는 툴을 알게 되어 테스트해보았습니다.
포스트의 생성 결과입니다.
포스트의 조회 결과입니다.
포스트의 수정 결과입니다.
포스트의 삭제 결과입니다.