BLOG ARTICLE 스프링 다운로드 | 1 ARTICLE FOUND

  1. 2011.08.17 [Spring] 스프링 3.0 에서 파일 다운로드 처리 (File Download) (9)


스프링에서 지원하는 다운로드를 쓰려면 아래와 같이 하시오.!

일단 기본적으로 파일 다운로드 처리하기에 앞서서 알아야 할 사항을 배워보도록 하자.

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"/>
@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 설정과 헤더설정을 해준 후 파일을 지정위치에 쓴다.

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 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;
}


여기까지가 

파일링크를 클릭해서 다운로드를 하는 일련의 과정을 코드로 풀어논 것이다.

복잡해 보이지만, ....복잡하다.......죄송;




열심히 뚝딱뚝닥 거리다보면 위그림처럼 다운로드가 될것이다!!!!!!!!!


YOUR COMMENT IS THE CRITICAL SUCCESS FACTOR FOR THE QUALITY OF BLOG POST
  1. 로스비 2011.08.17 20:05 신고  댓글주소  수정/삭제  댓글쓰기

    저번 처럼 이상하게 건들지도 않은 ListImpl이 오류가 생깁니다.

  2. 메로메로 2012.10.03 18:46 신고  댓글주소  수정/삭제  댓글쓰기

    지나가다가 잘배우고 갑니다. 많은 도움이 되었습니다. 이제 완전 초보인데요.

    이클립스를 세팅중인데요, 보리마고님의 이클립스를 보면 검은바탕까진 저도 설정을 햇는데, 나머지 글씨를 파란색과 형광색으로 하고 싶은데 방법좀 알려주시면 정말 감사하게습니다. ㅠ

    • 보리마고 2012.10.08 17:53 신고  댓글주소  수정/삭제

      이클립스 세팅이 아니라, 티스토리에 포스팅할때 하이라이팅 기능을 써서 코드를 저렇게 보이게 한겁니다. 이클립스는 코드 하이라이트 플러그인이 있으니 여러가지 찾아보셔서 마음에 드시는걸로 하세요 ㅎㅎ

  3. eugene 2014.05.07 12:19 신고  댓글주소  수정/삭제  댓글쓰기

    1.png가 나오는 이유는 무엇인지 궁금합니다
    직접 뷰로 값을 넘겨주는 건가요? 예제대로 하고 있는데 파일네임에 계속 null이 잡히네요

  4. kim 2014.05.30 11:31 신고  댓글주소  수정/삭제  댓글쓰기

    혹시 위 소스를 war 파일로 좀 받을수있나요?

  5. kim 2014.05.30 11:32 신고  댓글주소  수정/삭제  댓글쓰기

    가능하시다면 hg97804@naver.com
    으로 부탁좀 드리겟습니다

  6. Nathan 2015.01.16 10:30 신고  댓글주소  수정/삭제  댓글쓰기

    큰도움이 되었습니다. 감사합니다!

  7. LHN 2015.07.08 16:21 신고  댓글주소  수정/삭제  댓글쓰기

    정말 잘 배워 가요 ㅠ-ㅠ! 감사합니다.

  8. 오늘은진돗개 2015.11.25 15:00 신고  댓글주소  수정/삭제  댓글쓰기

    안녕하세요.
    궁금한게 있는데요.

    download.do에서 파일정보 데이터를 쿼리로 가져와서 다운받게하려고 하는데 파일 안만들고 가능한가요?
    File file = new File(fullPath);
    return new ModelAndView("download", "downloadFile", file);

    이거 대신 return new ModelAndView("download", "downloadFile", binary); 이런식으로요