Develop

[JAVA] 파일 다운로드 / 파일 이름 및 확장자 오류 해결 본문

웹 개발/Java

[JAVA] 파일 다운로드 / 파일 이름 및 확장자 오류 해결

개발 기록 2024. 7. 30. 14:20

 

파일 다운로드 구현하면서 알아본 내용

- ajax로 다운로드 하는 방법과 Java에서 다운로드 하는 방법은 다르다

- ajax 사용시 xhr.responseType = "blob" 라는 내용이 들어가야한다

- ajax로는 get방식만 가능하며 post방식은 불가능하다

- <a>태그를 이용한 ajax get방식은 보안에 취약하다

 

결론

- form submit (post)방법을 사용했다

- form submit 이라고 해서 꼭 페이지를 이동하는 것이 아니므로 써도 됨

- <a> 태그를 이용하여 스크립트 실행, 스크립트에서 form submit 실행

(이 동작도 보안측면에서 괜찮아보이진 않는다)

 


 

view.jsp

<form name="Frm" method="post">
	<input type="hidden" name="fileId"/>
</form>

<c:forEach var="file" items="${model.fileInfo }">
    <c:if test="${file.FILE_TYPE eq 'jpg' || file.FILE_TYPE eq 'jpeg'|| file.FILE_TYPE eq 'png' }">
        <img alt="${file.ORG_FILE_NAME }" src="/localFile/${file.FILE_NAME }" width="150px" height="150px">
    </c:if>
    <br>
    ${file.ORG_FILE_NAME }
    <a onclick="downloadFile('${file.FILE_ID}')">(다운로드)</a> <br>
</c:forEach>

 

위의 JSP페이지에서 다운로드 버튼 클릭시 downloadFile(파일ID) 함수 실행

 

JavaScript

function downloadFile(fileId){
	var f = document.Frm;
	
	f.fileId.value = fileId;
	f.action = "/download_file.do";
	f.submit();
}

 

인수로 받은 파일Id 값을 form에 입력하고 post방식으로 submit

 

 

Controller

/**
* 파일 다운로드
*/
@ResponseBody
@RequestMapping("download_file")
public void downloadFile(@RequestParam Map<String,Object> p
                        , ModelMap map
                        , HttpServletRequest resquest
                        , HttpServletResponse response
                        , HttpSession session) throws Exception{
	adminHelpService.downloadFile(p, resquest, response);
}

 

 

Service

/**
 * 파일 다운로드
 */
void downloadFile(Map p, HttpServletRequest resquest, HttpServletResponse response) throws Exception;

 

 

 ServiceImpl

@Override
public boolean downloadFile(Map p
                            , HttpServletRequest resquest
                            , HttpServletResponse response) throws Exception {
    Map dbparams = new Map();

    // 파일 정보 조회 (DB)
    dbparams.put("fileId", p.get("fileId"));
    Map fileInfo = fileDao.selectFileInfo(dbparams);

    String fileName = fileInfo.getStr("FILE_NAME"); // 저장된 이름
    String orgFileName = fileInfo.getStr("ORG_FILE_NAME"); // 원래 이름
    String extension = fileInfo.getStr("FILE_TYPE"); // 파일 확장자
    int fileSize = fileInfo.getInt("FILE_SIZE"); // 파일 크기

    // 파일 업로드 경로 - C:\\upload\\ 
    // 경로를 나타낼땐 \를 두개 사용
    File file = new File("C:\\upload\\" + fileName);
    long filelength = file.length();
    
    if(file.isFile() ){ // isFile() 파일이 있으면 true, 없으면 false 반환
    	try {
            // 한글 인코딩
            orgFileName = URLEncoder.encode(orgFileName + "." + extension, "UTF-8");
            
            response.setContentType("application/octet-stream");
            response.setHeader("Content-Disposition", "attachment; filename=" + orgFileName + ";");
            response.setHeader("Content-Transfer-Encoding", "binary");
            response.setCharacterEncoding("euc-kr");
            response.setHeader("Pragma", "no-cache");

			OutputStream os  = response.getOutputStream();
            
            // 방법1
            FileInputStream fis = new FileInputStream(file);
            int i = 0;

            byte[] buffer = new byte[1024];
            while((i = fis.read(buffer)) != -1){
                os.write(buffer, 0, i);
            }
            fis.close();

            // 방법2
            byte[] fileByte = FileUtils.readFileToByteArray(file);
            os.write(fileByte);
			
            // 공통
            os.flush();
            os.close();
           

        } catch(FileNotFoundException e){
            e.printStackTrace();
        } 
        catch (Exception e) {
            e.printStackTrace();
            System.out.println(e);
        }
    }
}

 

 

 

 view.jsp에서 (다운로드) 글자를 클릭하면

