본문 바로가기

SPRING

[file download] 스프링 BeanNameResolver 이용한 파일 다운로드

스프링 파일 다운로드를 다뤄볼게요.

그냥 쉽게 쉽게 예제랑 방법만 첨부할게요~

Spring 3.1이고요 저도 검색을 통해서 알아낸거지만 참 스프링은 개발하기 좋게 갖춰진 도구인 것 같아요.

스프링 파일 다운로드를 하기에 앞서

XML 설정을 좀 해볼게요.

<bean id="springDownload" class="util.component.FileDownload"/>

 bean을 하나 생성해주는데요. 이 bean은 viewresolver를 통해서 파일 다운로드 처리를 하는 클래스로 넘어가게 됩니다.

보통은 viewResolver에 prefix와 suffix를 제외하고 String문자열로 jsp 파일의 경로를 넣어주잖아요.

하나 궁금한게 생기죠 .. 저건 bean인데 viewResolver에서 어떻게 쟤가 그 놈인지 알아볼 수 있나요 ? 라고

물론 그 설정도 해주어야 합니다.

아래와 같이요.

1. ViewResolver

이건 흔히 ViewResolver를 설정할때 이렇게 쓰죠. 보통 쓰던거랑 똑같습니다.

 <bean    class="org.springframework.web.servlet.view.InternalResourceViewResolver"
       p:viewClass="org.springframework.web.servlet.view.JstlView" p:prefix="/WEB-INF/views" p:suffix=".jsp" p:order="1"/>

2.FileDownload Resolver

일단 클래스가 다릅니다. org.springframework.web.servlet.view.BeanNameViewResolver  beanNameResolver라고 되어 있네요. Bean이름으로 return할 수가 있겠네요. 다양한 부분에서 응용할 수 있을 것 같습니다.

여기서 보셔야 할거는 property name="order" value="0" 이고요. 이렇게 설정을 해주어야 beanName이 String 타입으로 return 되었을때 이 BeanNameResolver가 받게 됩니다. 그래서 우선순위로 0을 줌으로서 bean에서 먼저 찾고 없으면 InternalResourceViewResolver에서 찾게 됩니다.

 <bean class="org.springframework.web.servlet.view.BeanNameViewResolver">
  <property name="order" value="0"/>
 </bean>

XML에 BEAN이랑 BeanNameViewResolver를 설정해서 beanName으로도 viewResolver를 사용할 수 있게 설정을 마쳤네요.

그럼 이걸 어떻게 설정할까요 ?

첫번째로,

<bean id="springDownload" class="util.component.FileDownload"/>

이렇게 bean을 생성한 클래스를 만들어줘야겠죠. 이 클래스는 직접적으로 파일만 읽어와서 스트림으로 떨구는 것만 작업할 겁니다. 그래야 다른 파일다운로드에서도 공통적으로 쓸 수 있으니까요.

public class FileDownload extends AbstractView {

  public void Download(){
        setContentType("application/download; utf-8");
  }
          
  @Override
 protected void renderMergedOutputModel(Map<String, Object> model, HttpServletRequest request, HttpServletResponse response)
   throws Exception {
     
     File file = (File)model.get("fileDownload");
     String type = model.get("type").toString();
     
        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"));
        }
 
        response.setHeader("Content-Disposition", "attachment; filename=\"" + fileName+type+"\";");
        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){}
            }
        }
        out.flush();
    }
}

이 소스는 저도 어디서 긁어왔네요 ㅋㅋ

보시다시피

Map<String, Object> model,

HttpServletRequest request,

HttpServletResponse response

이러한 인자들을 넘겨받네요.

두번째로,

자 그럼 Controller에서는 어떻게 사용할까요.

 model.addAttribute("fileDownload", file);

이렇게 File을 생성해서 fileDownload란 key로 ModelMap에 담아서 넘깁니다.

위에 보시는 것처럼 위 클래스에도 ModelMap을 인자로 받고 있기 때문에 넘겨받을 수 있습니다. 찾아보시면 fileDownload 라는 key를 get하는걸 찾을 수 있어요.

return "springDownload";

자 이게 중요하죠. XML에서 생성했던 BeanName을 여기서 씁니다. 그래야 우리가 생성한 Class로 resolve 되게 되니까요.

정리할게요.

 

1. 파일 다운로드 처리를 담당할 공통 클래스를 만들고 xml에 bean을 생성한다.

2. dispatcher-servlet.xml에 BeanNameResolver를 생성하고 order를 0으로 설정한다

3. Controller에서 return "생성한 빈네임" 으로 해야하며 파일을 다운로드 할 객체를 model.addattribute("")로 넘기거나 파일 path만 넘겨서 파일 객체를 얻어올 수 있어야 한다.

라는 겁니다.

끝이구요~ 화면에서는 당연히 download할때 target을 hidden frame으로 줘야 하는거 잊지마시구요. 다른 방법 있으면 공유 좀 ㅋㅋ 전 아직 이렇게 쓰네요..