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

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

ajax를 이용하여 파일 전송하기

 
 

주요 특징

 

1. 비동기 통신

  • 페이지 새로고침 없이 통신: AJAX를 사용하면 파일 업로드를 포함한 서버와의 통신을 비동기적으로 처리할 수 있습니다. 이를 통해 사용자 경험이 향상되고, 페이지 새로고침 없이 데이터를 전송하고 받을 수 있습니다.

2. 사용자 인터페이스 향상

  • 실시간 응답: 파일 업로드 진행 상황을 실시간으로 사용자에게 보여줄 수 있어, 대기 시간 동안의 피드백을 제공할 수 있습니다.
  • 다양한 알림: 업로드 성공, 실패, 진행 상황 등 다양한 상태를 사용자에게 즉시 알릴 수 있습니다.

3. 보안

  • CSRF 보호: AJAX 요청은 일반적으로 CSRF 토큰을 포함하여 전송되므로, 보안 위협으로부터 데이터를 보호할 수 있습니다.
  • HTTPS 사용 권장: 민감한 데이터 전송 시 HTTPS를 사용하여 데이터의 무결성과 기밀성을 보장할 수 있습니다.
 
 
 

ajax 예시 :

 

html :

<!doctype html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1"> <title>Document</title> </head> <body> <h1>사진 파일 전송</h1> <hr> <form> <input type="text" id="username"><br> <input type="file" id="img"><br> </form> <script> let imgInput = document.querySelector("#img"); imgInput.addEventListener("change", (e) => { let file = imgInput.files[0]; //console.log("file", file); let reader = new FileReader(); reader.onload = () => { let username = document.querySelector("#username").value; let base64String = reader.result; //console.log(base64String); myUpload(username, base64String); } reader.readAsDataURL(file); }); async function myUpload(username, img) { let user = { username: username, img: img } let requestBody = JSON.stringify(user); //console.log(requestBody); let response = await fetch("v2/upload", { method: "post", body: requestBody, headers: { "Content-Type": "application/json; charset=utf-8" } }); let responseBody = await response.json(); if (responseBody.success) { location.href = "/"; } } </script> </body> </html>
 

JavaScript 코드 설명 :

 
  1. 파일 입력 필드 이벤트 리스너:
      • imgInput 변수는 파일 입력 필드(input[type="file"])를 선택합니다.
      • imgInput.addEventListener("change", (e) => { ... }): 파일 입력 필드의 변경 이벤트를 감지합니다.
        • 파일이 선택되면 file 변수에 파일 객체를 저장합니다.
        • FileReader 객체를 사용하여 파일을 읽습니다.
        • 파일이 읽히면 onload 이벤트 핸들러가 호출되어 다음 작업을 수행합니다:
          • 사용자 이름과 파일의 Base64 인코딩 문자열을 추출합니다.
          • myUpload 함수를 호출하여 파일을 서버에 업로드합니다.
  1. 비동기 파일 업로드 함수:
      • myUpload 함수는 사용자 이름과 Base64 인코딩된 파일을 매개변수로 받습니다.
      • 사용자 이름과 이미지를 포함하는 객체를 생성하여 JSON 문자열로 변환합니다.
      • fetch API를 사용하여 서버에 비동기적으로 POST 요청을 전송합니다.
        • 요청 본문에는 JSON 문자열이 포함됩니다.
        • 헤더에는 Content-Typeapplication/json; charset=utf-8로 설정합니다.
      • 서버 응답을 JSON 형식으로 파싱하고, 응답이 성공적일 경우 메인 페이지로 리디렉션합니다.
 
 
 

Controller :

@PostMapping("/v2/upload") public ResponseEntity<?> v2Upload(@RequestBody UploadRequest.V2DTO v2DTO) { uploadService.v2사진저장(v2DTO); Resp resp = new Resp(true, "성공", null); return ResponseEntity.ok(resp); }
 

