본문 바로가기
Web Development/Spring Legacy

[Spring / Legacy] AbstractView를 활용해 파일 다운로드 기능 구현해보기

by 감자맹고우 2022. 1. 21.
728x90
반응형

웹 프로젝트를 진행하다보면 업로드와 다운로드 기능을 거의 필수적으로 개발하게 된다.

오늘은 그 중에서 다운로드 기능에 대해서 정리해보려고 한다.

 

File Upload 로직이 서버단에서 이루어지는 것에 비해 File Download는 뷰단에서 이루어진다.

하지만, 진짜 View인 jsp 파일을 return 하는 것은 아니다.

대신 AbstractView라는 해석 그대로 추상View 라는 클래스를 이용하여 처리한다.

 

우리가 AbstractView 클래스를 상속받는 클래스를 만들고 리턴하기만 하면 해당 클래스는 뷰로 취급되어 다운로드 기능이 구현되는 것이다. 바로 알아보도록 하자.

 

반응형

 

[ 구현 과정 ]

 

<!-- servlet-context.xml -->
<beans:bean class="org.springframework.web.servlet.view.BeanNameViewResolver">
	<beans:property name="order" value="0" />
</beans:bean>

<beans:bean id="fileDownload" class="com.test.util.FileDownload" />

 

우선 위와 같은 방식으로 servlet-context.xml에 ViewResolver와 DownloadView를 bean 설정한다.

이 때, bean의 id와 class는 각각 프로젝트에 해당하는 내용으로 변경해야 한다.

src/main/java 내의 새로 생성한 클래스 위치를 잡아주어야 한다는 뜻이다.

 

즉, 위의 예시에서는 com.test라는 프로젝트 안에 util 패키지를 만들고 그 안에 FileDownload라는 Java Class를 새로 생성했고, 해당 위치를 적어준 상황이다.

 

다음은, DownloadView 클래스 작성이다.

 

<!--FileDownload 클래스(java) -->
@Component
public class FileDownload extends AbstractView{

	@SuppressWarnings("unchecked")
	@Override
	protected void renderMergedOutputModel(Map<String, Object> model, HttpServletRequest request, HttpServletResponse response) throws Exception {
		
		setContentType("application/download; charset=UTF-8");
		
		//파일 정보 Load
		Map<String, Object> fileMap = (Map<String, Object>) model.get("fileMap");
		String filePath = (String) fileMap.get("filePath");
		String fileName = (String) fileMap.get("fileSaveName");
		String fileOriginalName = (String) fileMap.get("fileOriginalName");
		File file = new File(filePath, fileName);

		response.setContentType(getContentType());
		response.setContentLength((int) file.length());
		
		String userAgent = request.getHeader("User-Agent");
		
		if(userAgent.indexOf("MSIE") != -1) {
			fileOriginalName = URLEncoder.encode(fileOriginalName,"UTF-8");
		}else {
			fileOriginalName = new String(fileOriginalName.getBytes("UTF-8"), "ISO-8859-1");
		}
		
		response.setHeader("Content-Transfer-Encoding", "binary;");
		response.setHeader("Content-Disposition", "attachment; filename=\"" + fileOriginalName + "\"");
		
		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 (IOException ioe) {
					ioe.printStackTrace();
				}
			}
			out.flush();
		}
		
	}

}

 

위와 같이 FileDownload 클래스에 AbstractView 클래스를 상속받고, AbstractView의 renderMergedOutputModel 메소드를 Override하여 작성해준다.

 

메소드 내부는 Controller에서 Map 으로 넘겨받은 파일 정보를 불러와 IE 사용/미사용을 구분하여 사용 시 URL encoder를 통해 encoding 해주고 다운로드 처리하는 로직이다.

 

반응형

 

이제 Controller를 작성해보자.

 

<!-- File Controller -->
@Controller
@RequestMapping(value = "/file")
public class FileController {

    @RequestMapping(value = "/fileDownload")
    public ModelAndView fileDownLoad(FileVO fileVO) {
    
    //DB에 저장된 파일 정보 Load
    fileVO = fileService.getFile(fileVO);
    Map<String, Object> fileMap = new HashMap<String, Object>();
	
    /* FileMap에 파일 정보 담기 */
    //DB에 저장된 File 경로 컬럼 값 Load(실제 저장된 경로와 일치)
    fileMap.put("filePath", fileVO.getfilePath() + File.separator);
    //DB에 저장된 File 이름(주로 인코딩하여 저장)
    fileMap.put("fileSaveName", fileVO.getFileSaveName());
    //DB에 저장된 File의 원본이름(인코딩 전 파일명)
    fileMap.put("fileOriginalName", fileVO.getFileOriginalName());
	
    //fileMap을 인자로 하는 fileDownload 클래스 반환
    return new ModelAndView("fileDownload", "fileMap", fileMap);
    
}

<!-- FileVO 예제 -->
public class FileVO {
    private int fileId;
    private String filePath;
    private String fileSaveName;
    private String fileOriginalName;
    
    ~~ getter, setter 생략 ~~
}

 

앞에서 말했듯 컨트롤러에서는 구현할 로직은 따로 없고, DB에서 FILE정보를 받아와 넣고 반환하기만 하면 된다.

 

반응형

 

이어서 jsp에서 접근하는 예제이다.

 

<!-- 1. a 태그 사용 시 -->
<a href="/file/fileDownload?fileId=1" download>다운로드</a>

<!-- 2. button 태그 사용 시 -->
<button onclick="location.href='/file/fileDownload?fileId=1'">다운로드</button>

 

이와 같이 DB의 FILE_ID 컬럼을 조회하여 다운로드 기능을 구현할 수 있다!

 

🤞 도움이 되셨기를 바랍니다. 한 번의 클릭과 댓글은 어딘가의 누군가에게 진실로 큰 힘이 됩니다. 🐱‍🏍

 

728x90
반응형

댓글