Framework/Spring

[Spring Framework]Ajax + FormData를 이용한 파일 전송

  • -
반응형

지금까지 경험한 바로 클라이언트단에서 파일 업로드를 하기 위해서 사용한 방법은 두가지가 있었습니다. Form-Submit을 이용한 방법과 Javascript-Ajax를 이용한 방법입니다.

 

오늘 포스팅할 내용은 자바스크립트를 이용한 파일 업로드입니다.

Ajax와 FormData를 이용해 비동기 방식으로 서버측에 파일을 보내보도록 하겠습니다.


FormData

FormData는 자바스크립트에서 제공해주는 객체로 key와 value로 데이터를 append/parsing 할 수 있다.

파일을 담는 과정은 아래에서 보도록 하자.

참고로 FormData를 사용할 때, IE는 버전 10 이상에서만 가능하다고 한다.

 

스프링은 설정이 반이라고 생각하는데 여기서도 사실 설정이 반이다.

 

1) 먼저, 파일 업로드를 위한 dependency를 받아준다.

 

pom.xml

<!-- File upload -->
<!-- https://mvnrepository.com/artifact/commons-fileupload/commons-fileupload -->
<dependency>
  <groupId>commons-fileupload</groupId>
  <artifactId>commons-fileupload</artifactId>
  <version>1.3.2</version>
</dependency>

<dependency>
  <groupId>commons-io</groupId>
  <artifactId>commons-io</artifactId>
  <version>2.5</version>
</dependency>

 

2) MultipartFilter를 선언, url-pattern을 지정해준다.

 

web.xml

<!-- MultipartFilter -->
 <filter>
	<filter-name>MultipartFilter</filter-name>
    <filter-class>org.springframework.web.multipart.support.MultipartFilter</filter-class>
</filter>
<filter-mapping>
	<filter-name>MultipartFilter</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>

 

3) Multipart 기능을 사용하기 위해서 MultipartResolver 설정해야 한다. MultipartResolver는 Multipart 형식의 데이터가 전송된 경우 해당 데이터를 스프링 MVC에서 사용할 수 있도록 변환해준다. DispatcherServlet은 이름이 "multipartResolver"인 bean을 사용하기 때문에 bean id를 다르게 지정할 경우 에러가 발생한다.

 

servlet-context.xml

<!-- 파일 업로드 데이터 관리 -->
<beans:bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">	        
  <beans:property name="maxUploadSize" value="10485760" />   <!-- Max upload size : 10MB -->	        
  <beans:property name="maxInMemorySize" value="10485760" /> <!-- Max size of file in memory : 10MB -->
</beans:bean>

 

4) allowCasualMultipartParsing 옵션 추가

Tomcat이 multipart/form-data 요청 본문을 자동으로 구문 분석하도록 Tomcat - context.xml 파일에 allowCasualMultipartParsing 옵션을 추가해주어야 한다. 이 옵션을 추가해주지 않았을 때, 404 에러로 경로를 찾지 못했다.

 

context.xml

<Context allowCasualMultipartParsing="true" path="/">
	<Resources cachingAllowed="true" cacheMaxSize="100000" />
	
    <!-- Default set of monitored resources. If one of these changes, the    -->
    <!-- web application will be reloaded.                                   -->
    <WatchedResource>WEB-INF/web.xml</WatchedResource>
    <WatchedResource>WEB-INF/tomcat-web.xml</WatchedResource>
    <WatchedResource>${catalina.base}/conf/web.xml</WatchedResource>

    <!-- Uncomment this to disable session persistence across Tomcat restarts -->
    <!--
    <Manager pathname="" />
    -->
</Context>

 

5) View 페이지

"mailFIle" id를 갖는 element가 변경될 경우 fnct_AddFiles 함수를 실행해 배열(filesTempArr)에 파일을 넣었다.

전송을 클릭하면 fnct_SendMail() 함수가 실행되고, formData에 배열에 담겨있는 파일을 append 하는 식이다.

 

mail.jsp

var filesTempArr = [];		// 파일 데이터를 담을 배열

/* 
 * 파일 추가
 */
function fnct_AddFiles(files) {	
	filesTempArr = [];

    var filesArr = Array.prototype.slice.call(files);    

    for(var i = 0; i < filesArr.length; i++) {        
    	filesTempArr.push(filesArr[i]);    	    	  
    }
}

