๐ Java ๋์ฉ๋ Excel ๋ฆฌํํ ๋ง
ํด๋ผ์ด์ธํธ โ ์๋ฒ์ฌ์ด๋
๋ก์ ๋ก์ง ๋ณ๊ฒฝ** DataTables๋? HTML ํ ์ด๋ธ์ ๋์ ์ผ๋ก ์ฒ๋ฆฌํ๊ธฐ ์ํ jQuery ํ๋ฌ๊ทธ์ธ์ด๋ค.
DataTables์ ๊ธฐ๋ฅ ์ค Export ๊ธฐ๋ฅ์ด ์๋๋ฐ, ํด๋ฆฝ๋ณด๋ ๋ณต์ฌ์ ์ธ์ ๋ฑ ์ ๊ธฐ๋ฅ๋ ์ง์ํ๋ค.
๊ธฐ์กด์ Excel์ถ๋ ฅ ๊ธฐ๋ฅ์ด ์ด DataTables์ Export ๊ธฐ๋ฅ์ผ๋ก ๋ง๋ค์ด์ ธ ์์๋ค.
ex) 10๋ง ๊ฐ ์ด์์ ํ์ ์์ ๋ก ๋ด๋ณด๋ด๋ฉด ๋ธ๋ผ์ฐ์ ์ ๋ฉ๋ชจ๋ฆฌ ํ๊ณ๋ฅผ ์ด๊ณผํ์ฌ ๊ฐ์ ๋ก ์ข ๋ฃ๋๋ ๊ฒฝ์ฐ๊ฐ ๋ง๋ค.
์๊ท๋ชจ ๋ฐ์ดํฐ์ Export์๋ ๊ฐ๋จํ ์ค์ ์ผ๋ก ๋น ๋ฅธ ๊ตฌํ์ด ๊ฐ๋ฅํ๋.
10๋ง๊ฐ ์ด์์ ๋์ฉ๋ ๋ฐ์ดํฐ์์๋ ํ๊ณ๊ฐ ๋ช
ํํ๋ค.
...
buttons: [
{
extend: 'excel',
name: 'Excel',
text: 'Excel',
filename: '์์
์ถ๋ ฅ_' + moment().format('YYYYMMDDhhmm'),
title: '',
action: serverSideButtonAction,
customize: function(xlsx) {
var sSh = xlsx.xl['styles.xml'];
var lastXfIndex = $('cellXfs xf', sSh).length - 1;
var sheet = xlsx.xl.worksheets['sheet1.xml'];
// ์คํ์ผ ์ ์ฉ
var n1 = '<xf numFmtId="0" fontId="2" fillId="2" borderId="1" applyFont="1" applyFill="1" applyBorder="1" xfId="0" applyAlignment="1">' +
'<alignment horizontal="center"/></xf>';
var n2 = '<xf numFmtId="0" fontId="0" fillId="0" borderId="1" applyFont="0" applyFill="0" applyBorder="0" xfId="0" applyAlignment="0">' +
'<alignment horizontal="right"/></xf>';
sSh.childNodes[0].childNodes[5].innerHTML += n1 + n2;
var greyBoldCentered = lastXfIndex + 1;
var value = lastXfIndex + 2;
$('c', sheet).attr('s', value);
$('row:first c', sheet).attr('s', greyBoldCentered);
}
}
]
SXSSFWorkbook
๋ฅผ ์ฌ์ฉํ์ฌ ๋งค์ฐ ํฐ ๋ฐ์ดํฐ๋ฅผ ์ฒ๋ฆฌํ ์ ์์ต๋๋ค.SXSSFWorkbook
๋?Apache POI ๋ผ์ด๋ธ๋ฌ๋ฆฌ์์ ์ ๊ณตํ๋ ๋์ฉ๋ Excel ํ์ผ ์์ฑ์ฉ ํด๋์ค
SXSSFWorkbook
์ ๋ฉ๋ชจ๋ฆฌ ์ ์ฝ์ ์ํด ๋์คํฌ ๊ธฐ๋ฐ ์คํธ๋ฆฌ๋ฐ ๋ฐฉ์์ ์ฌ์ฉํ์ฌ ๋ฉ๋ชจ๋ฆฌ์ ๋ชจ๋ ๋ฐ์ดํฐ๋ฅผ ์ฌ๋ฆฌ์ง ์๊ณ , ํ์ํ ๋ถ๋ถ๋ง ๋ฉ๋ชจ๋ฆฌ์ ์ ์งํ๋ค.
SimpleExcelFile
for (T t : data) {
renderBody(t, rowNum, bodyStyle, totalStyle, accumStyle);
if (rowNum % 10000 == 0 || rowNum == data.size()) { // 10,000๊ฑด ๋ง๋ค flush
try {
// ๋ง์ง๋ง ๋ฐ์ดํฐ์ ๊ฒฝ์ฐ, ๋จ๋ ๋ฐ์ดํฐ ๋งํผ๋ง flush, ์๋๊ฒฝ์ฐ 10,000๊ฑด์ฉ ํ๋ฌ์ฌ
workbook.getSheet(sheetName).flushRows(rowNum == data.size() ? data.size() % 10000 : 10000);
} catch (IOException e) {
throw new BadRequestException(e.getMessage());
}
}
rowNum++;
}
SimpleExcelMetaDataFactory
๋ฅผ ์ด์ฉํ์ฌ ์์
๋ฉํ๋ฐ์ดํฐ๋ฅผ ์์ฑSimpleExcelMetaDataFactory
SimpleExcelMetadata
๊ฐ์ฒด๋ฅผ ์์ฑํ๊ธฐ ์ํ ๊ธฐ๋ณธ ํ ์ ๊ณต(ํค๋, ์คํ์ผ, ํ๋ ๋ชฉ๋ก ๋ฑ)private void applyCellStyle(CellStyleMap cellStyleMap, ExcelColumnStyle fieldStyle, ExcelColumnStyle classDefaultStyle, String fieldName, CellPart part, Workbook workbook) {
/* dto ์ field ๊ฐ์ ์คํ์ผ์ด ์ค์ ๋์ด ์๋์ง ์ฒดํฌ */
boolean styleCheck = fieldStyle.excelCellStyleClass() != NullStyle.class;
/* dto ์ field ์ ์คํ์ผ ์กด์ฌ ์ ๋ฌด์ ๋ฐ๋ผ, ExcelCellKey ์ fieldName ์ง์ */
String fieldNameKey = styleCheck ? fieldName : "DEFAULT";
/* dto ์ field ์ ์คํ์ผ ์กด์ฌ ์ ๋ฌด์ ๋ฐ๋ผ ์คํ์ผ ์ค์ */
ExcelColumnStyle style = styleCheck ? fieldStyle : classDefaultStyle;
ExcelCellKey excelCellKey = ExcelCellKey.of(fieldNameKey, part);
/* ํด๋น ํค๊ฐ๊ณผ ๊ฐ์ ํค๊ฐ์ ๊ฐ์ง ๋ฐ์ดํฐ๊ฐ ์๋ ๊ฒฝ์ฐ styleMap ์ ์ถ๊ฐํ์ง ์์ */
if (!cellStyleMap.valueCheck(excelCellKey)) {
cellStyleMap.put(decideAppliedStyle(style, workbook),
excelCellKey,
workbook);
}
}
CustomExcelDto
@DefaultExcelHeaderStyle
: ์์
ํค๋์ ๊ธฐ๋ณธ ์คํ์ผ ์ ์ฉ
HeaderStyle.class
@DefaultExcelBodyStyle
: ์์
๋ฐ์ดํฐ ํ์ ๊ธฐ๋ณธ ์คํ์ผ ์ ์ฉ
BodyStyle.class
@DefaultExcelTotalRow
: ํฉ๊ณ ํ์ ๊ธฐ๋ณธ ์คํ์ผ ์ ์ฉ@DefaultExcelHeaderStyle(style = @ExcelColumnStyle(excelCellStyleClass = HeaderStyle.class))
@DefaultExcelBodyStyle(style = @ExcelColumnStyle(excelCellStyleClass = BodyStyle.class))
@DefaultExcelTotalRow(style = @ExcelColumnStyle(excelCellStyleClass = TotalRowStyle.class))
public class PgDepositListExcelDto {
@ExcelColumn(headerName = "No")
private String rowNum;
@ExcelColumn(headerName = "ํ์๋ฒํธ")
private String mbNo;
@ExcelColumn(headerName = "์์ด๋")
private String mbId;
@ExcelColumn(
headerName = "๊ธ์ก",
bodyStyle = @ExcelColumnStyle(excelCellStyleClass = AmountStyle.class),
totalRowStyle = @ExcelColumnStyle(excelCellStyleClass = TotalAmountStyle.class)
)
private long amt;
SimpleExcelMetaDataFactory์์ @ExcelColumn
์ด๋
ธํ
์ด์
์ด ๋ถ์ ํ๋๋ฅผ ์์งํ์ฌ ๋ฆฌ์คํธ์ ์ ์ฅ
public SimpleExcelMetadata createSimpleExcelMetaData(
Class<?> type, Workbook workbook, SheetType sheetType, boolean hasGroupHeader) {
List<Field> fields = getExcelAnnotatedFields(type);
List<String> headerNames = new ArrayList<>();
for (Field field : fields) {
ExcelColumn excelColumn = field.getAnnotation(ExcelColumn.class); // ์ด๋
ธํ
์ด์
์ฒดํฌ
String headerName = excelColumn.headerName();
headerNames.add(headerName);
applyCellStyle(cellStyleMap, excelColumn.headerStyle(), null, field.getName(), HEADER, workbook);
}
return new SimpleExcelMetadata(headerNames, fields, cellStyleMap, groups);
}
Service
CustomExcelDto
๋ก ํ์ฑ ํ simpleExcelWrite
๋ก ์์
์ถ๋ ฅ// 1) ์์
ํ์ผ ์์ฑ (๋ฐ์ดํฐ -> ExcelFile)
SimpleExcelFile<E> excelFile = new SimpleExcelFile<>(
simpleExcelWriteDto.getData(),
simpleExcelWriteDto.getType(),
simpleExcelWriteDto.getSheetName(),
simpleExcelWriteDto.getSheetType()
);
// 2) ExcelSetUpDto ๊ฐ๋จํ ๋ง๋ค์ด์, ๊ธฐ์กด write(...) ๋ฉ์๋ ์ฌ์ฉ
ExcelSetUpDto excelSetUpDto = ExcelSetUpDto.builder()
.response(simpleExcelWriteDto.getResponse())
.excel(excelFile.getWorkbook())
.excelPreFileTitle(simpleExcelWriteDto.getPreFileTitle())
.excelFilePath(simpleExcelWriteDto.getFilePath())
.build();
// 3) ํ ๋ฒ์ write
excelFile.write(excelSetUpDto);
case 1
์
๋ ฅ :
์์น๊ธ ์
๊ธ๋ด์ญ
์
๊ฐ์ : 40,000๊ฑด
์ถ๋ ฅ :
์คํจ
case 2
์
๋ ฅ :
์์น๊ธ ์
๊ธ๋ด์ญ
์
๊ฐ์ : 5,000๊ฑด
์ถ๋ ฅ :
์ฑ๊ณต
case1(4๋ง๊ฑด) - ๋ฉ๋ชจ๋ฆฌ ์ฌ์ฉ์จ 80% ์ด๊ณผ๋ก ์ธํ ์๋จ ๋ฐ์
์ดํ, case2(5์ฒ๊ฑด) - ๋ฉ๋ชจ๋ฆฌ ์ฌ์ฉ์จ 51%
test case
์
๋ ฅ :
์์น๊ธ ์
๊ธ๋ด์ญ
์
๊ฐ์ : 70,000๊ฑด
์ถ๋ ฅ :
์ฑ๊ณต
case1
์
๋ ฅ :
์์น๊ธ ์
๊ธ๋ด์ญ
์
๊ฐ์ : 70,000๊ฑด
์ถ๋ ฅ :
์ฑ๊ณต
case2
์
๋ ฅ :
์์น๊ธ ์
๊ธ๋ด์ญ
์
๊ฐ์ : 140,000๊ฑด
์ถ๋ ฅ :
์ฑ๊ณต
case3
์
๋ ฅ :
์์น๊ธ ์
๊ธ๋ด์ญ
์
๊ฐ์ : 240,000๊ฑด
์ถ๋ ฅ :
์ฑ๊ณต