첨부파일을 처리하고자..
첨부파일을 서버에 전송하는 방식은 크게 <form>태그를 이용해서 업로드 하는 방식과 Ajax를 이용하는 방식으로 나눠 볼 수있다.
<form>태그를 이용하는 방식 | 브라우저의 제한이 없어야 하는 경웨 사용 -일반적으로 페이지 이동과 동시에 첨부파일을 업로드하는 방식 - <iframe>을 이용해서 화면의 이동없이 첨부파일을 처리하는 방식 |
Ajax를 이용하는 방식 | 첨부파일을 별도로 처리하는 방식 -<input type='file'>을 이용하고 Ajax로 처리하는 방식 -HTML5 의 Drag and Drop기능이나 jQuery라이브러리를 이용해서 처리하는 방식 |
브라우저 상에서 첨부파일 처리하는 방식은 다양하지만, 서버쪽에서의 처리는 거으 ㅣ비슷하다.
지금의 프로젝트는 Ajax를 위주로 처리할 것이다.
시작전 새로운 브랜치생성
새로운 과정을 공부, 기능을 추가전에 브랜치를 만들어준다.
브랜치의 이름은 Study_fileUpload 로 지어 공부중인 브랜치임을 밝힌다.
첨부파일을 위한 설정
프로젝트가 web.xml을 이용하기에 첨부파일의 처리에 대한 설정을 위해 변경해주어야한다.
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
기존의 web파일이다. 2.5버전으로 되어있다. 이부분을 모두 수정하자.
<?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">
그리고 web.xml파일에 <servlet>태그내에 <multipart-config>를 추가해주자
<!-- 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>
해당 태그는 특정 사이즈의 메모리 사용, 업로드되는 파일을 저장할 공간과 업로드 파일의 최대 크기를 한번에 올릴 수 있는 최대 크기를 지정할 수있따.
필자는 40메가 넘기게 업로드하지않을거라 40메가로 지정했다.
지금 지정한건 WAS 자체의 설정일 뿐이니
지금 지정한것을 bean으로 등록해주자
servlet-context.xml 의 일부에 추가해주자
<beans:bean id="multipartResolver"
class="org.springframework.web.multipart.support.StandardServletMultipartResolver">
</beans:bean>
첨부파일을 처리하는 빈을 설정할 때는 id는 'multipartResolver'라는 이름으로 지정된 이름을 사용한다.
<form>방식의 파일 업로드
서버상에서 첨부파일의 처리는 컨트롤러에서 이루어지므로, UploadController를 작성한다.
UploadController 는 get방식으로 첨부파일을 업로드 할 수 있는 화면을 처리하는 메서드와 Post방식으로 첨부파일 업로드를 처리하는 메서드를 추가한다.
package org.study.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import lombok.extern.log4j.Log4j;
@Controller
@Log4j
public class UploadController {
@GetMapping("/uploadForm")
public void uploadForm() {
log.info("upload form");
}
}
UploadController에는 클래스 선언부에 @RequestMapping이 적용되지 않으므로, Web-inf/views 폴더에 uploadForm.jsp파일을 추가하자
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>
<form action="uploadFormAction" method="post"
enctype="multipart/form-data">
<input type='file' name='uploadFile' multiple>
<button>Submit</button>
</form>
</body>
</html>
내용은 간단하게 버튼만 구현하고, 값을 보내는 포스트 형식으로 폼을 구했다. 이때 특이하게 multople을 적어두었는데,
인풋태그 하나로 여거래의 파일을 업로드 할 수 있따.
Tomcat을 구동하여 확인해보자
http://localhost:8080/uploadForm 를 입력하여 확인하자
MultipartFile 타입을 제공받아 업로드 되는 파일 데이터를 쉽게 처리 할 수 있다.
인풋타입의 name속성으로 변수를 지정하여 처리한다.
@PostMapping("/uploadFormAction")
public void uploadFormPost(MultipartFile[] uploadFile, Model model) {
for (MultipartFile multipartFile : uploadFile) {
log.info("-------------------------------------");
log.info("Upload File Name: " + multipartFile.getOriginalFilename());
log.info("Upload File Size: " + multipartFile.getSize());
}
}
파일 처리는 스프링에서 제공하는 MultipartFile이라는 타입을 이용한다. 화면에서 첨부파일을 여러개 선택할 수 있으니
배열타입으로 설정한 후 파일을 업로드 해 보자.
과거 포트폴리오 제작위해 사진을 제작했는데 이중 4개를 선택해보겠다.
파일 4개가 정상적으로 인식된걸 알수가 있다.
그런데 아직 제출 이후 화면처리를 하지 않았기 때문에
위와 같은 404오류가 나타났다.
사실이때 500번 오류도 나타났다. -해결한 방법으로 찾아가기
https://uno-kim.tistory.com/41
예외처리)HTTP 상태 500 - 멀티업로드/Muliupload
멀티 업로드를 진행할때 아래와같은 오류가 떳다. 더보기 HTTP 상태 500 – 내부 서버 오류 타입 예외 보고 메시지 Request processing failed; nested exception is org.springframework.web.multipart.Multipart..
uno-kim.tistory.com
위처럼 파일명이 보인다.
이제 업로드 되는 파일을 저장해보겠다.
방법은 간단히 transferTo()를 이용해서 처리할 수 있다.
아까 작성했던 UploadController의 일부를 수정 해주자
package org.study.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("/uploadForm")
public void uploadForm() {
log.info("upload form");
}
@PostMapping("/uploadFormAction")
public void uploadFormPost(MultipartFile[] uploadFile, Model model) {
String uploadFolder = "C:\\programing\\upload";
for (MultipartFile multipartFile : uploadFile) {
log.info("-------------------------------------");
log.info("Upload File Name: " + multipartFile.getOriginalFilename());
log.info("Upload File Size: " + multipartFile.getSize());
File saveFile = new File(uploadFolder, multipartFile.getOriginalFilename());
try {
multipartFile.transferTo(saveFile);
log.info("업로드 성공!");
} catch (Exception e) {
log.error(e.getMessage());
} // end catch
} // end for
}
}
transferTo()의 파라미터로는 java.io.File의 객체를 지정하면 되기 때문에 업로드되는 원래 파일의 이름으로 C드라이브 upload폴더에 원래 이름으로 저장합니다.
필자는 C드라이브를 좀더 깔끔하게 정리해서 사용해서 따로 programing이라는 세부폴더를 만들어 쓰고있다.
그래서 C:\\programing\\upload 의 경로로 하여따...

