[Sprint Mission6]
1. ํ๋ก์ ํธ ๋ง์ผ์คํค
- ๋ฐ์ดํฐ๋ฒ ์ด์ค ํ๊ฒฝ ์ค์ ๋ฐ ๋ชจ๋ธ๋ง
- Spring Data JPA ํ๊ฒฝ ์ ์ฉ
- Entity ์ฐ๊ด ๊ด๊ณ ๋งคํ
- ๋ ํฌ์งํ ๋ฆฌ์ ์๋น์ค ๊ณ์ธต์ JPA ์ ์ฉ
- Transaction ์ฒ๋ฆฌ
- ํ์ด์ง๋ค์ด์ ๊ณผ ์ ๋ ฌ
- DTO์ ์ ๊ทน์ ์ธ ๋์ ๊ณผ MapStruct์ ํ์ฉ
- BinaryContent ์ ์ฅ ๋ก์ง ๊ณ ๋ํ
- ๋ฉํ์ ๋ณด์ ๋ฐ์ด๋๋ฆฌ ์ ๋ณด ๋ถ๋ฆฌ
- N+1 ๋ฌธ์ ํด๊ฒฐ
2. ๊ธฐ๋ณธ ์๊ตฌ์ฌํญ
2-1. API ๋ช ์ธ
- ์ด๋ฒ ๋ฏธ์ ์ ์๋์ API ์คํ๊ณผ ๋น๊ตํ๋ฉฐ ๊ตฌํํด๋ณด์ธ์.
- API ์คํ์ ์ค์ํ๋ค๋ฉด, ์๋์ ํ๋ก ํธ์๋ ์ฝ๋์ ํธํ๋ฉ๋๋ค.
โ ๏ธ ํ๋ก ํธ์๋ ์์ค ์ฝ๋๋ ์ฐธ๊ณ ์ฉ์ผ๋ก๋ง ํ์ฉํ์ธ์. ์์ ํ์ฌ ํ์ฉํ๋ ๊ฒฝ์ฐ ์ด์ด์ง๋ ์๊ตฌ์ฌํญ ๋๋ ๋ฏธ์ ์ ์ํํ๋ ๋ฐ ์ด๋ ค์์ด ์์ ์ ์์ต๋๋ค.
2-2. ๋ฐ์ดํฐ๋ฒ ์ด์ค
- ์๋์ ๊ฐ์ด ๋ฐ์ดํฐ๋ฒ ์ด์ค ํ๊ฒฝ์ ์ค์ ํ์ธ์.
- ๋ฐ์ดํฐ๋ฒ ์ด์ค:ย
discodeit - ์ ์ :ย
discodeit_user - ํจ์ค์๋:ย
notion ์ฐธ๊ณ
- ๋ฐ์ดํฐ๋ฒ ์ด์ค:ย
- ERD๋ฅผ ์ฐธ๊ณ ํ์ฌ DDL์ ์์ฑํ๊ณ , ํ
์ด๋ธ์ ์์ฑํ์ธ์.
-
์์ฑํ DDL ํ์ผ์ /src/main/resources/schema.sql ๊ฒฝ๋ก์ ํฌํจํ์ธ์.

