implementation 'org.apache.poi:poi-ooxml:5.2.2'
implementation group: 'fr.opensagres.xdocreport', name: 'fr.opensagres.xdocreport.converter.docx.xwpf', version: '2.0.4'
@PostMapping(consumes = "multipart/form-data")
public String upload(@RequestPart MultipartFile file) {
String result = termService.docx2html(file);
return result;
}
private String docx2html(MultipartFile file) {
//파일 유효성 확인
if (file.isEmpty()) { // 빈 파일인지 확인
throw new AdminException(AdminExceptionType.FILE_NOT_FOUND);
}
// 파일 확장자 확인 : docx 파일이 아니면 예외발생
String filename = file.getOriginalFilename();
if (!filename.substring(filename.lastIndexOf(".")).equals(".docx")) {
throw new AdminException(AdminExceptionType.INVALID_ARGUMENT, "파일 확장자 : " + filename.substring(filename.lastIndexOf(".")));
}
// Blob으로 저장해야하기 때문에 Blob으로 변환
Blob fileBlob = null;
try {
fileBlob = new SerialBlob(file.getBytes());
} catch (IOException | SQLException e) {
throw new AdminException(AdminExceptionType.INTERNAL_ERROR, e.getMessage());
}
InputStream ins = null;
String result = "";
try {
ins = blob.getBinaryStream();
XWPFDocument doc = new XWPFDocument(ins);
// html 파일 생성
OutputStream out = new ByteArrayOutputStream();
//파일로 저장 시
//OutputStream out = new FileOutputStream(new File("./html.html"));
XHTMLOptions options = XHTMLOptions.getDefault();
//그림 파일이 있는 경우 -> 해보지는 않음
//XHTMLOptions options = XHTMLOptions.create().URIResolver(new FileURIResolver(new File("word/media")));
XHTMLConverter.getInstance().convert(doc, out, options);
result = out.toString();
ins.close();
doc.close();
out.close();
System.out.println(result);
} catch (IOException | SQLException e) {
throw new AdminException(AdminExceptionType.INTERNAL_ERROR, e.getMessage());
}
return result;
}
자바 버전에 따라서 jaxb가 달라서 의존성 설정은 달라질 수 있다.
implementation 'org.docx4j:docx4j-ImportXHTML:11.4.8'
implementation 'org.docx4j:docx4j-JAXB-ReferenceImpl:11.4.9'
implementation 'org.docx4j:docx4j-JAXB-MOXy:11.4.9'
// NoClassDefFoundError: jakarta/xml/bind/ValidationEventHandler 대응
implementation group: 'jakarta.xml.bind', name: 'jakarta.xml.bind-api', version: '4.0.0'
implementation "org.glassfish.jaxb:jaxb-runtime:4.0.0"
implementation group: 'javax.xml.bind', name: 'jaxb-api', version: '2.3.1'
implementation group: 'jakarta.activation', name: 'jakarta.activation-api', version: '2.1.2'
implementation group: 'org.docx4j', name: 'docx4j-core', version: '11.4.9'
public String docx2xhtmlDocx4j() {
String result = "null";
WordprocessingMLPackage wordMLPackage;
try {
wordMLPackage = Docx4J.load(new File("../testfile.docx"));
} catch (Docx4JException e) {
throw new RuntimeException(e);
}
HTMLSettings htmlSettings = Docx4J.createHTMLSettings();
try {
htmlSettings.setOpcPackage(wordMLPackage);
// String으로 보고 싶은 경우
// OutputStream os = new ByteArrayOutputStream();
// file로 저장할 경우
OutputStream os = new FileOutputStream(new File("./xhtml.xhtml"));
// If you want XHTML output - 있으나 없으나 결과값은 같음..잘 모르겠습니다
// Docx4jProperties.setProperty("docx4j.Convert.Out.HTML.OutputMethodXML", true);
Docx4J.toHTML(htmlSettings, os, Docx4J.FLAG_NONE);
result = os.toString();
os.close();
} catch (Docx4JException | IOException e) {
throw new RuntimeException();
} finally {
// This would also do it, via finalize() methods
htmlSettings = null;
wordMLPackage = null;
}
return result;
}
public void xhtml2docxDocx4j() { // xhtml -> docx
String inputFileString = null;
try {
// xhtml 파일 읽어오기 -> 어차피 String으로 바꿔서 처리하기 때문에 Input은 원하는대로 넣어주면 된다.
inputFileString = FileUtils.readFileToString(new File("./xhtml.xhtml"), "UTF-8");
} catch (IOException e) {
throw new RuntimeException(e);
}
WordprocessingMLPackage wmp = null;
try {
// String으로 읽지 않고, 파일로 넣어서 처리할 수도 있으나 오류가 났었던 것 같다.
// wmp = Docx4J.load(actualFile);
wmp = WordprocessingMLPackage.createPackage();
NumberingDefinitionsPart ndp = new NumberingDefinitionsPart();
wmp.getMainDocumentPart().addTargetPart(ndp);
ndp.unmarshalDefaultNumbering();
} catch (InvalidFormatException | JAXBException e) {
throw new RuntimeException(e);
}
// Convert the XHTML, and add it into the empty docx we made
XHTMLImporterImpl importer = new XHTMLImporterImpl(wmp);
try {
wmp.getMainDocumentPart().getContent().addAll(
importer.convert(inputFileString, null));
// 파일로 저장
wmp.save(new File(System.getProperty("user.dir") + "/html.docx"));
} catch (Docx4JException e) {
throw new RuntimeException(e);
}
}
Docx4j
로 docx -> xhtml -> docx로 변환 시 대부분의 양식 (폰트 사이즈, 문단 배치 등)은 동일하나 여백, 폰트, 들여쓰기, <li>
태그 등에서 동일하지 않았다.