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) 포맷에 대한 설명도 함께 확인했음
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();
}
'무한루프 > 개발, 업무' 카테고리의 다른 글
스프링 부트(Spring Boot), 마이바티스(Mybatis), 메이븐(Maven) 백엔드 연동 설정(1) (0) | 2025.02.25 |
---|---|
요즘 다시 공부 중인 스프링 프레임워크 (0) | 2025.02.24 |
MariaDB 설치 후 DBeaver 설치 및 연결하기 (0) | 2025.02.24 |
오큘러스 고 (Oculus Go) 개발자 모드 변경 & 해상도 조정 문제 해결기 (0) | 2025.02.23 |
MS-SQL 알파벳 증가 표기 query (0) | 2025.02.21 |