Kim VamPa

[Spring][쇼핑몰 프로젝트][25] 업로드 이미지 출력 -2 본문

스프링 프레임워크/쇼핑몰 프로젝트

[Spring][쇼핑몰 프로젝트][25] 업로드 이미지 출력 -2

Kim VamPa 2021. 5. 25. 21:37
728x90
반응형
프로젝트 Github : https://github.com/sjinjin7/Blog_Project
프로젝트 포스팅 색인(index) : https://kimvampa.tistory.com/188

목표

업로드 이미지 출력 구현

 저번 포스팅에서는 이미지를 출력시켜는 메서드를 작성하였었습니다. 이번엔 이 메서드를 활용하여 '상품 등록 페이지'에서 업로드한 이미지를 선택하였을 때 미리 보기 할 수 있도록 구현해보겠습니다.

 

 

순서

1. 태그 추가 및 css 설정 추가

2. 이미지 출력 메서드 작성(showUploadImage())

3. encodeURIComponent() 적용

 

 

1. 태그 추가 및 css 설정 추가

 업로드 파일 선택 <input>태그 바로 밑에 업로드 한 이미지를 볼 수 있도록 코드를 추가할 것입니다. 추가할 위치는 아래의 그림에서 표시한 위치입니다.

 

그림 1-1

 

 id속성이 uploadResult인 <div> 태그를 추가하였습니다. 해당 <div> 태그를 타겟으로 내부에 이미지를 출력시킬 태그가 추가되도록 Javascript 코드를 작성할 것입니다.

 

<div id="uploadResult">
</div>

 

 지금부터 작성하는 태그는 Javascript를 통해 추가 될 태그들입니다. 어떠 한식으로 출력되는지 확인하고 미리 css 설정을 추가해주기 위해 작성해보겠습니다. 테스트를 위해 이전 포스팅에서 추가해주었던 "resources/ img"경로에 있는 Logo.png를 출력시켜보겠습니다.

 

 id속성 uploadResult인 <div> 태그 내부에 아래의 태그들을 추가해줍니다. class 속성명이 imgDeleteBtn 인 <div> 태그는 추후 구현할 이미지 삭제 기능을 수행 버튼입니다.

 

<div id="result_card">
	<div class="imgDeleteBtn">x</div>
	<img src="/resources/img/Logo.png">
</div>

 

그림 1-2

 

서버를 구동시켜서 어떤 식으로 출력되는지 확인합니다.

 

그림 1-3

 

 css설정을 추가해주겠습니다. css코드는 편의를 위해 css 파일에 따로 작성하지 않고 해당 'goodsEnroll.jsp'파일에 바로 추가해주겠습니다. jsp파일 상단 <head> 태그 내부에 <style> 태그를 추가하여 아래의 css 코드를 추가해줍니다.

 

<style type="text/css">
	#result_card img{
		max-width: 100%;
	    height: auto;
	    display: block;
	    padding: 5px;
	    margin-top: 10px;
	    margin: auto;	
	}
	#result_card {
		position: relative;
	}
	.imgDeleteBtn{
	    position: absolute;
	    top: 0;
	    right: 5%;
	    background-color: #ef7d7d;
	    color: wheat;
	    font-weight: 900;
	    width: 30px;
	    height: 30px;
	    border-radius: 50%;
	    line-height: 26px;
	    text-align: center;
	    border: none;
	    display: block;
	    cursor: pointer;	
	}
	
</style>

 

그림 1-4

 

 해당 페이지에 접속을 하여 적용이 의도대로 되었는지 확인합니다.

 

그림 1-5

 

 

 저번 포스팅에서 작성한 url 매핑 메서드를 활용하여 업로드되어 있는 이미지를 출력시켜보겠습니다. <img> 태그 src 속성에 이미지를 출력을 요청하는 url을 작성하여 테스트해보겠습니다.

 

그림 1-6

 

그림 1-7

 

그림 1-8

 

 정상적으로 출력되는 것을 확인하였기 때문에 id속성이 'result_card'인 <div> 태그와 그 내부 태그들을 지우거나 주석처리해줍니다.

 

그림 1-9

 

2. 이미지 출력 메서드 작성(showUploadImage())

 어떠한 형태로 출력할 것인지를 결정을 하였고 css 설정도 추가를 하였습니다. 따라서 앞서 지운(혹은 주석 처리한) 태그들을 js코드를 통해 동적으로 추가되도록 해주어야 합니다. 동작할 시점은 이미지 업로드를 요청 후 성공적으로 업로드 한 이미지에 대한 데이터(path, filename, uuid)들을 전달받았을 때입니다. 따라서 ajax succes 속성의 콜백 함수에 전달받은 이미지 데이터를 활용하여 이미지가 출력되도록 코드를 작성할 것입니다.

 

 작성할 코드의 량이 많기 때문에 콜백 함수 내부에 바로 작성하지 않고, 따로 메서드를 선언하여 그 구현부에 이미지를 출력하는 코드를 작성 한 뒤 해당 함수를 호출하는 형태로 진행하겠습니다.

 

 선언 및 호출할 메서드의 이름은 'showUploadImag'입니다. ajax의 success속성 속성값으로 작성한 콜백 함수에 앞으로 선언 및 구현할 showUploadImage() 메서드를 미리 호출하고 인자 값으로 서버로 전달받은 result 부여하였습니다. (reuslt, 즉 업로드한 이미지 데이터(filename, uuid, path)를 활용하여 이미지를 출력시키기 위함입니다.)

 

