spring - 다중 파일, 이미지

오늘·2021년 6월 9일
1

웹 페이지 연습

목록 보기
29/35

✔ 이하 사용한 이미지는 팀 프로젝트 때 따로 제작한 이미지 입니다.


다중 파일 업로드 하기

  • 스프링의 CommonsMultipartResolver 클래스를 이용하면 여러 개의 파일을 한꺼번에 업로드 할 수 있다.

CommonsMultipartResolver 클래스 속성


실습해보기

파일 구조

pom.xml 작성

파일 업로드에 필요한 라이브러리를 설치할 수 있도록 <dependency>

...
		<!-- 파일 업로드 -->
		<dependency>
			<groupId>commons-fileupload</groupId>
			<artifactId>commons-fileupload</artifactId>
			<version>1.2.1</version>
		</dependency>
		<dependency>
			<groupId>commons-io</groupId>
			<artifactId>commons-io</artifactId>
			<version>1.4</version>
		</dependency>
...

저장하고 받아진거 확인

servlet-context.xml

CommonsMultipartResolver 클래스를 multtipartResolver 빈으로 설정한다

...
	<!-- multipartResolver 빈 설정 -->
	<beans:bean id="multipartResolver"
				class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
		<beans:property name="maxUploadSize" value="52428800" />
		<beans:property name="maxInMemorySize" value="10000000" />
		<beans:property name="defaultEncoding" value="utf-8" />
	</beans:bean>
...

자바파일 준비

파일 업로드 및 다운로드 기능 컨트롤러 구현을 위해 작성

FileDownloadController.java

파일을 다운로드하는 컨트롤러 클래스. 버퍼기능을 이용해 브라우저로 빠르게 이미지를 전송할 것이다

package com.spring.pro28;

import java.io.File;
import java.io.FileInputStream;
import java.io.OutputStream;

import javax.servlet.http.HttpServletResponse;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;

@Controller
public class FileDownloadController {
	// 저장할 파일 위치 지정
	private static String CURR_IMAGE_REPO_PATH = "c://spring//image_repo";
	
	@RequestMapping("/download")
	// 다운로드할 이미지 파일이름을 param(전달)
	protected void download(@RequestParam("imageFileName") String imageFileName,
				HttpServletResponse response) throws Exception {
		OutputStream out = response.getOutputStream();
		String downFile = CURR_IMAGE_REPO_PATH + "\\" + imageFileName;
		
		// 다운로드할 파일 객체 생성하기
		File file = new File(downFile);
		response.setHeader("Cache-Control", "no-cache");
		
		// 헤더에 파일이름 설정
		response.addHeader("Content-disposition", "attachment; fileName = " + imageFileName);
		
		FileInputStream in = new FileInputStream(file);
		byte[] buffer = new byte[1024 * 8];
		
		// 버퍼를 이용해 한번에 8Kbyte 씩 브라우저로 전송한다
		while (true) {
			int count = in.read(buffer);
			if(count == -1) {
				break;
			}
			out.write(buffer, 0, count);
		}
		
		in.close();
		out.close();
	}
}

FiltUploadController.java

파일 업로드하는 부분

package com.spring.pro28;

import java.io.File;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import javax.servlet.http.HttpServletResponse;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.multipart.MultipartHttpServletRequest;
import org.springframework.web.servlet.ModelAndView;

@Controller
public class FileUploadController {
	private static final String CURR_IMAGE_REPO_PATH = "c:\\spring\\image_repo";
	
	// 업로드 창인 uploadForm.jsp를 반환할 것이다
	@RequestMapping(value="/form")
	public String form() {
		return "uploadForm";
	}
	
	@RequestMapping(value = "/upload", method = RequestMethod.POST)
	public ModelAndView upload(MultipartHttpServletRequest multipartRequest,
							HttpServletResponse response) throws Exception {
		multipartRequest.setCharacterEncoding("utf-8");
		
		// 매개변수 정보와 파일 정보를 저장할 Map 생성
		Map map = new HashMap();
		
		Enumeration enu = multipartRequest.getParameterNames();
		
		// 전송된 매개변수 값을 key/value로 map에 저장한다
		while (enu.hasMoreElements()) {
			String name = (String)enu.nextElement();
			String value = multipartRequest.getParameter(name);
			map.put(name, value);
		}
		
		// 파일을 업로드한 후 반환된 파일 이름이 저장되는 fileList를 다시 map에 저장할 것이다
		List fileList = fileProcess(multipartRequest);
		map.put("fileList", fileList);
		
		ModelAndView mav = new ModelAndView();
		
		// map을 결과창으로 포워딩
		mav.addObject("map", map);
		mav.setViewName("result");
		
		return mav;
	}
	
