Java :: Spring 파일 업로드 (multipart-form/data)
스프링 프레임워크의 내장 객체인 CommonsMultipartResolver 를 이용한 파일 업로드 방식이다.
1. pom.xml 설정
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | <?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> <!-- MultipartHttpServletRequset --> <dependencies> <dependency> <groupId>commons-io</groupId> <artifactId>commons-io</artifactId> <version>2.0.1</version> </dependency> <dependency> <groupId>commons-fileupload</groupId> <artifactId>commons-fileupload</artifactId> <version>1.2.2</version> </dependency> </dependencies> </project> | cs |
pom.xml 파일에서
ㄱ. commons-io.jar
ㄴ. commons-fileupload.jar
두 가지 .jar를 추가한다.
2. context.xml 설정
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | <?xml version="1.0" encoding="UTF-8"?> <beans xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://www.springframework.org/schema/beans" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"> <!-- MultipartResolver --> <bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver"> <property name="maxUploadSize" value="100000000"/> <property name="maxInMemorySize" value="100000000"/> </bean> </beans> | cs |
context.xml에서 CommonsMultipartResolver 객체를 추가한다.
CommonsMultipartResolver는 스프링 프레임워크에 내장되어 있는 MultipartResolver 이다.
* maxUploadSize : 한 번에 최대 올릴 수 있는 파일 사이즈
maxInMemorySize : 해당 경로에 최대로 저장할 수 있는 파일 사이즈
3. form 파일 업로드
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | <html> <head> <title>title</title> </head> <body> <!-- form enctype="multipart/form-data" 을 꼭 적어줘야 함 --> <form class="form-horizontal" method="post" action="<c:url value='/re/add'/>" enctype="multipart/form-data"> <!-- input type="file" 이라고 꼭 저어줘야 함 --> <input type="file" class="form-control1" id="uploadFile" name="uploadFile" style="border:0px solid black;"/> <button type="submit" class="btn btn-default">등록</button> <button type="reset" class="btn btn-default">취소</button> </form> </body> </html> | cs |
form enctype="multipart/form-data"라고 꼭 적어줘야 한다. 그렇지 않으면 form이 전송되지 않는다.
마찬가지로 전송할 파일 타입도 file이라고 적어줘야 한다.
4. MultipartResolver 클래스 작성
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 | package com.cafe24.smart.util; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.OutputStream; import java.io.PrintWriter; import java.net.URLEncoder; import java.util.Map; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.springframework.stereotype.Component; import org.springframework.util.FileCopyUtils; import org.springframework.web.multipart.MultipartFile; import org.springframework.web.multipart.MultipartHttpServletRequest; import org.springframework.web.servlet.view.AbstractView; import com.cafe24.smart.approve.domain.Draft; import com.cafe24.smart.reward.domain.Reward; // @Component > @Service // : 스프링 프레임워크가 관리하는 컴포넌트의 일반적 타입 // : 개발자가 직접 조작이 가능한 클래스의 경우 해당 어노테이션을 붙임 // : ( <=> @Bean : 개발자가 조작이 불가능한 외부 라이브러리를 Bean으로 등록시 사용) @Component public class UtilFile { String fileName = ""; // 프로젝트 내 지정된 경로에 파일을 저장하는 메소드 // DB에는 업로드된 전체 경로명으로만 지정되기 때문에(업로드한 파일 자체는 경로에 저장됨) // fileUpload() 메소드에서 전체 경로를 리턴받아 DB에 경로 그대로 저장 public String fileUpload(MultipartHttpServletRequest request, MultipartFile uploadFile, Object obj) { String path = ""; String fileName = ""; OutputStream out = null; PrintWriter printWriter = null; try { fileName = uploadFile.getOriginalFilename(); byte[] bytes = uploadFile.getBytes(); path = getSaveLocation(request, obj); System.out.println("UtilFile fileUpload fileName : " + fileName); System.out.println("UtilFile fileUpload uploadPath : " + path); File file = new File(path); // 파일명이 중복으로 존재할 경우 if (fileName != null && !fileName.equals("")) { if (file.exists()) { // 파일명 앞에 업로드 시간 초단위로 붙여 파일명 중복을 방지 fileName = System.currentTimeMillis() + "_" + fileName; file = new File(path + fileName); } } System.out.println("UtilFile fileUpload final fileName : " + fileName); System.out.println("UtilFile fileUpload file : " + file); out = new FileOutputStream(file); System.out.println("UtilFile fileUpload out : " + out); out.write(bytes); } catch (Exception e) { e.printStackTrace(); } finally { try { if (out != null) { out.close(); } if (printWriter != null) { printWriter.close(); } } catch (IOException e) { e.printStackTrace(); } } return path + fileName; } // 업로드 파일 저장 경로 얻는 메소드 // 업로드한 파일의 경로가 도메인 별로 달라야 했기 때문에 도메인의 형을 비교하여 파일 저장 정로를 다르게 지정함 private String getSaveLocation(MultipartHttpServletRequest request, Object obj) { String uploadPath = request.getSession().getServletContext().getRealPath("/"); String attachPath = "resources/files/"; // Reward인 경우 if (obj instanceof Reward) { attachPath += "reward/"; // Approval인 경우 } else if(obj instanceof Draft) { attachPath += "approval/"; // Document인 경우 } else { attachPath += "document/"; } System.out.println("UtilFile getSaveLocation path : " + uploadPath + attachPath); return uploadPath + attachPath; } } | cs |
시간이 촉박했기 때문에 파일의 경로를 암호화하는 UUID 객체는 사용하지 않았다.
getSaveLocation() 메소드에서 저장될 경로를 지정할 때 해당 프로젝트의 경로를 변수 uploadPath로 값 복사하였는데
로컬에서는 (본인의 컴퓨터) 에서는 아무리 해당 경로를 찾아봐도 업로드 했던 파일이 나오지 않는다.
그러나 cafe24 같은 서버에 프로젝트를 호스팅 하면 지정 경로로 업로드가 잘 되니 걱정하지 않아도 된다.
5. form에서 보낸 파일 업로드
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | @Controller public class RewardController { // 파일을 업로드하는 컨트롤러 클래스 메소드 @RequestMapping(value = "re/add", method = RequestMethod.POST) // 인자로 MulfiPartFile 객체, MultipartHttpServletRequest 객체, 업로드 하려는 도메인 클래스를 받는다 public String reAddProCtrl(@RequestParam("uploadFile") MultipartFile uploadFile, MultipartHttpServletRequest request, Reward reward) { System.out.println("RewardController reAddProCtrl uploadFile : " + uploadFile); System.out.println("RewardController reAddProCtrl reward : " + reward); // UtilFile 객체 생성 UtilFile utilFile = new UtilFile(); // 파일 업로드 결과값을 path로 받아온다(이미 fileUpload() 메소드에서 해당 경로에 업로드는 끝났음) String uploadPath = utilFile.fileUpload(request, uploadFile, reward); // 해당 경로만 받아 db에 저장 int n = rewardService.reAddServ(uploadPath, reward); System.out.println("RewardController reAddProCtrl n : " + n); System.out.println("RewardController reAddProCtrl uploadPath : " + uploadPath); return "redirect:listAll"; } } | cs |
이로서 업로드가 끝난다.