-
[JavaScript] SpringBoot 프로젝트 : 프로필 사진 기능 구현(4) - 이미지 미리보기(input type = "file", FileReader)프로젝트/기능 정리 2023. 6. 11. 14:52
목적
- 회원제 웹사이트 개발시 거의 필수적으로 사용되는 프로필 사진 등록 및 수정 기능 구현
- 프로필 이미지 등록 관련 DB, Java, JS 처리 총 정리
- 일부 받아서 쓴 코드 리뷰
지난 글까지는 기본이미지 또는 DB에 저장되어 있는 이미지를 가져와 JSP에 표시하는 과정을 살펴봤다.
그 과정에서 I/O Stream, VO, Mybatis, Tiles, AbstractView, Base64 encoding 등의 개념들도 짧게나마 정리했다.
이번 글 이후부터는 회원이 프로필 이미지를 등록하거나 수정할 때 처리과정을 알아보겠다.
데이터 흐름도는 다음과 같다.
[데이터 흐름도]
프로필이미지 데이터 흐름도 일단 JSP쪽 코드부터 보자.
[JSP]
JSP의 코드는 아래와 같은데, 프로필 이미지와 관련된 태그들만 적었다.
<!--페이지에 표시되는 프로필이미지--> <a href="#profile-change" data-bs-toggle="modal"> <img src = "${pageContext.request.contextPath}/mypage/photoView.do" class = "profile-photo"> </a> <!--모달창--> <div id="profile-change" class="modal fade" tabindex="-1" data-bs-backdrop="static" class="modal-dialog modal-dialog-centered"> <div class="modal-dialog modal-width"> <div class="modal-content"> <div class="modal-header"> <h5 class="modal-title" style = "margin-left: 70px;">프로필 사진 변경</h5> <button type="button" class="btn-close photo-reset" data-bs-dismiss="modal" aria-label="Close"></button> </div> <div class="modal-body"> <p> <img src = "${pageContext.request.contextPath}/mypage/photoView.do" class = "profile-photo" width = "150" height = "150"> <br> <br> <input type = "file" id = "upload" accept = "image/gif, image/png, image/jpeg" style = "margin-left : 57px;"> </p> </div> <div class="modal-footer justify-content-center" style = "align-items: center;"> <button type="button" class="btn photo-reset" id = "photo_reset" data-bs-dismiss="modal">닫기</button> <button type="button" class="btn" id = "photo_submit">변경</button> </div> </div> </div> </div>
모달창으로 구현하려고 위와 같이 좀 복잡해보이는 코드가 됐는데 실행 화면을 보면 다음과 같다.
프로필 변경 모달창 관심있게 봐야할 태그는 아래 3개다. 불필요한 인라인 스타일은 뺐다.
<!--IMG TAG--> <img src = "${pageContext.request.contextPath}/mypage/photoView.do" class = "profile-photo"> <!--INPUT TAG--> <input type = "file" id = "upload" accept = "image/gif, image/png, image/jpeg"> <!--BUTTONS--> <button type="button" class="btn photo-reset" id = "photo_reset" data-bs-dismiss="modal">닫기</button> <button type="button" class="btn" id = "photo_submit">변경</button>
일단 이 태그들과 각각의 class, id를 기억해 두자.
[JavaScript]
JS로는 아래 세 가지 기능을 구현했다.
- 회원이 input 태그를 통해 이미지 파일을 선택했을 때, 파일 크기 확인 및 화면에 선택한 이미지 미리보기
- 이미지 파일 선택 후 변경 버튼을 클릭했을 때, Ajax 실행
- 닫기 버튼을 클릭했을 때, 미리보기 이미지가 보이는 상태라면 원래 이미지로 변경(모달 닫기는 dismiss가 해줌)
이번엔 이미지 미리보기를 보도록 하자.
[JavaScript - 이미지 미리보기]
$(function(){ //처음 이미지 가져오기 let photo_path = $('.profile-photo').attr('src'); let my_photo; //회원이 업로드할 이미지 담을 변수 $('#upload').change(function(){ my_photo = this.files[0]; if(!my_photo){ $('.profile-photo').attr('src', photo_path); return } if(my_photo.size > 1024*1024){ alert(Math.round(my_photo.size/1024/1024) + 'MB(1MB까지만 업로드 가능)'); $('.profile-photo').attr('src',photo_path); $(this).val(''); return; } //이미지 미리보기 처리 let reader = new FileReader(); reader.readAsDataURL(my_photo); reader.onload = function(){ $('.profile-photo').attr('src', reader.result); }; }); //이하 코드 생략
[파일 업로드 체크]
가장 처음으로 해야할 것은 Input태그에 change 이벤트가 발생했을 때 파일이 업로드 됐는지 확인하는 것이다.
회원이 업로드할 이미지를 담을 변수인 my_photo에 this.files[0]을 할당했다.
그리고 조건문을 통해 my_photo에 데이터가 없으면 처음 설정되어 있던 이미지를 변경하지 않은 채 리턴하여 종료시켰다.
this.files[0]에 대해 간단히 설명하자면,
Input태그의 type을 file로 설정한 경우 FileList라는 것을 갖게 되는데, 여기에 Input 태그를 통해 등록한 파일들이 리스트로 저장되고 해당 리스트에서 인덱스로 파일을 불러오는 방식이다.
아래 예시를 보자.
<!--multiple 속성 추가--> <input type = "file" id = "upload" accept = "image/gif, image/png, image/jpeg" multiple="multiple">
태그에 multiple = "multiple" 속성을 추가해주면 파일을 여러개 등록할 수 있다.
$('#upload').change(function(){ console.log(this.files); console.log(this.files[0]); console.log(this.files[1]); });
파일이 추가되면 콘솔에 찍어서 확인해보기 위해 위와 같이 작성해줬다.
console 결과 화면 위와 같이 FileList 안에 업로드한 파일이 저장되어 있고, 각각 인덱스로 꺼내보면 하나의 File이 나온다.
프로필 이미지는 하나만 등록할 수 있으므로 multiple 속성을 빼고 그냥 files[0]하면 등록된 하나의 요소를 가져올 수 있다.
[파일 크기 체크]
다음은 파일 크기를 체크하는 부분이다.
코드는 간단하다.
my_photo.size(= this.files[0].size)하면 파일의 크기를 가져올 수 있다.
console.log(this.files[0].size);
직접 콘솔에 찍히는 것을 보면 다음과 같다.
console 결과 화면 여기서 나오는 크기는 파일의 byte 크기이다.
1024byte가 1KB니까 지금 이 파일은 약 25KB정도 되는 것이다.
1024byte가 1KB이고 1KB가 1024개 있으면 1MB이므로 1024 * 1024 하면 1MB가 된다. 뒤에 *2 해주면 2MB가 되니까 이런식으로 파일 크기를 체크해서 제한을 걸어두는 것이 좋다.
나는 파일 크기가 1MB이상이면 alert를 통해 제한 크기를 알려주고 Input태그에 들어온 데이터를 지운 뒤 리턴했다.
[파일 미리보기 처리]
마지막은 파일 미리보기 처리를 해주는 것이다.
회원이 파일을 업로드 했을 때, 당장 화면에 자신이 올린 이미지를 띄워 확인시켜주는 과정이다.
이를 위해 FileReader객체를 이용하는데 FileReader 객체에 대한 설명은 다음과 같다.
FileReader 설명 더 자세한 내용을 알고 싶다면 다음을 참고하자.
참고: https://developer.mozilla.org/ko/docs/Web/API/FileReader
암튼 이 FileReader 객체를 생성해서 readAsDataURL이라는 메소드를 사용했다. 이 메소드 설명은 다음과 같다.
readAsDataURL 설명 종합적으로 보면 FileReader 객체의 readAsDataURL메소드에 Input태그로 읽어 FileList에 담겨있던 파일을 넘겨주면, 이걸 base64 인코딩한 데이터가 result라는 속성에 담긴다는 것이다.
다시 해당 부분 코드를 보면 이렇다.
//FileReader 객체 생성 let reader = new FileReader(); //readAsDataURL에 Input 태그로 읽은 파일 넘겨주기 reader.readAsDataURL(my_photo); //파일읽기 로딩 완료시 reader.onload = function(){ //result 꺼내서 src 속성에 담아주기 $('.profile-photo').attr('src', reader.result); };
이렇게 하면 지난 글에서 다룬 것처럼 base64 인코딩 방식으로된 데이터가 src 속성에 들어가게된다.
[결과화면]
결과 화면 이번 글에서는 JS로 회원이 업로드한 이미지 미리보기 기능에 대해 알아봤다.
다음 글에서는 회원이 파일 선택 후 변경 버튼을 눌렀을 때 Ajax 방식으로 데이터를 전송하는 과정에 대해 다뤄보겠다.
'프로젝트 > 기능 정리' 카테고리의 다른 글