Spring 게시판 4- 게시글 CRUD

춤인형의 개발일지·2025년 1월 1일

Spring실습

목록 보기
5/40

24/12/30(월)

게시판 만들기

게시글 만들기 CRUD

게시판과 게시글의 관계
게시판과 게시글은 1:N관계이다.
게시판이 없는 게시글은 없다. 따라서 게시글을 생성할때 게시판 id가 있어야만 만들 수 있다.

1. DTO설계

  • Request
public record PostRequest(
        String content,
        String title,
        String createdAt
) {

}
  • Response
public record PostResponse(
        String title,
        String content,
        Long id,
        String createdAt) {
}

2. API설계 가지고 controller 작성
에러가 나든말든 일단, 작성하고 그 다음 함수들을 service에 생성해준다.

@RestController
public class PostController {

    private PostService postService;

    public PostController(PostService postService) {
        this.postService = postService;
    }

    //생성
    @PostMapping("/posts")
    public PostResponse createPost(@RequestBody PostRequest postRequest){
        return postService.create(postRequest);
    }

    //조회
    @GetMapping("/posts/{postId}")
    public PostResponse getPost(@PathVariable Long postId){
        return postService.getPostId(postId);
    }

    //수정
    @PutMapping("/posts/{postId}")
    public PostResponse putPost(@PathVariable Long postId, @RequestBody PostRequest postRequest){
        return postService.updatePost(postId,postRequest);
    }

    //삭제
    @DeleteMapping("/posts/{postId}")
    public void deletePost(@PathVariable Long postId){
        postService.deletePost(postId);
    }
}

3. controller의 service함수 작성

@Service
public class PostService {
    private PostRepository postRepository;

    public PostService(PostRepository postRepository) {
        this.postRepository = postRepository;
    }

Respository는 service에서 사용한다. 따라서 Respository를 먼저 만들어준다.

public interface PostRepository extends JpaRepository<Post, Long> {

그리고 Service에서 사용할 Entity도 만들어준다.

@Entity
public class Post {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    private String content;
    private String title;

    public Post() {
    }

    public Post(String content, String title){
        this.content = content;
        this.title = title;
    }

    public Long getId() {
        return id;
    }

    public String getContent() {
        return content;
    }

    public String getTitle() {
        return title;
    }

    public void setContent(String content) {
        this.content = content;
    }

    public void setTitle(String title) {
        this.title = title;
    }
}

❗Entity의 중요한 요소
1. id설정
2. 관계 설정
3. 기본 생성자
4. id값을 뺀 생성자 - Entity속 id값은 노출되어서는 안된다.
5. 전체 getter
5가지를 설정해놓아야 한다.
그리고 Service의 함수를 만들어준다.

//service
    public PostResponse create(PostRequest postRequest) {
        Post post = postRepository.save(new Post(postRequest.title(), postRequest.content()));
        return new PostResponse(post.getTitle(), post.getContent(), post.getId());
    }

    //조회
    public PostResponse getPostId(Long postId) {
        Post post = postRepository.findById(postId).orElseThrow();
        return new PostResponse(post.getTitle(), post.getContent(), postId);
    }


    @Transactional
    public PostResponse updatePost(Long postId, PostRequest postRequest) {
        Post post = postRepository.findById(postId).orElseThrow();
        post.setTitle(postRequest.title());
        post.setContent(postRequest.content());
        return new PostResponse(post.getTitle(), post.getContent(), postId);
    }

    public void deletePost(Long postId) {
        Post post = postRepository.findById(postId).orElseThrow();
        postRepository.delete(post);
    }
}
  • Service에서 한번 더 봐야할 것 - 수정
    먼저 수정을 요청한 id값을 먼저 찾는다.
 Post post = postRepository.findById(postId).orElseThrow();

그리고 수정을 하기 위해선 setter를 써야한다. setter함수는 Entitiy에 들어있다. Entity에서 setter를 설정해 준 후 set함수를 써서 변경해준다.

post.setTitle(postRequest.title());
        post.setContent(postRequest.content());

마지막에 반환만 하면 된다.

❗ @Transactional

