Published 2022. 8. 25. 21:59

 

BoardRequestDto.java 게시판 요청 데이터를 담당
BoardResponseDto.java 게시판 응답 데이터를 담당
BaseTimeEntity.java 반복되는 날짜 데이터의 공통 처리를 담당
Board.java board 테이블의 @Entity
BoardRepository.java JpaRepository의 구현체
BoardService.java 게시판 @Service

 

@Entity 실제 DB의 테이블과 매칭될 Class임을 명시한다
@MappedSuperclass 이 클래스를 상속하는 엔티티에 매핑되는 테이블을 생성한다.
@EntityListeners(AuditingEntityListener.class) Jpa 내부에서 엔티티 객체가 생성/변경되는 것을 감지하는 역할을 한다.
@CreateDate Jpa 에서 엔티티의 생성 시간을 처리한다.
@LastModifiedDate 최종 수정 시간을 자동으로 처리한다.
@GeneratedValue(strategy =GenerationType.IDENTITY) PK의 생성 규칙을 나타낸다.
@Builder 어느 필드에 어떤 값을 채워야 할지 명확하게 정하여 생성 시점에 값을 채워준다.
@Transactional 선언적 트랜잭션을 사용한다.
@Modifying @Query Annotation으로 작성 된 변경, 삭제 쿼리를 사용할 때 사용한다.
@Query SQL을 JPQL로 작성할 수 있고, nativeQuery=true 옵션으로 네이티브 쿼리도 사용 가능하게 한다.

 

 

 

 

 

entity.board

Entity를 정의한다.

테이블의 모든 필드와 Builder생성자를 구현한다.

package com.board.study.entity;

import lombok.AccessLevel;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;

@NoArgsConstructor(access = AccessLevel.PROTECTED)
@Getter
@Entity
public class Board extends BaseTimeEntity{

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    private String title;
    private String content;
    private int readCnt;
    private String registerId;

    @Builder
    public Board(Long id, String title, String content, int readCnt, String registerId) {
        this.id = id;
        this.title = title;
        this.content = content;
        this.readCnt = readCnt;
        this.registerId = registerId;
    }
}

 

 

 

BaseTimeEntity

 

com.board.study.entity

 

Entity에서 공통적으로 사용될 날짜 필드를 관리할 클래스를 정의한다.

꼭 날짜가 아니더라도 공통적으로 반복되는 필드를 정의하여 사용해도 된다.

package com.board.study.entity;

import lombok.Getter;
import org.springframework.data.annotation.CreatedDate;
import org.springframework.data.annotation.LastModifiedDate;
import org.springframework.data.jpa.domain.support.AuditingEntityListener;

import javax.persistence.EntityListeners;
import javax.persistence.MappedSuperclass;
import java.time.LocalDateTime;

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

    @CreatedDate
    private LocalDateTime registerTime;

    @LastModifiedDate
    private LocalDateTime updateTime;
}

 

 

 

 

 

 

BoardRequestDto

 

dto.board

 

게시물 등록, 수정, 상세 조회에 필요한 필드를 정의한다.

toEntity()  메서드는 Board Entity를 builder 하여 사용한다.

package com.board.study.dto.board;

import com.board.study.entity.Board;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;

@Getter
@Setter
@NoArgsConstructor
public class BoardRequestDto {
    private Long id;
    private String title;
    private String content;
    private String registerId;

    public Board toEntity() {
        return Board.builder()
                .title(title)
                .content(content)
                .registerId(registerId)
                .build();
    }
}

 

 

 

BoardResponseDto

 

게시물 목록, 상세 조회에 필요한 필드를 정의한다.

Board Entity를 BoardResponseDto에 맞게 변환하는 생성자를 생성한다.

package com.board.study.dto.board;

import com.board.study.entity.Board;
import lombok.Getter;

import java.time.LocalDateTime;

@Getter
public class BoardResponseDto {
    private Long id;
    private String title;
    private String content;
    private int readCnt;
    private String registerId;
    private LocalDateTime registerTime;

    public BoardResponseDto(Board entity) {
        this.id = entity.getId();
        this.title = entity.getTitle();
        this.content = entity.getContent();
        this.readCnt = entity.getReadCnt();
        this.registerId = entity.getRegisterId();
        this.registerTime = entity.getRegisterTime();
    }

    @Override
    public String toString() {
        return "BoardListDto [id=" + id + ", title=" + title + ", content=" + content + ", readCnt" + readCnt +
                ", registerId=" + registerId + ", registerTime=" + registerTime + "]";
    }
}

 

 

 

BoardRepository

 

JpaRepository를 상속받아 CRUD의 기능을 담당하는 인터페이스를 생성한다.

 

