Apache struts 프로젝트에서 servlet으로 pdf 파일 읽기
이번 글은 제목부터 보이듯이 조건이 많아 상당히 머리가 아팠다.
일단 현재 진행하고 있는 프로젝트가 Apache struts라는 태어나 처음 본 framework였고(Spring framework가 너무 익숙하다.)
pdf파일 view 또한 처음 진행 해봤다.
그리고 대망의 servlet... 얘는 아직도 잘 모르겠다.
시작해보자...
우선 파일 다운로드와 같이 a 태그에서 javascript를 호출하여 form을 전송하는 방식이었다.
- html
<a href="#" class="id_ok" onclick="pdfView('saveFileName'); return false;">읽기</a>
- javascript
function pdfView(saveFileName) {
let form = document.getElementById("thisForm");
let tmpFormTarget = form.target;
//form.target = "_blank"; 사용하면 웹브라우저 새창에서 열린다.
form.cmd.value="PDF_VIEW";
form.reg_no.value = saveFileName;
form.submit();
}
- JAVA controller
public void pdfView(WebForm form, HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
String href = "";
String fileName = form.getReg_no();
pdfServlet pdfServlet = new pdfServlet();
pdfServlet.doGet(form, request, response);
}
pdfServlet 파일에 doGet 함수를 호출한다.
- pdfServlet
public class pdfServlet extends HttpServlet {
public void doGet(WebForm form, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException {
String fileName = form.getReg_no();
PrintWriter stream = null;
BufferedInputStream buf = null;
try {
String pdfFilePath = PropertyUtil.getValue("pdf.file.path")+fileName+".pdf"; // application.properties에 선언된 pdf파일 경로 + saveFileName
String pathChcek = PropertyUtil.getValue("pdf.file.path"); // application.properties에 선언된 pdf파일 경로
File pdfFile = new File(pdfFilePath);
if(!pdfFile.getCanonicalPath().replace(File.separator, "/").startsWith(pathChcek)) { // 호출된 파일 경로 확인(보안) *중요
System.err.println("잘못된 접근입니다.");
throw new ServletException("잘못된 접근입니다.");
}
stream = response.getWriter();
response.setContentType("application/pdf"); // contentType 설정
FileInputStream fis = new FileInputStream(pdfFile);
response.setContentLength((int) pdfFile.length());
buf = new BufferedInputStream(fis);
int readBytes = 0;
while ((readBytes = buf.read()) != -1) {
stream.write(readBytes);
}
} catch (IOException ioe) {
throw new ServletException(ioe.getMessage());
} finally {
if (stream != null) stream.close();
if (buf != null) buf.close();
}
}
}
여기까지가 본인의 코드이다.
본인이 이번 기능에서 servlet을 사용하게된 이유는
Java에서 파일 다운로드처럼 getOutputStream을 사용하여서 처리할 수 있는 거 같았는데
그렇게 기능을 만들어보니
" getoutputstream() has already been called for this response " 이라는 오류를 만나게 되었다.
물론 기능이 안되는 건 아니었다 pdf 파일을 볼 수 있었는데 저런 오류가 자꾸 나와서 검색 해본 결과
try {
out.clear(); //out--> jsp자체 객체
out=pageContext.pushBody(); //out--> jsp자체 객체
OutputStream out = response.getOutputStream();
}
이렇게 outputstream을 생성하기 전에 jsp자체의 out객체를 비워주고 사용해야 합니다.
위와 같은 답을 찾을 수 있었다.
하지만 물론 본인이 잘 사용하지 못해서 그렇겠지만 본인의 오류는 해결되지 않았다.
더 검색해본 결과
'jsp가 아닌 서블릿에서 처리해줘야한다'는 글을 봤다.
그래서 더 모르겠다...
그래도 일단 해보자
servlet 파일을 만들고 extends HttpServlet 을 해주고
public class pdfServlet extends HttpServlet
그렇게 오류가 생겼던 getOutputStream이 아닌
PrintWriter stream = null;
stream = response.getWriter();
while ((readBytes = buf.read()) != -1) {
stream.write(readBytes);
}
PrintWriter를 사용했다.
생각 해보니 본인이 저번 파일 다운로드 글에서 처리했던 servlet 방식이랑 똑같다.
달라진 점이 있다면
response.setContentType("application/pdf");
contentType을 pdf로 변경해주었다.
이렇게 servlet을 사용해 pdf를 읽어봤는데 이제 나를 괴롭혔던
'getoutputstream() has already been called for this response' 이라는 오류 없이 pdf가 잘 읽힌다.
하지만 나는 아직도 servlet을 이해하지 못했고 찾아보니 본인 프로젝트는 Spring도 아니고 java 버전도 옛날 버전이라 사용하지 못했던 pdfViewer가 아주 많다.
왠만하면 그것들을 활용하길...