09009

[Spring Boot] 게시판 연습 (2) - 게시글 작성 : 게시글 작성 완료하기 본문

Back-End/Spring
[Spring Boot] 게시판 연습 (2) - 게시글 작성 : 게시글 작성 완료하기
09009 2024. 1. 23.

save.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>save</title>
</head>
<body>
    <!-- action속성: 목적지(서버주소), method속성: http request method(get, post) -->
    <form action="/board/save" method="post">
        writer: <input type="text" name="boardWriter"> <br>
        pass: <input type="text" name="boardPass"> <br>
        title: <input type="text" name="boardTitle"> <br>
        contents: <textarea name="boardContents" cols="30" rows="10"></textarea> <br>
        <input type="submit" value="글작성">
    </form>
</body>
</html>

 

 

BoardDTO

- @Getter, @Setter : getter, setter 메서드를 자동으로 만들어주는 어노테이션 
- @NoArgsConstructor: 기본 생성자

- @AllArgsConstructor: 모든 필드를 매개변수로 하는 생성자

package com.yyi.board.dto;

import lombok.*;

import java.time.LocalDateTime;

@Getter
@Setter
@ToString
@NoArgsConstructor
@AllArgsConstructor
// DTO (데이터를 전송할 때 사용하는 객체)
public class BoardDTO {
    private Long id;
    private String boardWriter;
    private String boardPass;
    private String boardTitle;
    private String boardContents;
    private int boardHits;
    private LocalDateTime boardCreatedTime;
    private LocalDateTime boardUpdatedTime;

}

 

 

BoardController

    @PostMapping("/save")
    public String save(@ModelAttribute BoardDTO boardDTO) {
        System.out.println("boardDTO = " + boardDTO);
        return null;
    }

}

 

여기까지 코드를 작성하고 이제 service, entity, repository 패키지와 클래스를 생성한다.

 

BoardEntity

Entity : DB의 테이블 역할을 하는 클래스

Spring Data JPA를 사용하면 별도로 테이블을 DB에 생성할 필요가 없게 된다.

package com.yyi.board1.entity;

import jakarta.persistence.*;
import lombok.Getter;
import lombok.Setter;

// DB의 테이블 역할을 하는 클래스
@Entity
@Getter
@Setter
@SequenceGenerator(
        name = "board_seq_generator"
        , sequenceName = "board_seq"
        , initialValue = 1
        , allocationSize = 1
)
@Table(name = "board_table")
public class BoardEntity {
    @Id // pk 지정
    @GeneratedValue(
            strategy = GenerationType.SEQUENCE
            , generator = "board_seq_generator"
    )
    private Long id;

    @Column(length = 20, nullable = false) // 크기는 20이고, null을 허용하지 않는다.
    private String boardWriter;

    @Column // default: 크기 255, null 가능 상태
    private String boardPass;

    @Column
    private String boardTitle;

    @Column(length = 500)
    private String boardContents;

    @Column
    private int boardHits;
}

 

시간에 대한 컬럼은 별도의 클래스로 구분한다.

BaseEntity

- 이 클래스 역할 : 시간정보를 다룰 수 있도록 함

package com.yyi.board.entity;

import jakarta.persistence.Column;
import jakarta.persistence.EntityListeners;
import jakarta.persistence.MappedSuperclass;
import lombok.Getter;
import org.hibernate.annotations.CreationTimestamp;
import org.hibernate.annotations.UpdateTimestamp;
import org.springframework.data.jpa.domain.support.AuditingEntityListener;

import java.time.LocalDateTime;

@MappedSuperclass
@EntityListeners(AuditingEntityListener.class)
@Getter
public class BaseEntity {

    @CreationTimestamp // 생성되었을 때의 시간을 만들어줌
    @Column(updatable = false) // updatable = false: 수정 시에는 관여를 안하게 설정
    private LocalDateTime createdTime;
    
    @UpdateTimestamp // 업데이트가 발생했을 때 시간정보를 알려줌
    @Column(insertable = false) // insertable = false : insert 시에는 관여를 안하게 설정
    private LocalDateTime updatedTime;
}

 

BoardEntity

- BaseEntity를 상속받는 코드 추가

package com.yyi.board1.entity;

import jakarta.persistence.*;
import lombok.Getter;
import lombok.Setter;