PK: Primary KeyUK: Unique KeyNN: Not NullFK: Foreign KeyON DELETE CASCADE: ์ฐ๊ด ์ํฐํฐ ์ญ์ ์ ๊ฐ์ด ์ญ์ ON DELETE SET NULL: ์ฐ๊ด ์ํฐํฐ ์ญ์ ์ NULL๋ก ๋ณ๊ฒฝ
-
2-3. Spring Data JPA ์ ์ฉํ๊ธฐ
- Spring Data JPA์ PostgreSQL์ ์ํ ์์กด์ฑ์ ์ถ๊ฐํ์ธ์.
- ์์ ๊ตฌ์ฑํ ๋ฐ์ดํฐ๋ฒ ์ด์ค์ ์ฐ๊ฒฐํ๊ธฐ ์ํ ์ค์ ๊ฐ์ย
application.yamlย ํ์ผ์ ์์ฑํ์ธ์. - ๋๋ฒ๊น
์ ์ํด SQL ๋ก๊ทธ์ ๊ด๋ จ๋ ์ค์ ๊ฐ์ย
application.yamlย ํ์ผ์ ์์ฑํ์ธ์.
2-4. ์ํฐํฐ ์ ์ํ๊ธฐ
- ํด๋์ค ๋ค์ด์ด๊ทธ๋จ์ ์ฐธ๊ณ ํด ๋๋ฉ์ธ ๋ชจ๋ธ์ ๊ณตํต ์์ฑ์ ์ถ์ ํด๋์ค๋ก ์ ์ํ๊ณ ์์ ๊ด๊ณ๋ฅผ ๊ตฌํํ์ธ์.
- ์ด๋ Serializable ์ธํฐํ์ด์ค๋ ์ ์ธํฉ๋๋ค.
- ํจํค์ง๋ช
:
com.sprint.mission.discodeit.entity.base -
ํด๋์ค ๋ค์ด์ด๊ทธ๋จ

- JPA์ ์ด๋
ธํ
์ด์
์ ํ์ฉํด
createdAt,updatedAt์์ฑ์ด ์๋์ผ๋ก ์ค์ ๋๋๋ก ๊ตฌํํ์ธ์.@CreatedDate,ย@LastModifiedDate
- ํด๋์ค ๋ค์ด์ด๊ทธ๋จ์ ์ฐธ๊ณ ํด ํด๋์ค ์ฐธ์กฐ ๊ด๊ณ๋ฅผ ์์ ํ์ธ์. ํ์ํ ๊ฒฝ์ฐ ์์ฑ์, update ๋ฉ์๋๋ฅผ ์์ ํ ์ ์์ต๋๋ค. ๋จ, ์์ง JPA Entity์ ๊ด๋ จ๋ ์ด๋
ธํ
์ด์
์ ์์ฑํ์ง ๋ง์ธ์.
-
ํด๋์ค ๋ค์ด์ด๊ทธ๋จ

