diff --git a/src/main/java/cokr/xit/base/file/xls/XLSWriter.java b/src/main/java/cokr/xit/base/file/xls/XLSWriter.java index 1979514..ba9b0c2 100644 --- a/src/main/java/cokr/xit/base/file/xls/XLSWriter.java +++ b/src/main/java/cokr/xit/base/file/xls/XLSWriter.java @@ -1,5 +1,6 @@ package cokr.xit.base.file.xls; +import java.io.FileInputStream; import java.io.InputStream; import java.io.OutputStream; import java.util.ArrayList; @@ -12,18 +13,33 @@ import java.util.function.Function; import java.util.function.Supplier; import java.util.stream.Stream; +import org.apache.poi.ooxml.POIXMLDocumentPart.RelationPart; import org.apache.poi.ss.usermodel.BorderStyle; import org.apache.poi.ss.usermodel.CellStyle; +import org.apache.poi.ss.usermodel.ClientAnchor; +import org.apache.poi.ss.usermodel.CreationHelper; import org.apache.poi.ss.usermodel.FillPatternType; import org.apache.poi.ss.usermodel.Font; import org.apache.poi.ss.usermodel.HorizontalAlignment; import org.apache.poi.ss.usermodel.VerticalAlignment; import org.apache.poi.ss.util.CellRangeAddress; import org.apache.poi.xssf.streaming.SXSSFCell; +import org.apache.poi.xssf.streaming.SXSSFDrawing; import org.apache.poi.xssf.streaming.SXSSFRow; import org.apache.poi.xssf.streaming.SXSSFSheet; import org.apache.poi.xssf.streaming.SXSSFWorkbook; +import org.apache.poi.xssf.usermodel.XSSFComment; +import org.apache.poi.xssf.usermodel.XSSFPictureData; +import org.apache.poi.xssf.usermodel.XSSFRelation; +import org.apache.poi.xssf.usermodel.XSSFVMLDrawing; import org.apache.poi.xssf.usermodel.XSSFWorkbook; +import org.openxmlformats.schemas.officeDocument.x2006.sharedTypes.STTrueFalse; +import org.springframework.util.FileCopyUtils; + +import com.fasterxml.jackson.core.type.TypeReference; +import com.microsoft.schemas.vml.CTFill; +import com.microsoft.schemas.vml.CTShape; +import com.microsoft.schemas.vml.STFillType; /**대용량 데이터를 엑셀 파일로 저장하는 유틸리티. * XLSWriter는 엑셀 템플릿 파일을 사용하도록 할 수 있다. @@ -188,22 +204,20 @@ public class XLSWriter extends XLS { * @return 현재 XLSWriter */ public XLSWriter value(Object val, Object style) { - if (isEmpty(val)) - return this; - - if (val instanceof String) { - cell.setCellValue((String)val); - } else if (val instanceof Number) { - Number number = (Number)val; - cell.setCellValue(number.doubleValue()); - } else if (val instanceof Date) { - cell.setCellValue((Date)val); - } else if (val instanceof Boolean) { - Boolean b = (Boolean)val; - cell.setCellValue(b.booleanValue()); - } else - throw new IllegalArgumentException(val.getClass().getName() + ": " + val); - + if (!isEmpty(val)) { + if (val instanceof String) { + cell.setCellValue((String)val); + } else if (val instanceof Number) { + Number number = (Number)val; + cell.setCellValue(number.doubleValue()); + } else if (val instanceof Date) { + cell.setCellValue((Date)val); + } else if (val instanceof Boolean) { + Boolean b = (Boolean)val; + cell.setCellValue(b.booleanValue()); + } else + throw new IllegalArgumentException(val.getClass().getName() + ": " + val); + } setCellStyle(style); return this; @@ -245,6 +259,8 @@ public class XLSWriter extends XLS { setCellStyle(val); } else if (val instanceof Formatter) { setCellStyle(val); + } else if (val instanceof Runnable) { + ((Runnable)val).run(); } else { col(x).value(val); ++x; @@ -302,6 +318,8 @@ public class XLSWriter extends XLS { val = formatter.convert.apply(map); } vals.add(val); + if (formatter.onCell != null) + vals.add(formatter.onCell.apply(map)); Styler styler = formatter.styler; CellStyle style = formatter.style; @@ -309,7 +327,6 @@ public class XLSWriter extends XLS { style = cellStyle(styler); if (style != null) vals.add(style); - } else { vals.add(map.get(obj)); } @@ -763,6 +780,8 @@ public class XLSWriter extends XLS { private CellStyle style; private Styler styler; + private Function, Runnable> onCell; + /**데이터 키를 설정한다. * @param key 데이터 키 * @return 현재 Formatter @@ -772,6 +791,15 @@ public class XLSWriter extends XLS { return this; } + /**데이터 포맷 function을 설정한다. + * @param func 데이터 포맷 설정 + * @return 현재 Formatter + */ + public Formatter format(Function, Object> func) { + convert = func; + return this; + } + /**셀스타일을 설정한다. * @param style 셀스타일 * @return 현재 Formatter @@ -790,12 +818,8 @@ public class XLSWriter extends XLS { return this; } - /**데이터 포맷 function을 설정한다. - * @param func 데이터 포맷 설정 - * @return 현재 Formatter - */ - public Formatter format(Function, Object> func) { - convert = func; + public Formatter onCell(Function, Runnable> func) { + onCell = func; return this; } } @@ -847,6 +871,10 @@ public class XLSWriter extends XLS { return defs.stream().map(CellDef::getValue).toList().toArray(); } + public static TypeReference> listType() { + return new TypeReference>() {}; + } + private String label, field; @@ -918,4 +946,93 @@ public class XLSWriter extends XLS { return this; } } + + public static class CommentSupport { + private XLSWriter writer; + private XSSFWorkbook workbook; + private CreationHelper factory; + private ClientAnchor anchor; + private Image image; + + public CommentSupport(XLSWriter writer) { + this.writer = writer; + workbook = this.writer.workbook.getXSSFWorkbook(); + factory = workbook.getCreationHelper(); + anchor = factory.createClientAnchor(); + image = new Image(this.writer); + } + + public XSSFComment create(String str) { + int row = writer.cell.getRowIndex(); + anchor.setRow1(row); + anchor.setRow2(row + 17); + int col = writer.cell.getColumnIndex(); + anchor.setCol1(col); + anchor.setCol2(col + 6); + + SXSSFDrawing drawing = writer.worksheet.createDrawingPatriarch(); + XSSFComment comment = (XSSFComment)drawing.createCellComment(anchor); + comment.setString(str); + writer.cell.setCellComment(comment); + return comment; + } + + public void setBackgroundImage(String title, String path) { + int picIndex = image.add(path); + XSSFPictureData pic = workbook.getAllPictures().get(picIndex); + XSSFVMLDrawing vml = writer.worksheet.getVMLDrawing(true); + RelationPart rp = vml.addRelation(null, XSSFRelation.IMAGES, pic); + + int row = writer.cell.getRowIndex(); + int col = writer.cell.getColumnIndex(); + CTShape shape = vml.findCommentShape(row, col); + CTFill fill = shape.getFillArray(0); + fill.setColor2(fill.getColor()); + fill.unsetColor(); + fill.setRelid(rp.getRelationship().getId()); + fill.setTitle(title); + fill.setRecolor(STTrueFalse.T); + fill.setRotate(STTrueFalse.T); + fill.setType(STFillType.FRAME); + } + + public void setImageComment(String path) { + create(""); + setBackgroundImage("", path); + } + + public Runnable getImageCommenter(String path) { + return () -> setImageComment(path); + } + } + + public static class Image { + private XLSWriter writer; + + public Image(XLSWriter writer) { + this.writer = writer; + } + + public int add(InputStream input, int imgType) { + try { + return writer.workbook.addPicture( + FileCopyUtils.copyToByteArray(input), + imgType + ); + } catch (Exception e) { + throw runtimeException(e); + } + } + + public int add(String path) { + String str = path.toLowerCase(); + int imgType = str.endsWith(".png") ? SXSSFWorkbook.PICTURE_TYPE_PNG : SXSSFWorkbook.PICTURE_TYPE_JPEG; + + try (FileInputStream input = new FileInputStream(path)) { + return add(input, imgType); + } catch (Exception e) { + throw runtimeException(e); + } + } + } } \ No newline at end of file