	private List<String> fileProcess(MultipartHttpServletRequest multipartRequest) throws Exception{
		List<String> fileList= new ArrayList<String>();
		
		// 첨부된 파일 이름을 가져올 것이다
		Iterator<String> fileNames = multipartRequest.getFileNames();
		
		while(fileNames.hasNext()){
			String fileName = fileNames.next();
			
			// 파일 이름에 대한 MultipartFile 객체 가져오기
			MultipartFile mFile = multipartRequest.getFile(fileName);
			// 실제 파일 이름 가져오기
			String originalFileName=mFile.getOriginalFilename();
			// 파일 이름을 하나씩 fileList에 저장하기
			fileList.add(originalFileName);
			
			File file = new File(CURR_IMAGE_REPO_PATH +"\\"+ fileName);
			
			// 첨부된 파일이 존재하는지 체크
			if(mFile.getSize()!=0){
				//경로상에 파일이 존재하지 않을 경우
				if(! file.exists()) {
					//경로에 해당하는 디렉토리를 만들어라
					if(file.getParentFile().mkdirs()){
						// 그 후에 파일을 생성해라
						file.createNewFile();
					}
				}
				// 임시로 저장된 mutilpartFile을 실제 파일로 저장
				mFile.transferTo(new File(CURR_IMAGE_REPO_PATH +"\\"+ originalFileName)); //임시로 저장된 multipartFile을 실제 파일로 전송
			}
		}
		// 첨부한 파일 이름이 저장된 fileList 반환해줘라
		return fileList;
	}
}

Jsp 파일

파일 업로드 창과 업로드한 파일을 표시할 결과창 준비

uploadForm.jsp

<%@ page language="java" contentType="text/html; charset=EUC-KR"
	pageEncoding="EUC-KR" isELIgnored="false"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"  %>
<c:set var="contextPath"  value="${pageContext.request.contextPath}"  />
<%  request.setCharacterEncoding("UTF-8"); %>

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>파일 업로드하기</title>
<script src="http://code.jquery.com/jquery-latest.js"></script>
<script>
	// 파일 업로드 name 값을 각각 다르게 하는 변수
	var cnt = 1;
	
	// 파일 추가를 클릭시 동적으로 파일 업로드를 추가할 것이라는 것
	// name 속성의 값으로 'file'+cnt 를 설정함으로써 값을 다르게 해준다
	function fn_addFile() {
		$("#d_file").append("<br>"+"<input  type='file' name='file"+cnt+"' />");
		cnt++;
	}
</script>

</head>
<body>
	<h1>파일 업로드 하기</h1>
	
	<!-- enctype : 파일 업로드시 반드시 mutilpart/form-data로 설정해야 한다 -->
	<form method="post" action="${contextPath}/upload" enctype="multipart/form-data">
		<label>아이디:</label>
    		<input type="text" name="id"><br>
		<label>이름:</label>
    		<input type="text" name="name"><br>
		
		<input type="button"  value="파일추가" onClick="fn_addFile()"/><br>
		<!-- 자바 스크립트를 이용해 <div> 태그안에 파일 업로드를 추가 -->
		<div id="d_file">
  		</div>
		<input type="submit"  value="업로드"/>
	</form>
</body>
</html>

result.jsp

<%@ page language="java" contentType="text/html; charset=EUC-KR"
    pageEncoding="EUC-KR" isELIgnored="false"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>결과 창</title>
</head>
<body>
	<h1> 업로드가 완료되어습니다 </h1>
	<label>아이디 : </label>
		<!-- value="${map.id }" : map으로 넘어온 매개변수 값을 표시할 것이다 -->
		<input type="text" name="id" value="${map.id }" readonly><br>
	<label>이름:</label>
		<input type="text" name="name" value="${map.name }" readonly><br>
	
	<div class="result-images">
		<!-- 업로드한 파일들을 forEach문을 이용해 <img> 태그에 표시 -->
		<c:forEach var="imageFileName" items="${ map.fileList}"  >
			<img src="${pageContext.request.contextPath }/download?imageFileName=${imageFileName }">
	        <br><br><br>
	    </c:forEach>         
	</div> <p> 
	
	<a href='${pageContext.request.contextPath }/form'> 다시 업로드 하시겠습니까? </a> </p>
</body>
</html>

실행하기

서버를 켜고 http://localhost:8700/pro28/form 를 요청하면 아이디/이름/파일추가가 뜬다. 그리고 파일 추가를 눌렀는데 안된다. 이건 uploadForm에서 스크립트 function fn_addFile() 이 부분이 잘 못된것이라 생각했고, 싹 지우고 다시 한자한자 쳐줬다. 그리고 다시 실행 -> 된다!


값을 넣고 업로드로 넘기면 (이미지를 한번에 여러개 여러개 넘기는 것도 가능하다)

이미지가 너무 커서 짤리는 데, 이런식으로 출력된다(오타가 있었네.. 기능이 오류없이 돌아간다는게 기뻐서 이제 봤다)

