[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