[Spring] 파일 업로드

Whatever·2022년 2월 10일
0

Spring(스프링)

목록 보기
16/29

참고사이트 : https://www.hanumoka.net/2018/09/06/spring-20180906-spring-file-upload/

서버에 파일을 저장할 때 고려해야 할 사항들.
1. 파일업로드 방식 결정하기
POST 방식 or Ajax 방식
2. 파일이름 중복
파일시스템에 파일을 저장할 때 파일이름이 중복되면 덮어써지게 된다. => UUID사용으로 해결
3. 파일 저장경로
개수가 많아지면 속도저하문제 발생 => 파일이 업로드되는 시점(날짜)으로 구분해서 폴더생성


파일 업로드 방식

1. POST 방식

post방식 VIEW

업로드

<%@ page language="java" contentType="text/html; charset=UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<!DOCTYPE html>
<html>
<head>
<title>파일 업로드 테스트</title>
</head>
<body>

<form action="/uploadTest/uploadFormAction" method="post"
	enctype="multipart/form-data">
	<input type="file" name="uploadFile" multiple />
	<button>Submit</button>
</form>

</body>
</html>

업로드버튼 클릭

<%@ page language="java" contentType="text/html; charset=UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<!DOCTYPE html>
<html>
<head>
<title>업로드 성공</title>
</head>
<body>
업로드 성공<br>
<c:forEach var="img" items="${list}">
	<img src="/resources/upload/${img}" />
</c:forEach>
</body>
</html>

Controller

	//<input type="file" name="uploadFile" multiple />
	//MultipartFile : 스프링 프레임워크에서 제공하는 타입
	@PostMapping("/uploadFormAction")
	public String uploadFormPost(MultipartFile[] uploadFile, Model model) {
		
	      // (1)파일 저장할 위치 설정
	      String uploadFolder = "D:\\A_TeachingMaterial\\6.JspSpring\\workspace\\springProj\\src\\main\\webapp\\resources\\upload";
	      
	      List<String> list = new ArrayList<String>();
	      
	      for(MultipartFile multipartFile : uploadFile) {
	         logger.info("-----------");
	         logger.info("파일명 : " + multipartFile.getOriginalFilename());
	         logger.info("파일크기 : " + multipartFile.getSize());
	         
	         
	         // uploadFolder\\gongu03.jpg으로 조립
	         // 이렇게 업로드 하겠다라고 설계
	         File saveFile = new File(uploadFolder, multipartFile.getOriginalFilename());
	         
	         try {
	            //파일 실제 명을 list에 담음
	            list.add(multipartFile.getOriginalFilename());
	            //transferTo() : 물리적으로 파일 업로드가 됨
	            multipartFile.transferTo(saveFile);
	         }catch(Exception e) {
	            logger.info(e.getMessage());
	         }//end catch
	      }//end for
	      //list : 파일명들이 들어있음
	      model.addAttribute("list", list);
	      
	      //forward
	      return "uploadTest/uploadSuccess";
	}

2. Ajax 방식

Ajax방식 VIEW

<%@ page language="java" contentType="text/html; charset=UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<!DOCTYPE html>
<html>
<head>
<script type="text/javascript" src="/resources/js/jquery-3.6.0.js"></script>
<title>Upload with Ajax</title>
<script type="text/javascript">
//파일을 담아두는 변수
var sel_file = [];

$(function(){
	//----------------이미지 미리보기 시작----------------
	$("#input_img").on("change", handleImgFileSelect);
	
	function handleImgFileSelect(e){
		//e.target : 파일 객체		
		//e.target.files : 파일객체 안의 파일들 
		var files = e.target.files;
		//파일을 잘라서 array로 만든다.
		var filesArr = Array.prototype.slice.call(files);
		
		//f: 파일 객체
		filesArr.forEach(function(f){
			//미리보기는 이미지만 가능함			
			if(!f.type.match("image.*")){
				alert("이미지만 가능합니다.");
				return;
			}
		
			//파일객체 복사
			sel_file.push(f);
            // 파일을 읽어주는 객체 생성
            var reader = new FileReader();
            reader.onload = function(e){
               //하나일 때
               //$("#img").attr("src", e.target.result);
               
               //forEach 반복 하면서 img 객체 생성
               //반복될 때마다 img가 새로 생성된다.
               var img_html = "<img src=\"" + e.target.result + "\" />";
               $(".img_wrap").append(img_html);
            }
            reader.readAsDataURL(f);
         });
	}
	//----------------이미지 미리보기 끝----------------
	//모든 파일명.확장자(exe|sh|zip|alx)는 업로드를 못하도록 막기 
	//첨부파일의 확장자가 exe, sh, zip, alz 경우 업로드를 제한
	var regex = new RegExp("(.*?)\.(exe|sh|zip|alx)$");
	//최대 5MB까지만 업로드 가능
	var maxSize = 5242880; //5MB
	//확장자, 크기 체크
	function checkExtension(fileName, fileSize){
		if(fileSize >= maxSize){
			alert("파일 사이즈 초과");
			return false;
		}
		
		if(regex.test(fileName)){
			alert("해당 종류의 파일은 업로드할 수 없습니다.");
			return false;
		}
		//체크 통과
		return true;
	}
	
	//Upload 버튼 클릭 시 수행
	$("#uploadBtn").on("click", function(e){
		//FormData : 가상의 <form> 태그
		//Ajax를 이용하는 파일 업로드는 FormData를 이용
		var formData = new FormData();
		//<input type="file" 요소
		var inputFile = $("input[name='uploadFile']");
		//<input type="file" 요소 내의 이미지들
		var files = inputFile[0].files;
		
// 		console.log(files);
		
		for(var i=0; i<files.length;i++){
			console.log(files[i]);
			//확장자, 크기 체크
			//function checkExtension(fileName, fileSize){
			if(!checkExtension(files[i].name, files[i].size)){//!true라면 실패
				return false;
			}
			formData.append("uploadFile", files[i]);
		}
	
		
		//없어?카드가?또?
		// 아리가또 아포가또
		//processData, contentType은 반드시 false여야 전송됨
		$.ajax({
			url:'/uploadTest/uploadAjaxAction',
			processData: false,
			contentType: false,
			data: formData,
			type:'POST',
			success: function(result){
				//JSON을 string으로 변환해서 console에 찍어보기
				console.log("result : " + JSON.stringify(result));
			}
		});
	});
	
});
</script>
</head>
<body>
<h1>Upload with Ajax</h1>

