클래스로더 오류 관련

2018. 2. 19. 10:42

오류 : 

가끔씩 uncompiled jsp 오류가 나올 때가 있다.


case 1 : 

jsp 파일은 계속 재컴파일되지만 가끔씩 누락되는 경우도 있다. ex) svn 원격 scp 이동시


case 2 :

was 기동 시에 jsp/java 파일을 클래스로더가 컴파일해서 class파일로 메모리에 올려 놓게 되는데

was를 내렸다가 올리더라도 클래스로더가 캐쉬메모리에 올려놓고 이미 캐쉬메모리에 있으니 다시 메모리에 올려놓지 않는 경우가 가끔 있다.


해결책 : 

이때에는 문제가 되는 jsp/java의 class파일 삭제 후 재컴파일을 유도하면 해결되는 경우가 있다.


결론 : 

클래스로더 문제라고 판단되면 해당 class파일 삭제 후 was를 재기동시켜 재컴파일을 유도 한다.

# 엑셀 내보내기 시 JSP 상단 설정


<%@ page language="java" contentType="application/vnd.ms-excel; name='excel', text/html; charset=UTF-8"

        pageEncoding="UTF-8"%>

<%     

    response.setHeader("Content-Disposition", "attachment; filename=diary.xls"); 

    response.setHeader("Content-Description", "JSP Generated Data"); 

    response.setContentType("application/vnd.ms-excel");

%>


# 엑셀 포맷 정리


Styling Excel cells with mso-number-format

mso-number-format:"0"NO Decimals
mso-number-format:"0\.000"3 Decimals
mso-number-format:"\#\,\#\#0\.000"Comma with 3 dec
mso-number-format:"mm\/dd\/yy"Date7
mso-number-format:"mmmm\ d\,\ yyyy"Date9
mso-number-format:"m\/d\/yy\ h\:mm\ AM\/PM"D -T AMPM
mso-number-format:"Short Date"01/03/1998
mso-number-format:"Medium Date"01-mar-98
mso-number-format:"d\-mmm\-yyyy"01-mar-1998
mso-number-format:"Short Time"5:16
mso-number-format:"Medium Time"5:16 am
mso-number-format:"Long Time"5:16:21:00
mso-number-format:"Percent"Percent - two decimals
mso-number-format:"0%"Percent - no decimals
mso-number-format:"0\.E+00"Scientific Notation
mso-number-format:"\@"Text
mso-number-format:"\#\ ???\/???"Fractions - up to 3 digits (312/943)
mso-number-format:"\0022£\0022\#\,\#\#0\.00"£12.76
mso-number-format:"\#\,\#\#0\.00_ \;\[Red\]\-\#\,\#\#0\.00\ "

2 decimals, negative numbers in red and signed
(1.56 -1.56)

.

# EXAMPLE


<td style='mso-number-format: "@";'>01034567890</td>

 

요런식으로 지정하면 "010" 요런 문자도 "10"으로 표시되지 않고 "010"으로 잘 나옴



출처: http://androphil.tistory.com/442 [소림사의 홍반장!]

* 현재 pdf다운로드 요건 : 

1. html to pdf 다운로드 기능

2. 다건의 데이터 클릭 후 다운로드 버튼 누를 경우 다건의 html 페이지를 하나의 pdf파일로 다운로드

-> 서버단에서 html 페이지를 읽어와 하나의 pdf파일로 합치기 때문에 로딩시간이 길다.


* 이슈사항 : 

URL 경로를 통해 파일을 다운로드 받는 것이 아닌, 빽단에서 response의 header를 아래와 같이 BufferOutputStream으로 출력할 경우

파일 다운로드 완료 타이밍을 어떻게 확인할 수 있나?

if (request.getHeader("User-Agent").toLowerCase().indexOf("msie") > -1 ||
        request.getHeader("User-Agent").toLowerCase().indexOf("edge") > -1 ||
        request.getHeader("User-Agent").toLowerCase().indexOf("rv:11.0") > -1
        ) {
    response.setHeader("Content-Disposition", "attachment; filename=\"" +
                                   (URLEncoder.encode(downloadPdfFilename,"UTF-8").replaceAll("\\+","%20")) + "\"");
} else {
    response.setHeader("Content-Disposition", "attachment; filename=\"" +
                                   (new String(downloadPdfFilename.getBytes("UTF-8"), "8859_1")) + "\"");
}
//out.clear();
//out = pageContext.pushBody();
BufferedInputStream in = new BufferedInputStream(new FileInputStream(file));
BufferedOutputStream os = new BufferedOutputStream(response.getOutputStream());
int read = 0;
while ((read = in.read()) != -1) {
    os.write(read);
}
// response.flushBuffer();
in.close();
// os.flush();
os.close();
file.delete();

