일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | ||||||
2 | 3 | 4 | 5 | 6 | 7 | 8 |
9 | 10 | 11 | 12 | 13 | 14 | 15 |
16 | 17 | 18 | 19 | 20 | 21 | 22 |
23 | 24 | 25 | 26 | 27 | 28 |
- 이터레이터
- 알파회계
- 자바편
- d
- 구멍가게코딩단
- 서버설정
- GIT
- 자료구조와 함께 배우는 알고리즘 입문
- 페이징
- 네트워크 설정
- 티스토리 쿠키 삭제
- 처음 만나는 AI 수학 with Python
- baeldung
- 코드로배우는스프링부트웹프로젝트
- 자료구조와함께배우는알고리즘입문
- 스프링부트핵심가이드
- ㅒ
- 데비안
- Kernighan의 C언어 프로그래밍
- 코드로배우는스프링웹프로젝트
- 리눅스
- /etc/network/interfaces
- 스프링 시큐리티
- 친절한SQL튜닝
- resttemplate
- 선형대수
- network configuration
- 처음 만나는 AI수학 with Python
- iterator
- 목록처리
- Today
- Total
bright jazz music
[bootBoard] N:1(다대일) 연관관계: 9-1. 프로젝트 적용: 게시물 등록 처리 본문
[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 열어보니 아예 이 설정이 들어있지 않았기 때문임.
# 따라서 아래의 방법으로 시도
이 역시 성공하지 못했다. Board의 Bno의 설정을 바꾸려면 이 칼럼이 외래키로 들어 있는 Member 설정 역시 바꿔줘야 하는데, 이 부분에서 서로가 서로의 제약 역할을 하면서 수정되지 않았다. (이 프로젝트를 진행하면서 처음에 코드를 잘못 작성한 적이 있는데, 그 때문에 DB 생성 시 설정이 잘못된 것으로 추측하고 있다.) 어쨌든 시간을 쏟으면 해결할 수 있는 문제같지만 그렇게 하지 않았다. 지금 내 목표는 이 과정을 한 번 끝내는 것이지 DB설정 공부가 아니기 때문이다.
때문에 DB 자체를 삭제하고 프로젝트를 재구동하였다. tests계열의 클래스에 적은 테스트들도 전부 테스트하여 정상적인 값으로 맞춰주었다.
-----------------------------------------
3. TEST : 결과
DB정상화 후 testRegist() 테스트에 성공.
Board 테이블에 추가된 데이터
'Framework > Spring' 카테고리의 다른 글
[bootBoard] N:1(다대일) 연관관계: 9-4. 프로젝트 적용: 게시물 삭제 처리 (0) | 2022.10.07 |
---|---|
[bootBoard] N:1(다대일) 연관관계: 9-2. 프로젝트 적용: 게시물 목록 처리 (0) | 2022.10.05 |
[bootBoard] N:1(다대일) 연관관계: 8-2. 조회 화면에 필요한 JPQL 생성 (0) | 2022.09.29 |
[bootBoard] N:1(다대일) 연관관계: 8-1. 목록화면에 필요한 JPQL 생성 (0) | 2022.09.28 |
[bootBoard] N:1(다대일) 연관관계: 7-2. JPQL과 left(outer) join 연관관계 X (0) | 2022.09.28 |