그리고 @Query을 사용한 JPQL 방식의 updateBoard() 메서드도 구현해 본다.

package com.board.study.repository;

import com.board.study.dto.board.BoardRequestDto;
import com.board.study.entity.Board;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Modifying;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;
import org.springframework.transaction.annotation.Transactional;

public interface BoardRepository extends JpaRepository<Board, Long> {

    String UPDATE_BOARD = "UPDATE Board " +
            "SET TITLE = :#{#boardRequestDto.title}, " +
            "CONTENT = :#{#boardRequestDto.content}, " +
            "UPDATE_TIME = NEW() " +
            "WHERE ID = :#{#boardRequestDto.id}";

    @Transactional
    @Modifying
    @Query(value = UPDATE_BOARD, nativeQuery = true)
    public int updateBoard(@Param("boardRequestDto") BoardRequestDto boardRequestDto);
}

 

 

 

BoardService

 

게시판 기능을 담당할 Service 클래스로 나중에 파일 및 페이징 처리를 추가할 예정이다.

지금은 간단한 CRUD 메서드만 작성한다.

package com.board.study.service;

import com.board.study.dto.board.BoardRequestDto;
import com.board.study.dto.board.BoardResponseDto;
import com.board.study.repository.BoardRepository;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

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

@RequiredArgsConstructor
@Service
public class BoardService {

    private final BoardRepository boardRepository;


    @Transactional
    public Long save(BoardRequestDto boardRequestDto) {
        return boardRepository.save(boardRequestDto.toEntity()).getId();
    }

    @Transactional(readOnly = true)
    public List<BoardResponseDto> findAll() {
        return boardRepository.findAll().stream().map(BoardResponseDto::new).collect(Collectors.toList());
    }

    public BoardResponseDto findById(Long id) {
        return new BoardResponseDto(boardRepository.findById(id).get());
    }

    public int updateBoard(BoardRequestDto boardRequestDto) {
        return boardRepository.updateBoard(boardRequestDto);
    }

    public void deleteById(Long id) {
        boardRepository.deleteById(id);
    }
}

 

 

 

StudyApplication

 

Application 클래스에 @EnableJpaAuditing을 추가해 Auditing기능을 활성화 한다.

package com.board.study;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.data.jpa.repository.config.EnableJpaAuditing;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@EnableJpaAuditing
@SpringBootApplication
public class StudyApplication {

   public static void main(String[] args) {
      SpringApplication.run(StudyApplication.class, args);
   }

}

 

테이블 생성

CREATE TABLE IF NOT EXISTS `board` (
  `id` bigint NOT NULL AUTO_INCREMENT COMMENT 'PK',
  `title` varchar(200) NOT NULL COMMENT '제목',
  `content` text NOT NULL COMMENT '내용',
  `read_cnt` int NOT NULL DEFAULT '0' COMMENT '조회수',
  `register_id` varchar(100) NOT NULL COMMENT '작성자',
  `register_time` datetime DEFAULT NULL COMMENT '작성일',
  `update_time` datetime DEFAULT NULL COMMENT '수정일',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci ROW_FORMAT=DYNAMIC COMMENT='게시판'

 

 

데이터베이스 설정(application.properties)

spring.profiles.active=local

# MySQL
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver

# DB Source URL
# ex) spring.datasource.url=jdbc:mysql://localhost:3306/test_db?useSSL=false&useUnicode=true&serverTimezone=Asia/Seoul
spring.datasource.url=jdbc:mysql://localhost:3303/Board?useSSL=false&useUnicode=true&serverTimezone=Asia/Seoul


# DB username
# ex) spring.datasource.username=root
spring.datasource.username=root

# DB password
# ex) spring.datasource.password=root
spring.datasource.password=0024

# 처리 시 발생하는 SQL 을 보여줄 것인지 결정
#spring.jpa.show-sql=true

# 프로젝트 실행 시 자동으로 DDL(create, alter, drop) 을 생성할 것인지 결정하는 설정
# create : 매번 테이블 생성을 새로 시도한다.
# update : 변경이 필요한 경우 alter 로 변경되고 테이블이 없는 경우 create 가 된다.
spring.jpa.hibernate.ddl-auto=update 

# 실제 JPA 구현체인 Hibernate 가 동작하면서 발생하는 SQL 을 포맷팅해서 출력한다. 실행되는 SQL 의 가독성을 높여준다.
spring.jpa.properties.hibernate.format_sql=true

#JPA
loglogging.level.org.hibernate.SQL=DEBUG
logging.level.org.hibernate.type.descriptor.sql.BasicBinder=TRACE

 

복사했습니다!