에러 발생
Poi 라이브러리를 사용하여 엑셀 다운로드 개발을 하는 도중, 다운로드된 파일을 열때마다 에러가 발생하였다.
[파일명]에 읽을 수 없는 내용이 있습니다. 이 통합 문서의 내용을 복구하시겠습니까? 이 통합 문서의 원본을 신뢰할 수 있는 경우 [예]를 클릭하십시오.
이 상태로 [예]를 누르게 되면 파일이 열리면서 아래 메세지가 적힌 팝업이 뜹니다
[파일명.xlsx](으)로 복구
읽을 수 없는 내용을 복구하거나 제거하여 파일을 열 수 있습니다.
[복구] 버튼을 누르면 엑셀파일은 알맞게 생성되었지만 열때마다 뜨는 경고창을 해결해야했다.
해결
Before
response.setHeader("Set-Cookie", "fileDownload=true; path=/"); response.setHeader("Content-Disposition", String.format("attachment; filename=" + excelName)); response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"); wb.write(response.getOutputStream());
내가 처음 사용했던 위 코드에서 단지 OutputStream을 close 해주지 않았기 때문이였다. response.getOutputStream().close() 한줄 때문에 엑셀 파일에서 내용을 손실했다는 에러가 발생한 것이였다.
After
ByteArrayOutputStream bout = new ByteArrayOutputStream(); wb.write(bout); bout.close(); response.setHeader("Set-Cookie", "fileDownload=true; path=/"); response.setHeader("Content-Disposition", "attachment; filename=" + excelName); response.setContentLength(bout.size()); ServletOutputStream out = response.getOutputStream(); out.write(bout.toByteArray()); out.flush(); out.close();
After 코드로 수정 후, 수행결과 에러는 해결되었다. 하지만 After 코드에도 문제는 있었다.
ByteArrayOutputStream 을 생성하고, wb.write(bout)로 해당 스트림에 wb객체 (엑셀파일)을 write한다.
(여기서, WorkBook 객체 wb의 write 메소드는 wb 객체에 쓰는게 아닌, bout 안에 자신을 쓴다는 뜻이다. = write out)그리고 다시한번 ServletOutputStream 을 생성하여 ByteArrayOutputStream 스트림 안의 내용을 wirte 한다.
위 코드는 Stream을 굳이 2번 생성한 것이다.
1. ByteArrayOutputStream을 선언하고,
2. ByteArrayOutputStream스트림에 WorkBook 객체 wb를 쓰고,
3. 또다시 ServletOutputStream을 선언하고, --> Stream 2번 생성
4. 해당 스트림에 ByteArrayOutputStream 의 객체를 toByteArray 메소드를 사용하하여 write 한것이다.
마무리
스트림 사용 이후, close() 메소드를 호출하는 것은 당연시 되어야한다. 그리고 위 예제에서는 flush() 메소드 호출 후 close() 메소드를 호출하지만 close() 메소드만 호출해도 flush()는 함께 호출됨을 알아두자.
'Project > Error' 카테고리의 다른 글
'ORA-01481: 숫자 형식 모델이 부적합합니다.' 해결하기 (0) | 2019.10.12 |
---|---|
org.apache.commons.fileupload.FileUploadException 에러발생 (ajax 다중파일업로드) (0) | 2018.05.03 |