본문 바로가기
괴발개발/java

프로필 이미지 변경 (update profile Image)

by 맛길만걷자 2024. 7. 16.
728x90
반응형

서블릿

package edu.kh.community.member.controller;

import java.io.IOException;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

import com.oreilly.servlet.MultipartRequest;

import edu.kh.community.common.MyRenamePolicy;
import edu.kh.community.member.model.service.MemberService;
import edu.kh.community.member.model.vo.Member;

@WebServlet("/member/myPage/profile")
public class MyPageProfileServlet extends HttpServlet{

	@Override
	protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
		//메인페이지 - > 프로필 이미지 클릭
		// 마이페이지 - > 프로필 클릭
				String path = "/WEB-INF/views/member/myPage-profile.jsp";
				req.getRequestDispatcher(path).forward(req,resp);
				
				
	}

	@Override
	protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {

		// 프로필 이미지 업로드 -> 변경
			try {
				
				//System.out.println(req.getParameter("profileImage")); //null
				
				// 파라미터가 얻어와지지 않는 이유
				// 1. enctype="multipart/form-data" -> 인코딩이 안되어 있어서 파라미터가 인지되지 않음
				// 2. input type = "file" -> 파일 형태 데이터
				// --> multiplart/form-data 형식의 요청을 처리할 수 있는 전용 Request 객체가 필요
				
				// --> MultipartRequest (cos.jar 라이브러리 이용 - http://servlets.com/cos/)
											//파일 업로드 라이브러리
				
				// *** MultipartRequst 사용을 위한 준비 단계
				// 1. 업로드되는 파일 크기의 전체 합을 지정(byte) 지정
				int maxSize = 1024 * 1024 *20;
							  //1 KB 1MB	20MB
				
				// 2. 업로드 되는 파일이 어디에 저장될지 경로 지정
				//		-> 서버 컴퓨터 내부 폴더(절대 경로)
				
				// 2-1. server option 확인
				// servers -> 서버 설정 선택 -> Overview -> server options
				// -> Serve Modules Without Pulishing 체크
				// 	  (업로드 되는 파일이 Webapp 폴더 내부에 저장될 수 있음)
				
				// 2-2. memberProfile 폴더까지의 절대 경로 얻어오기
				HttpSession session = req.getSession(); //session 얻어오는 것은 지장 X(사용 가능)
				
				//최상위 경로("/" == webapp폴더)의 실제 절대 경로를 얻어옴
				String root = session.getServletContext().getRealPath("/");
				// C:\workspace\5_Server\community\src\main\webapp
				
				//실제 파일이 저장되는 폴더의 경로
				String folderPath = "/resources/images/memberProfile/";
				
				// memberProfile 폴더 까지의 절대 경로
				String filePath = root + folderPath;
				
				
				// 3. 저장되는 파일의 파일명 중복을 방지하기 위한 파일명 변경 규칙
				// -> cos.jar 에서 제공하는 FileRenamePolicy 인터페이스 상속 클래스 생성
				// --> MyRenamePolicy 클래스 생성
				
				// 4. 파일 이외의 파라미터들의 문자 인코딩 지정
				String encoding = "UTF-8";
				
				// 5. MultipartRequest 생성
				// ***** (중요) ******
				// MultipartRequest 객체가 생성됨과 동시에 지정된 경로에
				// 지정된 파일 변경 정책에 맞게 이름이 바뀐 파일이 저장(서버 업로드)된다.
				
				MultipartRequest mpReq = new MultipartRequest(req, filePath, maxSize, encoding, new MyRenamePolicy());
				
				// 프로필 이미지 변경 Service 호출 시 필요한 값
				// 1) 로그인한 회원의 회원 번호
				Member loginMember = (Member)session.getAttribute("loginMember");
				int memberNo = loginMember.getMemberNo();
				
				// 2) 업로드된 프로필 이미지의 웹 접근 경로(folderPath + 변경된 파일명)
				
				//getOriginalFileName("input type='file'의 name 속성 값"+)
				
				// -> 원본 파일명
				
				//System.out.println(mpReq.getOriginalFileName("profileImage"));
				
				// getFilesystemName("input type="file"의 name 속성 값")
				// -> 변경된 파일명
				
				//System.out.println(mpReq.getFilesystemName("profileImage"));
				
				String profileImage = folderPath + mpReq.getFilesystemName("profileImage");
				
				// 프로필 이미지 변경 Service 호출 후 결과 반환 받기
				MemberService service = new MemberService();
				
				int result = service.updateProfileImage(memberNo,profileImage);
				
				if(result>0) {
					//성공
					session.setAttribute("message", "프로필 이미지가 변경되었습니다.");
					
					//DB의 프로필 이미지 정보는 변경되었으나
					// Session에 저장된 로그인 정보 중 프로필 이미지는 변경되지 않음
					// -> 동기화 작업 진행
					
					loginMember.setProfileImage(profileImage);
					
				} else { //실패
					session.setAttribute("message", "프로필 이미지 변경 실패 ㅠㅠ");
				}
				
				// 성공 / 실패 관계 없이 프로필 화면 재요청
				resp.sendRedirect("profile"); // 상대경로 (GET)
				
				
			}catch(Exception e){
				e.printStackTrace();
				
			}
				
		
	
	}

}

 

