728x90
이번시간에는 프로필 이미지 추가 / 변경 / 삭제 할 예정이다.
그 전에 이미지 선택 하여 동그란 화면에 이미지를 미리보기 할 예정이다.
📚 VS code
📕 myPage-profile.jsp (프로필 부분만 발췌함)
🤔 accpt = "image/*" : 이미지만 허락하겠다라는 뜻이다.
<section class="myPage-main">
<h1 class="myPage-title">프로필</h1>
<span class="myPage-subject">프로필 이미지를 변경할 수 있습니다.</span>
<form action="profile" method="POST" name="myPageFrm">
<div class="profile-image-area">
<img src="/resources/images/user.png" id="profileImage">
</div>
<span id="deleteImage">x</span>
<div class="profile-btn-area">
<label for="imageInput">이미지 선택</label> <%-- 이미지만 허락하겠다! --%>
<input type="file" name="profileImage" id="imageInput" accept="image/*">
<button>변경하기</button>
</div>
<div class="myPage-row">
<label>이메일</label>
<span>로그인 회원 이메일</span>
</div>
<div class="myPage-row">
<label>가입일</label>
<span>로그인 회원 가입일</span>
</div>
</form>
</section>
📕 myPage.js (프로필 부분만 발췌함)
const profileImage = document.getElementById("profileImage");//Img 태그
const deleteImage = document.getElementById("deleteImage");//x버튼
const imageInput = document.getElementById("imageInput");//input 태그
if(imageInput != null){ // main.js는 다른 jsp랑도 연결되어 있어 검사가 필요하다.
imageInput.addEventListener("change",e=>{
const maxSize = 1 * 1024 * 1024 * 2
const file = e.target.files[0]
if(file.size > maxSize){
alert("2MB 이하의 이미지를 선택해주세요")
return
}
const reader = new FileReader();
reader.readAsDateURL(file);
reader.onload = e =>{
const url = e.target.result;
profileImage.setAttribute("src",url)
}
}
}
🤔💭 코드 해석
change : input 값 입력 후 포커스를 잃었을 때 이전 값과 다르면 change 이벤트 발생
const maxSize = 1 * 1024 * 1024 * 2 // 파일의 최대 크기(2MB 크기 제한)
const file = e.target.files[0]; // 업로드한 파일의 정보가 담긴 객체
const reader = new FileReader(); // JS 파일을 읽는 객체 (파일을 읽고 클라이언트 컴퓨터에 저장)
reader.readAsDataURL(file);
// 매개변수에 작성된 file을 읽어서 저장 후
파일을 나타내는 URL을 result 속성으로 얻어올 수 있게 함
profileImage.setAttribute("src",url)
// 프로필 이미지 (img) 태그에 src 속성으로 추가
🤔💭 콘솔 해석
console.log(e.target); : input 태그 나옴
console.log(e.target.value) : 업로드된 파일 경로
console.log(e.target.files) : 업로드된 파일 정보가 담긴 배열
console.log(e.target.result) : 읽은 파일의 URL
🔮 출력화면
화면에 미리보기랑 x 표시 등등 모두 설정해놓았다.
이제 변경이나 취소를 위해 DB에 파일을 업로드 하기 위해서는 jsp / js 파일 업로드하기 위해 변수를 설정한다.
📚 VS code
📕 myPage.js (프로필 부분만 발췌함)
const profileImage = document.getElementById("profileImage");//Img 태그
const deleteImage = document.getElementById("deleteImage");//x버튼
const imageInput = document.getElementById("imageInput");//input 태그
let initCheck; //초기 프로필 이미지 상태를 저장하는 변수
// false == 기본 이미지 , true == 이전 업로드 이미지
let deleteCheck = -1; // 프로필 이미지가 새로 업로드 되거나 삭제 되었음을 나타내는 변수
// -1 == 초기값, 0 == 프로필 삭제(x버튼) 1== 새 이미지 업로드
let originalImage; // 초기 프로필 이미지 파일 경로 저장
if (imageInput != null) {
originalImage = profileImage.getAttribute("src");
// 회원 프로필 화면 진입 시 현재 회원의 프로필 이미지 상태를 확인
if(originalImage == "/resources/images/user.png"){ // 기본 이미지인 경우
initCheck = false;
} else{
initCheck = true;
}
imageInput.addEventListener("change", e => {
const maxSize = 1 * 1024 * 1024 * 2 // 파일의 최대 크기 (바이트단위) = 2MB최대 크기 제한
const file = e.target.files[0]; // 업로드한 파일의 정보가 담긴 객체
// 파일을 한번 선택한 후 취소 했을 때
if (file == undefined) {
console.log("파일 선택이 취소됨");
deleteCheck = -1; // 취소 == 파일 없음 -== 초기상태
// 취소 시 기존 프로필 이미지로 변경
profileImage.setAttribute("src", originalImage);
return;
}
if (file.size > maxSize) { // 선택된 파일의 크기가 최대 크기를 초과한 경우
alert("2MB이하의 이미지를 선택해주세요");
imageInput.value = ""; //(이렇게 안해주면 일단 올라가 있고 db에 반영 될 수 있따.)
// input type = "file"태그에 대입할 수 있는 value 는 ""(빈칸) 뿐이다.
deleteCheck = -1; // 취소 == 파일 없음 -== 초기상태
// 기존 프로필 이미지로 변경
profileImage.setAttribute("src", originalImage);
return;
}
const reader = new FileReader();
reader.readAsDataURL(file);
// 다 읽었을때
reader.onload = e => {
console.log(e.target)
console.log(e.target.result) //: 읽은 파일의 URL
const url = e.target.result;
// 프로필 이미지 (img) 태그에 src 속성으로 추가
profileImage.setAttribute("src", url)
deleteCheck = 1;
// 결론 : 이미지는 url 형식이고 읽으면 result로 반환할 수 있따!
}
});
// x 버튼 클릭 시
deleteImage.addEventListener("click", () => {
// 프로필 이미지를 기본 이미지로 변경
profileImage.setAttribute("src", "/resources/images/user.png")
imageInput.value = ""; // input type = "file"의 value삭제
deleteCheck = 0;
});
// #profileFrm이 제출 되었을때
document.getElementById("profileFrm").addEventListener("submit", e => {
// let initCheck;
// 초기 프로필 이미지 상태를 저장하는 변수
// false == 기본 이미지, true == 이전 업로드 이미지
// let deleteCheck = -1;
// 프로필 이미지가 새로 업로드 되거나 삭제 되었음을 나타내는 경우
// -1 == 초기값, 0 == 프로필 삭제(x버튼), 1 == 새 이미지 업로드
let flag = true;
// 프로필 이미지가 없다 -> 있다
if(!initCheck && deleteCheck == 1){
flag = false;
}
// 이전 프로필 이미지가 있다 -> 삭제
if(initCheck && deleteCheck == 0){
flag = false;
}
// 이전 프로필 이미지가 있다 -> 새 이미지
if(initCheck && deleteCheck == 1){
flag = false;
}
if(flag){ // fals == true -> 제출하면 안되는 경우
e.preventDefault(); // form 기본 이벤트 제거
alert("이미지 변경 후 클릭하세요.");
}
});
}
📕 myPage-profile.jsp (프로필 부분만 발췌함)
<form action="profile" method="POST" name="myPageFrm" id="profileFrm"
enctype="multipart/form-data">
<div class="profile-image-area">
<%-- 프로필 이미지가 없으면 기본 이미지 --%>
<c:if test="${empty loginMember.profileImage}" >
<img src="/resources/images/user.png" id="profileImage">
</c:if>
<%-- 프로필 이미지가 있으면 있는 이미지 --%>
<c:if test="${!empty loginMember.profileImage}" >
<img src="${loginMember.profileImage}" id="profileImage">
</c:if>
</div>
<span id="deleteImage">x</span>
<div class="profile-btn-area">
<label for="imageInput">이미지 선택</label>
<input type="file" name="profileImage" id="imageInput" accept="image/*">
<button>변경하기</button>
</div>
<div class="myPage-row">
<label>이메일</label>
<span>${loginMember.memberEmail}</span>
</div>
<div class="myPage-row">
<label>가입일</label>
<span>${loginMember.enrollDate}</span>
</div>
</form>
📖 multipart/form-data 란 ?
파일 제출 시 무조건 POST 방식
- enctype 속성 추가
- enctype : form 태그 데이터가 서버로 제출될 때 인코딩 되는 방법을 지정
(POST 방식 일 때만 사용가능)
- applicatiob/x-www-form-urlencoded : 모든 문자를 서버로 전송하기 전에 인코딩
(form 태그 기본값)
- multipart/form-data : 모든 문자를 인코딩 하지 않음
(원본 데이터가 유지되어 이미지, 파일등을 서버로 전송할 수 있음)
📗 porm.xml (필요한 부분만 발췌함)
<!-- 파일 업로드 관련 라이브러리 -->
<!-- https://mvnrepository.com/artifact/commons-fileupload/commons-fileupload -->
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>1.5</version>
</dependency>
📗 root-context.xml (필요한 부분만 발췌함)
<!--
파일 업로드를 위한 MutipartResolver 구현체 CommonsMultipartResolver bean 등록
-> CommonsMultipartResolver를 bean으로 등록하면
multipart/form-data 형식으로 요청 시 input type="file" 태그를 자동적으로 인식하여
MultipartFile 객체로 반환하고
파일 외의 데이터(정수, 문자열 등의 텍스트 데이터)는 기존처럼 사용 가능(MultipartRequest 필요 없음)
-->
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<property name="maxUploadSize" value="104857600"/>
<property name="maxUploadSizePerFile" value="104857600"/>
<property name="maxInMemorySize" value="104857600"/>
</bean>
<!--
104857600 byte == 100MB
maxUploadSize
: 한 요청당 업로드가 허용되는 최대 용량을 바이트 단위로 설정.
-1 은 제한이 없다는 뜻으로 이 프로퍼티를 지정하지 않을때 기본값.
maxUploadSizePerFile
: 한 파일당 업로드가 허용되는 최대 용량을 바이트 단위로 설정.
-1 은 제한이 없다는 뜻으로 이 프로퍼티를 지정하지 않을때 기본값.
maxInMemorySize
: 디스크에 저장하지 않고 메모리에 유지하도록
허용하는 바이트 단위의 최대 용량을 설정.
사이즈가 이보다 클 경우 이 사이즈 이상의 데이터는 파일에 저장됩니다.
기본값은 10240 바이트.
-->
728x90
'ON > spring' 카테고리의 다른 글
[ Spring ] 게시글 작성(제목+내용+사진) ⑪ (0) | 2023.08.28 |
---|---|
공공 데이터 - OPEN API (0) | 2023.08.25 |
[ Spring ] 게시글 상세 좋아요 | 조회수 ⑧ (0) | 2023.08.23 |
[ Spring ] 게시글 상세 조회 ⑦ (1) | 2023.08.22 |
[ Spring ] 게시글 목록 조회 ⑥ (1) | 2023.08.21 |