-
ํ์ดํ์ ๋ฐฉํฅ๊ณผ ํ์ดํ ์ ๋ฌด์ ์ ์ํ์ธ์.
-
- ERD์ ํด๋์ค ๋ค์ด์ด๊ทธ๋จ์ ํ ๋๋ก ์ฐ๊ด๊ด๊ณ ๋งคํ ์ ๋ณด๋ฅผ ํ๋ก ์ ๋ฆฌํด๋ณด์ธ์.(์ด ๋ด์ฉ์ PR์ ์ฒจ๋ถํด์ฃผ์ธ์.)
-
์์
์ํฐํฐ ๊ด๊ณ ๋ค์ค์ฑ ๋ฐฉํฅ์ฑ ๋ถ๋ชจ-์์ ๊ด๊ณ ์ฐ๊ด๊ด๊ณ์ ์ฃผ์ธ A:B 1:N BโA ๋จ๋ฐฉํฅ ๋ถ๋ชจ: A, ์์: B B ? ? ? ? ? ? ? ? ? ?
-
- JPA ์ฃผ์ ์ด๋
ธํ
์ด์
์ ํ์ฉํด ERD, ์ฐ๊ด๊ด๊ณ ๋งคํ ์ ๋ณด๋ฅผ ๋๋ฉ์ธ ๋ชจ๋ธ์ ๋ฐ์ํด๋ณด์ธ์.
@Entity,ย@Table@Column,ย@Enumerated@OneToMany,ย@OneToOne,ย@ManyToOne@JoinColumn,ย@JoinTable
- ERD์ ์ธ๋ํค ์ ์ฝ ์กฐ๊ฑด๊ณผ ์ฐ๊ด๊ด๊ณ ๋งคํ ์ ๋ณด์ ๋ถ๋ชจ-์์ ๊ด๊ณ๋ฅผ ๊ณ ๋ คํด ์์์ฑ ์ ์ด์ ๊ณ ์ ๊ฐ์ฒด๋ฅผ ์ ์ํ์ธ์.
cascade,ยorphanRemoval
2-5. ๋ ํฌ์งํ ๋ฆฌ์ ์๋น์ค์ JPA ๋์ ํ๊ธฐ
- ๊ธฐ์กด์ Repository ์ธํฐํ์ด์ค๋ฅผ JPARepository๋ก ์ ์ํ๊ณ ์ฟผ๋ฆฌ๋ฉ์๋๋ก ๋์ฒดํ์ธ์.
- FileRepository์ JCFRepository ๊ตฌํ์ฒด๋ ์ญ์ ํฉ๋๋ค.
- ์์์ฑ ์ปจํ
์คํธ์ ํน์ง์ ๋ง์ถ์ด ์๋น์ค ๋ ์ด์ด๋ฅผ ์์ ํด๋ณด์ธ์.
- ํํธ:ย
ํธ๋์ญ์ ,ย์์์ฑ ์ ์ด,ย๋ณ๊ฒฝ ๊ฐ์ง,ย์ง์ฐ๋ก๋ฉ
- ํํธ:ย
2-6. DTO ์ ๊ทน ๋์ ํ๊ธฐ
- Entity๋ฅผ Controller ๊น์ง ๊ทธ๋๋ก ๋
ธ์ถํ์ ๋ ๋ฐ์ํ ์ ์๋ ๋ฌธ์ ์ ์ ๋ํด ์ ๋ฆฌํด๋ณด์ธ์. DTO๋ฅผ ์ ๊ทน ๋์
ํ์ ๋ ๋ณด์ผ๋ฌํ๋ ์ดํธ ์ฝ๋๊ฐ ๋ง์์ง์ง๋ง, ๊ทธ๋ผ์๋ ๋ถ๊ตฌํ๊ณ ์ด๋ค ์ด์ ์ด ์๋์ง ์ ์ ์์๊ฑฐ์์.(์ด ๋ด์ฉ์ PR์ ์ฒจ๋ถํด์ฃผ์ธ์.)
- ํํธ
- Entity์ API์ ๊ฒฐํฉ
- ํ๋ก๋์ ํ๊ฒฝ์์๋ ์ฑ๋ฅ์ ๊ณ ๋ คํด OSIV๋ฅผ false๋ก ์ค์ ํ๋ ๊ฒฝ์ฐ๊ฐ ๋๋ถ๋ถ
- ์๋ฐฉํฅ ์ฐ๊ด๊ด๊ณ ์ ์ํ ์ฐธ์กฐ
- ๋ฏผ๊ฐํ ๋ฐ์ดํฐ
- ํํธ
- ๋ค์์ ํด๋์ค ๋ค์ด์ด๊ทธ๋จ์ ์ฐธ๊ณ ํ์ฌ DTO๋ฅผ ์ ์ํ์ธ์.

- Entity๋ฅผ DTO๋ก ๋งคํํ๋ ๋ก์ง์ ์ฑ
์์ง๋ Mapper ์ปดํฌ๋ํธ๋ฅผ ์ ์ํด ๋ฐ๋ณต๋๋ ์ฝ๋๋ฅผ ์ค์ฌ๋ณด์ธ์.
- ํจํค์ง๋ช
:ย
com.sprint.mission.discodeit.mapper