showUploadImage(result);

 

그림 2-1

 

<script> 태그 제일 하단에 showUploadImage를 선언 및 구현하겠습니다. 메서드를 선언하는 아래의 코드를 추가합니다.

 

	/* 이미지 출력 */
	function showUploadImage(uploadResultArr){
		
	}

 

그림 2-2

 

 success 콜백 함수가 실행된다는 것은 업로드 이미지 메서드가 정상적으로 수행되었다는 것이기 때문에 반환 데이터(result)를 전달받지 못할 가능성은 낮습니다. 하지만 혹여나 데이터를 전달 받지 못했을 경우에는 이미지를 출력시키는 태그를 추가해선 안되기 때문에 데이터를 검증하는 코드를 추가하겠습니다. 

 

 메서드의 구현부에 전달받은 데이터를 검증하는 코드를 추가합니다.

	/* 이미지 출력 */
	function showUploadImage(uploadResultArr){
		
		/* 전달받은 데이터 검증 */
		if(!uploadResultArr || uploadResultArr.length == 0){return}
		
	}	

 

 id 속성 uploadResult인 <div> 태그 요소에 쉽게 접근하기 위해 변수를 선언 및 초기화하였습니다.

 

	/* 이미지 출력 */
	function showUploadImage(uploadResultArr){
		
		/* 전달받은 데이터 검증 */
		if(!uploadResultArr || uploadResultArr.length == 0){return}
		
        let uploadResult = $("#uploadResult");
        
	}	

 

 서버에서 뷰로 반환할 때 List타입의 데이터를 전송했었고 뷰(view)에서는 해당 데이터를 배열 형태로 전달받습니다. 지금 우리는 한 개의 이미지 파일만 처리를 하기 때문에 이미지의 데이터(filename, path, uuid)에 쉽게 접근할 수 있도록 변수 obj를 선언하여 서버로부터 전달받은 배열 데이터의 첫 번째 요소로 초기화해주었습니다.

 

 

	/* 이미지 출력 */
	function showUploadImage(uploadResultArr){
		
		/* 전달받은 데이터 검증 */
		if(!uploadResultArr || uploadResultArr.length == 0){return}
		
		let uploadResult = $("#uploadResult");
		
		let obj = uploadResultArr[0];
		
	}	

 

 id속성 값 uploadResult 인 <div> 태그 내부에 이미지를 출력하는 태그 코드들을 추가할 차례입니다. 추가될 태그 코드를 저장할 변수를 선언하고 초기화해줍니다.

 

	
	/* 이미지 출력 */
	function showUploadImage(uploadResultArr){
		
		/* 전달받은 데이터 검증 */
		if(!uploadResultArr || uploadResultArr.length == 0){return}
		
		let uploadResult = $("#uploadResult");
		
		let obj = uploadResultArr[0];
		
		let str = "";
		
	}	

 

 추가한 str 변수에 추가되어야 할 태그 코드들을 문자열 값 형태로 추가해주기 전 한 가지 변수를 하나 더 추가해주겠습니다. 이미지 출력을 요청하는 url 매핑 메서드("/display")에 전달해줄 파일의 경로와 이름을 포함하는 값을 저장하기 위한 변수입니다. 아래의 코드를 추가해줍니다.

 

 (미리 보기 이미지는 썸네일 이미지가 출력되도록 값을 구성하였습니다.)

 

	/* 이미지 출력 */
	function showUploadImage(uploadResultArr){
		
		/* 전달받은 데이터 검증 */
		if(!uploadResultArr || uploadResultArr.length == 0){return}
		
		let uploadResult = $("#uploadResult");
		
		let obj = uploadResultArr[0];
		
		let str = "";
		
		let fileCallPath = obj.uploadPath + "/s_" + obj.uuid + "_" + obj.fileName;
		
	}	

 

 str 변수에 추가되어야 할 태그 코드인 문자열 값들을 저장해줍니다. 한 번에 값들을 다 넣어도 상관은 없습니다. 단지 추가될 코드 값들을 이해하도록 편하게 하기 위해 4번에 걸쳐서 값들을 추가해주었습니다.

 

	/* 이미지 출력 */
	function showUploadImage(uploadResultArr){
		
		/* 전달받은 데이터 검증 */
		if(!uploadResultArr || uploadResultArr.length == 0){return}
		
		let uploadResult = $("#uploadResult");
		
		let obj = uploadResultArr[0];
		
		let str = "";
		
		let fileCallPath = obj.uploadPath + "/s_" + obj.uuid + "_" + obj.fileName;
		
		str += "<div id='result_card'>";
		str += "<img src='/display?fileName=" + fileCallPath +"'>";
		str += "<div class='imgDeleteBtn'>x</div>";
		str += "</div>";		
		
	}	
	

 

 마지막으로 태그 코드가 담긴 문자열 값(str)을 uploadResult 태그에 append() 명령 혹은 html() 메서드를 호출하여 추가해줍니다.

 

	/* 이미지 출력 */
	function showUploadImage(uploadResultArr){
		
		/* 전달받은 데이터 검증 */
		if(!uploadResultArr || uploadResultArr.length == 0){return}
		
		let uploadResult = $("#uploadResult");
		
		let obj = uploadResultArr[0];
		
		let str = "";
		
		let fileCallPath = obj.uploadPath + "/s_" + obj.uuid + "_" + obj.fileName;
		
		str += "<div id='result_card'>";
		str += "<img src='/display?fileName=" + fileCallPath +"'>";
		str += "<div class='imgDeleteBtn'>x</div>";
		str += "</div>";		
		
   		uploadResult.append(str);     
        
	}	
	

 

 업로드 이미지 출력 코드 작성을 완료하였기 때문에 서버를 구동시켜서 테스트를 해봅니다.

 

