FRAMEWORK/SPRING

Spring MVC download files(01)

적외선 2014. 12. 2. 14:47

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

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

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