yu-jin-song님의 게시판 구현 게시물을 참고하였습니다.
✔️ 구현기능
- 게시글 작성 및 파일 업로드 동시 처리
- 다중 파일 업로드
- DB에 파일 자체를 저장하지 않고 파일 관련 정보만 저장. 실제 파일은 서버 내 지정 경로에 저장
// application.yml
spring:
servlet:
multipart:
maxFileSize: 10MB
maxRequestSize: 20MB
// build.gradle
dependencies {
...
implementation 'commons-io:commons-io:2.6'
}
IOUtils
패키지는 대부분 static 메소드이기 때문에 객체를 생성하지 않고 바로 사용 가능하다.
IOUtils
패키지 중 org.apache.commons.io.FileUtils
를 사용해 파일 관련 처리를 수행한다.
: 파일 정보가 저장될 entity
Board entity와의 관계는 다대일관계(N:1)이다.
(하나의 게시글이 여러 파일을 가짐)
⚠️ File
이 자체를 클래스 명으로 사용하지 않도록 주의하기
추후 수정
@JsonBackReference
: 순환참조를 방어하기 위한 어노테이션사용방법은 부모 클래스에
@JsonManagedReference
,
자식 클래스에@JsonBackReference
어노테이션을 추가해주면 된다.
// Board.java 코드 중 ... @OneToMany( mappedBy = "board", cascade = {CascadeType.PERSIST, CascadeType.REMOVE}, orphanRemoval = true ) ...
✔️
@OneToMany
옵션
- optional
: 해당 객체에 null이 들어갈 수 있는지
(@Column
어노테이션에서도nullable=true
로 세팅해도 null이 들어갈 수 있음)
- fetch
: 엔티티의 로딩 방식
-EAGER
: 연관된 엔티티를 바로 로딩
-LAZY
: 바로 로딩하지 않고 실제 해당 객체를 조회할 때 해당 엔티티를 로딩✔️ default값
@ManyToOne
:FetchType.EAGER
@OneToMany
:FetchType.LAZY
- cascade
: 영속성 전이 설정
-PERSIST
: 부모 엔티티를 저장할 때 자식 엔티티도 함께 저장
-REMOVE
: 부모 엔티티를 삭제하면 자식 엔티티도 함께 삭제
-DETACH
: 부모 엔티티가 Detach되면 자식 엔티티도 함께 detach. 즉, 변경사항이 반영되지 않는 상태가 됨
-REFRESH
: 부모 엔티티가 DB로부터 데이터를 다시 로드하면 자식 엔티티도 DB로부터 데이터를 다시 로딩
-MERGE
: 부모 엔티티가 detach 상태에서 자식 엔티티를 추가/변경한 이후 부모 엔티티가 merge를 수행하면 자식 엔티티도 변경 사항이 적용됨
-ALL
: 모든 cascade 옵션이 적용됨
- orphanRemoval
: 고아 객체를 삭제
이 옵션이true
라면 기존 null 처리된 자식을 delete
추후 수정
@RequestBody
: body로 전달받은 JSON 형태의 데이터를 파싱Content-Type이 multipart/form-data로 전달되어 올 때는 예외 발생
➡️ 그런데 파일/이미지는 multipart/form-data 형태로 요청하기 때문에 @RequestBody
를 사용할 수 없다.
yu-jin-song님의 블로그 Controller 부분 참고하기
yu-jin-song님의 블로그 Controller 부분 참고하기
실무에서는 두 방법을 혼합하여 사용하기도 한다고 한다.
추후 수정
추후 수정
-
File.separator
: 이 API를 통해 각 OS에 호환되는 파일 경로를 구함
📌 List의
null
vsisEmpty()
null
: List의 변수가 그 어떤 주솟값도 참조하지 않은 상태
(인스턴스가 존재하지 않는 상태)
isEmpty()
: 인스턴스는 생성된 상태 또는 주솟값을 참조하고는 있지만 아무런 데이터가 적재되어 있지 않은 상태
순환참조 참고
@OneToMany 옵션 참고
@OneToMany orphanRemoval 참고
게시판 구현 참고