최근 PDF 출력 기능을 개발하던 중 예상하지 못한 문제를 경험했습니다.
대부분의 PDF는 정상적으로 생성되었지만, 특정 데이터에서만 PDF 파일 크기가 0KB(또는 0Byte)로 생성되며 출력에 실패하는 현상이 발생했습니다.
처음에는 PDF 라이브러리 문제나 한글 인코딩 문제를 의심했습니다. 하지만 원인은 전혀 예상하지 못한 곳에 있었습니다.
이번 글에서는 문제를 어떻게 분석했고, 어떤 과정을 거쳐 원인을 찾았으며, 최종적으로 어떻게 해결했는지 실제 사례를 바탕으로 정리해 보겠습니다.
원인을 찾은 과정
처음에는 PDF 생성 라이브러리의 문제라고 생각했습니다.
하지만 이상했던 점은 모든 데이터에서 문제가 발생한 것이 아니라 특정 데이터에서만 동일한 현상이 발생했다는 것이었습니다.
그래서 정상적으로 출력되는 데이터와 출력되지 않는 데이터를 하나씩 비교하기 시작했습니다.
비교하는 과정에서 출력되지 않는 데이터의 공통점을 찾기 시작했고, 한 가지 특징을 발견했습니다.
출력이 실패하는 데이터에는 모두 ‘<‘ , ‘>’ 특수문자가 포함되어 있었고, 정상적으로 출력되는 데이터에는 해당 문자가 없었습니다.
혹시나 하는 마음에 해당 문자를 ‘(‘ , ‘)’로 변경한 뒤 다시 PDF를 생성해 보았습니다.
그 결과 PDF가 정상적으로 생성되었고, 문제의 원인이 데이터에 포함된 특수문자라는 것을 확인할 수 있었습니다.
아래는 문제가 발생한 데이터 예시입니다.
정상 데이터
Java 2026 입문
오류 데이터
Java <2026> 고급
수정 후
Java (2026) 고급
해결 방법
당시에는 서비스를 빠르게 정상화해야 하는 상황이었기 때문에, 가장 영향이 적은 방법을 선택했습니다.
출력용 데이터를 조회하는 SQL에서 ‘<‘, ‘>’ 문자를 각각 ‘(‘ , ‘)’로 치환하도록 수정했습니다.
예를 들어 Oracle에서는 REPLACE() 함수를 이용해 다음과 같이 처리할 수 있습니다.
SELECT
REPLACE(REPLACE(COLUMN_NAME, '<', '('), '>', ')') AS COLUMN_NAME
FROM TABLE_NAME;
위 예시는 이해를 돕기 위한 예제이며, 실제 프로젝트에서는 사용하는 컬럼명과 테이블명에 맞게 적용하면 됩니다.
처럼 처리할 수 있습니다.
물론 프로젝트 구조에 따라서는 XML Escape 또는 HTML Escape 처리를 적용하는 것이 더 적절한 방법일 수도 있습니다.
이번 사례에서는 쿼리만 수정할 수 있는 상황이었기 때문에 문자열 치환 방식을 선택했습니다. 하지만 장기적으로는 출력 과정에서 적절한 Escape 처리를 적용하는 것이 더 바람직합니다.
이번 경험을 통해 느낀 점
처음에는 PDF 라이브러리나 서버 문제라고 생각했습니다.
하지만 실제 원인은 데이터에 포함된 특수문자 하나였습니다.
장애를 해결할 때는 최근 변경된 코드만 계속 확인하기보다, 정상적으로 동작하는 데이터와 실패하는 데이터의 차이를 비교하는 것이 원인을 찾는 데 훨씬 효과적일 수 있다는 점을 다시 한번 느꼈습니다.
마무리
이번 문제는 특수문자 ‘<‘ ,’>’ 하나 때문에 발생했지만 원인을 찾기까지는 생각보다 많은 시간이 걸렸습니다.
특히 다른 데이터는 모두 정상이고 특정 데이터에서만 문제가 발생한다면 서버나 라이브러리보다 입력 데이터의 차이를 먼저 확인해 보는 것이 도움이 될 수 있습니다.
혹시 MyBatis나 PDF 출력 기능을 개발하면서 특정 데이터에서만 PDF 생성이 실패하는 현상을 겪고 있다면, 라이브러리나 서버 환경을 의심하기 전에 입력 데이터에 포함된 특수문자와 XML Escape 처리 여부를 먼저 확인해 보시기 바랍니다.