본문으로 바로가기

Spring 파일 첨부(업로드)

category 카테고리 없음 2019. 5. 9. 21:25

Ajax를 이용한 파일 업로드를 사용합니다.

우선 서버 폴더로 C아래 upload폴더와 하위폴더 temp를 만들어줍니다.

 

파일 업로드를 하기위해서는 서블릿 3.1.0 버전으로 맞춥니다.

 

<!-- Servlet -->
<dependency>
		<groupId>javax.servlet</groupId>
		<artifactId>javax.servlet-api</artifactId>
		<version>3.1.0</version>
		<scope>provided</scope>
</dependency>

그리고 web.xml에서 multipart를 위해서 아래와 같이 작성합니다.

 

<!-- Processes application requests -->
	<servlet>
		<servlet-name>appServlet</servlet-name>
		<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
		<init-param>
			<param-name>contextConfigLocation</param-name>
			<param-value>/WEB-INF/spring/appServlet/servlet-context.xml</param-value>
		</init-param>
		<load-on-startup>1</load-on-startup>
		
		<multipart-config>
			<location>C:\\upload\\temp</location>
			<max-file-size>20971520</max-file-size> <!-- 1MB * 20 -->
			<max-request-size>41943040</max-request-size> <!-- 40MB -->
			<file-size-threshold>20971520</file-size-threshold> <!-- 20MB -->
		</multipart-config>
	</servlet>

그다음 웹 관련 파일 servlet-context.xml에 아래를 추가해줍니다.

 

	<beans:bean id="multipartResolver" class="org.springframework.web.multipart.support.StandardServletMultipartResolver">
	</beans:bean>

우선 업로드할 컨트롤러를 작성합시다.

package org.zerock.controller;

import java.io.File;

import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.multipart.MultipartFile;

import lombok.extern.log4j.Log4j;

@Controller
@Log4j
public class UploadController {
	
	@GetMapping("/uploadAjax")
	public void uploadAjax() {
		log.info("upload Ajax");
		
	}

}

 

 

우선 파일을 업로드할 화면인 uploadAjax.jsp를 Get 방식으로 보여주기 위해 GetMapping을 통해 보여줍니다.

 

즉 사용자가 get방식으로 요청 시 uploadAjax.jsp가 화면에 보이게 됩니다. 

 

업로드 화면

위에 처럼 uploadAjax.jsp를 작성해 봅시다.

 

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
<h1>Upload with Ajax</h1>

<div class='uploadDiv'>
	<input type='file' name='uploadFile' multiple>
</div>

<button id='uploadBtn'>Upload</button>
</body>

input 타입을 file로 하고 다수의 파일을 위해 multiple을 적용시킵니다.

 

그 다음 Ajax를 처리해줍니다. JQuery를 cdn 방식으로 적용 시켜줍니다.

 

cdn은 다음과 같이 uploadAjax.jsp에 작성합니다.

 

<script
  src="https://code.jquery.com/jquery-3.4.1.js"
  integrity="sha256-WpOohJOqMqqyKL9FccASB9O0KwACQJpFTUBLTYOVvVU="
  crossorigin="anonymous"></script>

그리고 ajax를 아래와 같이 작성합니다. ( uploadAjax.jsp에서 <script> 부분)

 

<script>
$(document).ready(function(){

	$("#uploadBtn").on("click",function(e){
		var formData = new FormData();
		
		var inputFile = $("input[name='uploadFile']");
		
		var files = inputFile[0].files;
		
		console.log(files);
		
		for(var i=0; i<files.length; i++){
			formData.append("uploadFile",files[i]);
		}
		
		$.ajax({
			url: '/uploadAjax',
			processData: false,
			contentType: false,
			data: formData,
			type: 'POST',
			success: function(result){
				alert("Uploaded");
			}
		});
	});
});
</script>

여기서 주의사항은 processData와 contentType을 false로 지정해주어야 가능합니다.

 

업로드 버튼이 눌리면 클릭 이벤트로 처리를 하는데 formData를 사용합니다. 즉 업로드할 파일을 formData에 넣어주고

 

이를 ajax로 /uploadAjax(post 방식)으로 뿌려줍니다. 이때 formData를 보내고 컨트롤러에서 처리하게 되고 반환합니다.

 

성공시 Uploaded가 뜹니다.

 

이를 위해 컨트롤러 Post 부분을 처리해줍시다.  아래와 같습니다.

 

@PostMapping("/uploadAjax")
	public void uploadAjaxPost(MultipartFile[] uploadFile)
	{
		log.info("update Ajax post....");
		String uploadFolder = "C:\\upload";
		
		for(MultipartFile multipartFile : uploadFile) {
			log.info("----------------------------");
			log.info("Upload File Name: "+multipartFile.getOriginalFilename());
			log.info("Upload File Size: "+multipartFile.getSize());
			String uploadFileName = multipartFile.getOriginalFilename();
			
			//iE has file path
			uploadFileName = uploadFileName.substring(uploadFileName.lastIndexOf("\\")+1);
			
			log.info("only file name(for IE): "+uploadFileName);
			
			
			File saveFile = new File(uploadFolder,uploadFileName);
			
			try {
				multipartFile.transferTo(saveFile);
				
			}catch(Exception e) {
				log.error(e.getMessage());
			}
		}
	}

