관리 메뉴

bright jazz music

[bootBoard] N:1(다대일) 연관관계: 9-1. 프로젝트 적용: 게시물 등록 처리 본문

Framework/Spring

[bootBoard] N:1(다대일) 연관관계: 9-1. 프로젝트 적용: 게시물 등록 처리

bright jazz music 2022. 10. 4. 20:38

기존 프로젝트 내용을 참고해서 브라우저에서 확인할 수 있는 코드 작성

 

1. DTO 계층과 서비스 계층 작성

 

 

//BoardDTO.java

package com.example.bootboard.dto;

import lombok.*;

import java.time.LocalDateTime;

@Data	//getter and setter 생성
@ToString	//toString 메서드 생성
@Builder	//Builder 클래스를 롬복이 만들어줌
@AllArgsConstructor	//모든 필드를 파라미터로 갖는 생성자를 만든다
@NoArgsConstructor	//파라미터가 없는 생성자를 만든다.
public class BoardDTO {
    
    private Long bno;
    
    private String title;
    
    private String content;
    
    private String writerEmail;// 작성자 email (id)
    
    private String writerName; //작성자 명
    
    private LocalDateTime regDate;
    
    private LocalDateTime modDate;
    
    private int replyCount; //해당 게시글 댓글 수
}

//참고: @RequiredArgsConstructor는 어노테이션 아래에 있는 필드를 파라미터로 갖는 생성자를 만든다.

 

BoardDTO의 경우 Member에 대한 참조는 구성하지 않고 작성한다. DTO는 화면에 전달하는 데이터이거나 그 반대쪽으로 전달되는 데이터를 기준으로 하기 때문에 엔티티 클래스의 구성과 일치하지 않는 경우가 많다.

 

BoardDTO 클래스와 Board 엔티티 클래스의 차이점:

BoardDTO가 Member를 참조한는 대신 화면에서 필요한 작성자의 이메일과 작성자의 이름으로 처리한다는 것.

 

목록 화면에서도 BoardDTO를 이용하기 때문에 댓글의 개수를 의미하는 replyCount도 추가한다. 

 

 

2. BoardService 인터페이스 & BoardServiceImpl 클래스 작성

 

  • 게시물을 등록하기 위해 BoardDTO 타입을 파라미터로 전달받고, 생성된 게시물의 번호를 반환해야 한다.
  • 실제 처리 과정에서 BoardDTO를 Board Entity 타입으로 변환할 필요가 있다.
  • 이에 대한 처리는 BoardService 인터페이스에 dtoToEntity()를 작성해서 처리한다.

 

 

//BoardService.java

package com.example.bootboard.service;

import com.example.bootboard.dto.BoardDTO;
import com.example.bootboard.entity.Board;
import com.example.bootboard.entity.Member;

public interface BoardService {

    Long register(BoardDTO dto);
    
	//dtoToEntity() 메서드: BoardDTO를 Board엔티티 타입으로 변환한다.
    default Board dtoToEntity(BoardDTO dto) {
        Member member = Member.builder().email(dto.getWriterEmail()).build();
	
    //Board 클래스는 엔티티 클래스이다.
        Board board = Board.builder()
                .bno(dto.getBno())
                .title(dto.getTitle())
                .content(dto.getContent())
                .writer(member)
                .build();

        return board;
    }
}

 

  • DTO가 연관관계를 가진 Board 엔티티 객체와 Member 엔티티 객체를 구성해야 한다. 
  • 따라서 dtoToEntity()는 내부적으로 Member 엔티티를 처리하는 과정을 거친다.
  • 이 때 Member는 실제 DB에 있는 이메일 주소를 사용해야 한다.
  • 작성된 dtoToEntity()는 BoardServiceImpl의 register()에서 사용한다.

 

//BoardServiceImpl.java

package com.example.bootboard.service;

import com.example.bootboard.dto.BoardDTO;
import com.example.bootboard.entity.Board;
import com.example.bootboard.repository.BoardRepository;
import lombok.RequiredArgsConstructor;
import lombok.extern.log4j.Log4j2;
import org.springframework.stereotype.Service;

@Service
@RequiredArgsConstructor
@Log4j2
public class BoardServiceImpl implements BoardService {

    private final BoardRepository repository; // 자동 주입 final

