파일 데이터 전송하기 (1)

화낼거양's avatar
Dec 06, 2024
파일 데이터 전송하기 (1)
 
 

multipart/form-data 란?

 
💡
multipart/form-data는 폼 데이터가 여러 부분으로 나뉘어져 전송되는 인코딩 타입입니다. 주로 파일 업로드와 같이 큰 데이터를 포함한 폼을 서버로 전송할 때 사용됩니다. 이 방식은 각 부분이 경계(boundary)로 구분되며, 각각의 부분은 파일, 텍스트 필드 등 다양한 데이터를 포함할 수 있습니다.
 

주요 특징

 
  1. 복수 부분:
      • 폼 데이터는 여러 부분으로 나뉩니다. 각각의 부분은 텍스트 필드 값이나 파일을 포함할 수 있습니다.
      • 각 부분은 경계(boundary) 문자열로 구분됩니다.
  1. 파일 업로드 지원:
      • 파일과 같은 바이너리 데이터를 전송할 때 적합합니다.
      • 텍스트 필드와 파일을 동일한 폼으로 함께 전송할 수 있습니다.
  1. 헤더 정보:
      • 각 부분은 고유의 헤더를 가지며, 콘텐츠 타입, 이름 등의 정보가 포함됩니다.
      • 예: Content-Disposition: form-data; name="fieldname"; filename="filename.jpg"
 

예시

 
아래는 multipart/form-data를 사용하여 텍스트 필드와 파일을 전송하는 예시입니다:
<form action="/upload" method="post" enctype="multipart/form-data"> <input type="text" name="username"> <br> <input type="file" name="file"> <br> <input type="submit" value="Upload"> </form>
 
 

폼 태그

 
<form action="/v1/upload" method="post" enctype="multipart/form-data">
  • action="/v1/upload": 폼이 제출될 때 데이터를 전송할 URL입니다. 여기서는 "/v1/upload"로 전송됩니다.
  • method="post": 데이터를 전송할 HTTP 메서드를 지정합니다. POST 메서드는 데이터를 서버로 전송하는 데 사용됩니다.
  • enctype="multipart/form-data": 파일과 같은 바이너리 데이터를 전송할 때 필요한 인코딩 타입입니다.
 

입력 필드

 
  1. 사용자 이름 입력:
    1. `<input type="text" name="username"> <br>`
      • type="text": 텍스트 입력 필드를 생성합니다.
      • name="username": 입력 필드의 이름을 지정합니다. 서버로 전송될 때 이 이름으로 값을 참조합니다.
  1. 파일 업로드 입력:
    1. <input type="file" name="img"> <br>
      • type="file": 파일 선택 입력 필드를 생성합니다.
      • name="img": 입력 필드의 이름을 지정합니다. 사용자가 선택한 파일을 서버로 전송할 때 이 이름으로 파일을 참조합니다.
  1. 제출 버튼:
    1. <input type="submit">
      • type="submit": 폼 제출 버튼을 생성합니다. 사용자가 이 버튼을 클릭하면 폼 데이터가 지정된 action URL로 전송됩니다.
 
 
서버로 전송되는 데이터는 다음과 같이 구성됩니다:
Content-Type: multipart/form-data; boundary=----WebKitFormBoundary7MA4YWxkTrZu0gW ------WebKitFormBoundary7MA4YWxkTrZu0gW Content-Disposition: form-data; name="username" JohnDoe ------WebKitFormBoundary7MA4YWxkTrZu0gW Content-Disposition: form-data; name="file"; filename="photo.jpg" Content-Type: image/jpeg (binary data) ------WebKitFormBoundary7MA4YWxkTrZu0gW--
여기서 boundary는 각 부분을 구분하는 문자열입니다. 각 부분은 Content-Disposition 헤더로 이름과 파일 이름 등을 지정하며, 파일의 경우 Content-Type 헤더로 파일의 MIME 타입을 나타냅니다.
 
 
 
 

데이터를 전달받고, DB에 저장하기

 
💡
html파일 내용은 위의 form태그 예제와 동일합니다.
 
 
Controller :
@PostMapping("/v1/upload") public String v1Upload(UploadRequest.V1DTO v1DTO) { uploadService.v1사진저장(v1DTO); return "index"; }
 
Service :
@Transactional public void v1사진저장(UploadRequest.V1DTO v1DTO){ // static 메서드로 프로젝트에 이미지를 저장한 뒤 db에 저장할 dbUrl 문자열을 반환합니다. String dbUrl = FileUtil.fileSave(v1DTO.getImg()); // db에 저장 uploadRepository.save(v1DTO.toEntity(dbUrl)); }
 
Service에서 사용한 fileSave 메서드 :
public class FileUtil { public static String fileSave(MultipartFile file) { // 1. DTO에 사진파일명을 롤링 시킨다. String imgName = UUID.randomUUID()+"_"+file.getOriginalFilename(); String profileUrl = "images/"+imgName; String dbUrl = "/upload/"+imgName; // 2. DTO에 사진을 파일로 저장 (images 폴더) try { Path path = Paths.get(profileUrl); Files.write(path, file.getBytes()); return dbUrl; } catch (IOException e) { throw new RuntimeException(e.getMessage()); } } }
 

프로젝트 저장경로와 DB저장 경로

 
  1. 프로젝트에 저장하는 경로:
      • profileUrl 변수에 지정된 "images/" + imgName 경로는 실제 파일이 저장되는 서버의 디렉토리를 나타냅니다.
      • 예: images/unique-identifier_filename.jpg
      • 이는 서버 내부의 디렉토리 경로로, 파일 시스템에서 직접 접근할 수 있는 경로입니다.
  1. 데이터베이스에 저장하는 경로:
      • dbUrl 변수에 지정된 "/upload/" + imgName 경로는 웹에서 접근 가능한 URL을 나타냅니다.
      • 예: /upload/unique-identifier_filename.jpg
      • 이는 클라이언트가 파일에 접근할 수 있도록 서버에서 제공하는 URL입니다.
 

경로가 서로 다른 이유?

 
보안상의 이유로, 실제 파일이 저장된 경로와 클라이언트가 접근하는 경로를 분리하는 것이 일반적입니다. 이렇게 하면 다음과 같은 이점을 얻을 수 있습니다:
 
  • 파일 보호: 서버의 내부 디렉토리 구조를 외부에 노출하지 않음으로써 파일 시스템을 보호할 수 있습니다.
  • URL 관리: 웹 서버가 제공하는 URL을 통해 파일에 접근 권한을 제어할 수 있습니다. 예를 들어, 특정 사용자만 파일에 접근할 수 있도록 설정할 수 있습니다.
  • 유연성: 파일 경로를 변경하더라도 클라이언트 측의 URL은 유지될 수 있습니다.
 
Repository :
public void save(Upload upload) { em.persist(upload); }
 
Share article

moohyun