변경점

 
  • 메서드 서명:
    • public ResponseEntity<?> v2Upload(@RequestBody UploadRequest.V2DTO v2DTO)
    • V2DTO필드 : name(String), img(String)
  • 업로드 서비스 호출:
    • uploadService.v2사진저장(v2DTO);
    • uploadServicev2사진저장 메서드를 호출하여 v2DTO를 통해 전달된 데이터를 처리합니다.
  • 응답 객체 생성:
    • Resp resp = new Resp(true, "성공", null);
    • Resp 객체를 생성하여 클라이언트로 보낼 응답 데이터를 구성합니다.
    • Resp 객체의 필드:
      • success 필드: 업로드가 성공했음을 나타내는 true 값.
      • message 필드: 응답 메시지로 "성공"을 설정.
      • data 필드: 추가적인 데이터가 없는 경우 null로 설정.
  • 응답 반환:
    • return ResponseEntity.ok(resp);
    • ResponseEntity.ok(resp)를 호출하여 HTTP 200 OK 상태와 함께 Resp 객체를 응답 본문으로 반환합니다.
 
 
 
 

Service :

@Transactional public void v2사진저장(UploadRequest.V2DTO v2DTO) { String profileUrl = FileUtil.fileSave(v2DTO.getImg()); uploadRepository.save(v2DTO.toEntity(profileUrl)); }
 
 
 
Service에서 사용한 fileSave 메서드 :
public static String fileSave(String base64) { String mimeType = base64.substring(5, base64.indexOf(";base64,")); String result = mimeType.split("/")[1]; String imgName = UUID.randomUUID().toString() + result; String profileUrl = "images/"+imgName; String dbUrl = "/upload/"+imgName; String base64Data = base64.split(",")[1]; byte[] decodedBytes = Base64.getDecoder().decode(base64Data); try { Path path = Paths.get(profileUrl); Files.write(path, decodedBytes); return dbUrl; } catch (IOException e) { throw new RuntimeException(e.getMessage()); } }
 
  • base64 문자열을 받아오기 위해 오버로딩으로 메서드 구현
 

메서드 세부 설명

 
  1. Mime Type 추출:
    1. String mimeType = base64.substring(5, base64.indexOf(";base64,")); String result = mimeType.split("/")[1];
      • base64.substring(5, base64.indexOf(";base64,")): Base64 문자열의 처음 부분에서 MIME 타입을 추출합니다.
      • mimeType.split("/")[1]: MIME 타입에서 파일 확장자를 얻습니다.
  1. 파일 이름 생성:
    1. String imgName = UUID.randomUUID().toString() + result; String profileUrl = "images/"+imgName; String dbUrl = "/upload/"+imgName;
      • UUID.randomUUID().toString(): 고유한 파일 이름을 생성하기 위해 UUID를 사용합니다.
      • profileUrl: 서버의 파일 시스템에 저장될 파일의 경로입니다.
      • dbUrl: 데이터베이스에 저장될 파일의 URL 경로입니다.
  1. Base64 데이터 추출 및 디코딩:
    1. String base64Data = base64.split(",")[1]; byte[] decodedBytes = Base64.getDecoder().decode(base64Data);
      • base64.split(",")[1]: Base64 인코딩된 이미지 데이터 부분을 추출합니다.
      • Base64.getDecoder().decode(base64Data): Base64 인코딩된 데이터를 디코딩하여 바이트 배열로 변환합니다.
  1. 파일 쓰기 및 반환 경로:
    1. try { Path path = Paths.get(profileUrl); Files.write(path, decodedBytes); return dbUrl; } catch (IOException e) { throw new RuntimeException(e.getMessage()); }
      • Paths.get(profileUrl): 파일 경로를 생성합니다.
      • Files.write(path, decodedBytes): 디코딩된 바이트 데이터를 해당 경로에 파일로 씁니다.
      • 파일 쓰기에 성공하면 dbUrl을 반환합니다.
      • 예외 발생 시 RuntimeException을 발생시킵니다.
 
 
 
Repository : 변경점 없음
 
Share article

moohyun