|
|
|
@ -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<Map<?, ?>, 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<Map<?, ?>, 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<Map<?, ?>, Object> func) {
|
|
|
|
|
convert = func;
|
|
|
|
|
public Formatter onCell(Function<Map<?, ?>, 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<List<CellDef>> listType() {
|
|
|
|
|
return new TypeReference<List<CellDef>>() {};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|