무한루프/개발, 업무

Java에서 Word 파일 다루기 - Apache POI 사용법

시원한생맥주 2025. 2. 24. 10:28

 

Java에서 Word 파일 다루기 - Apache POI 사용법

 

입력된 데이터를 Word 파일로 저장해야 해서 여러 방법을 찾아봤는데, Apache POI를 사용하면 좋다고 하더라.

다른 방법도 있지만, POI가 가장 잘 알려져 있는 것 같아서 선택.

 

구글 덕분에 빠르게 자료를 찾을 수 있었지만, 한글 사이트보다는 영어 사이트에서 더 많은 정보가 있어서..

주로 영문 사이트를 참고했음.

 

 

 

 

Apache POI 공식 API 문서

https://poi.apache.org/apidocs/dev/org/apache/poi/xwpf/usermodel/XWPFDocument.html

 

XWPFDocument (POI API Documentation)

High(ish) level class for working with .docx files. This class tries to hide some of the complexity of the underlying file format, but as it's not a mature and stable API yet, certain parts of the XML structure come through. You'll therefore almost certain

poi.apache.org

 

Word 파일을 다루는 Office Open XML(OOXML) 포맷에 대한 설명도 함께 확인했음

http://officeopenxml.com/

 

Office Open XML - What is OOXML?

What is OOXML? Office Open XML, also known as OpenXML or OOXML, is an XML-based format for office documents, including word processing documents, spreadsheets, presentations, as well as charts, diagrams, shapes, and other graphical material. The specificat

officeopenxml.com

 

 

 

 

Maven에 Apache POI 의존성 추가하기

Maven 프로젝트에 Apache POI를 추가하려면 아래의 디펜던시를 pom.xml 파일에 추가하면 된다.

<dependency>
    <groupId>org.apache.poi</groupId>
    <artifactId>poi</artifactId>
    <version>5.2.3</version>
</dependency>
<dependency>
    <groupId>org.apache.poi</groupId>
    <artifactId>poi-ooxml</artifactId>
    <version>5.2.3</version>
</dependency>
<dependency>
    <groupId>org.apache.poi</groupId>
    <artifactId>poi-ooxml-schemas</artifactId>
    <version>4.1.2</version>
</dependency>

 

 

 

간단한 테스트 코드

FileInputStream fis = new FileInputStream("C:/path/to/template.docx");
XWPFDocument document = new XWPFDocument(fis);

// 작업 후 저장
FileOutputStream out = new FileOutputStream("C:/path/to/output.docx");
document.write(out);

 

 

Word 파일 생성 예시

public String saveDoc(WordFile reqDoc) throws Exception {
    try (XWPFDocument document = new XWPFDocument()) {
        Date date = new Date();
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy년MM월dd일 HH시MM분ss초");
        String formattedDate = sdf.format(date);

        XWPFParagraph paragraph = document.createParagraph();
        paragraph.setBorderBottom(Borders.SINGLE);
        XWPFRun run = paragraph.createRun();
        paragraph.setAlignment(ParagraphAlignment.CENTER);
        run.setText(formattedDate);
        run.addBreak();
        run.setText(formattedDate);
        run.addBreak(BreakType.PAGE);

        // 페이지 설정
        CTDocument1 ctd1 = paragraph.getDocument().getDocument();
        CTBody body = ctd1.getBody();
        if (!body.isSetSectPr()) {
            body.addNewSectPr();
        }
        CTSectPr section = body.getSectPr();
        if (!section.isSetPgSz()) {
            section.addNewPgSz();
        }
        CTPageSz pageSize = section.getPgSz();

        // 페이지 가로
        pageSize.setOrient(STPageOrientation.LANDSCAPE);
        pageSize.setW(BigInteger.valueOf(842 * 20));
        pageSize.setH(BigInteger.valueOf(595 * 20));

        // 페이지 세로
        pageSize.setOrient(STPageOrientation.PORTRAIT);
        pageSize.setH(BigInteger.valueOf(842 * 20));
        pageSize.setW(BigInteger.valueOf(595 * 20));

        // 표 생성
        XWPFTable table = document.createTable();
        XWPFTableRow row = table.getRow(0);
        row.getCell(0).setText("헤더 로우1 컬럼1");
        row.addNewTableCell().setText("헤더 로우1 컬럼2");
        // 추가적인 행과 셀도 비슷한 방식으로 추가할 수 있음

        row = table.createRow();
        row.getCell(0).setText("헤더 로우2 컬럼1");


        // VMerge
        for (int i = 0; i < 4; i++) {
            table.getRow(0).getCell(i).getCTTc().addNewTcPr().addNewVMerge().setVal(STMerge.RESTART);
            table.getRow(1).getCell(i).getCTTc().addNewTcPr().addNewVMerge().setVal(STMerge.CONTINUE);
            table.getRow(2).getCell(i).getCTTc().addNewTcPr().addNewVMerge().setVal(STMerge.CONTINUE);
        }

        table.getRow(1).getCell(4).getCTTc().addNewTcPr().addNewVMerge().setVal(STMerge.RESTART);
        table.getRow(2).getCell(4).getCTTc().addNewTcPr().addNewVMerge().setVal(STMerge.CONTINUE);
 
        table.getRow(1).getCell(5).getCTTc().addNewTcPr().addNewVMerge().setVal(STMerge.RESTART);
        table.getRow(2).getCell(5).getCTTc().addNewTcPr().addNewVMerge().setVal(STMerge.CONTINUE);

        // HMerge
        table.getRow(0).getCell(4).getCTTc().addNewTcPr().addNewHMerge().setVal(STMerge.RESTART);
        table.getRow(0).getCell(5).getCTTc().addNewTcPr().addNewHMerge().setVal(STMerge.CONTINUE);
        table.getRow(0).getCell(6).getCTTc().addNewTcPr().addNewHMerge().setVal(STMerge.CONTINUE);
        table.getRow(0).getCell(7).getCTTc().addNewTcPr().addNewHMerge().setVal(STMerge.CONTINUE);
        table.getRow(0).getCell(8).getCTTc().addNewTcPr().addNewHMerge().setVal(STMerge.CONTINUE);
        table.getRow(0).getCell(9).getCTTc().addNewTcPr().addNewHMerge().setVal(STMerge.CONTINUE);
 
        table.getRow(1).getCell(6).getCTTc().addNewTcPr().addNewHMerge().setVal(STMerge.RESTART);
        table.getRow(1).getCell(7).getCTTc().addNewTcPr().addNewHMerge().setVal(STMerge.CONTINUE);

        table.getRow(1).getCell(8).getCTTc().addNewTcPr().addNewHMerge().setVal(STMerge.RESTART);
        table.getRow(1).getCell(9).getCTTc().addNewTcPr().addNewHMerge().setVal(STMerge.CONTINUE);

        for (int iRow = 0; iRow < 3; ++iRow) {
             row = table.createRow();

             for (int iCol = 0; iCol < 10; ++iCol) {
                   row.getCell(iCol).setText("row_" + iRow + " col_" + iCol);
             }
        }

        // 파일 저장
        try (FileOutputStream out = new FileOutputStream("C:/path/to/" + reqDoc.getFileName() + "_" + formattedDate + ".docx")) {
            document.write(out);
        }

        return formattedDate;
    } catch (Exception e) {
        e.printStackTrace();
        return "워드 생성 실패";
    }
}
 
 

 