* 시도해본 방법


1. response.getWriter().print() 메서드를 통해 script로 로딩바 종료 메서드 호출.

StringBuffer script = new StringBuffer();
script.append("<script type="\"text/javascript\"">");
script.append("tmsComm.destroyProgressBar();");
script.append("</script>");
response.getWriter().print(script.toString());

-> response를 통해 buffer stream으로 파일도 출력하고, text로도 출력해 script단을 호출하려 했으나

    다음과 같은 에러 발생(java.lang.IllegralStateException)



구글링 결과 response는 2가지 형식으로 출력이 불가능하다. 이미 stream형태로 출력하기 때문에 text로 출력 불가

(상식적으로도 그러는게 당연)


2. jsp단에서 직접 <script>코드 추가



20row의 sout은 back단의 시스템 로그에 찍히지만, 

23row의 alert는 response로 이미 파일 스트림을 출력했으므로 front단은 읽지 않아서 alert이 찍히지 않는다.

따라서 이 방법으로도 구별 불가.


3. form의 target을 iframe으로 주어서 iframe onload(파일다운로드 작업 완료) 이벤트 시 호출

// 1번 방법
$(document).on("load","#hideIframe",function (){
        alert("aaaa");
        tmsComm.destroyProgressBar();
});
// 2번 방법
$("#hideIframe").on("load",function () {
        alert("aaaa");
        tmsComm.destroyProgressBar();
});
// 3번 방법
 document.getElementById("hideIframe").onload = function () {
        alert("ccccccc");
};

-> 1~3번 방법까지 다 시도 해봤으나 onload 이벤트 메소드 자체가 호출 되지가 않는다.

-> 구글링 결과 stackoverflow형님에게서 다음과 같은 결과를 얻을 수 있었다.


         Unfortunately it is not possible to use an iframe's onload event in Chrome if the content is an attachment.


         안타깝게도 콘텐츠가 첨부 파일 인 경우 Chrome에서 iframe onload 이벤트를 사용할 수 없습니다.


4. ajax 호출(?) ->  ajax의 경우 string/xml통신 기반이다. 따라서 response값을 string값으로 url주소를 넘겨주어서 파일 다운로드가 가능하지만

 언제 다운로드가 완료됬는지는 확인 불가. 게다가 지금 상황은 response값을 파일 스트림으로 곧바로 넘겨주는 경우이다.




* 해결책


약 4~5시간의 뻘짓 끝에 stackoverflow형님의 도움을 받아 해결. 


형님 왈 : I hate this, but I couldn't find any other way than checking whether it is still loading or not except by checking at intervals.


나도 이 방법이 싫지만 아직 로딩 중인지 아닌지를 확인하는 방법을 이 방법 외에는 어떤 방법도 찾지 못했다.

var timer = setInterval(function () {
    iframe = document.getElementById('iframedownload');
    var iframeDoc = iframe.contentDocument || iframe.contentWindow.document;
    // Check if loading is complete
    if (iframeDoc.readyState == 'complete' || iframeDoc.readyState == 'interactive') {
        tmsComm.destroyProgressBar();
        clearInterval(timer);
        return;
    }
}, 4000); 

이 방법은 파일 다운로드 시에 4초에 1번씩 iframe의 상태값을 확인해서 iframe상태가 complete이거나 interactive인 경우 timer와 로딩바를 중단시키는 방법이다.


결국 찾다찾다 이 방법을 채택하였지만 완벽하지 못하다. 가장 좋은 방법은 이 것일 거 같다.


※ response를 파일 스트림으로 넘기는 것이 아니라 URL로 던져주어서 서버의 파일을 다운로드 받게 하고 서버단에서는 특정날짜/특정시간에 PDF파일들을 삭제하는 쉘 스크립트를 작성하는 것


이 부분은 고도화 작업시에 다시 진행할 예정이다.

+ Recent posts