티스토리 뷰


파일 업로드에 이어 파일 다운로드를 배워 보겠습니다.

1. content.jsp ( 게시판의 글을 읽는 View 페이지 에서 다운로드할 파일을 클릭한다. )

2. download.ktds 요청과 함께 파일 이름이 파라미터로 넘어간다

3. 파일 이름을 가지고서 실제 파일이 저장되어 있는 경로에 파일을 가져와 전송한다.


◎ content.jsp 파일에서 다운로드 요청을 날리는 라인입니다.

1
<span style="font-size: 10pt;"><a href="/bbs2/download.ktds?fname=${article.fname}">${article.fname}</a></span>

◎ controller 에서 요청을 받아 처리할 소스를 작성합니다.

1
2
3
4
5
6
7
8
9
10
<span style="font-size: 10pt;"> @RequestMapping("/download.ktds")
    public ModelAndView download(@RequestParam("fname") String fname) {
        String realFolder = "d:/upload/";
        mav = new ModelAndView();
 
        mav.addObject("fileName", new File(realFolder + fname));
        mav.setViewName("downloadView");
        return mav;
    }
</span>

파일 이름과 본인이 지정한 업로드 폴더를 이용하여, File 객체에 담고 ModelAndView의 객체로 저장합니다.

ModelAndView의 View 이름을 downloadView 로 지정합니다

여기서 downloadView 는 View 이름을 가지고서, Download 를 처리 할 Bean 을 연결 하기 위해서 입니다.

앞서서 JSON 처리할 때 살펴본 BeanNameViewResolver 가 여기서 또 활용 됩니다.

bbs의 bean 설정 파일에 BeanNameViewResolver 를 추가하고, download를 처리할 bean 인 DownloadImpl.java 도 등록을 합니다

1
2
3
4
<p><span style="font-size: 10pt;"><bean id="downloadView" class="com.ktds.bbs.service.DownLoadImple"></bean>
 
<bean id="viewResolver"  class="org.springframework.web.servlet.view.BeanNameViewResolver" />
</span></p>

여기서 중요한 점은 bean id downloadView 와 ModelAndView의 downloadView 이름이 같아야 BeanNameViewResolver가 bean 연결을 해줍니다.

◎ DownloadImpl.java의 소스 코드 입니다.

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
<span style="font-size: 10pt;">package com.ktds.bbs.service;
 
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.web.servlet.view.AbstractView;
 
public class DownLoadImple extends AbstractView {
    @Override
    protected void renderMergedOutputModel(Map<String, Object> map, HttpServletRequest req, HttpServletResponse res) throws Exception {
 
        String fileName = null;
        File file = (File) map.get("fileName");
 
        res.setContentType("application/download;");
        int length = (int) file.length();
        res.setContentLength(length);
 
        // 익스플로러 인지 확인
        String userAgent = req.getHeader("User-Agent");
        boolean ie = userAgent.indexOf("MSIE") > -1;
 
        if (ie) {
            fileName = URLEncoder.encode(file.getName(), "utf-8").replace("+""%20");
        } else {
            fileName = new String(file.getName().getBytes("utf-8"), "iso-8859-1").replace("+", "%20");
        }
 
        res.setHeader("Content-Disposition", "attachment;" + " filename=\"" + fileName + "\";");
        OutputStream out = res.getOutputStream();
        FileInputStream fis = null;
 
        try {
            int temp;
            fis = new FileInputStream(file);
            while ((temp = fis.read()) != -1) {
                out.write(temp);
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (fis != null) {
                try {
                    fis.close();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }
    }
}
</span>

AbstractView 로 상속을 하면, View 로 활용할 수 있다.

AbstractView를 상속하면, 추상메소드인 renderMergedOutputModel 를 구현하여 하는데 자세한 내용은 API를 더 참고해보도록 한다.

이 메소드의 인수는 ( map<string, object>, HttpServletRequest req, HttpServletResponse res ) 3가지 이며,

첫 번째 map 은 앞에서 모델에 입력한 file 정보가 될 것이다. 이 map 과 request, response를 이용하여 위 소스 코드와 같이 다운로드가 가능해지도록 구현하면 다운로드가 가능해진다.

또한, 브라우저 별로 url encoding 이 조금씩 다르므로 위의 explorer 와 그 외의 브라우저로 구분하는 것 처럼

fileName 을 변환 시켜야 한다. (이 내용은 검색해서 더 공부 해보도록 한다)