우당탕탕 개발일지
16일차_게시판 프로젝트(9) 본문
1. File Entity 설계 및 연관관계
1-1. 설명
게시물 하나에 파일 N개를 등록할려고 한다.
이때 파일을 관리하는 Table(tb_board_file)를 하나 생성하여 관리할 것이다.
게시물 테이블인 tb_board과 tb_board_file 에게 연관관계 부여한다.
연관관계를 통해 하나의 게시물에 따른 여러개의 첨부파일을 관리한다.
연관관계 유형 >> 1 : N (게시물 : 파일)
tb_board 에서 한행을 조회하면 tb_board_file 에서 해당 파일의 모든 행을 가지고 온다.
1-2. 연관관계란?
[ 정의 ]
연관 관계란 객체의 참조와 테이블의 외래 키를 매핑시키는 것
[ 연관관계 매핑 ]
우리는 JPA를 사용하므로써 entity들의 연관 관계를 매핑해두고 필요할 때
해당 entitiy와 연관된 entitiy를 사용하며 좀 더 객체 지향적인 프로그래밍을 할 수 있다.
→ JPA는 ORM을 이용하고 , ORM은 관계형 데이터 베이스를 연결시켜주는 것이니까 객체 (entity)마다 연결을 할 수 있는 것.
[참고]
https://velog.io/@nyong_i/JPA-%EC%97%B0%EA%B4%80-%EA%B4%80%EA%B3%84
[JPA] 연관 관계
연관관계에 대해서 알아보자.
velog.io
JPA 관계형 DB 연관관계 매핑하기
연관관계 매핑을 하는 방법에 대해서 간단하게 정리를 해보았다.우리는 JPA를 사용하므로써 entity들의 연관 관계를 매핑해두고 필요할 때 해당 entitiy와 연관된 entitiy를 사용하며 좀 더 객체 지향
velog.io
1-3. 기본키? 외래키?
[ 기본키 ]
- 정의 : 테이블에서 각 행의 정보를 식별할 수 있는 키
- 특징
- 유일성 O
- 중복 X, Null X
- 해당 PK필드는 다른테이블의 필드에서 참조 당함
- 예시
주민등록번호
[ 외래키 ]
- 정의 : 다른 테이블의 PK를 통해 참조
- 특징
- 1 : N 관계에서 N에 해당 하는 쪽에 외래키 지정
외래키 : board_id
[참고]
https://velog.io/@jch9537/DATABASE-PK-FK
[DATABASE] 기본키(PK), 외래키(FK)
데이터 모델링을 하며 ERD(Entity Relationship Diagram: 개체관계도)에 테이블을 만들면서 테이블간의 관계 연결에 대해 어려움을 겪었다.요약하면 부모와 자식/ 참조하는 테이블과 참조되는 테이블로
velog.io
https://keembloo.tistory.com/42
데이터베이스 기본키(PK), 외래키(FK)
1 . 기본키 식별키 Primary Key (PK) 테이블의 유일한 값을 가지는 필드 데이터의 중복이 없는 식별가능한 필드를 선정 테이블 1개당 PK필드 1개 이상 (권장) 중복 , null , 공백은 사용불가 해당 PK필드는
keembloo.tistory.com
1-4. 소스
BoardFileEntity.java
자식 Entity
파일 정보를 관리하는 Entity -> Table 이름 : tb_board_table
1. 컬럼명 설정
- id : PK
- originalFileName : 실제 파일명
- storedFileName : 서버 저장용 파일명
2. 외래키 지정
- 컬럼명 : board_id
- 연관관계 : @ManyToOne (N : 1 >> 파일 N개 : 게시물 1개) >> 자식 Entity
- FetchType.LAZY : 지연로딩 >> 연관관계에 있는 Entity를 가져오지 않고 필요한 경우에 호출하여 데이터 요청
3. private BoardEntity boardEntity; (변수 선언)
- tb_board 테이블의 기본키인 Long 타입이 아닌 BoardEntity 타입 사용
- 실제 DB에서는 Long 타입으로 저장
BoardEntity.java
부모 Entity
게시물 정보 관리 Entity > Table 이름 : tb_board
1. 연관관계 : @OneToMany (1 : N >> 게시물 1개 : 파일 N개) >> 부모 Entity
2. mappedBy : 어떤 것과 매핑할 것인지 >> 연관관계에서 주인
BoardFileEntity에서 선언한 BoardEntity 타입의 변수명과 동일한 이름 사용
3. CascadeType.REMOVE >> 1-6 참고
4. orphanRemoval = true >> 1-6 참고
5. fetch 위와 동일
[참고] 양방향 연관관계
JPA @OneToMany, @ManyToOne으로 연관관계 관리하기
안녕하세요, 오늘은 스프링을 이용하면서 자주 쓰는 JPA에 대해서 이야기해보려고 합니다. JPA는 스프링 개발을 하면서 이제 거의 필수가 된 ORM 기술입니다. @OneToMany, @ManyToOne 어노테이션은 1:N, N:1
velog.io
[참고] Fetch
https://velog.io/@may_yun/JPA-Fetch-%EC%A0%84%EB%9E%B5
[JPA] Fetch 전략
애플리케이션이 DB로부터 데이터를 가지고 오는 것DB와 통신하여 데이터를 읽는 것에는 큰 비용이 소모되기 때문에 이를 해결하는 전략fetch 전략에는 FetchType.EAGER(즉시로딩), FetchType.LAZY(지연로딩
velog.io
1-5. 결과 화면
1-6. 부모 Entity 관련 설정
[ Cascade ]
>> 엔티티의 상태 변화를 전파시키는 옵션
[ orphanRemoval]
>> 고아 객체를 제거하는 옵션
부모 Entity | 부모, 자식 Entity 연관관계 | ||
삭제 | 삭제 | 변경 | |
CascadeType.REMOVE | 자식 Entity 삭제 O |
자식 엔티티가 DB 삭제 X 외래키 값만 변경 |
자식 엔티티가 DB에 삭제 X 외래키 값만 변경 |
orphanRemoval = true | 자식 엔티티가 DB에서 삭제 O (고아 객체로 취급) |
[참고] 정의
https://yarisong.tistory.com/35
Spring Data JPA -Cascade와 orphanRemoval?
1. CasCade란? 엔티티의 상태 변화를 전파시키는 옵션이다. 간단히 이야기하면 특정 엔티티를 변화시킬때 그에 따라 연관된 엔티티도 같이 상태가 변한다는 의미이다. 2. CasCade Type? 총 6가지의 Type
yarisong.tistory.com
[참고] 비교
https://velog.io/@yuseogi0218/JPA-CascadeType.REMOVE-vs-orphanRemoval-true
JPA - CascadeType.REMOVE vs orphanRemoval = true
CascadeType.REMOVE 와 orphanRemoval = true 옵션이 각각 고아객체를 어떻게 처리하는지 알아보았습니다.
velog.io
[참고] 부모? 자식?
[JPA] 연관관계에 자주 쓰이는 property들
부모 엔티티: 먼저 자료가 저장되어 있어야 할 쪽자식 엔티티: 부모 엔티티의 PK를 FK로 참조하는 쪽주식별관계: 부모엔티티의 PK를 자식엔티티의 PK로 참조비식별관계: 부모엔티티의 PK를 자식엔
velog.io
1-7. 유튜브 영상
https://www.youtube.com/watch?v=UU2xVPXBh34&list=PLV9zd3otBRt7jmXvwCkmvJ8dH5tR_20c0&index=17
2. 파일 DB 저장
첨부파일 있을 경우에 따른 데이터 저장!
지난 게시물(15일차, 3-2 참고)에 이어서 6, 7번 작업
15일차 (3-2 참고) : 2024.03.22 - [취준] - 15일차_게시판 프로젝트(8)
2-1. 작업 순서
6. tb_Board 에 해당 데이터 save 처리 (-> 게시물 관련 Data)
7. tb_Board_File 에 해당 데이터 save 처리 (-> 첨부파일 관련 Data)
BoardService.java
>> 받아온 Data를 DB에 저장
public void save(BoardDTO boardDTO) throws IOException {
// throws IOException : save 메소드에서 발생한 예외를 상위 메소드인 BoardService 에서 처리하기 위해 사용
// 상위에서 처리하는게 더 올바른 경우도 있고 해당 메소드에서 처리하는게 더 올바른 경우가 있다!
// 파일 첨부 여부에 따라 로직 분리
if(boardDTO.getBoardFile().isEmpty()) {
// 첨부 파일 X
// 1. DTO의 값들을 Entity에 옮겨담는 함수 호출
BoardEntity boardEntity = BoardEntity.toSaveEntitiy(boardDTO);
// 2. DB에 저장 (tb_board)
// save : JPA가 가지고 있는 함수
boardRepository.save(boardEntity);
} else {
// 파일 첨부 ㅇ
/*
1. DTO에 담긴 파일 추출 (실제 파일)
2. 파일의 이름 추출
3. 서버 저장용 이름 생성
: 내사진.jpg -> 8397980824_내사진.jpg
4. 저장 경로 설정
5. 해당 경로에 파일 저장
6. tb_Board 에 해당 데이터 save 처리 (-> 게시물 관련 Data)
7. tb_Board_File 에 해당 데이터 save 처리 (-> 첨부파일 관련 Data)
*/
MultipartFile boardFile = boardDTO.getBoardFile(); // 1
String originalFilename = boardFile.getOriginalFilename(); // 2
String storedFileName = System.currentTimeMillis() + " " + originalFilename; // 3
String savePath = "E:/Board_File/" + storedFileName; // 4. 실제 존재하는 경로 값
boardFile.transferTo(new File(savePath)); // 5
// transferTo : 파일 저장 메소드 & 예외 발생 가능성으로 인해서 throws IOException 사용
// 6
BoardEntity boardEntity = BoardEntity.toSaveFileEntitiy(boardDTO); // 6-1. DTO -> Entity (id값이 없다)
Long savedId = boardRepository.save(boardEntity).getId(); // 6-2. Entity 객체 저장(tb_board) & 저장한 id 가져오기
System.out.println("저장한 ID (첨부파일 O ) : " + savedId);
BoardEntity board = boardRepository.findById(savedId).get(); // 6-3. 저장한 id에 대한 Data 가져오기
// 7
BoardFileEntity boardFileEntity = BoardFileEntity.toBoardFileEntity(board, originalFilename, storedFileName); // 7-1. File Entity에 저장
boardFileRepository.save(boardFileEntity); // 7-2. DB에 저장 (tb_board_file)
}
}
2-2. tb_Board 에 해당 데이터 save 처리
>> 게시물 관련 Data
BoardService.java
1. 객체 변환
- toSaveFileEntity : DTO -> Entity
- 아래 BoardEntity.java 소스 참고
2. savedId
- boardEntity 객체를 DB(tb_baord)에 저장
- 저장한 Row의 Id값 가져오기
3. board
- 찾은 Id 값으로 해당 Row 데이터 가져오기
BoardEntity.java
>> toSaveFileEntity
1. 역할 : DTO -> Entity
2. 게시물 기본 Data 변환
3. 첨부파일이 있는 경우임으로 setFileAttached 값 '1' 로 설정
2-3. tb_Board_File 에 해당 데이터 save 처리
>> 파일 관련 Data
BoardService.java
1. boardFileEntity
- 해당 함수를 통해 File Entity 초기화
- board >> 바로 위에서 특정 id값에 대한 Row의 데이터가 저장되어 있음
- BoardFileEntity class에 정의되어 있는 함수
2. save
- DB (tb_board_file)에 저장
- BoardFileRepository 인터페이스의 save 기능 사용
BoardFileEntity.java
>> toBoardFileEntity
1. 매개변수
- boardEntity : 게시물 기본 Data
- originalFileName : 실제 파일명
- storeFileName : 서버 저장용 파일명
2. 역할
- File Entity 초기화
BoardFileRepository.java
1. Jpa 상속 받음
2. 파일 관련된 데이터 작업을 위한 Repository
3. BoardFileRepository 어노테이션 생략 가능
[참고] BoardFileRepository 어노테이션 생략
Repository Interface에 @Respoitory가 없는 이유
Notion Link www.notion.so/Repository-Interface-Respoitory-6d78269d33d54e828ffb219153965eb7 Repository Interface에 @Respoitory가 없는 이유 @Repository 는 컴포넌트 스캔 뿐만이 아니라 JPA의 예외를 스프링에서 공통적으로 처리
kingds.tistory.com
2-4. 유튜브 영상
https://www.youtube.com/watch?v=woNhl5skn-g&list=PLV9zd3otBRt7jmXvwCkmvJ8dH5tR_20c0&index=18
3. 게시글 조회 시, 파일첨부 이미지 출력
3-1. 첨부파일 관련 정보 DTO로 객체 변환
BoardDto.java
1. 추가
- getFileAttached : 0 or 1
2. 파일이 있을 경우
- 원본 파일명과 서버 저장용 파일명 저장해야 함 -> 해당 데이터는 file Entity에 존재함
- 부모 Entity인 BoardEntity를 통해서 자식 file Entity의 값 중 1번쨰 요소를 들고옴.
detail.html
1. 첨부파일이 있을 경우에만 해당 부분 노출
2. 파일명 노출
3-2. 정적 리소스
WebConfig.java
addResourceHandler : "/upload/" 로 시작하는 모든 요청에 대해 핸들러 동작
addResourceLocations: 실제 리소스가 존재하는 외부 경로를 지정
[ 참고 ] WebMvcConfigurer
https://jake-seo-dev.tistory.com/605
스프링 WebMvcConfigurer 인터페이스란?
WebMvcConfigurer 란? 스프링 프레임워크에서 제공하는 인터페이스이다. 보일러플레이트 코드 없이 요구사항에 맞게 프레임워크를 조정할 수 있게 해준다. 특정한 스프링 클래스를 구현하거나 상속
jake-seo-dev.tistory.com
[ 참고 ] Configuration
https://jaeano.tistory.com/entry/Spring-Boot-Configuration-Component-Configuration-Bean
[Spring Boot] Configuration Component (@Configuration, @Bean)
이번에는 @Configuratoin 어노테이션에 대해 알아 볼 것이다. 우선 Configuration이란? 구성이라는 뜻이다. 스프링에서도 같은 의미도 사용된다. 사용도 특별하지 않다. 다른 어노테이션들 처럼 클래스
jaeano.tistory.com
[ 참고 ] addResourceHandler
https://wildeveloperetrain.tistory.com/41#google_vignette
Spring Boot 프로젝트 외부 경로 파일 접근하기 addResourceHandlers
Spring Boot 프로젝트 외부 경로에 있는 파일 접근하기 addResourceHandlers 실서버에서 배포하여 실행중인 웹 애플리케이션 상에서 웹 사이트에 접속하여 파일 및 이미지 업로드를 실시할 때, 이미지 업
wildeveloperetrain.tistory.com
3-3. 결과화면
3-4. 유튜브 영상
https://www.youtube.com/watch?v=L_osf9DqqY4&list=PLV9zd3otBRt7jmXvwCkmvJ8dH5tR_20c0&index=19
'개발 프로젝트 > 게시물 프로젝트' 카테고리의 다른 글
18일차_게시판 프로젝트(11) (0) | 2024.03.27 |
---|---|
17일차_게시판 프로젝트(10) (0) | 2024.03.26 |
15일차_게시판 프로젝트(8) (0) | 2024.03.22 |
14일차_게시판 프로젝트(7) (0) | 2024.03.21 |
13일차_게시판 프로젝트(6) (0) | 2024.03.20 |