- ํจํค์ง๋ช
:ย
2-7. BinaryContent ์ ์ฅ ๋ก์ง ๊ณ ๋ํ
๋ฐ์ดํฐ๋ฒ ์ด์ค์ ์ด๋ฏธ์ง์ ๊ฐ์ ํ์ผ์ ์ ์ฅํ๋ฉด ์ฑ๋ฅ ์ ๋ถ๋ฆฌํ ์ ์ด ๋ง์ต๋๋ค. ๋ฐ๋ผ์ ์ค์ ๋ฐ์ด๋๋ฆฌ ๋ฐ์ดํฐ๋ ๋ณ๋์ ๊ณต๊ฐ์ ์ ์ฅํ๊ณ , ๋ฐ์ดํฐ๋ฒ ์ด์ค์๋ ๋ฐ์ด๋๋ฆฌ ๋ฐ์ดํฐ์ ๋ํ ๋ฉํ ์ ๋ณด(ํ์ผ๋ช , ํฌ๊ธฐ, ์ ํ ๋ฑ)๋ง ์ ์ฅํ๋ ๊ฒ์ด ์ข์ต๋๋ค.
- BinaryContent ์ํฐํฐ๋ ํ์ผ์ ๋ฉํ ์ ๋ณด(
fileName,size,contentType)๋ง ํํํ๋๋กbytes์์ฑ์ ์ ๊ฑฐํ์ธ์. - BinaryContent์
byte[]๋ฐ์ดํฐ ์ ์ฅ์ ๋ด๋นํ๋ ์ธํฐํ์ด์ค๋ฅผ ์ค๊ณํ์ธ์. ์ ์ฅ ๋งค์ฒด์ ํ์ฅ์ฑ(๋ก์ปฌ ์ ์ฅ์, ์๊ฒฉ ์ ์ฅ์)์ ๊ณ ๋ คํด ์ธํฐํ์ด์ค๋ถํฐ ์ค๊ณํฉ๋๋ค.- ํจํค์ง๋ช
:
com.sprint.mission.discodeit.storage -
ํด๋์ค ๋ค์ด์ด๊ทธ๋จ

- BinaryContentStorage
- ๋ฐ์ด๋๋ฆฌ ๋ฐ์ดํฐ์ ์ ์ฅ/๋ก๋๋ฅผ ๋ด๋นํ๋ ์ปดํฌ๋ํธ์ ๋๋ค.
UUID put(UUID, byte[])- UUID ํค ์ ๋ณด๋ฅผ ๋ฐํ์ผ๋กย
byte[]ย ๋ฐ์ดํฐ๋ฅผ ์ ์ฅํฉ๋๋ค. - UUID๋ BinaryContent์ Id ์ ๋๋ค.
- UUID ํค ์ ๋ณด๋ฅผ ๋ฐํ์ผ๋กย
InputStream get(UUID)- ํค ์ ๋ณด๋ฅผ ๋ฐํ์ผ๋กย
byte[]ย ๋ฐ์ดํฐ๋ฅผ ์ฝ์ด InputStream ํ์ ์ผ๋ก ๋ฐํํฉ๋๋ค. - UUID๋ BinaryContent์ Id ์ ๋๋ค.
- ํค ์ ๋ณด๋ฅผ ๋ฐํ์ผ๋กย
ResponseEntity<?> download(BinaryContentDto)- HTTP API๋ก ๋ค์ด๋ก๋ ๊ธฐ๋ฅ์ ์ ๊ณตํฉ๋๋ค.
- BinaryContentDto ์ ๋ณด๋ฅผ ๋ฐํ์ผ๋ก ํ์ผ์ ๋ค์ด๋ก๋ํ ์ ์๋ ์๋ต์ ๋ฐํํฉ๋๋ค.
- ํจํค์ง๋ช
:
- ์๋น์ค ๋ ์ด์ด์์ ๊ธฐ์กด์ BinaryContent๋ฅผ ์ ์ฅํ๋ ๋ก์ง์ BinaryContentStorage๋ฅผ ํ์ฉํ๋๋ก ๋ฆฌํฉํ ๋งํ์ธ์.
- BinaryContentController์ ํ์ผ์ ๋ค์ด๋ก๋ํ๋ API๋ฅผ ์ถ๊ฐํ๊ณ , BinaryContentStorage์ ๋ก์ง์ ์์ํ์ธ์.
- ์๋ํฌ์ธํธ:
GET /api/binaryContents/{binaryContentId}/download - ์์ฒญ
- ๊ฐ: BinaryContentId
- ๋ฐฉ์: Query Parameter
- ์๋ต:
ResponseEntity<?> -
ํด๋์ค ๋ค์ด์ด๊ทธ๋จ

