Spring MVC download files(01)
스프링에서 지원하는 다운로드를 쓰려면 아래와 같이 하시오.!
일단 기본적으로 파일 다운로드 처리하기에 앞서서 알아야 할 사항을 배워보도록 하자.
1. 파일링크를 클릭할때 컨트롤러 클래스에게 파일패스와 파일이름을 던져주고
2. 받은 컨트롤러 클래스에서 그 파일 패스와 파일이름으로 file 을 만들어서 (DownloadController)
3. 뷰로 전달을 할 것이다.
4. 그럼 뷰에서 받은 file 정보를 이용해서 실제 파일을 읽어들인 다음 원하는 위치에 쓰는 작업을 한다. (DownloadView)
일반적인 컨트롤러 클래스에서 작업을 한 후, 뷰 페이지로 결과값을 뿌려주는 것인데
일반적인 뷰페이지는 JSP 페이지였다.
하지만 다운로드에 사용될 뷰는 JSP 가 아니라 클래스 파일이다.
그렇기 때문에 아래처럼 일반적으로 사용하던 viewResolver 가 처리하는 것이 아니라
<bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/"/>
<property name="suffix" value=".jsp"/>
<property name="order" value="1"/>
</bean>
download 만을 처리하는 viewResolver 가 따로 존재해야 한다. 여기에는 id값이 없다...주의할것!!!!!!!!!
<bean class="org.springframework.web.servlet.view.BeanNameViewResolver">
<property name="order" value="0"/>
</bean>
주의할 점은 위 두 코드에 포함된 프로퍼티를 보면 order 라는 프로퍼티가 있는데
이 프로퍼티는 두개이상 존재하는 viewResolver 를 위해서
우선순위를 매기는 것이다. 만약 우선순위를 명시 하지 않으면 "가장 낮은 우선순위를 갖게 된다."
우선순위는 "0"이 가장 먼저 실행되고, 이후로 매겨지는 순서에 따라 실행된다.
다음 viewResolver가 실행되는 기준은 "null" 이 반환되느냐 가 기준이다.
그렇기 때문에 널값이 있을수 없는 InternalResourceViewResolver 가 우선순위가 높게 되면,
다른 viewResolver 는 사용되지 않게되는
문제가 있다. (항상 뷰 이름에 매핑이 되는 뷰 객체를 리턴하기 때문)
그래서 InternalResourceViewResolver 은 우선순위가 가장 낮아야 한다.
그러면 이제 BeanNameViewResolver 를 사용하는 법을 알아 보자
BeanNameViewResolver (파일 다운로드 viewResolver)
"null" 이 반환되지 않는다면, (즉 컨트롤러 클래스에서 리턴되온 뷰페이지 값과 일치하는 빈이 있는 경우)
컨트롤러 클래스에서 리턴되온 뷰페이지 값과 일치하는 빈이 등록되있는 경우는 그 빈에 해당하는 컨트롤러 클래스가
파일 다운로드를 처리하게 된다.
그렇기 때문에 컨트롤러 클래스에서 viewResolver 로 던져줄 뷰페이지 이름과, 처리할 View 클래스 빈이름이 같아야 한다.
(이말을 반대로 하자면, 실제 jsp 가 보여져야될 때는 리턴값과, view 빈 이름이 같아서는 절대 안된다.)
<bean id="download" class="Spring.DownloadView"/>
- 이 코드가 다운로드를 처리할 뷰 클래스를 등록하는 것이다.
저기 id="download" 라고 되있는 부분과, 클래스에서 리턴된 값이 같아야 한다.
그리고 url 을 처리할 컨트롤러 클래스도 등록되야되겠지.
<bean id="down" class="Spring.DownloadController"/>
여기 까지가 좀 복잡하지만 servlet.xml 파일을 설정하는 부분이다.
하나하나 천천히 다시 읽어보면 이해가 될 것이다.
이제 처음부터 하나씩 따라가보자.
파일 이름에 링크를 걸어서 컨트롤러 클래스로 넘기는 부분부터 시작
<a href="/Spring_margo/download.do?path=${path }&fileName=${itemBean.fileName }" > ${itemBean.fileName } </a>
download.do 로 파일네임과 패스를 넘기게 되어있다.
그럼 저 url 을 처리하는 컨트롤 클래스는 아래와 같다.
<bean id="down" class="Spring.DownloadController"/>
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 DownloadController implements ApplicationContextAware{ private WebApplicationContext context = null ; @RequestMapping ( "download.do" ) public ModelAndView download( @RequestParam ( "path" )String path, @RequestParam ( "fileName" )String fileName){ String fullPath = path + "\\" + fileName; File file = new File(fullPath); return new ModelAndView( "download" , "downloadFile" , file); } @Override public void setApplicationContext(ApplicationContext arg0) throws BeansException { // TODO Auto-generated method stub this .context = (WebApplicationContext)arg0; } } |
@RequestMapping("download.do") 어노테이션으로 지정해준것처럼
download.do 가 들어오면 저 메소드가 동작한다.
링크에서 준것처럼 패스와 파일네임을 받아서
파일에 조합해서 쓰고 "download" 뷰페이지로 파일을 "downloadFile"이름으로 삽입하고 리턴시킨다.
그러면 <bean class="org.springframework.web.servlet.view.BeanNameViewResolver">
저 viewResolver 가 먼저 리턴을 처리하려 할 것이다.
"download"로 등록된 빈이 있는지 찾아 보는데 우리는 아까 "download"로 뷰클래스를 등록시켜 놓았다.
<bean id="download" class="Spring.DownloadView"/>
이제 DownloadView.java 클래스가 뷰페이지로 동작할 것이다.
뷰페이지에서는 map 에 등록된 파일을 이용해서 encoding 설정과 헤더설정을 해준 후 파일을 지정위치에 쓴다.
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 | import java.io.File; import java.io.FileInputStream; import java.io.OutputStream; import java.net.URLEncoder; import java.util.Map; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.springframework.util.FileCopyUtils; import org.springframework.web.servlet.view.AbstractView; public class DownloadView extends AbstractView { public void Download(){ setContentType( "application/download; utf-8" ); } @Override protected void renderMergedOutputModel(Map<string, object= "" > model, HttpServletRequest request, HttpServletResponse response) throws Exception { // TODO Auto-generated method stub File file = (File)model.get( "downloadFile" ); System.out.println( "DownloadView --> file.getPath() : " + file.getPath()); System.out.println( "DownloadView --> file.getName() : " + file.getName()); response.setContentType(getContentType()); response.setContentLength(( int )file.length()); String userAgent = request.getHeader( "User-Agent" ); boolean ie = userAgent.indexOf( "MSIE" ) > - 1 ; String fileName = null ; if (ie){ fileName = URLEncoder.encode(file.getName(), "utf-8" ); } else { fileName = new String(file.getName().getBytes( "utf-8" )); } // end if; response.setHeader( "Content-Disposition" , "attachment; filename=\"" + fileName + "\";" ); response.setHeader( "Content-Transfer-Encoding" , "binary" ); OutputStream out = response.getOutputStream(); FileInputStream fis = null ; try { fis = new FileInputStream(file); FileCopyUtils.copy(fis, out); } catch (Exception e){ e.printStackTrace(); } finally { if (fis != null ){ try { fis.close(); } catch (Exception e){} } } // try end; out.flush(); } // render() end; } </string,> |
출처 - http://winmargo.tistory.com/103