Apache POI 라이브러리를 이용해서 엑셀 파일을 만드는 작업을 한 번 해 보았습니다.
해 볼 것이 여러가지 있을 텐데요. 워낙 잘 만들어진 라이브러라 여러 곳에서 레퍼런스들을 많이 발견 할 수 있을 것입니다. 여기서 한 가지 엑셀을 만들었다면, 이렇게 만들어진 엑셀 파일인 workbook 여러 개를 합쳐서 만들어 보는 작업을 한 번 해 보려고 합니다.
- 엑셀 파일-Workbook- 합치기
위 파일 합치는 것은 찾아 보면 많이 나와 있습니다.
저의 경우에는 다음 스택 오버플로우 답변을 사용 했습니다.
일단 저번에 만들어 봤던 메서드들이 다 똑 같기 때문에, 해당 하는 메서드 말고 Workbook 객체를 반환하는 메서드들을 하나씩 만들어 보겠습니다.
public static Workbook getWorkbookForMyDataExcel(List<MyExcelObj> myexcelObjList)
{
Workbook workbook = null;
Sheet sheet = null;
final String sheetName = "MyFirstSheet";
final String headerNames[][]
= new String[][]{
{"컬럼1", "컬럼2", "컬럼3", "컬럼4", "컬럼5", "컬럼6", "컬럼7"},
{"Col1", "Col2", "Col3", "Col4", "Col5", "Col6", "Col7"}
};
final int numberOfColumns = headerNames[0].length;
//logger.debug("numberOfColumns:{}", numberOfColumns);
try
{
workbook = new XSSFWorkbook();
sheet = workbook.createSheet(sheetName);
Row headerRow = sheet.createRow(0);
String columnName = null;
// exclude the first column which is the ID field
for (int i = 0; i < numberOfColumns; i++) {
columnName = headerNames[0][i];
Cell headerCell = headerRow.createCell(i);
headerCell.setCellValue(columnName);
columnName = null;
}
} catch (Exception e) {
System.out.println("File IO error:");
e.printStackTrace();
}
String Col1 = null;
String Col2 = null;
String Col3 = null;
String Col4 = null;
String Col5 = null;
String Col6 = null;
String Col7 = null;
MyExcelObj selfObj = null;
try
{
int rowCount = 1;
for(Iterator<MyExcelObj> checkIter = myexcelObjList.iterator(); checkIter.hasNext();)
{
selfObj = checkIter.next();
Row row = sheet.createRow(rowCount++);
Col1 = selfObj.getCol1();
Col2 = selfObj.getCol2();
Col3 = selfObj.getCol3();
Col4 = selfObj.getCol4();
Col5 = selfObj.getCol5();
Col6 = selfObj.getCol6();
Col7 = selfObj.getCol7();
Cell cell1 = row.createCell(0);
Cell cell2 = row.createCell(1);
Cell cell3 = row.createCell(2);
Cell cell4 = row.createCell(3);
Cell cell5 = row.createCell(4);
Cell cell6 = row.createCell(5);
Cell cell7 = row.createCell(6);
cell1.setCellValue(Col1);
cell2.setCellValue(Col2);
cell3.setCellValue(Col3);
cell4.setCellValue(Col4);
cell5.setCellValue(Col5);
cell6.setCellValue(Col6);
cell7.setCellValue(Col7);
Col1 = null;
Col2 = null;
Col3 = null;
Col4 = null;
Col5 = null;
Col6 = null;
Col7 = null;
}
} catch (Exception e) {
e.printStackTrace();
}
return workbook;
}
그럼, 원래 만들어 놓았던 export 메서드들도 간단히 다음과 같이 변경 하면 되겠죠?
여기서 중요한 점은 sheetName 이름이 중복이 있으면 안된다는 것을 명심 해야 합니다~~
public static void exportMyDataToExcel(List<MyExcelObj> myexcelObjList)
{
Workbook workbook = null;
try
{
workbook = getWorkbookForMyDataExcel(myexcelObjList);
}
finally
{
try {
if(workbook != null) workbook.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
그리고, 위의 스택오버플로우 답변에 있던 메서드를 Workbook의 리스트를 받는 메서드로 변경 하고, 일반적인 클래스 명으로 다 바꾸어 보겠습니다...
우선, Workbook 객체의 리스트를 받는 메서드를 정의 해 줍니다.
public void exportWorkbookListToExcel(final String fileName, final List<Workbook> workbookList)
{
Workbook myWorkBook = new XSSFWorkbook();
int workbooks = workbookList.size();
Workbook workbook = null;
for (int iWorkbook = 0; iWorkbook < workbooks; iWorkbook++) {
try {
workbook = workbookList.get(iWorkbook);
exportWorkbookListToExcel(myWorkBook, workbook);
} catch (IOException e) {
e.printStackTrace();
}
}
BufferedOutputStream bos;
try {
bos = new BufferedOutputStream(
new FileOutputStream(fileName, true));
myWorkBook.write(bos);
bos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
최종적으로 결과물인 엑셀로 저장 할 객체는 코드에서 보듯이 myWorkBook 객체이며, 실제 구현은 XSSFWorkbook 클래스의 인스턴스 입니다.
그런다음, 메서드를 오버로딩 하여 결과 엑셀 객체와 각 각의 workbook 객체를 받을 수 있는 메서드를 다음과 같이 만들어 주었습니다.
public void exportWorkbookListToExcel(Workbook myWorkBook, Workbook workbook) throws IOException {
Sheet sheet = null;
Row row = null;
Cell cell = null;
Sheet mySheet = null;
Row myRow = null;
Cell myCell = null;
int sheets = workbook.getNumberOfSheets();
int fCell = 0;
int lCell = 0;
int fRow = 0;
int lRow = 0;
for (int iSheet = 0; iSheet < sheets; iSheet++) {
sheet = workbook.getSheetAt(iSheet);
if (sheet != null) {
mySheet = myWorkBook.createSheet(sheet.getSheetName());
fRow = sheet.getFirstRowNum();
lRow = sheet.getLastRowNum();
for (int iRow = fRow; iRow <= lRow; iRow++) {
row = sheet.getRow(iRow);
myRow = mySheet.createRow(iRow);
if (row != null) {
fCell = row.getFirstCellNum();
lCell = row.getLastCellNum();
for (int iCell = fCell; iCell < lCell; iCell++) {
cell = row.getCell(iCell);
myCell = myRow.createCell(iCell);
if (cell != null) {
CellType thisCelltype = cell.getCellType();
myCell.setCellType(thisCelltype);
if(thisCelltype == CellType.BLANK)
myCell.setCellValue("");
else if(thisCelltype == CellType.BOOLEAN)
myCell.setCellValue(cell.getBooleanCellValue());
else if(thisCelltype == CellType._NONE)
myCell.setCellErrorValue(cell.getErrorCellValue());
else if(thisCelltype == CellType.FORMULA)
myCell.setCellFormula(cell.getCellFormula());
else if(thisCelltype == CellType.NUMERIC)
myCell.setCellValue(cell.getNumericCellValue());
else if(thisCelltype == CellType.STRING)
myCell.setCellValue(cell.getStringCellValue());
else
myCell.setCellFormula(cell.getCellFormula());
}
}
}
}
}
}
}
그럼 결과를 확인 해 볼까요?
우선 테스트 코드는 다음과 같습니다.
final String fileName = "5)Total_workbook.xlsx";
final List<Workbook> workbookList = new ArrayList<Workbook>();
workbookList.add(TobeeExcelSheet.getWorkbookForMyData(myxcelList));
workbookList.add(TobeeExcelSheet.getWorkbookForMyData2(myxcelList2));
workbookList.add(TobeeExcelSheet.getWorkbookForMyData3(myxcelList3));
workbookList.add(TobeeExcelSheet.getWorkbookForMyData4(myxcelList4));
TobeeExcelSheet.exportWorkbookListToExcel(fileName, workbookList);
결과는?
음... 불행히도 스타일이 적용이 안된 것을 확인 할 수가 있었습니다.
그래서 스타일이 적용 될 수 있도록 코드를 다음처럼 바꿔 보았습니다.
for (int iCell = fCell; iCell < lCell; iCell++) {
cell = row.getCell(iCell);
myCell = myRow.createCell(iCell);
if (cell != null) {
CellType thisCelltype = cell.getCellType();
myCell.setCellType(thisCelltype);
if(thisCelltype == CellType.BLANK)
myCell.setCellValue("");
else if(thisCelltype == CellType.BOOLEAN)
myCell.setCellValue(cell.getBooleanCellValue());
else if(thisCelltype == CellType._NONE)
myCell.setCellErrorValue(cell.getErrorCellValue());
else if(thisCelltype == CellType.FORMULA)
myCell.setCellFormula(cell.getCellFormula());
else if(thisCelltype == CellType.NUMERIC)
myCell.setCellValue(cell.getNumericCellValue());
else if(thisCelltype == CellType.STRING)
myCell.setCellValue(cell.getStringCellValue());
else
myCell.setCellFormula(cell.getCellFormula());
myCell.setCellStyle(cell.getCellStyle());
}
}
위의 코드에서 바뀐 부분은
myCell.setCellStyle(cell.getCellStyle());
이며, 코드 자체는 그럴싸 해 보입니다...만,
오류의 향기는 어쩔수가 없네요...
다음 스택오버플로우 문서를 확인 해 볼 수가 있었습니다.
그런 식의 코딩은 안 됩니다. CellStyle 객체들은 특정한 하나의 workbook의 객체 들입니다.
이 객체들은 꽤 복잡하며, 대부분의 스타일들은 workbook 내에 있죠, 그래서 간단하게 재 사용 할 수가 없습니다. 그래서 이러한 도움이 되는 예외가 발생 한 것이죠~!
이렇게 재 사용 하는 것이 아니라, 전체 스타일의 상세를 복사하기 위해서 cloneStyleFrom(CellStyle) 메서드를 대신 사용 할 필요가 있습니다.
아래 코드 처럼요:
Workbook wb = WorkbookFactory.create(new File("existing.xls"));
CellStyle origStyle = wb.getCellStyleAt(1); // Or from a cell
Workbook newWB = new XSSFWorkbook();
Sheet sheet = newWB.createSheet();
Row r1 = sheet.createRow(0);
Cell c1 = r1.createCell(0);
CellStyle newStyle = newWB.createCellStyle();
newStyle.cloneStyleFrom(origStyle);
c1.setCellStyle(newStyle);
newWB.write(new FileOutpuStream("new.xlsx"));
위의 코드를 바탕으로 다시 한 번 재 구성 해보도록 하겠습니다.
for (int iCell = fCell; iCell < lCell; iCell++) {
cell = row.getCell(iCell);
myCell = myRow.createCell(iCell);
if (cell != null) {
CellType thisCelltype = cell.getCellType();
myCell.setCellType(thisCelltype);
if(thisCelltype == CellType.BLANK)
myCell.setCellValue("");
else if(thisCelltype == CellType.BOOLEAN)
myCell.setCellValue(cell.getBooleanCellValue());
else if(thisCelltype == CellType._NONE)
myCell.setCellErrorValue(cell.getErrorCellValue());
else if(thisCelltype == CellType.FORMULA)
myCell.setCellFormula(cell.getCellFormula());
else if(thisCelltype == CellType.NUMERIC)
myCell.setCellValue(cell.getNumericCellValue());
else if(thisCelltype == CellType.STRING)
myCell.setCellValue(cell.getStringCellValue());
else
myCell.setCellFormula(cell.getCellFormula());
//myCell.setCellStyle(cell.getCellStyle());
CellStyle newStyle = myWorkBook.createCellStyle();
newStyle.cloneStyleFrom(cell.getCellStyle());
myCell.setCellStyle(newStyle);
}
}
다시 결과를 한 번 볼까요?
제대로 스타일이 적용 되어 나오는 것을 확인 해 볼 수 있었습니다.
다음은 exportWorkbookListToExcel 메서드의 최종 본입니다. autoSizeColumn 메서드도 적용 된 거을 확인 할 수 있을 것입니다.
public static void exportWorkbookListToExcel(Workbook myWorkBook, Workbook workbook) throws IOException {
Sheet sheet = null;
Row row = null;
Cell cell = null;
Sheet mySheet = null;
Row myRow = null;
Cell myCell = null;
int sheets = workbook.getNumberOfSheets();
int fCell = 0;
int lCell = 0;
int fRow = 0;
int lRow = 0;
for (int iSheet = 0; iSheet < sheets; iSheet++) {
sheet = workbook.getSheetAt(iSheet);
if (sheet != null) {
mySheet = myWorkBook.createSheet(sheet.getSheetName());
fRow = sheet.getFirstRowNum();
lRow = sheet.getLastRowNum();
for (int iRow = fRow; iRow <= lRow; iRow++) {
row = sheet.getRow(iRow);
myRow = mySheet.createRow(iRow);
if (row != null) {
fCell = row.getFirstCellNum();
lCell = row.getLastCellNum();
for (int iCell = fCell; iCell < lCell; iCell++) {
cell = row.getCell(iCell);
myCell = myRow.createCell(iCell);
if (cell != null) {
CellType thisCelltype = cell.getCellType();
myCell.setCellType(thisCelltype);
if(thisCelltype == CellType.BLANK)
myCell.setCellValue("");
else if(thisCelltype == CellType.BOOLEAN)
myCell.setCellValue(cell.getBooleanCellValue());
else if(thisCelltype == CellType._NONE)
myCell.setCellErrorValue(cell.getErrorCellValue());
else if(thisCelltype == CellType.FORMULA)
myCell.setCellFormula(cell.getCellFormula());
else if(thisCelltype == CellType.NUMERIC)
myCell.setCellValue(cell.getNumericCellValue());
else if(thisCelltype == CellType.STRING)
myCell.setCellValue(cell.getStringCellValue());
else
myCell.setCellFormula(cell.getCellFormula());
//myCell.setCellStyle(cell.getCellStyle());
CellStyle newStyle = myWorkBook.createCellStyle();
newStyle.cloneStyleFrom(cell.getCellStyle());
myCell.setCellStyle(newStyle);
mySheet.autoSizeColumn(iCell);
}
}
}
}
}
}
}
다음은 결과 물입니다.
이상 입니다요~
'프로그래밍' 카테고리의 다른 글
OpenCV의 역사 (0) | 2022.11.07 |
---|---|
Nodejs 로 Http GET 메시지 테스트 하기 (1) | 2022.09.10 |
아파치 POI로 하는 Excel 프로그래밍 (0) | 2022.09.03 |
Guice - Google (2) | 2022.08.30 |
DisconnectedContext 오류 (0) | 2022.04.28 |