20211201 TIL - 로컬에 파일을 저장해보자

JIHYE·2021년 12월 1일
0
post-thumbnail

52market Project

우리의 귀요미 오이마켓이 2번째 스프린트 주간을 맞이했다
나는 게시글을 업로드할때 함께 이미지를 올릴수있는 기능을 맡아서 진행하기로 하였다
사진 업로드만큼 쉬운게 없었는데 내가 구현하려니 세상에서 제일 어려운 것이었다 😫
파일을 업로드 하기위해서는 필요한 친구가 있는데 그것이 바로 Multipartfile 라는 친구다

Spring doc 에서 Multipartfile을 어떻게 설명했는지 살펴보자

멀티파트 요청에서 수신된 업로드된 파일의 표현입니다.
파일 내용은 메모리에 저장되거나 일시적으로 디스크에 저장됩니다. 두 경우 모두 사용자는 원하는 경우 파일 내용을 세션 수준 또는 영구 저장소에 복사할 책임이 있습니다. 임시 저장소는 요청 처리가 끝나면 지워집니다.

사실 구선생님이 번역해준거라 조금 어색한 감이 있지만 파일을 업로드하면 잠시 보관해주는 친구이다
나는 잠시 저장되어있는 파일을 내가 저장해서 사용하면 되겠네! 라는 생각으로 접근했다

Multipartfile

처음 테이블을 구성할 당시에는 imageString으로 저장하면 될거라고 생각하고 설계했는데, 이미지 파일의 이름과 경로가 함께 있어야 불러올 수 있을것이라 생각이 들어서 Entity classString fileNameString filePath를 추가해주었다

원래 구현되어있던 Service에도 코드 수정을 해주었다

	// 경로지정
        String projectPath = System.getProperty("user.dir") + 
        			"\\src\\main\\resources\\static\\files";
        
        // 랜덤 식별자 생성
        UUID uuid = UUID.randomUUID();
       
       // uuid_원래파일명
        String fileName = uuid + "_" + file.getOriginalFilename();
       
       // 빈 파일 생성
        File saveFile = new File(projectPath, fileName);
       
       // 업로드 된 파일 저장
        file.transferTo(saveFile);

파일명이 중복될 것을 방지하기위에 randomUUID를 사용했는데 일단 이건 임시 방편이고 더 좋은 방법이 있으면 적용할 예정이다

테스트를 위해 아주 원시의 html파일을 하나 생성해주고, ajax를 이용해서 서버와 통신을 해보았다. 처음에는 FormData를 모르고 String으로 파일을 보내려다가 계속 실패를 맛보았다

여기서 FormData란...

FormData 인터페이스는 form 필드와 그 값을 나타내는 일련의 key/value 쌍을 쉽게 생성할 수 있는 방법을 제공합니다.
출처 : mozilla.org

넘겨줘야하는 정보를 모두 append해주고나니 정상작동 하였다

function upload() {
            let title = $("#title").val();
            let content = $("#content").val();
            let form = $("#file")[0].files[0];
            let formData = new FormData();
            formData.append('file', form);
            formData.append('title', title);
            formData.append('content',content);

            $.ajax({
                method: "POST",
                url: "/api/article/write",
                enctype: "multipart/form-data",
                data: formData,
                processData: false,
                contentType: false,
                cache: false,
                success: function (data) {
                    alert("등록 성공")
                    window.location.reload();
                }
            })
        }

dataType 대신 enctype에 내가 사용할 multipart/form-data를 꼭 추가해주고, processDatacontentType 는 기본값이 true이기 때문에 false로 변경 해주어야한다

  • contentType : false 로 선언 시 content-type 헤더가 multipart/form-data로 전송
  • processData : false로 선언 시 formData를 string으로 변환하지 않음
    출처 : stackoverflow

로컬에 이미지가 촥촥 쌓이길래 아...내가 해내다니!!!!😆 하면서 기뻤는데 그 알 수없는 찜찜함이 나를 감쌌다 😫
저장된 이미지를 불러오려고 할 때 그 찜찜함의 이유를 알 수 있었는데...
Entity에 저장한 fileNamefilePathnull이었다...

why null....?

나는 파일만 저장하고 테이블에 저장해주지 않았던 것이었다 🤯
그걸 깨우치는데 많은 시간을 할애했지만 해결했다는것에 또 뿌듯해 하고 있는 와중에...

이제 한번 브라우저에서 불러와볼까? 했지만 일단 내 로컬에 저장되어있는 이미지이기 때문에 브라우저에서는 불러올 수가 없었다
이건 S3에 업로드해야 해결이 될 것 같은데...
일단 오늘은 저장에 성공한 것만으로도 매우 만족한다 🤣

profile
초보개발자의 개발일기

0개의 댓글