워드파일 html파일 변환 (docx to html, xhtml to docx)

Coastby·2023년 7월 3일
0

라이브러리

목록 보기
1/1

✨ Apache POI & XHTMLConverter 사용 (docx -> html)

1. 의존성 추가

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'

2. Controller 작성

    @PostMapping(consumes = "multipart/form-data")
    public String upload(@RequestPart MultipartFile file) {
        String result = termService.docx2html(file);
        return result;
    }

3. 로직 작성

    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;
    }

✨ Docx4j (docx -> xhtml, xhtml -> docx)

⭕ docx -> xhtml

1. 의존성 추가

자바 버전에 따라서 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'

2. docx -> xhtml

    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;
    }

⭕ xhtml -> docx

	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>태그 등에서 동일하지 않았다.

profile
훈이야 화이팅

0개의 댓글