표 스타일 적용 예시

 

표에 스타일을 적용하는 예시도 있다. 이 예시에서는 각 행에 색상을 입히고, 셀에 데이터를 삽입하는 방식으로 진행했다.

public static void createStyledTable() throws Exception {
	// Create a new document from scratch
	XWPFDocument doc = new XWPFDocument();
	// -- OR --
	// open an existing empty document with styles already defined
	// XWPFDocument doc = new XWPFDocument(new
	// FileInputStream("base_document.docx"));

	// Create a new table with 6 rows and 3 columns
	int nRows = 6;
	int nCols = 3;
	XWPFTable table = doc.createTable(nRows, nCols);

	// Set the table style. If the style is not defined, the table style
	// will become "Normal".
	CTTblPr tblPr = table.getCTTbl().getTblPr();
	CTString styleStr = tblPr.addNewTblStyle();
	styleStr.setVal("StyledTable");

	// Get a list of the rows in the table
	List<XWPFTableRow> rows = table.getRows();
	int rowCt = 0;
	int colCt = 0;
	for (XWPFTableRow row : rows) {
		// get table row properties (trPr)
		CTTrPr trPr = row.getCtRow().addNewTrPr();
		// set row height; units = twentieth of a point, 360 = 0.25"
		CTHeight ht = trPr.addNewTrHeight();
		ht.setVal(BigInteger.valueOf(360));

		// get the cells in this row
		List<XWPFTableCell> cells = row.getTableCells();
		// add content to each cell
		for (XWPFTableCell cell : cells) {
			// get a table cell properties element (tcPr)
			CTTcPr tcpr = cell.getCTTc().addNewTcPr();
			// set vertical alignment to "center"
			CTVerticalJc va = tcpr.addNewVAlign();
			va.setVal(STVerticalJc.CENTER);

			// create cell color element
			CTShd ctshd = tcpr.addNewShd();
			ctshd.setColor("auto");
			ctshd.setVal(STShd.CLEAR);
			if (rowCt == 0) {
				// header row
				ctshd.setFill("A7BFDE");
			} else if (rowCt % 2 == 0) {
				// even row
				ctshd.setFill("D3DFEE");
			} else {
				// odd row
				ctshd.setFill("EDF2F8");
			}

			// get 1st paragraph in cell's paragraph list
			XWPFParagraph para = cell.getParagraphs().get(0);
			// create a run to contain the content
			XWPFRun rh = para.createRun();
			// style cell as desired
			if (colCt == nCols - 1) {
				// last column is 10pt Courier
				rh.setFontSize(10);
				rh.setFontFamily("Courier");
			}
			if (rowCt == 0) {
				// header row
				rh.setText("header row, col " + colCt);
				rh.setBold(true);
				para.setAlignment(ParagraphAlignment.CENTER);
			} else if (rowCt % 2 == 0) {
				// even row
				rh.setText("row " + rowCt + ", col " + colCt);
				para.setAlignment(ParagraphAlignment.LEFT);
			} else {
				// odd row
				rh.setText("row " + rowCt + ", col " + colCt);
				para.setAlignment(ParagraphAlignment.LEFT);
			}
			colCt++;
		} // for cell
		colCt = 0;
		rowCt++;
	} // for row

	// write the file
	FileOutputStream out = new FileOutputStream("C:/Users/on/Desktop/styledTable.docx");
	doc.write(out);
	out.close();
}