function fnct_SendMail() {	
	var formData = new FormData($("#frm")[0]);
	formData.append("mailTitle"   , $("#mailTitle").val());
	formData.append("CkmailContent", $("#CkmailContent").val());
    
	for(var i = 0; i < filesTempArr.length; i++) {
		formData.append("files", filesTempArr[i]);
	}	

	$.ajax({
		type : "POST",
		url : "/mail/sendMail.ajax",
		data : formData,
		processData: false,
		contentType: false,				
		success : function(data) {				
			if(data.result == "SUCCESS") {
				alert("파일이 전송되었습니다.");				
			} else {
				alert("파일 전송에 실패하였습니다.");
			}  		    		  
	 	},
	 	error : function(request, status, error) {
	 		alert("code : " + request.status + "\n" + "message : " + request.responseText + "\n" + "error : " + error);
		}
	});
}

$(document).ready(function() {	
	/* 파일 첨부 */
	$("#mailFile").on("change", function(){ 
		fnct_AddFiles(this.files); 
	});		
}
<form:form id="frm" method="POST">
	<input type="file" class="form-control" multiple="multiple" id="mailFile" name="mailFile[]">	
</form:form>

 

6) 서버단 처리

서버단에서 파일을 받을 때 MultipartHttpServletRequest 클래스를 이용해 파일을 추출할 수 있다.

View 페이지에서 파일이 아닌 text 형태로 append 후에 서버단에서 받아올 때 한글이 깨지는 현상이 있었다. 

mailTitle과 mailContent 변수가 그것인데 이 경우 변환 작업을 한번 거쳐주면 된다.

주석을 따라 보면 알겠지만 파일 생성시 생성 시간을 덧붙여 중복이 되지 않게끔 처리하였다.

 

MailController.java

@RequestMapping(value = "/mail/sendMail.ajax", method = { RequestMethod.POST })
	public @ResponseBody HashMap<String, Object> fileUpload(HttpSession session, MultipartHttpServletRequest mtfRequest) throws Exception {
		SimpleDateFormat sdf = new SimpleDateFormat ( "yyyyMMddHHmmss");		
		Date date = new Date();
		
		CommonUtil commonUtil = new CommonUtil();
		JSONObject result = new JSONObject(); 					
		MailVO mailVO = new MailVO();

		String PATH = "D:\\PLANM\\file\\";		
		String fileName = "";		// 파일 이름(확장자 제외)
		String fileFullName = "";	// 파일 이름(확장자 포함)
		String fileType = "";		// 파일 확장자				
		String fileUploadTime = sdf.format(date);	// 파일 업로드 시간(yyyymmddhhmmss)
		
		String[] mailTitle   = mtfRequest.getParameterValues("mailTitle");		
		String[] mailContent = mtfRequest.getParameterValues("CkmailContent");
		// FormData 사용시 한글이 깨지는 것을 방지
		String convertTomailTitle   = new String(mailTitle[0].getBytes("8859_1"),"utf-8");  		
		String convertToContent = new String(mailContent[0].getBytes("8859_1"),"utf-8");
		
		try {			
			Iterator<String> itr =  mtfRequest.getFileNames();
        	
        	if(itr.hasNext()) {        		        		
        		List<MultipartFile> mpf = mtfRequest.getFiles((String) itr.next());
        		
        		for(int i = 0; i < mpf.size(); i++) {
          			File file = new File(PATH + mpf.get(i).getOriginalFilename());
          		
          			fileFullName = mpf.get(i).getOriginalFilename();
        			fileName = FilenameUtils.getBaseName(mpf.get(i).getOriginalFilename());
        			fileType = fileFullName.substring(fileFullName.lastIndexOf(".")+1, fileFullName.length());
            			
          			file = new File(PATH + fileName + "_" + fileUploadTime + "." + fileType);          				
          			
           		 	logger.info("----------------------- FILE UPLOAD START ---------------------------");
           		 	logger.info("FILE : " + file.getAbsolutePath());
           		 	logger.info("SIZE : " + mpf.get(i).getSize() + "bytes");
           		 	logger.info("----------------------- FILE UPLOAD END -----------------------------");
           		            		 	
           		 	mpf.get(i).transferTo(file);	// 파일 전송
           	 	}           	         		
        	}        	        				
			
          	result.put("result", "SUCCESS");         	
		} catch (Exception e) {
			e.printStackTrace();
			result.put("result", "ERROR");			
		}
        	
        return result;
	}

업로드된 파일들

 

여기에는 구현되지 않았지만 디렉토리를 만드는 것도 가능하며, 파일의 업로드뿐 아니라 삭제도 가능하다.


+ 피드백은 언제나 환영입니다 :)

반응형
Contents

포스팅 주소를 복사했습니다.

이 글이 도움이 되었다면 공감 부탁드립니다.