본문으로 바로가기

[스프링]19. ajax 파일 전송에 대한 이해(1)

category SPRING/스프링 2021. 5. 25. 15:46
728x90
반응형
SMALL

파일 전송을 위한 의존성 설정

pom.xml

<dependency>
		<groupId>javax.servlet</groupId>
		<artifactId>javax.servlet-api</artifactId>
		<version>3.1.0</version>
</dependency>

서블릿 3.0이상 버전 설정

web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xmlns="http://xmlns.jcp.org/xml/ns/javaee"
	xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
	id="WebApp_ID" version="3.1">//버전변경

	<!-- The definition of the Root Spring Container shared by all Servlets 
		and Filters -->
	<context-param>
		<param-name>contextConfigLocation</param-name>
		<param-value>/WEB-INF/spring/root-context.xml
    
    </param-value>
	</context-param>

	<!-- Creates the Spring Container shared by all Servlets and Filters -->
	<listener>
		<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
	</listener>

	<!-- 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-mapping>
		<servlet-name>appServlet</servlet-name>
		<url-pattern>/</url-pattern>
	</servlet-mapping>

<!-- 한글 인코딩 설정 -->
<filter>
    <filter-name>encodingFilter</filter-name>
    <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
    <init-param>
      <param-name>encoding</param-name>
      <param-value>UTF-8</param-value>
    </init-param>
  </filter>

  <filter-mapping>
    <filter-name>encodingFilter</filter-name>
    <url-pattern>/*</url-pattern>
  </filter-mapping>
  
<!--   	<filter>
		<filter-name>springSecurityFilterChain</filter-name>
		<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
	</filter>

	<filter-mapping>
		<filter-name>springSecurityFilterChain</filter-name>
		<url-pattern>/*</url-pattern>
	</filter-mapping>
 -->
  
  
  
  
</web-app>

web.xml 또한 버전을 3.0이상으로 변경 및 <multipart-config> 추가

 

servlet-context.xml

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

첨부파일 처리하는 빈 추가


Form 을 이용한 파일전송 테스트

uploadForm.jsp

<body>
<form action="uploadFormAction" method="post" enctype="multipart/form-data">
	<input type='file' name='uploadFile' multiple>
	<button>전송</button>
</form>
</body>

enctype 속성값을 multipart/from-data 지정해야하며

최근 브라우저에서는 multiple 이라는 속성을 지원하여 여러개의 파일을 업로드 할 수 있음(ie10 이상에서만 지원)

 

UploadController

@PostMapping("/uploadFormAction")
public void uploadFormAction(MultipartFile[] uploadFile, Model model) {
		
		String uploadFolder = "C:\\upload1";
		
		for(MultipartFile multipartFile:uploadFile) {
			log.info("==========");
			log.info("업로드 파일이름:  "+multipartFile.getOriginalFilename());
			log.info("업로드 파일크기:  "+multipartFile.getSize());
			
			File saveFile = new File(uploadFolder, multipartFile.getOriginalFilename());
			try {
				multipartFile.transferTo(saveFile);
			} catch (Exception e) {
				log.error(e.getMessage());
			}
		}
	}

여러개의 파일을 업로드 할 수 있기때문에 MultipartFile의 배열 타입으로 받으며

업로된 파일을 transferTo() 의 파라미터로 File 객체를 지정하여 파일을 저장한다.

콘솔과 함께 파일이 서버에 저장됨을 확인 할 수 있다.

 

Ajax를 이용한 파일전송 테스트

uploadAjax.jsp

	<div class='uploadDiv'>
		<input type='file' name='uploadFile' multiple>
	</div>
	<button id='uploadBtn'>Upload</button>

JQuery를 쓰기위해 cdn 선언

<script src="https://code.jquery.com/jquery-3.3.1.min.js"
		integrity="sha256-FgpCb/KJQlLNfOu91ta32o/NMZxltwRo8QtmkMRdAu8="
		crossorigin="anonymous"></script>

<script>

 

$("#uploadBtn").on("click", function(e) {

			var formData = new FormData();

			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 : '/uploadAjaxAction',
				processData : false,
				contentType : false,
				data : formData,
				type : 'POST',
				dataType : 'json',
				success : function(result) {

					console.log(result);

					showUploadedFile(result);

					$(".uploadDiv").html(cloneObj.html());

				}
			}); //$.ajax

		});

ajax를 통해서 JSON타입으로 formData에 정보를 담아서 전송한다.

processData와 contentType은 반드시 false로 지정한다,

UploadController

//파일 저장
	@PostMapping(value="/uploadAjaxAction", produces= MediaType.APPLICATION_JSON_UTF8_VALUE)
	@ResponseBody
	public ResponseEntity<List<AttachFileDTO>>uploadAjaxPost(MultipartFile[] uploadFile){
		
		//파일 여러개->배열형태
		List<AttachFileDTO> list = new ArrayList<>();
		String uploadFolder = "C:\\upload1";
		
		//getFolder 메서드로 폴더 패턴 생성
		String uploadFolerPath = getFolder();
		//폴더 만들기(부모,자식)
		File uploadPath = new File(uploadFolder,uploadFolerPath);
		
		//업로드 폴더가 존재하지 않는다면 만들어준다.
		if(uploadPath.exists() == false) {
			uploadPath.mkdirs();
		}
		
		for(MultipartFile multipartFile : uploadFile) {
			AttachFileDTO dto = new AttachFileDTO();
			
			String uploadFileName = multipartFile.getOriginalFilename();
			//ie의 경우 전체 파일 경로가 전송됨으로 \\까지 제외한 문자열이 실제 파일이름으로 저장
			uploadFileName =uploadFileName.substring(uploadFileName.lastIndexOf("\\")+1);
			log.info("오직 파일 이름만:  "+uploadFileName);
			dto.setFileName(uploadFileName);
			
			//중복방지 uuid 적용==========================================================
			UUID uuid = UUID.randomUUID();
				//[uuid랜덤값_파일 본래이름]
			uploadFileName = uuid.toString()+"_"+uploadFileName;
			
			try {
				//브라우저에서 업로드된 파일을 서버내에 생성(부모,자식)
				File saveFile = new File(uploadPath, uploadFileName);
				//브라우저에서 업로드받은 파일을 서버의 파일 도착지인 saveFile로 transferTo 을 이용해 전송
				multipartFile.transferTo(saveFile);
				
				dto.setUuid(uuid.toString());
				dto.setUploadPath(uploadFolerPath);
				
				//업로드된 파일이 이미지이면 썸네일 파일하나를 더 생성해준다.
				if(checkImageType(saveFile)) {
					dto.setImage(true);
					FileOutputStream thumbnail = new FileOutputStream(new File(uploadPath, "s_"+uploadFileName));
					
					//Thumbnailator이용 파일생성->파라미터값으로 weight height 지정 가능
					Thumbnailator.createThumbnail(multipartFile.getInputStream(), thumbnail,100,100);
					thumbnail.close();
				}
				list.add(dto);
			} catch (Exception e) {
				e.printStackTrace();
			}
		}//End for
		return new ResponseEntity<>(list,HttpStatus.OK);
	}

파일이 서버에 들어옴을 확인 할 수 있다.

 

파일 업로드의 크기제한

정규식을 이용하여 파일 업로드의 제한을 걸자

//업로드 파일 타입 제한==============================================================	
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;
		}
//파일타입의 변경유무가 있을시(파일을 업로드시)========================================================================	
	$("input[type='file']").change(function(e){
		var formData = new FormData();
		var inputFile = $("input[name='uploadFile']");
		var files = inputFile[0].files;
		
		for(var i=0; i<files[i].length; i++){
			//확인 메서드에서 false가 나오면 안됨
			if(!checkExtension(files[i].name, files[i].size)){
				return false;
			}
			//append:요소추가
			formData.append("uploadFile",files[i]);
		}
		//ajax로 서버(uploadAjaxAction)에 전송
		$.ajax({
			url: '/uploadAjaxAction1',
			processData: false, 
			contentType: false,
			data: formData,
			type: 'POST',
			dataType: 'json',
			success: function(result){
				console.log(result)
				showUploadResult(result);
			}
		}); // End ajax
		
	}); //End change

 

uploadController

년/월/일 형식의 폴더를 생성하여 업로된 파일을 그에 맞게 저장하게 설정 하였다.

@PostMapping("/uploadAjaxAction1")
	public void uploadFormAction(MultipartFile[] uploadFile, Model model) {
		
		String uploadFolder = "C:\\upload1";
		
		File uploadPath = new File(uploadFolder,getFolder());
		log.info(uploadPath);
		
		if(uploadPath.exists() == false) {
			uploadPath.mkdirs();
		}
		
		for(MultipartFile multipartFile : uploadFile) {
			log.info("==========");
			log.info("업로드 파일이름:  "+multipartFile.getOriginalFilename());
			log.info("업로드 파일크기:  "+multipartFile.getSize());
			
			String uploadFileName = multipartFile.getOriginalFilename();
			//IE
			uploadFileName = uploadFileName.substring(uploadFileName.lastIndexOf("\\")+1);
			log.info(uploadFileName);
			
			File saveFile = new File(uploadPath, uploadFileName);
			try {
				multipartFile.transferTo(saveFile);
			} catch (Exception e) {
				log.error(e.getMessage());
			}
		}
	}

해당 날짜폴더에 업로드된 파일을 확인 할 수 있음

 

그러나 똑같은 파일의 이름을 업로드시 구분하기 어렵기 때에 uuid를 적용시켜서 파일 고유 이름으로 저장하게 바꾸어 보자

uuid적용

//중복방지 uuid 적용==========================================================
			UUID uuid = UUID.randomUUID();
				//[uuid랜덤값_파일 본래이름]
			uploadFileName = uuid.toString()+"_"+uploadFileName;
			
			try {
				//브라우저에서 업로드된 파일을 서버내에 생성(부모,자식)
				File saveFile = new File(uploadPath, uploadFileName);

위의 기존코드에서 조금 수정되었다

uploadFileName을 uuid로 적용시켜서 File객체에 넣어주자

uuid가 적용됨을 확인 할 수 있다.

728x90
반응형
LIST