위처럼 입력한 아이디/이름, 이미지가 출력되고 하단에 다시 업로드 할 것인지 뜬다

누르면 다시 uploadForm으로 돌아간다

그리고 지정된 위치에 (FileDownloadController 에서 파일 위치를 적어줬다) 파일이 생성되고, 업로드한 이미지가 저장된 모습을 확인할 수 있었다


썸네일 이미지로 활용하기

썸네일 이미지를 사용하면, 상품 목록 나열시 빠르게 이미지를 표시할 수 있다

pom.xml

썸네일 라이브러리 설정하기

...
	<!-- 썸네일 이미지 -->
	<dependency>
		<groupId>net.coobird</groupId>
		<artifactId>thumbnailator</artifactId>
		<version>0.4.8</version>
	</dependency>
...

라이브러리가 추가된거 확인

FileDownloadController.java

package com.spring.pro28.ex02;

import java.io.File;
import java.io.FileInputStream;
import java.io.OutputStream;

import javax.servlet.http.HttpServletResponse;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;

import net.coobird.thumbnailator.Thumbnailator;
import net.coobird.thumbnailator.Thumbnails;

@Controller
public class FileDownloadController {
	private static String CURR_IMAGE_REPO_PATH = "c://spring//image_repo";
	
	@RequestMapping("/download")
	protected void download(@RequestParam("imageFileName") String imageFileName,
					HttpServletResponse response) throws Exception {
		OutputStream out = response.getOutputStream();
		String filePath = CURR_IMAGE_REPO_PATH + "\\" + imageFileName;
		File image = new File(filePath);
		
		// 확장자를 제외한 원본 이미지 파일의 이름 가져오기
		// .jpg 나 .png 이런 식이니까 . 이전의 이름 가져오기
		int lastindex = imageFileName.lastIndexOf(".");
		String fileName = imageFileName.substring(0, lastindex);
		
		// 원본 이미지 파일 이름과
		// 같은 이름의 썸네일 파일에 대한 File 객체 생성하기
		File thumbnail = new File(CURR_IMAGE_REPO_PATH + "\\" + "Thumbnailator" + "\\" + fileName+ ".png");
		
		// 원본 이미지 파일을 가로세로 50픽셀인 png형식으로 재 생성한다
		if (image.exists()) {
			thumbnail.getParentFile().mkdirs();
			Thumbnails.of(image).size(50, 50).outputFormat("png").toFile(thumbnail);
		}
		
		// 생성된 썸네일 파일을 브라우저로 전송한다
		FileInputStream in = new FileInputStream(thumbnail);
		byte[] buffer = new byte[1024 * 8];
		while (true) {
			int cnt = in.read(buffer);
			if (cnt == -1) {
				break;
			}
			out.write(buffer, 0, cnt);
		}
		
		in.close();
		out.close();
	}
}

실행

http://localhost:8700/pro28/form 으로 요청해서 하는데, 우리는 이미 ex02 파일 밖에 (실습1에 사용한) FileDownController 가 있기 때문에 그대로 실행하면 아까와 똑같은 결과가 나올 것이다. 따라서 먼저 사용한 FileDownController 의 @Controller는 지워주고(또는 주석처리 해주고) ex02의 FileDownController는 @Controller가 제대로 붙어있는지 확인한다.

실행하면 아까와 같이 입력창이 나온다

값을 넣고 업로드로 넘겨주면 이번에는 이미지가 작아진 상태로 뜨는 것을 확인할 수 있다.

그리고 설정한 위치에 파일 생성 후 변경된 썸네일 사진들이 들어가 있는 모습도 확인 가능했다


썸네일 이미지 바로 출력하기

원본 이미지를 바로 출력하려면 FileUploadcontroller에서 아래와 같이 변경하면된다

...
		File thumbnail = new File(CURR_IMAGE_REPO_PATH + "\\" + "Thumbnailator" + "\\" + fileName+ ".png");
		
		// 원본 이미지 파일을 가로세로 50픽셀인 png형식으로 재 생성한다
		if (image.exists()) {
			// 원본 이미지에 대한 썸네일 이미지를 생성 한 후 OutputStream 객체에 바로 할당한다
			Thumbnails.of(image).size(50, 50).outputFormat("png").toOutputStream(out);
		} else { return; }
		
        	// 썸네일 이미지를 OutputStream 객체를 이용해 브라우저로 바로 전송
		byte[] buffer = new byte[1024 * 8];
		out.write(buffer);
		
		out.close();
	}

실행

입력창에 값을 넣고, 업로드로 보내면

이미지가 잘 출력되는데.. 이름 값은 왜 깨지는 것이지

아까 이미지가 저장되었던 파일에 가도 새롭게 저장된 파일은 없다는 걸 확인할 수 있었다


0개의 댓글