BinaryContent 저장로직 고도화

2026. 3. 9. 17:43·코드잇 스프린트/실습

데이터베이스에 이미지와 같은 파일을 저장하면 성능 상 불리한 점이 많습니다.

따라서 실제 바이너리 데이터는 별도의 공간에 저장하고, 데이터베이스에는 바이너리 데이터에 대한 메타 정보(파일명, 크기, 유형 등)만 저장하는 것이 좋습니다.

 

전체 동작 흐름

서비스에서 파일 업로드시 발생흐름은Client ->  Contoller -> BinaryContentService.create()BinaryContentService.create()내 DB에 bytes를 제외한 이름,size,contentType등의 메타 데이터 저장binaryContentStorage.put()으로 로컬 디스크에 저장. {root}/{UUID} 경로에 ...

 

다운로드 흐름

Client -> GET /api/binaryContents{binaryContentId}/download URI로 요청BinaryContentController -> binaryContentStorage.download()  반환

 

BinaryContent
id          : 550e8400-e29b-41d4-a716-446655440000
fileName    : profile.png
contentType : image/png
size        : 24500

이런 메타데이터가 DB에 저장이 된다.

로컬 디스크 저장 위치는 storage/550e8400-e29b-41d4-a716-446655440000

이 파일은 실제 PNG 바이너리 데이터가 들어있는 파일이다.

 

@Override
    public ResponseEntity<Resource> download(BinaryContentDto dto) {

        InputStream stream = get(dto.id());

        Resource resource = new InputStreamResource(stream);

        return ResponseEntity.ok()
                .header(
                        HttpHeaders.CONTENT_DISPOSITION,
                        "attachment; filename=\"" + dto.fileName() + "\""
                )
                .contentType(MediaType.parseMediaType(dto.contentType()))
                .body(resource);


    }

다운로드 요청을 하게 되면 

GET /api/binaryContents/550e8400-e29b-41d4-a716-446655440000/download

이렇게 들어오고, Controller 내부에서 

BinaryContentDto dto = new BinaryContentDto(
    550e8400-e29b-41d4-a716-446655440000,
    "profile.png",
    24500L,
    "image/png",
    null
);

이렇게 생성되고, 이를

binaryContentStorage.download(binaryContentDto);

를 호출한 결과를 반환한다.

 

BinaryContentStorage의 구현체 내 download() 실행

@Override
    public InputStream get(UUID id) {
        Path path = resolvePath(id);

        try {
            return Files.newInputStream(path);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }

    }

@Override
    public ResponseEntity<Resource> download(BinaryContentDto dto) {

        InputStream stream = get(dto.id());

        Resource resource = new InputStreamResource(stream);

        return ResponseEntity.ok()
                .header(
                        HttpHeaders.CONTENT_DISPOSITION,
                        "attachment; filename=\"" + dto.fileName() + "\""
                )
                .contentType(MediaType.parseMediaType(dto.contentType()))
                .body(resource);


    }
  • get() 함수내 resolvePath(id)에는 
  •  
private Path resolvePath(UUID id){
        return root.resolve(id.toString());
    }

"550e8400-e29b-41d4-a716-446655440000"라는 문자열

root는 사용자가 설정한 "storage" 라는 폴더 경로.

storage.resolve("550e8400-e29b-41d4-a716-446655440000") ->  storage/550e8400-e29b-41d4-a716-446655440000

가 resolvePath의 반환값이 된다.

 

따라서 get()내 path =  storage/550e8400-e29b-41d4-a716-446655440000가 될것이고,

Files.newInputStream(path)를 통해  "storage/550e8400-e29b-41d4-a716-446655440000" 파일을 열고 읽을 수 있는 스트림을 만들어줘 -> 해당 파일이 실제로 존재하면 파일을 읽을 수 있는 InputStream 객체가 생성된다.

 

따라서 download()내 stream 객체에는 파일을 읽을 수 있는 InputStream 객체가 담긴다.

-> storage/550e8400-e29b-41d4-a716-446655440000 파일을 읽는 스트림

 

그 다음 stream을 Spring이 HTTP 응답으로 다룰 수 있게 포장한다.

 

다운 흐름

Local Disk
storage/{UUID}
      │
      ▼
Files.newInputStream()
      │
      ▼
InputStream
      │
      ▼
InputStreamResource
      │
      ▼
ResponseEntity<Resource>
      │
      ▼
HTTP Response
      │
      ▼
Browser Download

 

'코드잇 스프린트 > 실습' 카테고리의 다른 글

디스코드 프로젝트 실습: JPA Public 채널생성시 ReadStatus에 채널id가 null값으로 들어간다.  (0) 2026.03.10
MapStruct는 <T> 제네릭 타입 메서드 자체는 구현코드 생성 못한다.  (0) 2026.03.10
MapStruct 라이브러리를 통해 Entity를 DTO로 자동 변환  (0) 2026.03.09
Entity를 Controller까지 그대로 노출 할때 발생할 수 있는 문제점  (0) 2026.03.09
디스코드 프로젝트 실습: Entity 정의하기(JPA 어노테이션,cascade,고아객체)  (0) 2026.03.05
'코드잇 스프린트/실습' 카테고리의 다른 글
  • 디스코드 프로젝트 실습: JPA Public 채널생성시 ReadStatus에 채널id가 null값으로 들어간다.
  • MapStruct는 <T> 제네릭 타입 메서드 자체는 구현코드 생성 못한다.
  • MapStruct 라이브러리를 통해 Entity를 DTO로 자동 변환
  • Entity를 Controller까지 그대로 노출 할때 발생할 수 있는 문제점
과컴
과컴
벡엔드 개발자 최소기준 맞추겠습니다.
  • 과컴
    곽의 프로그램
    과컴
  • 전체
    오늘
    어제
    • 분류 전체보기 (76)
      • 위클리페이퍼 (6)
      • 파이썬 (4)
      • 코드잇 스프린트 (48)
        • Spring 이론 (7)
        • Java이론 (11)
        • 실습 (23)
      • 백엔드 개발자 최소기준 (1)
      • 코딩테스트 (5)
        • 알고리즘 (0)
        • SQL (1)
      • Git (5)
      • 스프링부트 핵심가이드 (1)
      • 트러블 슈팅 (2)
  • 블로그 메뉴

    • 홈
  • 링크

  • 공지사항

  • 인기 글

  • 태그

    파이썬기초
    백준1075번
    혼공파
    파이썬
    백준2576
    백준브론즈
    문자열
    백준1152
    파이썬입문
  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.6
과컴
BinaryContent 저장로직 고도화
상단으로

티스토리툴바