그림 2-3

 

 실행을 해보면 현재의 코드는 에러가 납니다. 웹 브라우저의 개발자 도구 console 창을 보며 해당 이유를 알 수 있습니다. 

 

그림 2-4

 

 위 그림을 보시면 서버로 전송된 파라미터 값 중 파일의 경로(년, 월, 일)의 구분자 '\' 때문에 생긴 문제입니다. 저번 포스팅에서 이미지 출력 url을 테스트할 때 파라미터 값의 구분자로서 '/'을 사용해주어야 정상적으로 출력이 되었습니다. 경로의 '\'을 '/'으로 변경해주어야 합니다.

 

 fileCallPath 변수를 선언 및 초기화하는 코드에서 경로 부분의 코드를 아래와 같이 수정해 주면 됩니다. replace(/\\/g, '/') 의미는 대상 String 문자열 중 모든 '\'을 '/'로 변경해준다는 의미입니다. Javascript는 Java의 reaplceAll과 같은 메서드가 없기 때문에 replace 메서드의 인자 값으로 정규표현식을 사용하여 치환 대상 모든 문자를 지정을 할 수 있습니다.

 

// 변경 전
let fileCallPath = obj.uploadPath + "/s_" + obj.uuid + "_" + obj.fileName;

// 변경 후
let fileCallPath = obj.uploadPath.replace(/\\/g, '/') + "/s_" + obj.uuid + "_" + obj.fileName;

 

변경 후 다시 테스트를 해보면 정상적으로 이미지가 출력이 됩니다.

 

그림 2-5

 

 

3. encodeURIComponent() 적용

  위의 테스트에서는 파일 이름에 한글이 들어갔지만, 웹브라우저에서 자동으로 한글 문자를 UTF-8로 변환을 해주었기 때문에 정상적으로 동작을 하였습니다. 하지만 UTF-8로 인코딩을 자동으로 해주지 않는 웹브라우저가 있기 때문에 지금의 코드가 동작하지 않을 수도 있습니다. 따라서 encodeURIComponent() 메서드를 활용하여 코드를 보완해줄 것입니다. 

 

 encodeURIComponent() 메서드는 다음의 문자 A-Z a-z 0-9 - _ . ! ~ * ' ( )을 제외한 모든 문자를 UTF-8로 인코딩하여 이스케이프 문자로 변환을 해줍니다. 

 

 fileCallPath 변수를 선언 및 초기화 한 문자 코드를 아래와 같이 encodeURIComponent()를 적용한 코드로 변경을 해줍니다.

 

//변경 전
let fileCallPath = obj.uploadPath.replace(/\\/g, '/') + "/s_" + obj.uuid + "_" + obj.fileName;

//변경 후
let fileCallPath = encodeURIComponent(obj.uploadPath.replace(/\\/g, '/') + "/s_" + obj.uuid + "_" + obj.fileName);

 

 더불어서 encodeURIComponent() 메서드는 '/'와 '\'문자 또한 인코딩을 하기 때문에 replace() 메서드를 사용 안 해도 해당 URI로 동작이 됩니다.

 

// replace 적용 => 동작 o
let fileCallPath = encodeURIComponent(obj.uploadPath.replace(/\\/g, '/') + "/s_" + obj.uuid + "_" + obj.fileName);
// replace 적용 x => 동작 o
let fileCallPath = encodeURIComponent(obj.uploadPath + "/s_" + obj.uuid + "_" + obj.fileName);

 

그림 3-1

 

 마지막으로 테스트를 하여 코드가 정상적으로 동작을 하는지 확인합니다.

 

그림 3-2

 

 

REFERENCE

 

DATE

  • 2020.05.25
728x90
반응형
Comments