반응형

스프링 프로젝트에서 파일 업로드와 다운로드를 하는 방법을 알아보겠습니다.

 

이번 포스팅에선 다운로드 예제를 작성했습니다.

 

추가 메이븐 다운로드 없이 스프링 설정만 하시면 됩니다.

 

 

 

파일 다운로드

web.xml

<!-- Filter -->
<filter>
	<filter-name>encodingFilter</filter-name>
	<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
	<init-param>
		<param-name>encoding</param-name>
		<param-value>utf-8</param-value>
	</init-param>
</filter>
<filter-mapping>
	<filter-name>encodingFilter</filter-name>
	<url-pattern>/*</url-pattern>
</filter-mapping>
<!-- Filter -->


<!-- Processes application requests -->
<servlet>
	<servlet-name>appServlet</servlet-name>
	<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
	<init-param>
		<param-name>contextConfigLocation</param-name>
		<param-value>/WEB-INF/spring/servlet-context.xml</param-value>
	</init-param>
	<load-on-startup>1</load-on-startup>
</servlet>

먼저 web.xml에서 필터 설정과 DispatcherServlet상태를 확인하겠습니다.

필터를 통해 utf-8 인코딩 처리를 하였고 servlet-context.xml의 위치는 /WEB-INF/spring/servlet-context.xml 로 지정하였습니다.

 

servel-context.xml

<!-- spring-donwload bean -->
<beans:bean class="org.springframework.web.servlet.view.BeanNameViewResolver">
    <beans:property name="order" value="0" />
</beans:bean>
<beans:bean id="downloadView" class="com.psw.myapp.utils.DownloadView" />
<!-- /spring-donwload bean -->

<!-- Resolves views selected for rendering by @Controllers to .jsp resources in the /WEB-INF/views directory -->
<beans:bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
	<beans:property name="prefix" value="/WEB-INF/views/" />
	<beans:property name="suffix" value=".jsp" />
	<beans:property name="order" value="1" />
</beans:bean>

InternalResourceViewResolverorder순서를 1로 변경하였습니다.

DonwloadView 자바파일에서 다운로드 처리를 진행할 것이며 bean등록 처리를 해기 위해 BeanNameViewResolver를 사용했습니다.

serlet-context.xml 위치

 

 

CommonController.java

import java.io.File;
import java.io.IOException;
import java.util.HashMap;

import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.servlet.ModelAndView;

@Controller
@RequestMapping("/common")
public class CommonController{
	
	private static final String FILE_SERVER_PATH = "C:/test";

	@RequestMapping("/download")
	public ModelAndView download(@RequestParam HashMap<Object, Object> params, ModelAndView mv) {
		String fileName = (String) params.get("fileName");
		String fullPath = FILE_SERVER_PATH + "/" + fileName;
		File file = new File(fullPath);
		
		mv.setViewName("downloadView");
		mv.addObject("downloadFile", file);
		return mv;
	}
}

모든 파일은 C:/test에 있다고 가정하였습니다.

파일은 전달받은 fileName 파라미터값을 통해 파일을 세팅합니다.

downloadFile에 다운로드할 파일을 처리하고 bean등록을한 downloadView로 넘길것입니다.

 

 

DownloadView.java

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 {

	@Override
	protected void renderMergedOutputModel(Map<String, Object> model, HttpServletRequest request, HttpServletResponse response)
			throws Exception {

		File file = (File)model.get("downloadFile");
        if(file != null) {
            String fileName = null;
            String userAgent = request.getHeader("User-Agent");
            
            if(userAgent.indexOf("MSIE") > -1 || userAgent.indexOf("Trident") > -1){
                fileName = URLEncoder.encode(file.getName(), "utf-8").replaceAll("\\+", "%20");;
            }else if(userAgent.indexOf("Chrome") > -1) {
            	StringBuffer sb = new StringBuffer();
            	for(int i=0; i<file.getName().length(); i++) {
            		char c = file.getName().charAt(i);
            		if(c > '~') {
            			sb.append(URLEncoder.encode(""+c, "UTF-8"));
            		}else {
            			sb.append(c);
            		}
            	}
            	fileName = sb.toString();
            }else {
            	fileName = new String(file.getName().getBytes("utf-8"));
            }
            response.setContentType(getContentType());
            response.setContentLength((int)file.length());
            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){
                    	e.printStackTrace();
                    }
                }
                
                if(out != null) {
                	out.flush();
                }
            }
            
        }
	}
}

donwloadView는 AbstractView를 상속받아 사용합니다.

AbstractViewView구현을 위한 추상클래스로 컨트롤러가 반환한 모델과 병합되는 뷰입니다.

 

앞서 CommonController.java에서 세팅한 file인 downloadFile을 받아서 ie인지 체크 후 헤더 세팅과 OutputStream을 통해 파일을 출력합니다.

 

또한, 주의사항으로 브라우저마다의 인코딩이 달라서 User-Agent를 통해 접속한 브라우저를 체크하고 출력해줄 파일명을 만들때 인코딩 방식을 다르게 해야합니다. IE의 경우엔 11버전부턴 식별문자가 Trident로 변경되어 MSIE와 같이 조건문에 추가하였습니다.

 

controller와 downloadView 위치

 

이제 다운로드가 정상적으로 되는지 테스트 해보겠습니다.

전 board.jsp라는곳에서 처리할 예정이므로 컨트롤러와 jsp를 추가로 만들겠습니다.

 

 

BoardController.java

import java.util.HashMap;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.servlet.ModelAndView;

@Controller
@RequestMapping("/board")
public class BoardController {
	
	@RequestMapping("/board.do")
	public ModelAndView board(@RequestParam HashMap<Object, Object> params, ModelAndView mv) {
		mv.setViewName("board/board");
		return mv;
	}
}

board/board.do url로 요청이 들어오면 board/board.jsp를 호출하도록 컨트롤러 설정을 했습니다.

 

 

board.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
    
<!DOCTYPE html>
<html>
  <head>
	<meta charset="UTF-8">
	<meta name="description" content="">
	<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
    <title>파일 다운로드</title>
  </head>
  <body>
  	<div class="content">
		<br/><br/>
		<h3>파일 다운로드</h3>
		<a href="/common/download.do?fileName=이미지예제.jpg">download</a>
	</div>
  </body>
  
</html>

board.jsp

이제 마지막으로 WEB-INF/views/board 디렉토리와 board.jsp파일을 만들고 board.jsp를 작성했습니다.

 

board.jsp

a태그를 클릭하시면 CommonContorller에 요청을 했다가 DownloadView를 통해 다운로드가 되는 것을 볼 수 있습니다.

 

 

 

c:/test/이미지예제.jpg

 

다운로드된 jpg

 

 

 

IE 인코딩 에러

 

예제를 그대로 진행하면 한글명때문에 익스에서 하시는분들은 에러가 발생할 수 있습니다.

IE 예외처리 인코딩을 위해 jsp부분을 수정해주시면 됩니다.

 

 

board.jsp

<%@page import="java.net.URLEncoder"%>

...

<a href="/common/download.do?fileName=<%=URLEncoder.encode("이미지예제.jpg")%>">download</a>

URLEncoder를 추가 import해주시고 파라미터부분을 인코딩하여 넘기시면 IE에서도 되는 걸 확인 할 수 있습니다.

 

IE에서 정상 다운로드 처리

 

 

 

파일 업로드는 아래 URL에서 진행됩니다.

https://myhappyman.tistory.com/89

 

Spring - 파일 업로드 예제

https://myhappyman.tistory.com/86 Spring - 파일 다운로드 예제 - IE, Chrome (스프링 파일 다운로드 구성) 스프링 프로젝트에서 파일 업로드와 다운로드를 하는 방법을 알아보겠습니다. 이번 포스팅에선 다운로..

myhappyman.tistory.com

 

반응형