간단한 파일 업로드 기능을 만들어야 할 일이 생겨서, Spring 2.5의 annotation을 이용한 Action에서 이를 처리하게 했습니다. 실무에서 썼던 것을 더 단순한 예제로 재구성해서 정리해봅니다.
Maven의 pom.xml에 파일업로드 기능에서 참조하는 commons-fileupload 라이브러리에 대한 dependency를 추가합니다.
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>1.2.1</version>
</dependency>
web.xml에는 applicationContext 파일의 위치를 지정하고, *.do를 스프링에서 처리하도록 설정합니다.
<servlet>
<servlet-name>dispatcher</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:applicationContext.xml</param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>dispatcher</servlet-name>
<url-pattern>*.do</url-pattern>
</servlet-mapping>
업로드 기능을 간단히 테스트할 수 있는 jsp페이지를 만들어봅니다. 단순히 파일 1개를 "file"이라는 변수명으로 업로드 요청을 하는 페이지입니다.
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ taglib prefix="spring" uri="http://www.springframework.org/tags"%>
<%@ taglib prefix="form" uri="http://www.springframework.org/tags/form"%>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>업로드 테스트</title>
</head>
<body>
<form action="/study/upload.do" method="post" enctype="multipart/form-data">
<p>
<label for="file">파일1 </label>
<input type="file" name="file">
</p>
<p>
<input type="submit" value="전송"/>
</p>
</form>
</body>
</html>
그리고 applicationContext파일을 아래와 같이 선언합니다. DefaultAnnotationHandlerMapping
을 이용해서 annotation을 이용한 Controller 설정을가능하게 합니다. <context:component-scan/>
태그를 사용해서, 설정을 scan할 패키지를지정합니다. 그리고, 파일이 저장될 디렉토리는 ${repository.path}
속성으로 표시했습니다.
Maven의 resource filter기능을 이용해서 실행환경에 따라 다른 값을 넣게 하면 편리합니다.
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="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">
<bean class="org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping">
<property name="alwaysUseFullPath" value="true"/>
</bean>
<bean id="multipartResolver"
class="org.springframework.web.multipart.commons.CommonsMultipartResolver"/>
<bean id="respository" class="study.repository.FileRepository">
<constructor-arg value="${repository.path}" />
</bean>
<context:component-scan base-package="study.action"/>
</beans>
실제적인 파일의 저장기능을 담당하는 클래스인 FileRepository에서는 간단하게 UIDD를 이용해서 키를 생성하고 path필드로 지정된 디렉토리에 저장을 해줍니다.
package study.repository;
import java.io.File;
import java.io.IOException;
import java.util.UUID;
import org.springframework.web.multipart.MultipartFile;
public class FileRepository {
private String path;
public FileRepository(String path) {
this.path = path;
File saveFolder = new File(path);
if(!saveFolder.exists() || saveFolder.isFile()){
saveFolder.mkdirs();
}
}
public String saveFile(MultipartFile sourcefile) throws IOException{
if ((sourcefile==null)||(sourcefile.isEmpty())) return null;
String key = UUID.randomUUID().toString();
String targetFilePath = path+"/"+ key;
sourcefile.transferTo(new File(targetFilePath));
return key;
}
}
추가적으로 키값을 넣어주면 파일을 반환해주는 메소드나, 파일의 종류나 날짜에 따라서 하위 디렉토리를 구분해서 생성하는 기능도 넣을 수있을 것입니다. 그리고 더 확장한다면, 따로 주요 메서드를 선언한 Repository 라는 인터페이스를 정의하고, DB를저장소로 활용하는 DbRepository 와 같이 이름 붙인 구현 클래스도 만들어 볼 수 있겠습니다.
그리고 @Controller , @RequestMapping, @RequestParam, @Autowired의 Anntation을활용해서 Controller 클래스를 작성합니다. 업로드 후 화면에 키값만 뿌도록 해서 java.io.Writer클래스를 화면출력을 위해 사용했습니다.
package study.action;
import java.io.IOException;
import java.io.Writer;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.multipart.MultipartFile;
import study.repository.FileRepository;
@Controller
public class FileAction {
private FileRepository respository;
@Autowired
public void setRespository(FileRepository respository) {
this.respository = respository;
}
@RequestMapping("/upload.do")
public void execute(@RequestParam("file") MultipartFile file,
Writer out) throws IOException{
String key = respository.saveFile(file);
out.write(key);
}
}
MultipartFile 클래스를 파라미터로 받는 메서드는 MockMultiPartFile를 이용해서 테스트하면 됩니다.
참고로 최근 로드존슨이 인터뷰에서 한 말에 따르면 기존 Spring MVC의 Controller interface는 삭제될 것이라고 하네요.
Twitter
Google+
Facebook
Reddit
LinkedIn
StumbleUpon
Email