본문 바로가기
Language/Spring

파일 업로드 쉽게 구현하기 (Spring Ajax 다중파일 업로드 & 개별삭제 & 개수제한 & 초기화) ②

by tyrannojung 2021. 5. 28.
반응형

sample

파일 업로드 게시판

 

파일 업로드가 되는 게시판은 대부분의 사이트에 꼭 하나씩 있습니다. 사이트를 구축할 때 기본이 되는 파일 업로드이지만 불편함 없이 다양한 기능이 필요할 때도 있습니다. 어디에서나 쓸 수 있게 모듈화를 해놓았고, 정리를 해놓았으며 해당 내용을 공유하고자 합니다.

 

앞전에는 커스터마이징에 대한 간단한 방법을 정리를 공유했으며, 이번에는 2번 type="file" multiple="multiple"를 통하여 다중 파일 업로드와, AJAX를 통한 스프링 파일 업로드, 그리고 다중 파일 업로드 진행 시 개별 파일 삭제, 개수 제한까지 구현해보겠습니다.

 

1. input type="file" UI 스타일변경(커스터마이징) 링크

2.

- 다중 파일업로드(멀티파일 업로드)

- AJAX로 SPRING 파일 업로드

- input file multiple 부분(선택) 삭제 후 업로드 & input file multiple max (개수 제한)

 

기본 세팅 pom.xml , servlet-context.xml

 

pom.xml

<!-- https://mvnrepository.com/artifact/commons-io/commons-io -->
<!-- 대용량 파일 처리 -->
<dependency>
  <groupId>commons-io</groupId>
  <artifactId>commons-io</artifactId>
  <version>2.6</version>
</dependency>

<!-- commons-fileupload -->
<!-- multipart등을 사용할수 있음 -->
<dependency>
  <groupId>commons-fileupload</groupId>
  <artifactId>commons-fileupload</artifactId>
  <version>1.3.1</version>
</dependency>	

servlet-context.xml

<!-- 개인적인 위치기 때문에 원하시는 위치를 잡으셔도 됩니다~ -->
<resources mapping="/**" location="/resources/" />

<!-- 스프링에서 기본으로 제공하는 multipartResolver는 CommonsMultipartResolver 이므로, 순수한 multipartResolver를 사용하기 위해 빈 이름으로 "multipartResolver"를 등록해야함 + 프로퍼티를 이용 최대 가능한 업로드 사이즈 지정함 -->
<beans:bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
	<beans:property name="maxUploadSize" value="10000000"></beans:property>
</beans:bean>

 

 

사용자 페이지(VIEW)

HTML & JAVASCRIPT & JQUERY

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<html lang="en">
<head>
  <title>파일업로드예제</title>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css">
  <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.16.0/umd/popper.min.js"></script>
  <script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.5.2/js/bootstrap.min.js"></script>
</head>
<body>

<div class="container">
  <h2>파일업로드</h2>
  <form name="dataForm" id="dataForm" onsubmit="return registerAction()">
  	<button id="btn-upload" type="button" style="border: 1px solid #ddd; outline: none;">파일 추가</button>
  	<input id="input_file" multiple="multiple" type="file" style="display:none;">
  	<span style="font-size:10px; color: gray;">※첨부파일은 최대 10개까지 등록이 가능합니다.</span>
  	<div class="data_file_txt" id="data_file_txt" style="margin:40px;">
		<span>첨부 파일</span>
		<br />
		<div id="articlefileChange">
		</div>
	</div>
  	<button type="submit" style="border: 1px solid #ddd; outline: none;">전송</button>
  </form>
</div>


<!-- 파일 업로드 스크립트 -->
<script>
$(document).ready(function()
		// input file 파일 첨부시 fileCheck 함수 실행
		{
			$("#input_file").on("change", fileCheck);
		});

/**
 * 첨부파일로직
 */
$(function () {
    $('#btn-upload').click(function (e) {
        e.preventDefault();
        $('#input_file').click();
    });
});

// 파일 현재 필드 숫자 totalCount랑 비교값
var fileCount = 0;
// 해당 숫자를 수정하여 전체 업로드 갯수를 정한다.
var totalCount = 10;
// 파일 고유넘버
var fileNum = 0;
// 첨부파일 배열
var content_files = new Array();

function fileCheck(e) {
    var files = e.target.files;
    
    // 파일 배열 담기
    var filesArr = Array.prototype.slice.call(files);
    
    // 파일 개수 확인 및 제한
    if (fileCount + filesArr.length > totalCount) {
      $.alert('파일은 최대 '+totalCount+'개까지 업로드 할 수 있습니다.');
      return;
    } else {
    	 fileCount = fileCount + filesArr.length;
    }
    
    // 각각의 파일 배열담기 및 기타
    filesArr.forEach(function (f) {
      var reader = new FileReader();
      reader.onload = function (e) {
        content_files.push(f);
        $('#articlefileChange').append(
       		'<div id="file' + fileNum + '" onclick="fileDelete(\'file' + fileNum + '\')">'
       		+ '<font style="font-size:12px">' + f.name + '</font>'  
       		+ '<img src="/img/icon_minus.png" style="width:20px; height:auto; vertical-align: middle; cursor: pointer;"/>' 
       		+ '<div/>'
		);
        fileNum ++;
      };
      reader.readAsDataURL(f);
    });
    console.log(content_files);
    //초기화 한다.
    $("#input_file").val("");
  }

