GroupDocs Viewer Java 튜토리얼: Word를 HTML로 변환하고 주석이 있는 문서 렌더링
소개
문서 변환 시 검토자의 메모, 댓글 또는 주석을 모두 유지하면서 Word를 HTML로 변환해야 한다면, 여기가 바로 적합한 곳입니다. 많은 Java 개발자들이 문서 변환 과정에서 원본 파일에 포함된 소중한 피드백이 사라지는 문제에 부딪히곤 합니다. 이 튜토리얼에서는 GroupDocs Viewer for Java를 사용하여 Word를 HTML로 변환하고 Word, Excel, PowerPoint, PDF 등 다양한 문서 유형을 주석 데이터를 잃지 않고 렌더링하는 방법을 단계별로 안내합니다.
GroupDocs Viewer가 프로덕션에 적합한 선택인 이유, 환경 설정 방법, 필요한 정확한 코드, 그리고 대용량 파일에서도 성능을 빠르게 유지하는 검증된 팁을 확인할 수 있습니다.

주석이 포함된 문서를 GroupDocs.Viewer for Java로 렌더링
이 튜토리얼에서 마스터할 내용:
- 완전한 GroupDocs Viewer 설정 및 구성
- 주석이 보존된 Word를 HTML로 변환 단계별 진행
- 일반적인 문제 해결 방법 및 피해야 할 함정
- 실제 적용 패턴 및 모범 사례
- 프로덕션 사용을 위한 성능 최적화 기법
빠른 답변
- GroupDocs Viewer가 Word를 HTML로 변환할 수 있나요? 예—한 줄의 코드로 HTML 렌더링 및 주석 지원을 활성화합니다.
- 댓글이 HTML 출력에 유지되나요? 물론—
setRenderComments(true)가 모든 댓글과 주석을 보존합니다. - 필요한 Java 버전은? JDK 8 이상.
- 프로덕션에 라이선스가 필요합니까? 전체 라이선스를 사용하면 워터마크가 제거되고 모든 기능이 활성화됩니다.
- 렌더링 속도를 어떻게 개선하나요? 특정 페이지만 렌더링하고, 외부 리소스를 사용하며, JVM 힙 크기를 늘립니다.
주석이 포함된 “convert word to html”란?
*“Convert Word to HTML”*는 Microsoft Word .docx 파일을 웹에 적합한 HTML 문서로 변환하면서 원본 레이아웃, 스타일 및 포함된 모든 주석을 유지하는 것을 의미합니다. 이 과정으로 브라우저가 문서를 작성자가 의도한 그대로, 검토자 피드백까지 포함하여 표시할 수 있습니다.
왜 Java용 GroupDocs Viewer를 선택해야 할까요?
코드에 들어가기 전에, Java 기반 문서 렌더링을 위한 최고의 라이브러리인 GroupDocs Viewer를 선택해야 하는 이유를 살펴보겠습니다:
- 170개 이상의 지원 포맷 – 라이브러리는 DOCX부터 CAD 파일까지 모든 형식을 처리하여 변환 요구 사항을 하나의 의존성으로 해결합니다.
- 타사 Office 설치 불필요 – Microsoft Office, LibreOffice 등 무거운 런타임이 없어도 모든 OS에서 작동합니다.
- 포맷 및 주석 보존 – 댓글, 각주, 변경 추적이 변환 과정에서도 그대로 유지됩니다.
- 빠르고 가벼운 엔진 – 일반적인 100페이지 문서는 표준 4코어 서버에서 2초 미만에 렌더링됩니다.
- 탄탄한 문서와 활발한 커뮤니티 – 문제 발생 시 예제, 포럼, 빠른 지원을 받을 수 있습니다.
이 접근 방식을 사용할 때
- 검토자 메모를 표시해야 하는 웹 기반 문서 뷰어 구축
- 피드백이 계속 표시되어야 하는 협업 검토 플랫폼 제작
- 법률 포털에서 온라인 표시를 위한 레거시 계약서 변환
- 학습 자료에 강사 댓글을 삽입하는 e‑learning 솔루션 개발
전제 조건 및 환경 설정
필요 사항
- Java Development Kit (JDK) 8+ – 애플리케이션을 구동하는 런타임.
- Maven 3.6+ – 의존성 관리 및 프로젝트 빌드용.
- 선호하는 IDE – IntelliJ IDEA, Eclipse, VS Code 중 선택.
- 주석이 포함된 샘플 문서 – 검토자 메모가 들어 있는 DOCX, XLSX, PPTX 파일.
개발 환경 설정
단계 1: Java 설치 확인
터미널을 열고 다음을 실행하십시오:
java -version
버전 문자열이 1.8 이상으로 시작하는 것을 확인할 수 있습니다. 그렇지 않다면 공식 Oracle 또는 OpenJDK 웹사이트에서 최신 JDK를 다운로드하십시오.
단계 2: Maven 설치 확인
Run:
mvn -v
Maven은 버전과 사용 중인 Java 버전을 출력해야 합니다. 명령을 인식하지 못한다면 Apache 웹사이트에서 Maven을 설치하십시오.
단계 3: 새로운 Maven 프로젝트 생성
Generate a skeleton project with:
mvn archetype:generate -DgroupId=com.example.viewer -DartifactId=viewer-demo -DarchetypeArtifactId=maven-archetype-quickstart -DinteractiveMode=false
생성된 viewer-demo 폴더로 이동하면 GroupDocs Viewer를 추가할 준비가 됩니다.
GroupDocs.Viewer for Java 설정
의존성 추가
모든 GroupDocs Viewer Java 튜토리얼의 첫 단계는 라이브러리를 프로젝트에 추가하는 것입니다. pom.xml 파일에 다음 구성을 추가하십시오:
<dependency>
<groupId>com.groupdocs</groupId>
<artifactId>groupdocs-viewer</artifactId>
<version>25.2</version>
</dependency>
팁: 최신 버전을 확인하려면 항상 GroupDocs releases page를 확인하십시오. 라이브러리는 정기적인 업데이트와 버그 수정으로 활발히 유지 관리됩니다.
라이선스 옵션 이해
GroupDocs는 다양한 프로젝트 요구에 맞는 유연한 라이선스를 제공합니다:
- 무료 체험 (학습에 최적): 전체 기능 접근 및 평가용 워터마크가 포함된 30일 평가판.
- 임시 라이선스 (개발용): 워터마크 없이 연장된 평가판; PoC 프로젝트에 적합합니다. GroupDocs Temporary License Page에서 요청하십시오.
- 전체 라이선스 (프로덕션 준비): 제한이나 워터마크가 없으며 상업적 사용이 허용됩니다. GroupDocs Purchase Page에서 구매 가능.
기본 초기화 패턴
Here’s the fundamental pattern you’ll use throughout this tutorial:
try (Viewer viewer = new Viewer("input.docx")) {
// Rendering options will be set later
}
이 패턴이 작동하는 이유:
- 자동 리소스 관리는 메모리 누수를 방지합니다.
- 예외 처리는 일반적인 파일 접근 문제를 포착합니다.
- 깨끗하고 가독성 높은 코드는 대규모 프로젝트에서도 유지 관리가 쉽습니다.
핵심 구현: 주석이 있는 문서 렌더링
프로세스 이해
GroupDocs Viewer로 문서를 렌더링하면 라이브러리는 네 가지 주요 단계를 수행합니다:
- 문서 분석 – 입력 파일을 파싱하고 내부 표현을 구축합니다.
- 주석 추출 – 모든 댓글, 각주 및 주석을 식별합니다.
- HTML 생성 – 원본 레이아웃을 그대로 반영하는 깔끔하고 표준 준수 HTML을 생성합니다.
- 리소스 처리 – 이미지, CSS, 폰트를 인라인 또는 외부 파일로 번들링합니다.
단계별 구현
단계 1: 파일 경로 설정
Organise your input and output locations early to avoid path‑related errors:
Path inputPath = Paths.get("documents/sample-with-comments.docx");
Path outputDir = Paths.get("output/html");
Files.createDirectories(outputDir);
이 접근 방식의 이유:
java.io.File보다 신뢰성이 높은 최신 Java NIO.2PathAPI를 사용합니다.- 설명적인 변수 이름으로 디버깅이 쉬워집니다.
- 출력 패턴의
{0}플레이스홀더가 페이지 번호로 자동 교체됩니다.
단계 2: HTML 렌더링 옵션 구성
여기가 핵심입니다. GroupDocs에 문서를 어떻게 렌더링할지 정확히 지정합니다:
HtmlViewOptions viewOptions = HtmlViewOptions.forEmbeddedResources(outputDir);
viewOptions.setRenderComments(true); // Preserve every comment
viewOptions.setPageNumberPrefix("page_");
HtmlViewOptions는 리소스 처리와 주석 렌더링을 포함하여 문서를 HTML로 렌더링하는 방식을 구성합니다.
핵심 구성 세부 사항:
forEmbeddedResources()는 CSS, 이미지, 폰트를 HTML에 직접 포함시켜 출력물을 휴대 가능하게 합니다.setRenderComments(true)는 convert word to html이 모든 검토자 메모를 유지하도록 하는 한 줄 코드입니다.- 대안인
forExternalResources()를 사용하면 더 가벼운 HTML 파일을 위해 자산을 별도로 저장할 수 있습니다.
단계 3: 렌더링 실행
이제 모든 요소를 결합합니다:
try (Viewer viewer = new Viewer(inputPath.toFile())) {
viewer.view(viewOptions);
}
Viewer는 문서를 로드하고 렌더링 작업을 수행하는 주요 클래스입니다.
view 호출은 Word 파일을 읽고, 주석을 추출하며, HTML 페이지를 생성하고 output/html에 기록합니다. 각 페이지는 page_1.html, page_2.html 등으로 저장됩니다.
완전한 작동 예제
모든 요소를 결합하면 주석이 그대로 유지된 상태로 Word 문서를 HTML로 변환하는 단일 실행 가능한 클래스를 얻을 수 있습니다. (전체 소스 코드는 공식 GitHub 저장소에서 확인할 수 있습니다.)
고급 구성 및 옵션
동적 출력 디렉터리 설정
For larger applications you may want to generate output directories based on user IDs or timestamps:
String userId = "12345";
Path dynamicOutput = Paths.get("output", userId, LocalDate.now().toString());
Files.createDirectories(dynamicOutput);
HtmlViewOptions dynamicOptions = HtmlViewOptions.forEmbeddedResources(dynamicOutput);
일반적인 문제 및 트러블슈팅
문제 1: “File Not Found” 오류
입력 경로가 작업 디렉터리를 기준으로 절대 경로나 상대 경로인지 확인하고 파일 권한을 검증하십시오. Path 객체를 사용하면 일반적인 문자열 연결 실수를 피할 수 있습니다.
문제 2: 출력에 주석이 표시되지 않음
setRenderComments(true)가 viewer.view() 이전에 호출되었는지 다시 확인하십시오. 또한 원본 문서에 실제로 주석이 포함되어 있는지도 확인하세요; viewer.getDocumentInfo().getComments()를 통해 확인할 수 있습니다.
문제 3: 대용량 문서에서 메모리 부족 오류
GroupDocs Viewer는 데이터를 스트리밍하지만, 500페이지 이상과 같은 매우 큰 파일은 여전히 JVM 힙에 부담을 줄 수 있습니다. -Xmx4g와 같이 힙 크기를 늘리거나 필요한 페이지만 렌더링하십시오.
문제 4: 렌더링 성능 저하
viewer.view(pageRange, viewOptions)를 사용해 특정 페이지 범위만 렌더링하십시오. 외부 리소스(forExternalResources())를 사용하면 HTML 페이로드 크기도 줄어 브라우저 렌더링 속도가 빨라집니다.
실제 구현 패턴
패턴 1: 웹 애플리케이션 통합
Integrate the rendering logic into a Spring Boot controller to serve HTML on demand:
@RestController
@RequestMapping("/api/view")
public class DocumentController {
@GetMapping("/{id}")
public ResponseEntity<Resource> renderDocument(@PathVariable String id) throws IOException {
Path docPath = Paths.get("documents", id + ".docx");
Path outDir = Files.createTempDirectory("viewer");
HtmlViewOptions options = HtmlViewOptions.forEmbeddedResources(outDir);
options.setRenderComments(true);
try (Viewer viewer = new Viewer(docPath.toFile())) {
viewer.view(options);
}
// Return the first HTML page as a Resource
Path firstPage = outDir.resolve("page_1.html");
Resource resource = new UrlResource(firstPage.toUri());
return ResponseEntity.ok()
.contentType(MediaType.TEXT_HTML)
.body(resource);
}
}
패턴 2: 다중 문서 배치 처리
전체 폴더의 Word 파일을 변환해야 할 경우, 디렉터리를 순회하면서 동일한 HtmlViewOptions 인스턴스를 재사용하여 객체 생성 오버헤드를 최소화합니다.
성능 최적화 및 모범 사례
메모리 관리 팁
Viewer인스턴스에는 항상 try‑with‑resources를 사용하십시오.- 대용량 문서는 배치 처리하여 한 번에 모두 메모리에 로드하지 마십시오.
VisualVM과 같은 도구로 JVM 힙 사용량을 모니터링하고 필요에 따라-Xmx를 조정하십시오.- 자주 접근하는 문서는 적절한 캐싱을 구현하여 반복 렌더링을 방지하십시오.
리소스 사용 가이드라인
For Small Applications (< 100 documents/day):
HtmlViewOptions options = HtmlViewOptions.forEmbeddedResources(Paths.get("output"));
options.setRenderComments(true);
For High‑Volume Applications (1000+ documents/day):
HtmlViewOptions options = HtmlViewOptions.forExternalResources(Paths.get("output"));
options.setRenderComments(true);
options.setCacheEnabled(true);
캐싱 전략
렌더링된 HTML을 문서 해시를 키로 하는 분산 캐시(예: Redis)에 저장합니다. 요청이 들어오면 먼저 캐시를 확인하고, 히트 시 즉시 캐시된 HTML을 제공하여 렌더링 엔진을 우회합니다.
GroupDocs Viewer와 대안 선택 시점
GroupDocs Viewer가 적합한 경우
- 문서 관리 시스템 – 다양한 파일 유형과 주석을 표시해야 할 때.
- 협업 검토 플랫폼 – 모든 참여자에게 댓글이 보이도록 해야 할 때.
- 교육 도구 – 강사 메모가 강의 슬라이드와 함께 표시될 때.
- 법률 애플리케이션 – 변호사 주석이 포함된 계약서를 정확히 렌더링해야 할 때.
다음 경우 대안을 고려하세요
- 간단한 PDF 표시 – 브라우저 기본 PDF 뷰어만으로 충분할 때.
- 기본 이미지 변환 –
ImageIO등 가벼운 라이브러리가 적합할 때. - 순수 텍스트 추출 – Apache POI 또는 iText가 더 적합할 때.
자주 묻는 질문
Q: 주석 없이 문서를 렌더링할 수 있나요?
A: 예—setRenderComments(true) 호출을 생략하거나 false로 설정하면 됩니다.
Q: 어떤 파일 형식이 주석 렌더링을 지원하나요?
A: 대부분의 주요 형식—DOC/DOCX, XLS/XLSX, PPT/PPTX, PDF 등. 전체 목록은 official documentation에서 확인하십시오.
Q: HTML 출력 스타일을 커스터마이즈할 수 있나요?
A: 물론입니다. HtmlViewOptions.setEmbedResources(false)를 사용해 외부 CSS 파일을 생성한 뒤, 렌더링 후 자체 스타일시트를 추가하면 됩니다.
Q: 비밀번호로 보호된 문서를 어떻게 처리하나요?
A: 비밀번호가 포함된 LoadOptions 인스턴스를 제공하십시오:
LoadOptions를 사용하면 비밀번호와 같은 문서 로딩 매개변수를 지정할 수 있습니다.
LoadOptions loadOptions = new LoadOptions("myPassword");
try (Viewer viewer = new Viewer(inputPath.toFile(), loadOptions)) {
viewer.view(viewOptions);
}
Q: 특정 페이지만 렌더링할 수 있나요?
A: 예—PageNumber 컬렉션을 받는 오버로드된 view 메서드를 사용하십시오:
PageNumber는 페이지 일부를 렌더링할 때 사용되는 특정 페이지 인덱스를 나타냅니다.
viewer.view(new int[]{1, 3, 5}, viewOptions);
Q: 대용량 문서의 렌더링이 왜 느린가요?
A: 큰 파일은 처리 시간이 더 많이 필요합니다. 필요한 페이지만 렌더링하고, 외부 리소스를 사용하며, JVM 힙을 늘리고, 비동기 처리를 활성화하면 속도를 개선할 수 있습니다.
Q: 렌더링 진행 상황을 어떻게 모니터링할 수 있나요?
A: GroupDocs Viewer는 내장 콜백을 제공하지 않지만, viewer.view() 전후에 System.nanoTime()을 사용해 작업 시간을 측정하고 로그에 기록할 수 있습니다.
Q: 원본 문서가 손상된 경우 어떻게 되나요?
A: 라이브러리는 ViewerException을 발생시킵니다. 호출을 try‑catch 블록으로 감싸고 오류를 로그에 기록하여 정상적으로 처리하도록 합니다.
Q: 상업용 애플리케이션에서 GroupDocs Viewer를 사용할 수 있나요?
A: 예, 하지만 상업용 라이선스가 필요합니다. 무료 체험은 워터마크가 포함되어 있으며, 프로덕션 사용 시 제거해야 합니다.
Q: 사용 제한이 있나요?
A: 라이브러리 자체에는 제한이 없지만, 라이선스 계약에 사용 한도가 정의될 수 있습니다. 계약서를 확인하십시오.
Q: GroupDocs Viewer를 포함한 애플리케이션을 재배포할 수 있나요?
A: 자체 애플리케이션은 배포 가능하지만, GroupDocs 라이브러리 바이너리를 재배포할 수는 없습니다. 라이선스 조항을 확인하십시오.
다음 단계 및 고급 주제
이제 convert word to html을 주석을 보존하면서 수행하는 탄탄한 기반을 갖추었습니다. 전문성을 심화할 수 있는 몇 가지 방향을 소개합니다:
- 워터마크 – 브랜드 또는 기밀성을 위해 렌더링된 페이지에 맞춤 워터마크를 추가합니다.
- 메타데이터 추출 –
viewer.getDocumentInfo()를 통해 작성자, 생성 날짜, 페이지 수 등을 가져옵니다. - 맞춤 뷰어 – PDF, 스프레드시트, 프레젠테이션용 특수 뷰어를 구축하여 주석을 다르게 숨기거나 강조합니다.
- 클라우드 스토리지 통합 – AWS S3, Azure Blob, Google Drive 등에서 파일을 직접 렌더링하고 로컬에 다운로드하지 않습니다.
권장 학습 경로
- 다양한 파일 형식 실험 – Excel, PowerPoint, PDF 파일을 시도해 형식별 주석 처리 방식을 확인합니다.
- 간단한 웹 뷰어 구축 –
<iframe>또는 AJAX를 통해 생성된 HTML을 로드하는 최소 HTML 페이지를 만듭니다. - GroupDocs 생태계 탐색 – 엔드‑투‑엔드 문서 워크플로를 위해 GroupDocs Annotation, Comparison, Signature을 살펴봅니다.
- 커뮤니티 참여 – 팁, 샘플 프로젝트, 지원을 위해 GroupDocs Forum에 참여하십시오.
도움 및 지원 받기
공식 리소스
커뮤니티 리소스
- Stack Overflow (tag:
groupdocs-viewer) - Reddit 프로그래밍 커뮤니티
- Java 개발자 Discord 서버
마지막 업데이트: 2026-05-21
테스트 환경: GroupDocs.Viewer 25.2 for Java
작성자: GroupDocs
java -version
javac -version
mvn -version
mvn archetype:generate -DgroupId=com.example.documentviewer -DartifactId=groupdocs-viewer-demo -DarchetypeArtifactId=maven-archetype-quickstart -DinteractiveMode=false
<repositories>
<repository>
<id>repository.groupdocs.com</id>
<name>GroupDocs Repository</name>
<url>https://releases.groupdocs.com/viewer/java/</url>
</repository>
</repositories>
<dependencies>
<dependency>
<groupId>com.groupdocs</groupId>
<artifactId>groupdocs-viewer</artifactId>
<version>25.2</version>
</dependency>
</dependencies>
import com.groupdocs.viewer.Viewer;
// The try-with-resources pattern ensures proper cleanup
try (Viewer viewer = new Viewer("path/to/your/document.docx")) {
// All rendering operations happen here
// Resources are automatically closed when done
} catch (Exception e) {
System.err.println("Error rendering document: " + e.getMessage());
e.printStackTrace();
}
import java.nio.file.Path;
import java.nio.file.Paths;
// Create a descriptive output directory
Path outputDirectory = Paths.get("rendered-documents");
Path pageFilePathFormat = outputDirectory.resolve("page_{0}.html");
import com.groupdocs.viewer.options.HtmlViewOptions;
// Create HTML options with embedded resources
HtmlViewOptions viewOptions = HtmlViewOptions.forEmbeddedResources(pageFilePathFormat);
// The crucial setting – enable comment rendering!
viewOptions.setRenderComments(true);
import com.groupdocs.viewer.Viewer;
try (Viewer viewer = new Viewer("path/to/your/document.docx")) {
// Create output directory if it doesn't exist
if (!outputDirectory.toFile().exists()) {
outputDirectory.toFile().mkdirs();
}
// Perform the actual rendering
viewer.view(viewOptions);
System.out.println("Document rendered successfully!");
System.out.println("Output location: " + outputDirectory.toAbsolutePath());
} catch (Exception e) {
System.err.println("Rendering failed: " + e.getMessage());
e.printStackTrace();
}
package com.example.documentviewer;
import com.groupdocs.viewer.Viewer;
import com.groupdocs.viewer.options.HtmlViewOptions;
import java.nio.file.Path;
import java.nio.file.Paths;
public class DocumentRenderer {
public static void main(String[] args) {
renderDocumentWithComments("sample-document.docx", "output");
}
public static void renderDocumentWithComments(String inputFile, String outputDir) {
// Set up paths
Path outputDirectory = Paths.get(outputDir);
Path pageFilePathFormat = outputDirectory.resolve("page_{0}.html");
// Configure rendering options
HtmlViewOptions viewOptions = HtmlViewOptions.forEmbeddedResources(pageFilePathFormat);
viewOptions.setRenderComments(true);
// Render the document
try (Viewer viewer = new Viewer(inputFile)) {
// Ensure output directory exists
outputDirectory.toFile().mkdirs();
// Execute rendering
viewer.view(viewOptions);
System.out.println("✓ Document rendered with comments preserved");
System.out.println("📂 Output directory: " + outputDirectory.toAbsolutePath());
} catch (Exception e) {
System.err.println("❌ Rendering failed: " + e.getMessage());
e.printStackTrace();
}
}
}
import java.nio.file.Path;
import java.nio.file.Paths;
public class PathManager {
/**
* Creates a structured output path based on document name and timestamp
*/
public static Path getOutputDirectoryPath(String documentName) {
String timestamp = String.valueOf(System.currentTimeMillis());
String cleanDocName = documentName.replaceAll("[^a-zA-Z0-9]", "_");
return Paths.get("rendered-docs")
.resolve(cleanDocName)
.resolve(timestamp);
}
/**
* Simple output directory for basic use cases
*/
public static Path getSimpleOutputPath(String folderName) {
return Paths.get("output").resolve(folderName);
}
}
// Always check if file exists before processing
Path inputPath = Paths.get("your-document.docx");
if (!inputPath.toFile().exists()) {
throw new IllegalArgumentException("Input file not found: " + inputPath.toAbsolutePath());
}
// Check if file is readable
if (!inputPath.toFile().canRead()) {
throw new IllegalArgumentException("Cannot read input file: " + inputPath.toAbsolutePath());
}
HtmlViewOptions viewOptions = HtmlViewOptions.forEmbeddedResources(pageFilePathFormat);
// This line is crucial – don't forget it!
viewOptions.setRenderComments(true);
// For debugging, you can verify the setting:
System.out.println("Comments enabled: " + viewOptions.isRenderComments());
// Increase JVM heap size when running
// java -Xmx2g -Xms1g YourApplication
// Or process documents page by page for very large files
HtmlViewOptions viewOptions = HtmlViewOptions.forEmbeddedResources(pageFilePathFormat);
viewOptions.setRenderComments(true);
// Render only specific pages if needed
viewer.view(viewOptions, 1, 2, 3); // Renders only pages 1, 2, and 3
// Use external resources for faster processing of multiple pages
HtmlViewOptions viewOptions = HtmlViewOptions.forExternalResources(
pageFilePathFormat,
"resources/page_{0}/",
"resources/page_{0}/{0}"
);
// Enable caching if processing the same document multiple times
// (Note: Implement caching at application level)
@RestController
@RequestMapping("/api/documents")
public class DocumentController {
@PostMapping("/render")
public ResponseEntity<String> renderDocument(
@RequestParam("file") MultipartFile file) {
try {
// Save uploaded file temporarily
Path tempFile = Files.createTempFile("upload", ".tmp");
file.transferTo(tempFile.toFile());
// Render with comments
String outputDir = renderDocumentWithComments(
tempFile.toString(),
"web-output"
);
return ResponseEntity.ok("Document rendered: " + outputDir);
} catch (Exception e) {
return ResponseEntity.badRequest()
.body("Rendering failed: " + e.getMessage());
}
}
}
public class BatchDocumentProcessor {
public void processFolderWithComments(String inputFolder) {
File folder = new File(inputFolder);
File[] files = folder.listFiles((dir, name) ->
name.toLowerCase().endsWith(".docx") ||
name.toLowerCase().endsWith(".xlsx") ||
name.toLowerCase().endsWith(".pptx")
);
if (files == null) return;
for (File file : files) {
try {
String outputDir = file.getName().replace(".", "_") + "_output";
renderDocumentWithComments(file.getAbsolutePath(), outputDir);
System.out.println("✓ Processed: " + file.getName());
} catch (Exception e) {
System.err.println("❌ Failed to process " + file.getName() + ": " + e.getMessage());
}
}
}
}
// Simple approach works fine
try (Viewer viewer = new Viewer(documentPath)) {
viewer.view(viewOptions);
}
public class DocumentRenderingService {
private final ExecutorService executorService =
Executors.newFixedThreadPool(4); // Limit concurrent renderings
public CompletableFuture<String> renderAsync(String documentPath) {
return CompletableFuture.supplyAsync(() -> {
try (Viewer viewer = new Viewer(documentPath)) {
// Rendering logic here
return "success";
} catch (Exception e) {
throw new RuntimeException(e);
}
}, executorService);
}
}
public class CachedDocumentRenderer {
private final Map<String, String> renderCache = new ConcurrentHashMap<>();
public String renderWithCaching(String documentPath) {
String cacheKey = generateCacheKey(documentPath);
return renderCache.computeIfAbsent(cacheKey, key -> {
// Only render if not already cached
return performActualRendering(documentPath);
});
}
private String generateCacheKey(String documentPath) {
// Include file modification time in cache key
File file = new File(documentPath);
return documentPath + "_" + file.lastModified();
}
}
LoadOptions loadOptions = new LoadOptions();
loadOptions.setPassword("your-password");
try (Viewer viewer = new Viewer("protected-doc.docx", loadOptions)) {
// Render as usual
}
viewer.view(viewOptions, 1, 3, 5); // Renders only pages 1, 3, and 5
System.out.println("Starting render for: " + documentName);
long startTime = System.currentTimeMillis();
viewer.view(viewOptions);
long endTime = System.currentTimeMillis();
System.out.println("Rendering completed in: " + (endTime - startTime) + "ms");
try (Viewer viewer = new Viewer(documentPath)) {
viewer.view(viewOptions);
} catch (CorruptOrDamagedFileException e) {
System.err.println("Document is corrupted: " + e.getMessage());
} catch (Exception e) {
System.err.println("General error: " + e.getMessage());
}