동일하게 작동을 시켜보았다.
결과는 404으로 처리가 되었지만
업로드가 성공되었다고 로그를 확인할 수 있으며,
내가 지정한 경로에 사진 4개가 깨짐없이 업로드 되어있음을 확인했다.
Ajax를 이용하는 파일업로드
지금까지 기본적인 방법으로 업로드 하는 방법을 보았따. 약간 워밍업으로 식으로 하였다. 개념을 충분히 익히기 위한?
Ajax를 이용하는 첨부파일 처리는 FormData라는 객체를 이용한다.
우선 UploadController에 Get방식으로 첨부파일을 업로드하는 페이지를 제작한다.
@GetMapping("/upload")
public void uploadAjax() {
log.info("upload ajax");
}
web-inf/views 폴더에는 uploadjsp 페이지를 간단하게 작성한다.
대략적으로 공부하고 테스트겸 넘어가는것이니 큰 디자인은 없다.
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>
<div class='uploadDiv'>
<input type='file' name='uploadFile' multiple>
</div>
<button id='uploadBtn'>Upload</button>
</body>
</html>
이 파일은 JavaScript를 이용해서 처리할 수도 있지만, jQuery를 이용해서 처리하는 것이 편리하므로 jQuery라이브러리 경로를 추가해주자
<script src="https://code.jquery.com/jquery-3.3.1.min.js"
integrity="sha256-FgpCb/KJQlLNfOu91ta32o/NMZxltwRo8QtmkMRdAu8="
crossorigin="anonymous"></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);
});
});
</script>
제이쿼리를 이용하는 경우에 파일 업로드는 FormDaTA라는 객체를 이용하게 된다.
이는 쉽게 말해서 가상의 form태그와 같다, Ajax를 이용하는 파일업로드는 FromData를 이용해서 필요한 파라미터를 담아서 전송하는 방식이다.
본격적으로 첨부파일 데이터를 전송하기 전에 여러 개의 파일을 선택했을 때 jQuery에서 파일 데이터를 처리가 가능한지 브라우저에서 먼저 확인해야 한다.
아까와 동일하게 사진파일 4개를 선택하고 http://localhost:8080/upload 를 통해서 확인해보자
이제 파일첨부기능은 구현했으니 파일 전송하는 기능을 구현해보자
이또한 jQuery를 이용해서 구현하겠다.
기존 함수에 반복을 이용해서 업로드를 하도록 첨부한 파일을 for문을 통해 add되도록하겠다.
<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);
//add filedate tp formdata
for (var i = 0; i < files.length; i++) {
forData.append("uploadFile", files[i]);
}
$.ajax({
url : '/uploadAjaxAction',
processData : false,
contentType : false,
data : formData,
type : 'POST',
success : function(result) {
alert("Uploaded");
}
});
});
});
</script>
첨부파일 데이터는 formData에 추가한 뒤에 Ajax를 통해서 formData자체를 전송한다.
이때 processData와 contentType은 반드시 'false'로 지정해야만 전송되므로 주의하자
UploadController에서는 기존과 동일하게 MultipleFile 타입을 이용해서 첨부파일 데이터를 첨부한다.
그러기위해서 UploadController에 Post방식으로 받는 메서드를 만든다.
이떄 주의할 점은 인터넷 익스플로우가 내가 지금 사용하고있는 브라우저인 웨일과다르게
해당 파일의 전체 경로를 파일이름인양 가져온다. 그것을 위해서 한줄을 추가해주자
uploadFileName = uploadFileName.substring(uploadFileName.lastIndexOf("\\") + 1);
큰일에 작용되는건아니지만 substring을 이용해서 파일이름의 \\가 붙은 마지막까지 다 제거한다는 것이다.
그러면 경로가 모두 지워진다.
@PostMapping("/uploadAjaxAction")
public void uploadAjaxPost(MultipartFile[] uploadFile) {
log.info("update ajax post.........");
String uploadFolder = "C:\\programing\\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: " + uploadFileName);
File saveFile = new File(uploadFolder, uploadFileName);
try {
multipartFile.transferTo(saveFile);
log.info("업로드 성공!");
} catch (Exception e) {
log.error(e.getMessage());
} // end catch
} // end for
}
자바파일을 작성하고 다시 실행을 해보자
업로드처리가 정상적으로 되었다고 받았다.
첨부파일을 서버에 전송하고 저장하는 일은 그다지 복잡하지 않았따.
그러나 생각해야 할것들이 있다.
- 동일한 이름의 파일이 업로드 되었을때 ?
- 이미지 파일의 경우 원본 파일의 용량이 큰 경우 섬네일 이미지를 생성해야 하는 문제
- 이미지 파일과 일반 파일을 구분해서 다운로드 혹은 페이지에서 조회하도록 처리하는 문제
- 첨부파일 공격에 대비하기 위한 업로드 파일의 확장자 제한
이제 이런것들을 해결하면서 좀더 업로드하는 환경을 꾸미도록 해보자
'Spring공부 > 3-파일업로드' 카테고리의 다른 글
파일업로드(6)-첨부파일삭제 (0) | 2021.10.14 |
---|---|
파일업로드(5)-원본 이미지 보여주기 (0) | 2021.10.14 |
파일업로드(4)-첨부파일의 다운로드 (0) | 2021.10.13 |
파일업로드(3)-업로드데이터변환 (0) | 2021.10.13 |
파일업로드(2) (0) | 2021.10.13 |
댓글