다운로드가 되었지만

 

파일명과 확장자가 @RequestMapping 명과 같았다...

 

다운 받은 파일의 확장자를

 

이렇게 .jpg로 바꿔주고 파일을 열어보니

 

 

 

잘 다운되었음을 알 수 있다

 

이렇게 했는데도 파일을 못읽는다면 그건 다운이 제대로 안된거임

 

 response.setHeader("Content-Dispositon", "attachment; filename=" + orgFileName + ";");

 

 

service단에서 위와같이 다운받을시의 이름을 정해줬는데

왜 이렇게 다운되는건지 한참을 찾았다.

 

그러다 발견한 글

 

파일다운로드시 파일명이 세팅되지 않습니다. | 묻고 답하기 | 표준프레임워크 포털 eGovFrame

 

묻고 답하기 | 표준프레임워크 포털 eGovFrame

처리중입니다. 잠시만 기다려주십시오.

www.egovframe.go.kr

 

 

파일 이름이 제대로 다운되지 않는 이유는 인코딩 때문이라고 한다

 

출처 파일다운로드시 파일명이 세팅되지 않습니다. ❘ 묻고 답하기 ❘ 표준프레임워크 포털 eGovFrame

 

출처 파일다운로드시 파일명이 세팅되지 않습니다. ❘ 묻고 답하기 ❘ 표준프레임워크 포털 eGovFrame

 

 

 

그래서 service단에 브라우저별 인코딩 처리 부분을 추가해주었다

 

// 웹 브라우저 종류 조회
String browser = resquest.getHeader("user-agent");
orgFileName = orgFileName + "." + extension;

// 엣지 || IE
if(browser.contains("Edge") || browser.contains("MSIE") || browser.contains("Trident")){
    orgFileName = URLEncoder.encode(orgFileName, "UTF-8").replace("\\+", "%20");
    response.setHeader("Content-Dispositon", "attachment; filename=\"" + orgFileName);
}
// 크롬 || 오페라
if(browser.contains("chrome") || browser.contains("Opera")){
    orgFileName = new String(orgFileName.getBytes("UTF-8"), "ISO-8859-1");
    response.setHeader("Content-Dispositon", "attachment; filename=\"" + orgFileName);
}
// 파이어폭스
if(browser.contains("Firefox")){
    orgFileName = new String(orgFileName.getBytes("UTF-8"), "ISO-8859-1");
    response.setHeader("Content-Dispositon", "attachment; filename=" + orgFileName);
}

 


 

근데도 문제 해결이 안됐고 원인을 찾았다................

그냥 오타였다.........

response.setHeader("Content-Dispositon", "attachment; filename=" + java.net.URLEncoder.encode(orgFileName, "UTF-8") + extension + ";");

response.setHeader("Content-Disposition", "attachment; filename=" + java.net.URLEncoder.encode(orgFileName, "UTF-8") + extension + ";");

 

 

Content-Disposition 에서 tion이 아닌 ton으로 입력했던것이다..........내 이틀.....

해결돼서 다행인걸까.....

 

최종 ServiceImpl 내용

@Override
public void downloadFile(Map p
                            , HttpServletRequest resquest
                            , HttpServletResponse response) throws Exception {
    Map dbparams = new Map();

    // 파일 정보 조회
    dbparams.put("fileId", p.get("fileId"));
    Map fileInfo = fileDao.selectFileInfo(dbparams);

    String fileName = fileInfo.getStr("FILE_NAME");
    String orgFileName = fileInfo.getStr("ORG_FILE_NAME");
    int fileSize = fileInfo.getInt("FILE_SIZE");
    String extension = "." + fileInfo.getStr("FILE_TYPE");

    File file = new File("C:\\upload\\" + fileName);

    if(file.isFile() ){
        try {
            response.setContentLength(fileSize);
            response.setHeader("Content-Disposition", "attachment; filename=" + URLEncoder.encode(orgFileName, "UTF-8") + extension + ";");
            response.setContentType("application/octet-stream");
            response.setHeader("Content-Transfer-Encoding", "binary");

            byte[] fileByte = FileUtils.readFileToByteArray(file);

            OutputStream os  = response.getOutputStream();
            os.write(fileByte);

            os.flush();
            os.close();

        } catch(FileNotFoundException e){
            e.printStackTrace();
        } 
        catch (Exception e) {
            e.printStackTrace();
            System.out.println(e);
        }
    }
}

 

 

다운로드는 쉬운데 인코딩이 날 괴롭혔다...