Ajax를 통해 넘어온 파일을 받아 File을 통해 저장하고 이를 transferTo를 통해 보냅니다. 

 

그러면 아까 만들어놓은 폴더에 업로드가 됩니다.

 

전체 컨트롤러 코드는 아래와 같습니다.

 

package org.zerock.controller;

import java.io.File;

import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.multipart.MultipartFile;

import lombok.extern.log4j.Log4j;

@Controller
@Log4j
public class UploadController {

	@GetMapping("/uploadAjax")
	public void uploadAjax() {
		log.info("upload Ajax");
		
	}
	@PostMapping("/uploadAjax")
	public void uploadAjaxPost(MultipartFile[] uploadFile)
	{
		log.info("update Ajax post....");
		String uploadFolder = "C:\\upload";
		
		for(MultipartFile multipartFile : uploadFile) {
			log.info("----------------------------");
			log.info("Upload File Name: "+multipartFile.getOriginalFilename());
			log.info("Upload File Size: "+multipartFile.getSize());
			String uploadFileName = multipartFile.getOriginalFilename();
			
			//iE has file path
			uploadFileName = uploadFileName.substring(uploadFileName.lastIndexOf("\\")+1);
			
			log.info("only file name(for IE): "+uploadFileName);
			
			
			File saveFile = new File(uploadFolder,uploadFileName);
			
			try {
				multipartFile.transferTo(saveFile);
				
			}catch(Exception e) {
				log.error(e.getMessage());
			}
		}
	}
	
	
}

 

그리고 추가적으로 용량이 큰 파일이나 불법 프로그램 업로드 방지를 위해 확장자를 제한시켜주는 용도가 많이 쓰입니다.

 

이들 모두 정규화식과 자바스크립트를 이용해 처리합니다. 위에 자바스크립트 코드에 추가로 함수를 작성합니다.

 

var regex = new RegExp("(.*?)\.(exe|sh|zip|alz)$"); //파일 확장자 정규식 
var maxSize = 5242880; // 5MB
	
function checkExtension(fileName,fileSize){
	if(fileSize >= maxSize){
		alert("파일 사이즈 초과");
		return false;
	}
		
	if(regex.test(fileName)){
		alert("해당 종류의 파일은 업로드할 수 없습니다.");
		return false;
	}
	return true;
}

regex는 정규화식으로 파일 확장자를 정해주고 maxSize는 5MB으로 최대 크기를 지정해줍니다.

 

checExtension 함수에서 파일 이름과 파일 사이즈를 매개변수로 받아서 파일 사이즈를 maxSize와 비교하고

 

정규화 test함수를 통해 정규화 테스를 합니다. 만약 exe나 sh나 zip이나 alz 확장자가 있을 시 바로 업로드 못하게 막습니다.

 

전체 uploadAjax.jsp는 아래와 같습니다.

 

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
<h1>Upload with Ajax</h1>

<div class='uploadDiv'>
	<input type='file' name='uploadFile' multiple>
</div>

<button id='uploadBtn'>Upload</button>

<script
  src="https://code.jquery.com/jquery-3.4.1.js"
  integrity="sha256-WpOohJOqMqqyKL9FccASB9O0KwACQJpFTUBLTYOVvVU="
  crossorigin="anonymous"></script>
  
<script>
$(document).ready(function(){
	
	var regex = new RegExp("(.*?)\.(exe|sh|zip|alz)$"); //파일 확장자 정규식 
	var maxSize = 5242880; // 5MB
	
	function checkExtension(fileName,fileSize){
		if(fileSize >= maxSize){
			alert("파일 사이즈 초과");
			return false;
		}
		
		if(regex.test(fileName)){
			alert("해당 종류의 파일은 업로드할 수 없습니다.");
			return false;
		}
		return true;
	}
	
	$("#uploadBtn").on("click",function(e){
		var formData = new FormData();
		
		var inputFile = $("input[name='uploadFile']");
		
		var files = inputFile[0].files;
		
		console.log(files);
		
		for(var i=0; i<files.length; i++){
			if(!checkExtension(files[i].name,files[i].size)){
				return false;
			}
			formData.append("uploadFile",files[i]);
		}
		
		$.ajax({
			url: '/uploadAjax',
			processData: false,
			contentType: false,
			data: formData,
			type: 'POST',
			success: function(result){
				alert("Uploaded");
			}
		});
	});
});
</script>
</body>
</html>

위 함수를 if(!checkExtension(files[i].name,files[i].size))으로 이용합니다.

 

결과는 아래와 같습니다.