- ์๋ํฌ์ธํธ:
- ๋ก์ปฌ ๋์คํฌ ์ ์ฅ ๋ฐฉ์์ผ๋ก BinaryContentStorage ๊ตฌํ์ฒด๋ฅผ ๊ตฌํํ์ธ์.
-
ํด๋์ค ๋ค์ด์ด๊ทธ๋จ

-
discodeit.storage.type๊ฐ์ดlocal์ธ ๊ฒฝ์ฐ์๋ง Bean์ผ๋ก ๋ฑ๋ก๋์ด์ผ ํฉ๋๋ค.Path root- ๋ก์ปฌ ๋์คํฌ์ ๋ฃจํธ ๊ฒฝ๋ก์ ๋๋ค.
discodeit.storage.local.root-pathย ์ค์ ๊ฐ์ ์ ์ํ๊ณ , ์ด ๊ฐ์ ํตํด ์ฃผ์ ํฉ๋๋ค.
void init()- ๋ฃจํธ ๋๋ ํ ๋ฆฌ๋ฅผ ์ด๊ธฐํํฉ๋๋ค.
- Bean์ด ์์ฑ๋๋ฉด ์๋์ผ๋ก ํธ์ถ๋๋๋ก ํฉ๋๋ค.
Path resolvePath(UUID)- ํ์ผ์ ์ค์ ์ ์ฅ ์์น์ ๋ํ ๊ท์น์ ์ ์ํฉ๋๋ค.
- ํ์ผ ์ ์ฅ ์์น ๊ท์น ์์:ย
{root}/{UUID}
- ํ์ผ ์ ์ฅ ์์น ๊ท์น ์์:ย
put,ยgetย ๋ฉ์๋์์ ํธ์ถํด ์ผ๊ด๋ ํ์ผ ๊ฒฝ๋ก ๊ท์น์ ์ ์งํฉ๋๋ค.
- ํ์ผ์ ์ค์ ์ ์ฅ ์์น์ ๋ํ ๊ท์น์ ์ ์ํฉ๋๋ค.
ResponseEntity<Resource> donwload(BinaryContentDto)getย ๋ฉ์๋๋ฅผ ํตํด ํ์ผ์ ๋ฐ์ด๋๋ฆฌ ๋ฐ์ดํฐ๋ฅผ ์กฐํํฉ๋๋ค.- BinaryContentDto์ ๋ฐ์ด๋๋ฆฌ ๋ฐ์ดํฐ๋ฅผ ํ์ฉํดย
ResponseEntity<Resource>ย ์๋ต์ ์์ฑ ํ ๋ฐํํฉ๋๋ค.
2-8. ํ์ด์ง๊ณผ ์ ๋ ฌ
- ๋ฉ์์ง ๋ชฉ๋ก์ ์กฐํํ ๋ ๋ค์์ ์กฐ๊ฑด์ ๋ฐ๋ผ ํ์ด์ง๋ค์ด์
์ฒ๋ฆฌ๋ฅผ ํด๋ณด์ธ์.
- 50๊ฐ์ฉ ์ต๊ทผ ๋ฉ์์ง ์์ผ๋ก ์กฐํํฉ๋๋ค.
- ์ด ๋ฉ์์ง๊ฐ ๋ช๊ฐ์ธ์ง ์ ํ์๋ ์์ต๋๋ค.
- ์ผ๊ด๋ ํ์ด์ง๋ค์ด์
์๋ต์ ์ํด ์ ๋ค๋ฆญ์ ํ์ฉํด DTO๋ก ๊ตฌํํ์ธ์.
- ํจํค์ง๋ช
:
com.sprint.mission.discodeit.dto.response -
ํด๋์ค ๋ค์ด์ด๊ทธ๋จ

