[java] jsp에서 파일 다운로드 구현 시 한글,특수문자 파일명 오류 해결방법

 
자바에서 파일 다운로드를 구현하다 보면 문제가 발생할 때가 있다.
그건 바로 다운로드는 되지만 파일명의 특수문자가 깨진다거나 한글파일명은 다운로드가 안 되는 경우이다.
그래서 오늘은 파일다운로드 할때 어떤 브라우저를 사용하더라도 최대한 다운로드가 실패하지 않게 구현하는 방법을 알아보자.
 

사용자페이지

<a href="#download" data-filename="${파일명}" data-filepath="${파일경로}">${파일명}</a>
<a href="#download" data-filename="${파일명2}" data-filepath="${파일경로2}">${파일명2}</a>
<a href="#download" data-filename="${파일명3}" data-filepath="${파일경로3}">${파일명3}</a>

<form id="fileForm" action="<c:url value='/file/download'/>" method="post">
    <input type="hidden" name="filePath">
    <input type="hidden" name="fileName">
</form>

<script type="text/javascript">
	$(function() {
       	$("a[href='#download']").click(function(e) {
            e.preventDefault();
            console.log('#download');
            var fileForm = $("#fileForm");
            var fileName = $(this).data("filename");
            var filePath = $(this).data("filepath");

            console.log(filePath, fileName);
            fileForm.find("input[name='filePath']").val("${nasRoot}" + filePath);
            fileForm.find("input[name='fileName']").val(fileName);

            fileForm.submit();
            });
        });
</script>

파일명을 A 태그로 감싸고 data값에 파일명과 파일경로를 써 주었다.

다운로드 클릭 이벤트가 일어나면 A tag에 있는 data 속성값을 가져와서 변수에 담는다.
미리 만들어둔 download form에 넣고 submit()을 실행한다.
 

파일 다운로드 컨트롤러

@RequestMapping(value = "/file/download")
public void download(Model model, HttpServletResponse response, @RequestParam(value = "fileName") String fileName, @RequestParam(value = "filePath") String filePath,HttpServletRequest request) throws Exception {

    logger.info("/file/download : " + filePath  + fileName);

    try{                                        
        request.setCharacterEncoding("UTF-8");
        fileName = new String(fileName.getBytes("UTF-8"), "UTF-8");
        File file = new File(filePath, fileName);

        if(file.isFile()){
            int bytes = (int)file.length();
            String header = request.getHeader("User-Agent");

            if (header.contains("MSIE") || header.contains("Trident")) {
                fileName = URLEncoder.encode(fileName,"UTF-8").replaceAll("\\+", "%20");
                response.setHeader("Content-Disposition", "attachment;filename=" + fileName + ";");
            } else {
                fileName = new String(fileName.getBytes("UTF-8"), "ISO-8859-1");
               response.setHeader("Content-Disposition", "attachment; filename=\"" + fileName + "\"");
            }

            response.setContentType( "application/download; UTF-8" );
            response.setContentLength(bytes);
            response.setHeader("Content-Type", "application/octet-stream");                
            response.setHeader("Content-Transfer-Encoding", "binary;");
            response.setHeader("Pragma", "no-cache;");
            response.setHeader("Expires", "-1;");

            BufferedInputStream fin = new BufferedInputStream(new FileInputStream(file));
            BufferedOutputStream outs = new BufferedOutputStream(response.getOutputStream());

            byte[] readByte = new byte[4096];
            try{
                while((bytes = fin.read(readByte)) > 0){
                    outs.write(readByte, 0, bytes);
                    outs.flush();
                }
            }catch(Exception ex){

            }finally{
                outs.close();
                fin.close();
            }
        }
    }catch(Exception ex){
        ex.printStackTrace();
    }
}

컨트롤러를 하나만들고 파일명과 파일경로를 받아서 파일 다운로드를 시작한다.

파일명과 파일경로를 이용해 파일객체를 생성한다.

 

file.isFile()을 이용해 파일이 있는지는 체크한후 파일명을 변환해준다.

파일명은 브라우저 중 MSIE로 분류되는 mozila와 Trident로 분류되는 IE는 UTF-8로 변환하고 나머지는 UTF-8 인코딩 형태로 받은 후 ISO-8859-1로 문자를 생성한다.
 
파일명은 중복이 될수 있기에 보통   pk나 인덱스, 시간 등으로 변환해서 db에 저장한다.
원본파일명이 따로 있다면  header 값 중 Content-Disposition의 fileName 값을 원본파일명으로 넣어주면 된다.
 
 
참고 글: https://eastglow.github.io/back-end/2018/11/06/Java-%ED%8C%8C%EC%9D%BC-%EB%8B%A4%EC%9A%B4%EB%A1%9C%EB%93%9C-%EC%8B%9C-%ED%95%9C%EA%B8%80-%EB%B0%8F-%ED%8A%B9%EC%88%98%EB%AC%B8%EC%9E%90-%EA%B9%A8%EC%A7%90,-%EB%8B%A4%EC%9A%B4%EB%A1%9C%EB%93%9C-%EB%B6%88%EA%B0%80-%EC%98%A4%EB%A5%98.html