// 파일 부분 삭제 함수
function fileDelete(fileNum){
    var no = fileNum.replace(/[^0-9]/g, "");
    content_files[no].is_delete = true;
	$('#' + fileNum).remove();
	fileCount --;
    console.log(content_files);
}

/*
 * 폼 submit 로직
 */
	function registerAction(){
		
	var form = $("form")[0];        
 	var formData = new FormData(form);
		for (var x = 0; x < content_files.length; x++) {
			// 삭제 안한것만 담아 준다. 
			if(!content_files[x].is_delete){
				 formData.append("article_file", content_files[x]);
			}
		}
   /*
   * 파일업로드 multiple ajax처리
   */    
	$.ajax({
   	      type: "POST",
   	   	  enctype: "multipart/form-data",
   	      url: "/file-upload",
       	  data : formData,
       	  processData: false,
   	      contentType: false,
   	      success: function (data) {
   	    	if(JSON.parse(data)['result'] == "OK"){
   	    		alert("파일업로드 성공");
			} else
				alert("서버내 오류로 처리가 지연되고있습니다. 잠시 후 다시 시도해주세요");
   	      },
   	      error: function (xhr, status, error) {
   	    	alert("서버오류로 지연되고있습니다. 잠시 후 다시 시도해주시기 바랍니다.");
   	     return false;
   	      }
   	    });
   	    return false;
	}
</script>
</body>
</html>

 

전체적인 원리는 다음과 같습니다.

 

1. input type="file" multiple="multiple"이 동작할때(document ready에서 실행), 해당 파일을 가져와서 배열에 담아주고 input file은 초기화 해줍니다.

*input file multiple 특성상 중복파일은 업로드가 되지 않습니다. 초기화를 해야 중복파일도 업데이트가 가능해집니다. 

 

2. 파일을 담고 -이미지를 클릭했을때 delete 되었다고 변경합니다.

 

3. ajax로 보낼때 delete된것을 제외하고 보냅니다.

 

JAVA

SPRING

	@ResponseBody
	@RequestMapping(value = "/file-upload", method = RequestMethod.POST)
	public String fileUpload(
			@RequestParam("article_file") List<MultipartFile> multipartFile
			, HttpServletRequest request) {
		
		String strResult = "{ \"result\":\"FAIL\" }";
		String contextRoot = new HttpServletRequestWrapper(request).getRealPath("/");
		String fileRoot;
		try {
			// 파일이 있을때 탄다.
			if(multipartFile.size() > 0 && !multipartFile.get(0).getOriginalFilename().equals("")) {
				
				for(MultipartFile file:multipartFile) {
					fileRoot = contextRoot + "resources/upload/";
					System.out.println(fileRoot);
					
					String originalFileName = file.getOriginalFilename();	//오리지날 파일명
					String extension = originalFileName.substring(originalFileName.lastIndexOf("."));	//파일 확장자
					String savedFileName = UUID.randomUUID() + extension;	//저장될 파일 명
					
					File targetFile = new File(fileRoot + savedFileName);	
					try {
						InputStream fileStream = file.getInputStream();
						FileUtils.copyInputStreamToFile(fileStream, targetFile); //파일 저장
						
					} catch (Exception e) {
						//파일삭제
						FileUtils.deleteQuietly(targetFile);	//저장된 현재 파일 삭제
						e.printStackTrace();
						break;
					}
				}
				strResult = "{ \"result\":\"OK\" }";
			}
			// 파일 아무것도 첨부 안했을때 탄다.(게시판일때, 업로드 없이 글을 등록하는경우)
			else
				strResult = "{ \"result\":\"OK\" }";
		}catch(Exception e){
			e.printStackTrace();
		}
		return strResult;
	}

 

완성본

-이미지는 구하셔서 첨부해주세요~

 

정리

 

SPRING에서 input file multiple과 AJAX multipart/form-data처리 파일 선택 업로드, 파일 선택 삭제, 다중 파일 업로드 개수 제한까지 다 가능한 소스입니다. 

 

이 정도 예제를 잘 가공해서 사용하면 충분히 어떤 게시판에서든 활용이 가능할 겁니다.

혹시라도 구현 진행 중에 안 되는 부분 있으시면 댓글 남겨주시면 소스 보내드릴게요~ 

또한 내용상 오류가 있거나 잘못된 점이 있으면 댓글 남겨주시면 진심으로 감사하겠습니다!

 

 

반응형

댓글