content: ์ค์ ๋ฐ์ดํฐ์ ๋๋ค.number: ํ์ด์ง ๋ฒํธ์ ๋๋ค.size: ํ์ด์ง์ ํฌ๊ธฐ์ ๋๋ค.totalElements: T ๋ฐ์ดํฐ์ ์ด ๊ฐฏ์๋ฅผ ์๋ฏธํ๋ฉฐ, null์ผ ์ ์์ต๋๋ค.
- ํจํค์ง๋ช
:
- Slice ๋๋ Page ๊ฐ์ฒด๋ก๋ถํฐ DTO๋ฅผ ์์ฑํ๋ Mapper๋ฅผ ๊ตฌํํ์ธ์.
-
ํจํค์ง๋ช :
com.sprint.mission.discodeit.mapper
-
ํ์ฅ์ฑ์ ์ํด ์ ๋ค๋ฆญ ๋ฉ์๋๋ก ๊ตฌํํ์ธ์.
-
3. ์ฌํ ์๊ตฌ์ฌํญ
3-1. N+1 ๋ฌธ์
- N+1 ๋ฌธ์ ๊ฐ ๋ฐ์ํ๋ ์ฟผ๋ฆฌ๋ฅผ ์ฐพ๊ณ ํด๊ฒฐํด๋ณด์ธ์.
3-2. ์ฝ๊ธฐ์ ์ฉ ํธ๋์ญ์ ํ์ฉ
- ํ๋ก๋์
ํ๊ฒฝ์์๋ OSIV๋ฅผ ๋นํ์ฑํํ๋ ๊ฒฝ์ฐ๊ฐ ๋ง์ต๋๋ค. ์ด๋ ์๋น์ค ๋ ์ด์ด์ ์กฐํ ๋ฉ์๋์์ ๋ฐ์ํ ์ ์๋ ๋ฌธ์ ๋ฅผ ์๋ณํ๊ณ , ์ฝ๊ธฐ ์ ์ฉ ํธ๋์ญ์
์ ํ์ฉํด ๋ฌธ์ ๋ฅผ ํด๊ฒฐํด๋ณด์ธ์.
- OSIV ๋นํ์ฑํํ๊ธฐ
spring: jpa: open-in-view: false
- OSIV ๋นํ์ฑํํ๊ธฐ
3-3. ํ์ด์ง๋ค์ด์ ์ต์ ํ
- ์คํ์ ํ์ด์ง๋ค์ด์ ๊ณผ ์ปค์ ํ์ด์ง๋ค์ด์ ๋ฐฉ์์ ์ฐจ์ด์ ๋ํด ์ ๋ฆฌํด๋ณด์ธ์.
์ด ๋ด์ฉ์ PR์ ์ฒจ๋ถํด์ฃผ์ธ์.
- ๊ธฐ์กด์ ๊ตฌํํ ์คํ์
ํ์ด์ง๋ค์ด์
์ ์ปค์ ํ์ด์ง๋ค์ด์
์ผ๋ก ๋ฆฌํฉํ ๋งํ์ธ์.
-
PageResponse๋ ๋ค์๊ณผ ๊ฐ์ด ๋ณ๊ฒฝํ์ธ์.

- ๋ค์์ API ๋ช ์ธ๋ฅผ ์ค์ํ์ธ์.
- API ์คํ์ ์ค์ํ๋ค๋ฉด, ์๋์ ํ๋ก ํธ์๋ ์ฝ๋์ ํธํ๋ฉ๋๋ค.
-
โ ๏ธ ํ๋ก ํธ์๋ ์์ค ์ฝ๋๋ ์ฐธ๊ณ ์ฉ์ผ๋ก๋ง ํ์ฉํ์ธ์. ์์ ํ์ฌ ํ์ฉํ๋ ๊ฒฝ์ฐ ์ด์ด์ง๋ ์๊ตฌ์ฌํญ ๋๋ ๋ฏธ์ ์ ์ํํ๋ ๋ฐ ์ด๋ ค์์ด ์์ ์ ์์ต๋๋ค.
3-4. MapStruct ์ ์ฉ
- Entity์ DTO๋ฅผ ๋งคํํ๋ ๋ณด์ผ๋ฌํ๋ ์ดํธ ์ฝ๋๋ฅผย MapStructย ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ํ์ฉํด ๊ฐ์ํํด๋ณด์ธ์.
Leave a comment