    @Override
    public Long register(BoardDTO dto) {

        log.info(dto);
        
        //dtoToEntity() : DTO를 받아서 Entity객체로 변환. Board와 연관관계인 Member 엔티티도 처리
        Board board =  dtoToEntity(dto);

        repository.save(board);
        return board.getBno();
    }
}

 

3. TEST : 게시물 등록

테스트를 통해 게시물을 등록한다. (아직 화면, 화면과 연결하는 로직을 만들지 않았기 때문에 DB에 등록되는지 여부로 확인한다.)

 

 

//BoardServiceTests.java

package com.example.bootboard.service;

import com.example.bootboard.dto.BoardDTO;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

@SpringBootTest
public class BoardServiceTests {
    
    @Autowired
    private BoardService boardService;
    
    @Test
    public void testRegister() {

        BoardDTO dto = BoardDTO.builder()
                .title("Test.")
                .content("Test ...")
                .writerEmail("user55@aaa.com") //현재 DB에 존재한느 회원 이메일
                .build();
        
        Long bno = boardService.register(dto);
    }
    
}

-----------------------------------------

문제 발생

에러 발생

2022-10-04 21:28:22.588  WARN 25748 --- [    Test worker] o.m.jdbc.message.server.ErrorPacket      : Error: 1364-HY000: Field 'bno' doesn't have a default value
2022-10-04 21:28:22.590  WARN 25748 --- [    Test worker] o.h.engine.jdbc.spi.SqlExceptionHelper   : SQL Error: 1364, SQLState: HY000
2022-10-04 21:28:22.590 ERROR 25748 --- [    Test worker] o.h.engine.jdbc.spi.SqlExceptionHelper   : (conn=1255) Field 'bno' doesn't have a default value

could not execute statement; nested exception is org.hibernate.exception.GenericJDBCException: could not execute statement
org.springframework.orm.jpa.JpaSystemException: could not execute statement; nested exception is org.hibernate.exception.GenericJDBCException: could not execute statement

문제 발생 원인 :

bno에 값이 지정되어 있지 않았기 때문. 

예전 버전의 mysql에는 insert시 칼럼의 값이 비워져 있으면 ' '이 자동 입력되었음

현재는 STRICT_TRANS_TABLES 때문에 오류 발생 시킴.

mysql/mariadb의 설정파일인 my.cnf 아래의 문구를 찾아서 주석처리하고 DB 재구동 할 것.

#sql_mode=NO_ENGINE_SUBSTITUTION,STRICT_TRANS_TABLES 
sql_mode=NO_ENGINE_SUBSTITUTION

#그러나 이 방법으로 해결 못했음.
#my.ini 열어보니 아예 이 설정이 들어있지 않았기 때문임.
# 따라서 아래의 방법으로 시도

https://wickedmagic.tistory.com/534

 

[MySQL] Field '칼럼' doesn't have a default value 에러

[MySQL] Field '칼럼' doesn't have a default value 에러 이번 에러는 서버 이전때문에 MySQL 버전업을 하고 테스트중 발생한 에러이다. 처음에는 서버 설정이 다르거나 MySQL 버전이 다름으로서 발생한 에러인

wickedmagic.tistory.com

 

이 역시 성공하지 못했다. Board의 Bno의 설정을 바꾸려면 이 칼럼이 외래키로 들어 있는 Member 설정 역시 바꿔줘야 하는데, 이 부분에서 서로가 서로의 제약 역할을 하면서 수정되지 않았다. (이 프로젝트를 진행하면서 처음에 코드를 잘못 작성한 적이 있는데, 그 때문에 DB 생성 시 설정이 잘못된 것으로 추측하고 있다.) 어쨌든 시간을 쏟으면 해결할 수 있는 문제같지만 그렇게 하지 않았다. 지금 내 목표는 이 과정을 한 번 끝내는 것이지 DB설정 공부가 아니기 때문이다.

 

때문에 DB 자체를 삭제하고 프로젝트를 재구동하였다. tests계열의 클래스에 적은 테스트들도 전부 테스트하여 정상적인 값으로 맞춰주었다.

-----------------------------------------

 

 

3. TEST : 결과

DB정상화 후 testRegist() 테스트에 성공.

 

Board 테이블에 추가된 데이터

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Comments