// DB의 테이블 역할을 하는 클래스
@Entity
@Getter
@Setter
@SequenceGenerator(
        name = "board_seq_generator"
        , sequenceName = "board_seq"
        , initialValue = 1
        , allocationSize = 1
)
@Table(name = "board_table")
public class BoardEntity extends BaseEntity {
    @Id // pk 지정
    @GeneratedValue(
            strategy = GenerationType.SEQUENCE
            , generator = "board_seq_generator"
    )
    private Long id;

    @Column(length = 20, nullable = false) // 크기는 20이고, null을 허용하지 않는다.
    private String boardWriter;

    @Column // default: 크기 255, null 가능 상태
    private String boardPass;

    @Column
    private String boardTitle;

    @Column(length = 500)
    private String boardContents;

    @Column
    private int boardHits;
}

 

 

BoardService 기본 설정

package com.yyi.board.service;

import org.springframework.stereotype.Service;

@Service
public class BoardService {


}

 

BoardRepository 기본 설정

package com.yyi.board.repository;

import com.yyi.board.entity.BoardEntity;
import org.springframework.data.jpa.repository.JpaRepository;

public interface BoardRepository extends JpaRepository<BoardEntity, Long> {
    
}

 

Controller에서 Service 호출하는 코드 작성

BoardController

package com.yyi.board.controller;

import com.yyi.board.dto.BoardDTO;
import com.yyi.board.service.BoardService;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;

@Controller
@RequiredArgsConstructor // 생성자 주입 방식으로 의존성을 주입받게 된다
@RequestMapping("/board")
public class BoardController {
    private final BoardService boardService;
    @GetMapping("/save")
    public String saveForm() {
        return "save";
    }

    @PostMapping("/save")
    public String save(@ModelAttribute BoardDTO boardDTO) {
        System.out.println("boardDTO = " + boardDTO);
        boardService.save(boardDTO);
        return null;
    }

}

 

 

!! 중요 

repository는 일반적으로 entity 클래스만 받아준다.

Service 클래스에서는 아래와 같이 변환하는 과정이 많이 발생한다.

 - service에서 하는 작업 중의 하나
 DTO -> Entity (Entity 클래스에서 수행)
 Entity -> DTO (DTO 클래스에서 수행)
 컨트롤러로부터 호출받을 때는 DTO로 넘겨받고, Repository에 넘겨줄때는 entity로 넘겨준다
 DB에 데이터를 조회할 때는 repository로부터 entity 형태로 받아온다.
 그것을 컨트롤러로 다시 줄 때는 dto로 바꿔줘야 한다.

 

BoardService

일단 여기까지 작성

package com.yyi.board.service;

import com.yyi.board.dto.BoardDTO;
import com.yyi.board.repository.BoardRepository;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;

// DTO -> Entity (Entity 클래스에서 수행)
// Entity -> DTO (DTO 클래스에서 수행)

@Service
@RequiredArgsConstructor
public class BoardService {
    private final BoardRepository boardRepository;

    public void save(BoardDTO boardDTO) {
        boardRepository.save();
    }
}

 

BoardEntity

코드 추가

    // dto에 담긴 값들을 entity 객체에 옮겨담는 작업
    public static BoardEntity toSaveEntity(BoardDTO boardDTO) {
        BoardEntity boardEntity = new BoardEntity();
        boardEntity.setBoardWriter(boardDTO.getBoardWriter());
        boardEntity.setBoardPass(boardDTO.getBoardPass());
        boardEntity.setBoardTitle(boardDTO.getBoardTitle());
        boardEntity.setBoardContents(boardDTO.getBoardContents());
        boardEntity.setBoardHits(0); // 조회수는 기본으로 0이니까
        return boardEntity;
    }

 

BoardService

코드 추가

    public void save(BoardDTO boardDTO) {
        BoardEntity boardEntity = BoardEntity.toSaveEntity(boardDTO);
        boardRepository.save(boardEntity);
    }

 

BoardController

코드 수정

    @PostMapping("/save")
    public String save(@ModelAttribute BoardDTO boardDTO) {
        System.out.println("boardDTO = " + boardDTO);
        boardService.save(boardDTO);
        return "index";
    }

 

여기까지 작성하고 실행