  • 수행되어야 모든 것들을 모아놓은 것이다. 수행할 일들을 모두 처리하지 못 한 경우에는 원 상태로 복구한다. 즉, 작업의 일부만 적용되는 현상이 발생하지 않는다.
  • 수정이 제대로 변경되려면 트렌젝션을 붙여야한다.
  • ex) 송금:
    나는 엄마한테 송금을 했는데, 중간에 끊겨버리면 내 돈은 날라가버리고, 엄마는 돈을 못받는 경우가 생긴다. 이런 경우를 방지하기 위해 트렌젝션을 붙여준다. 그러면 중간에 끊겼을때 다시 원상태로 돌아가기 떄문에 내 돈이 다시 내 통장으로 돌아오게 된다.

관계 맺기

앞서 이야기 했듯이 1:N관계를 맺어야한다.
Entity에서 관계를 맺어주는데, N에 @ManyToOne을 붙여주면된다.

   @ManyToOne
    //게시글은 하나의 게시판에 온다
    private Board board;

원래 Entity는 DB에 칼럼을 정의한다. DB는 String, int 이런 bigint들은 알기 때문에 뭔가를 해주지 않아도 알아서 들어가는데, board는 칼럼이 처음보기 때문에 칼럼에 넣어주지 않는다. 따라서 @를 붙여 이건 칼럼이 아니라, 내가 관계를 매핑한거야~ 라고 알려주는 것이다.


관계 맺은 게시글 만들기

관계를 맺었다. 라는 건 boardId가 없으면 게시글 작성이 안된다 라는 것이다.

1. Entity 생성자의 board를 넣어준다.

 public Post(String content, String title, String createdAt, Board board){
        this.content = content;
        this.title = title;
        this.createdAt = createdAt;
        this.board = board;
    }

2. BoardId가 있어야 게시글 작성이 되기 때문에 Requeest에도 boardId가 있어야한다.

public record PostRequest(
        String content,
        String title,
        String createdAt,
        Long boardId
) {
}

3. controller수정

@GetMapping("/posts")
    public List<PostResponse> getOneBoard(@RequestParam(required = false) Long boardId){
        return postService.getContentInTitle(boardId);
    }

posts 자체를 조회했을 때 boardId를 RequestParam으로 받고, 그걸 토대로 service도 수정한다.

RequestBody vs RequestParam

  • RequestBody : http body에 있는 내용을 오브젝트로 반환한다.
  • RequestParam : URL에 요청 파라미터를 보낸다.

4. Service수정
1. 게시글을 만들 때 무조건 boardId를 받아줘야한다.

public PostResponse create(PostRequest postRequest) {
       //board의 id를 저장해야된다.
       Board board = boardRepository.findById(postRequest.boardId()).orElseThrow();
       Post post = postRepository.save(new Post(postRequest.title(), postRequest.content(), postRequest.createdAt(), board));
       return new PostResponse(post.getTitle(), post.getContent(), post.getId(), post.getCreatedAt());
   }
  1. 찾을 때 Request.boardId를 찾아, 먼저 boardId가 있는지 검사
  2. save할때 boardId를 저장해 특정 게시판 안에 저장되게함
  3. 반환할 때 boardId도 같이 반환해서 특정 게시판이 어디인지 프론트에 보냄
  1. 게시글 조회할때 boardId를 찾아야한다. 근데 postRespository에는 boardId가 없기 때문에 그걸 찾는 JPA쿼리 메서드를 작성해줘야한다.
public interface PostRepository extends JpaRepository<Post, Long> {
List<Post> findByBoardId(Long boardId);
}

특정 게시판내의 게시글 만드는 함수
게시글은 여러개니까 List형태로 만든다.

public List<PostResponse> getContentInTitle(Long boardId) {
        List<Post> byBoardId = postRepository.findByBoardId(boardId);
        return byBoardId.stream().map(
                post-> new PostResponse(
                        post.getTitle(),
                        post.getContent(),
                        post.getId(),
                        post.getCreatedAt())).toList();
    }

이렇게 하면 하나의 게시판의 모든 게시글을 조회할 수 있다.


😐 느낀점

일단, 너무 힘드러~~~~~
관계를 맺었을 때는, 그 관계맺은 Id를 꼭 받아서 그걸 가지고 만들어야한다.
그걸 해주지 않아서 나는 1시간동안 애먹었음!

0개의 댓글