jsp

            <form action="profile" method="post" name="myPage-form"
                    enctype="multipart/form-data" onsubmit="return profileValidate()">
                
                    <div class="profile-image-area">
                        <c:if test="${empty loginMember.profileImage}">
                        <img src="${contextPath}/resources/images/user.png" id="profile-image">
                        </c:if>
                        <c:if test="${!empty loginMember.profileImage}">
                            <img src="${contextPath}${loginMember.profileImage}" id="profile-image">
                        </c:if>
                    </div>

                    <div class="profile-btn-area">
                        <label for="input-image"> 이미지 선택</label>
                        <input type="file" name="profileImage" id="input-image" accept="image/*">
                        <!-- accept="image/*" : 이미지 파일 확장자만 선택 허용 -->
                        <!-- accept="video/*" : 동영상 파일 확장자만 선택 허용 -->
                        <!-- accept=".pdf" : pdf 파일만 선택 허용 -->
                        <button>변경하기</button>
                    </div>
 </form>

 

js

회원 프로필 이미지 변경(미리보기)
const inputImage = document.getElemnetById("input-image");
if(inputImage != null){ // inputImage 요소가 화면에 존재할 때
//input type="file"요서는 파일이 선택 될 때 change 이벤트가 발생함

// this : 이벤트 발생한 요소 (input type ="file")

// file: input type= "file"만 사용 가능한 속성으로 선택된 파일 목록(배열)반환

console.log(this.files); // 리스트로 반환되는 것을 알수있음
console.log(this.files[0]; // 파일 목록에서 첫 번째 파일 객체를 선택

if(this.files[0] != undefinde){ //파일이 선택되었을때 , 선택이안됨 undefinde
// 자바스크립트의 FileReader
// - 웹 애플리케이션이 비동기적으로 데이터를 일기 위하여 사용하는 객체

reader.readAsDataURL(this.files[0]);
// FileReader.readAsDataURL(파일);
// - 지정된 파일의 내용을 읽기 시작합니다.
// - 읽어 오는게 완료되면 result 속에 data:에 읽어온 파일의 위치를 나타내는 URL이 포함된다.
// -> 해당 URL을 이용해서 브라우저에 이미지를 볼 수 있다.

//reader.onload = function(){}
// - FileReader가 파일을 다 읽어온 경우 함수를 수행

reader.onload = function(e){
                // e : 이벤트 발생 객체
                // e.target : 이벤트가 발생한 요소(객체) -> FileReader
                // e.target.result : FileReader가 읽어온 파일의 URL
                // console.log(e.target.result);

                // 프로필 이미지의 src 속성의 값을 FileReader가 읽어온 파일의 URL로 변경
                const profileImage = document.getElementById("profile-image");

                profileImage.setAttribute("src", e.target.result);
                // -> setAttribute() 호출 시 중복되는 속성이 존재하면 덮어쓰기


            }

        }

    })

}


// 이미지 선택 확인
function profileValidate(){

    const inputImage = document.getElementById("input-image");

    if(inputImage.value==""){ // 파일선택 X == 빈문자열
        alert("이미지를 선택한 후 변경 버튼을 클릭해 주세요.")
        return false;
    }

    return true;

}



}

 

 

파일명 변경 클래스

package edu.kh.community.common;

import java.io.File;
import java.text.SimpleDateFormat;
import java.util.Date;

import com.oreilly.servlet.multipart.FileRenamePolicy;

// 파일명 변경 정책

public class MyRenamePolicy implements FileRenamePolicy {

	@Override
	public File rename(File originalFile) {
		
		  long currentTime = System.currentTimeMillis();
	      // 1970년 1월 1일 오전 9시 부터 현재 시간까지의 경과한 ms를 반환
		  
	      SimpleDateFormat ft = new SimpleDateFormat("yyyyMMddHHmmss");
	      
	      int ranNum = (int) (Math.random() * 100000); // 5자리 랜덤 숫자 생성
	                        
	      String str = "_" + String.format("%05d", ranNum);
	      					// user.png
	      					// 20240716120630_01234.png
	                           
	      // String.format : 문자열을 지정된 패턴의 형식으로 변경하는 메소드
	      // %05d : 오른쪽 정렬된 십진 정수(d) 5자리(5)형태로 변경. 빈자리는 0으로 채움(0)

	      // 파일명을 변경해도 확장자를 유지하기 위하여
	      // 별도로 확장자 명 가져오기
	      String name = originalFile.getName();
	      String ext = null;

	      int dot = name.lastIndexOf(".");

	      if (dot != -1) {
	         // dot 포함해서 확장자 추출 (ext)
	         ext = name.substring(dot);
	      } else {
	         // 확장자가 없는 경우
	         ext = "";
	      }

	      String fileName = ft.format(new Date(currentTime)) + str + ext;
	      					// 20240716120630_01234 	+	_01234 + .png
	      
	      File newFile = new File(originalFile.getParent(), fileName);

	      return newFile;

		
	}

}

 

서비스

	/** 프로필 이미지 service
	 * @param memberNo
	 * @param profileImage
	 * @return result
	 */
	public int updateProfileImage(int memberNo, String profileImage) throws Exception {
		
		Connection conn = getConnection();
		int result = dao.updateProfileImage(conn,memberNo,profileImage);
		
		if(result>0) commit(conn);
		else 		 rollback(conn);
		
		close(conn);
		
		return result;
	}

 

dao

/** 업데이트 프로필 이미지
	 * @param conn
	 * @param memberNo
	 * @param profileImage
	 * @return result
	 * @throws Exception
	 */
	public int updateProfileImage(Connection conn, int memberNo, String profileImage) throws Exception {
		
		int result=0;
		
		try {
			String sql = prop.getProperty("updateProfileImage");
			pstmt = conn.prepareStatement(sql);
			pstmt.setString(1,profileImage );
			pstmt.setInt(2,memberNo);
			
			result= pstmt.executeUpdate();
			
			
			
		}finally {
			close(pstmt);
		}
		
		
		return result;
	}

 

sql

	<!-- 프로필 이미지 업데이트  -->
	<entry key="updateProfileImage">
	UPDATE MEMBER SET PROFILE_IMG =?
	WHERE MEMBER_NO = ?
	</entry>

 

728x90
반응형