<div class="uploadDiv">
	<input type="file" id="input_img" name="uploadFile" multiple>
</div>

<button id="uploadBtn">Upload</button>
<div class="img_wrap">
	
</div>
</body>
</html>

Controller

	//<form> 태그를 이용하던 방식과 동일한 방식으로 처리됨
	//Ajax 방식으로 결과 데이터를 전달하므로 Model을 사용하지 않음.
	@ResponseBody
	@PostMapping("/uploadAjaxAction")
	public List<AttachFileVO> uploadAjaxAction(MultipartFile[] uploadFile) {
		
		String uploadFolder = "D:\\A_TeachingMaterial\\6.JspSpring\\workspace\\springProj\\src\\main\\webapp\\resources\\upload";
		
		//연/월/일 폴더 생성 시작-------
		File uploadPath = new File(uploadFolder, getFolder());
		logger.info("uploadPath : " + uploadPath);
		logger.info("uploadPath.exists() : " + uploadPath.exists());
		
		if(uploadPath.exists()==false) {//해당 경로가 없으면 생성해줘야함
			uploadPath.mkdirs();			
		}
		//연/월/일 폴더 생성 끝-------
		
		//첨부된 파일의 이름을 담을 List
		List<AttachFileVO> list = new ArrayList<AttachFileVO>();
		
		for(MultipartFile multipartFile : uploadFile) {
			logger.info("-----------");
			logger.info("파일명 : " + multipartFile.getOriginalFilename());
			logger.info("파일크기 : " + multipartFile.getSize());
			
			AttachFileVO attachFileVO = new AttachFileVO();
			// 1) fileName 세팅
			attachFileVO.setFileName(multipartFile.getOriginalFilename());
			
			//-----------UUID 파일명 처리 시작 ----------------------------
			//동일한 이름으로 업로드되면 기존 파일을 지우게 되므로 이를 방지하기 위함
			UUID uuid = UUID.randomUUID();
			
			String uploadFileName = uuid.toString() + "-" + multipartFile.getOriginalFilename();
			// c:\\upload\\gongu03.jpg으로 조립
			// 이렇게 업로드 하겠다라고 설계 uploadFolder -> uploadPath
			File saveFile = new File(uploadPath,uploadFileName);
			//-----------UUID 파일명 처리 끝 ----------------------------
			
			try {
				
				//transferTo() : 물리적으로 파일 업로드가 됨
				multipartFile.transferTo(saveFile);
			
				//2) uploadPath
				attachFileVO.setUploadPath(uploadPath.getPath());
				//3) uuid
				attachFileVO.setUuid(uuid.toString());
				
				//-------썸네일 처리 시작---------
				//이미지 파일인지 체킹
				if(checkImageType(saveFile)) {
					logger.info("이미지 파일? true");
					//4) image여부
					attachFileVO.setImage(true);
					
					//uploadPath : 연/월/일이 포함된 경로
					//uploadFileName : UUID가 포함된 파일명
					FileOutputStream thumbnail = 
							new FileOutputStream(
									new File(uploadPath,"s_"+uploadFileName));
					Thumbnailator.createThumbnail(multipartFile.getInputStream(),
							thumbnail, 100, 100);
					thumbnail.close();
				}else {
					logger.info("이미지 파일? false");
				}
				//-------썸네일 처리 끝---------
				
				//파일 객체(AttachFileVO)를 list에 담음
				list.add(attachFileVO);
			}catch(Exception e){
				logger.info(e.getMessage());
			}//end catch
		}//end for
		
		return list;
	}//end uploadAjaxAction
	
	//첨부파일을 보관하는 폴더를 연/월/일 계층 형태로 생성하기 위함
	private String getFolder() {
		SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
		Date date = new Date();
		String str = sdf.format(date);
		return str.replace("-", File.separator);
	}
	
	//특정한 파일이 이미지 타입인지 검사해주는 메소드
	private boolean checkImageType(File file) {
		try {
			//file.toPath() : 파일의 전체 경로
			logger.info("file.toPath() : " + file.toPath());
			String contentType = Files.probeContentType(file.toPath());
			logger.info("contentType : " + contentType);
			//contentType이 image로 시작하면 이미지 타입이므로 true를 리턴함
			return contentType.startsWith("image");
		}catch(IOException e) {
			e.printStackTrace();
		}
		return false;
	}

0개의 댓글