JXLS, XLSWriter 추가
parent
0f467b4158
commit
815ac2676e
@ -0,0 +1,15 @@
|
|||||||
|
package cokr.xit.base.file;
|
||||||
|
|
||||||
|
import java.io.OutputStream;
|
||||||
|
|
||||||
|
public interface Downloadable {
|
||||||
|
String getFilename();
|
||||||
|
|
||||||
|
String getContentType();
|
||||||
|
|
||||||
|
String getDisposition();
|
||||||
|
|
||||||
|
Number getLength();
|
||||||
|
|
||||||
|
void write(OutputStream out);
|
||||||
|
}
|
@ -1,229 +0,0 @@
|
|||||||
package cokr.xit.base.file;
|
|
||||||
|
|
||||||
import java.io.File;
|
|
||||||
import java.io.FileInputStream;
|
|
||||||
import java.io.FileOutputStream;
|
|
||||||
import java.util.Date;
|
|
||||||
import java.util.function.Consumer;
|
|
||||||
|
|
||||||
import org.apache.poi.ss.usermodel.Cell;
|
|
||||||
import org.apache.poi.ss.usermodel.CellStyle;
|
|
||||||
import org.apache.poi.ss.usermodel.Row;
|
|
||||||
import org.apache.poi.xssf.usermodel.XSSFSheet;
|
|
||||||
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
|
|
||||||
import org.springframework.util.ResourceUtils;
|
|
||||||
|
|
||||||
import cokr.xit.foundation.AbstractComponent;
|
|
||||||
import cokr.xit.foundation.data.StringMap;
|
|
||||||
|
|
||||||
/**엑셀 스프레드시트의 읽기나 쓰기를 돕는 유틸리티
|
|
||||||
* @author mjkhan
|
|
||||||
*/
|
|
||||||
public class XLS extends AbstractComponent {
|
|
||||||
/**엑셀 파일(*.xlsx)의 mime type */
|
|
||||||
public static final String MIME_TYPE = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";
|
|
||||||
|
|
||||||
/**워크시트에 데이터셋의 각 요소(row)의 값을 쓰기 위한 Functional interface
|
|
||||||
* @author mjkhan
|
|
||||||
* @param <E> 데이터셋의 요소(row) 유형
|
|
||||||
*/
|
|
||||||
@FunctionalInterface
|
|
||||||
public static interface Writer<E> {
|
|
||||||
/**워크시트에 데이터셋의 각 요소(row)의 값을 쓴다.
|
|
||||||
* @param sheet 워크시트
|
|
||||||
* @param element 데이터셋의 각 요소(row)
|
|
||||||
* @param index 데이터셋의 요소의 인덱스. 0부터 시작
|
|
||||||
*/
|
|
||||||
void write(XSSFSheet sheet, E element, int index);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**셀의 값을 읽어 반환한다.
|
|
||||||
* @param cell 셀
|
|
||||||
* @return 셀의 값
|
|
||||||
*/
|
|
||||||
public static Object getValue(Cell cell) {
|
|
||||||
switch (cell.getCellType()) {
|
|
||||||
case STRING: return cell.getStringCellValue();
|
|
||||||
case NUMERIC: return cell.getNumericCellValue();
|
|
||||||
case BOOLEAN: return cell.getBooleanCellValue();
|
|
||||||
case BLANK: return "";
|
|
||||||
default: return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**값을 셀에 설정한다.
|
|
||||||
* @param cell Cell
|
|
||||||
* @param value 값
|
|
||||||
*/
|
|
||||||
public static void setValue(Cell cell, Object value) {
|
|
||||||
if (isEmpty(value)) {
|
|
||||||
cell.setCellValue("");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (value instanceof String) {
|
|
||||||
cell.setCellValue((String)value);
|
|
||||||
} else if (value instanceof Number) {
|
|
||||||
Number number = (Number)value;
|
|
||||||
cell.setCellValue(number.doubleValue());
|
|
||||||
} else if (value instanceof Date) {
|
|
||||||
cell.setCellValue((Date)value);
|
|
||||||
} else if (value instanceof Boolean) {
|
|
||||||
Boolean b = (Boolean)value;
|
|
||||||
cell.setCellValue(b.booleanValue());
|
|
||||||
} else
|
|
||||||
throw new IllegalArgumentException(value.getClass().getName() + ": " + value);
|
|
||||||
}
|
|
||||||
|
|
||||||
private StringMap<CellStyle> styles;
|
|
||||||
|
|
||||||
public void setValue(String key, Cell cell, Object value) {
|
|
||||||
setValue(cell, value);
|
|
||||||
|
|
||||||
if (styles == null)
|
|
||||||
styles = new StringMap<>();
|
|
||||||
|
|
||||||
CellStyle style = styles.get(key);
|
|
||||||
if (style == null)
|
|
||||||
styles.put(key, style = cell.getCellStyle());
|
|
||||||
|
|
||||||
cell.setCellStyle(style);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**셀의 값을 읽어 String으로 반환한다.
|
|
||||||
* @param cell 셀
|
|
||||||
* @return 셀의 문자열값
|
|
||||||
*/
|
|
||||||
public static String getString(Cell cell) {
|
|
||||||
Object value = getValue(cell);
|
|
||||||
return isEmpty(value) ? ""
|
|
||||||
: value instanceof String ? (String)value
|
|
||||||
: value.toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**셀의 값을 읽어 Number로 반환한다.
|
|
||||||
* @param cell 셀
|
|
||||||
* @return
|
|
||||||
* <ul><li>셀의 숫자값</li>
|
|
||||||
* <li>값이 비어있으면 0</li>
|
|
||||||
* </ul>
|
|
||||||
*/
|
|
||||||
public static Number getNumber(Cell cell) {
|
|
||||||
Object value = getValue(cell);
|
|
||||||
return isEmpty(value) ? 0
|
|
||||||
: value instanceof Number ? (Number)value
|
|
||||||
: value instanceof String ? Double.parseDouble((String)value)
|
|
||||||
: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**셀의 값을 읽어 Boolean으로 반환한다.
|
|
||||||
* @param cell 셀
|
|
||||||
* @return
|
|
||||||
* <ul><li>셀의 Boolean값</li>
|
|
||||||
* <li>값이 비어있으면 false</li>
|
|
||||||
* </ul>
|
|
||||||
*/
|
|
||||||
public static Boolean getBoolean(Cell cell) {
|
|
||||||
Object value = getValue(cell);
|
|
||||||
return isEmpty(value) ? false
|
|
||||||
: value instanceof Boolean ? (Boolean)value
|
|
||||||
: Boolean.valueOf(value.toString());
|
|
||||||
}
|
|
||||||
|
|
||||||
private XSSFWorkbook workbook;
|
|
||||||
|
|
||||||
/**FileInputStream에서 엑셀 스프레드시트를 읽어들인다.
|
|
||||||
* @param input FileInputStream
|
|
||||||
* @return XLS
|
|
||||||
*/
|
|
||||||
public XLS load(FileInputStream input) {
|
|
||||||
try {
|
|
||||||
workbook = new XSSFWorkbook(input);
|
|
||||||
return this;
|
|
||||||
} catch (Exception e) {
|
|
||||||
throw applicationException(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**지정한 경로의 파일에서 엑셀 스프레드시트를 읽어들인다.
|
|
||||||
* @param path 파일 경로. classpath:..., 또는 file:...
|
|
||||||
* @return XLS
|
|
||||||
*/
|
|
||||||
public XLS load(String path) {
|
|
||||||
try (FileInputStream input = new FileInputStream(ResourceUtils.getFile(path))) {
|
|
||||||
return load(input);
|
|
||||||
} catch (Exception e) {
|
|
||||||
throw applicationException(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**엑셀 스프레드시트의 워크북을 반환한다.
|
|
||||||
* @return 엑셀 스프레드시트의 워크북
|
|
||||||
*/
|
|
||||||
public XSSFWorkbook getWorkbook() {
|
|
||||||
return ifEmpty(workbook, () -> workbook = new XSSFWorkbook());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**엑셀 스프레드시트에서 지정하는 인덱스의 워크시트를 반환한다.
|
|
||||||
* @param index 워크시트 인덱스. 0부터 시작
|
|
||||||
* @return 엑셀 스프레드시트 워크시트
|
|
||||||
*/
|
|
||||||
public XSSFSheet getWorksheet(int index) {
|
|
||||||
int count = getWorkbook().getNumberOfSheets();
|
|
||||||
return index < count ? workbook.getSheetAt(index) : workbook.createSheet();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**지정하는 인덱스의 워크시트를 읽는다.
|
|
||||||
* @param sheetIndex 워크시트 인덱스. 0부터 시작
|
|
||||||
* @param reader 워크시트의 각 row의 셀값을 읽어 작업을 수행하는 Function
|
|
||||||
* @return XLS
|
|
||||||
*/
|
|
||||||
public XLS read(int sheetIndex, Consumer<Row> reader) {
|
|
||||||
if (reader == null) return this;
|
|
||||||
|
|
||||||
XSSFSheet worksheet = getWorksheet(sheetIndex);
|
|
||||||
for (Row row: worksheet) {
|
|
||||||
reader.accept(row);
|
|
||||||
}
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**지정하는 인덱스의 워크시트에 dataset의 각 row의 값들을 쓴다.
|
|
||||||
* @param sheetIndex 워크시트 인덱스. 0부터 시작
|
|
||||||
* @param dataset 데이터셋
|
|
||||||
* @param writer dataset의 각 row의 값들을 워크시트에 쓰는 Function
|
|
||||||
* @return XLS
|
|
||||||
*/
|
|
||||||
public <E, T extends Iterable<E>> XLS write(int sheetIndex, T dataset, Writer<E> writer) {
|
|
||||||
XSSFSheet worksheet = getWorksheet(sheetIndex);
|
|
||||||
if (!isEmpty(dataset)) {
|
|
||||||
int index = -1;
|
|
||||||
for (E e: dataset) {
|
|
||||||
++index;
|
|
||||||
writer.write(worksheet, e, index);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (styles != null) {
|
|
||||||
styles.clear();
|
|
||||||
styles = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**지정하는 경로로 엑셀 스프레드시트를 저장하고 해당 파일을 반환한다.
|
|
||||||
* @param path 저장할 파일 경로
|
|
||||||
* @return 스프레드시트 파일
|
|
||||||
*/
|
|
||||||
public File write(String path) {
|
|
||||||
if (workbook == null)
|
|
||||||
throw new NullPointerException("No workbook to write");
|
|
||||||
|
|
||||||
try (FileOutputStream out = new FileOutputStream(path);) {
|
|
||||||
workbook.write(out);
|
|
||||||
return new File(path);
|
|
||||||
} catch (Exception e) {
|
|
||||||
throw applicationException(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,51 +1,43 @@
|
|||||||
package cokr.xit.base.file.web;
|
package cokr.xit.base.file.web;
|
||||||
|
|
||||||
import java.io.InputStream;
|
|
||||||
import java.net.URLEncoder;
|
import java.net.URLEncoder;
|
||||||
import java.text.SimpleDateFormat;
|
|
||||||
import java.util.Date;
|
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
import javax.servlet.http.HttpServletRequest;
|
import javax.servlet.http.HttpServletRequest;
|
||||||
import javax.servlet.http.HttpServletResponse;
|
import javax.servlet.http.HttpServletResponse;
|
||||||
|
|
||||||
import org.jxls.common.Context;
|
|
||||||
import org.jxls.util.JxlsHelper;
|
|
||||||
import org.springframework.core.io.ClassPathResource;
|
|
||||||
import org.springframework.web.servlet.view.AbstractView;
|
import org.springframework.web.servlet.view.AbstractView;
|
||||||
|
|
||||||
import cokr.xit.foundation.Assert;
|
import cokr.xit.base.file.xls.XLS;
|
||||||
|
|
||||||
|
/**사용자가 요청하는 데이터를 엑셀파일로 제공하는 뷰.
|
||||||
|
* 사용 순서는 다음과 같다.
|
||||||
|
* 엑셀 템플릿파일 작성. 템플릿 작성법은
|
||||||
|
* https://jxls.sourceforge.net
|
||||||
|
* https://ddoriya.tistory.com/entry/JXLS-POI-JAVA%EC%97%90%EC%84%9C-Excel-%EC%82%AC%EC%9A%A9%ED%95%98%EB%8A%94-%EA%B5%AC%ED%98%84-%EB%B0%A9%EB%B2%95-%EB%B0%8F-%EC%A2%85%EB%A5%98-%EB%B9%84%EA%B5%90
|
||||||
|
* 스프링 파일에 'xlsView' Bean 설정
|
||||||
|
* 콘트롤러(*Controller.java)
|
||||||
|
* ModelAndView의 이름을 'xlsView'로 지정
|
||||||
|
* ModelAndView에
|
||||||
|
* 엑셀 처리기 ('xls') 설정
|
||||||
|
* DatasetControl (JSP / *.js)
|
||||||
|
* 파라미터 설정
|
||||||
|
* download() 호출
|
||||||
|
*
|
||||||
|
* @author mjkhan
|
||||||
|
*/
|
||||||
public class XLSView extends AbstractView {
|
public class XLSView extends AbstractView {
|
||||||
@Override
|
@Override
|
||||||
protected void renderMergedOutputModel(Map<String, Object> model, HttpServletRequest hreq, HttpServletResponse hresp) throws Exception {
|
protected void renderMergedOutputModel(Map<String, Object> model, HttpServletRequest hreq, HttpServletResponse hresp) throws Exception {
|
||||||
try (InputStream input = getInputStream(model)) {
|
XLS xls = (XLS)model.get("xls");
|
||||||
String filename = getFilename(model);
|
|
||||||
|
|
||||||
Context ctx = new Context();
|
|
||||||
model.forEach(ctx::putVar);
|
|
||||||
|
|
||||||
String charset = "UTF-8";
|
|
||||||
hresp.setCharacterEncoding(charset);
|
|
||||||
hresp.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
|
|
||||||
hresp.setHeader("Content-Disposition", "attachment; filename=\"" + URLEncoder.encode(filename, charset) +"\"");
|
|
||||||
|
|
||||||
JxlsHelper.getInstance().processTemplate(input, hresp.getOutputStream(), ctx);
|
String charset = "UTF-8";
|
||||||
}
|
String filename = xls.getFilename();
|
||||||
}
|
|
||||||
|
|
||||||
private InputStream getInputStream(Map<String, Object> model) throws Exception {
|
|
||||||
String path = (String)model.remove("template");
|
|
||||||
if (Assert.isEmpty(path))
|
|
||||||
throw new RuntimeException("'template' not found");
|
|
||||||
|
|
||||||
return new ClassPathResource(path).getInputStream();
|
hresp.setCharacterEncoding(charset);
|
||||||
}
|
hresp.setContentType(XLS.MIME_TYPE);
|
||||||
|
hresp.setHeader("Content-Disposition", "attachment; filename=\"" + URLEncoder.encode(filename, charset) +"\"");
|
||||||
|
|
||||||
private String getFilename(Map<String, Object> model) {
|
xls.write(hresp.getOutputStream());
|
||||||
return Assert.ifEmpty(
|
|
||||||
(String)model.remove("filename"),
|
|
||||||
() -> new SimpleDateFormat("yyyyMMdd-HHmmss").format(new Date()) + ".xlsx"
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -0,0 +1,68 @@
|
|||||||
|
package cokr.xit.base.file.xls;
|
||||||
|
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.io.OutputStream;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.LinkedHashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import org.jxls.common.Context;
|
||||||
|
import org.jxls.util.JxlsHelper;
|
||||||
|
|
||||||
|
public class JXLS extends XLS {
|
||||||
|
private Context ctx;
|
||||||
|
private Map<String, Object> data;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public JXLS setTemplate(String template) {
|
||||||
|
super.setTemplate(template);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public JXLS setFilename(String filename) {
|
||||||
|
super.setFilename(filename);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**엑셀 파일에 저장할 데이터들을 반환한다.
|
||||||
|
* @return 엑셀 파일에 저장할 데이터
|
||||||
|
*/
|
||||||
|
public Map<String, Object> getData() {
|
||||||
|
return data != null ? data : Collections.emptyMap();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**엑셀 파일에 저장할 데이터들을 설정한다.
|
||||||
|
* @param map 엑셀 파일에 저장할 데이터
|
||||||
|
* @return 현재 XLS
|
||||||
|
*/
|
||||||
|
public JXLS setData(Map<String, Object> map) {
|
||||||
|
data = map;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**엑셀 파일에 저장할 데이터들을 설정한다.
|
||||||
|
* @param key 데이터 키
|
||||||
|
* @param obj 데이터
|
||||||
|
* @return 현재 XLS
|
||||||
|
*/
|
||||||
|
public JXLS setData(String key, Object obj) {
|
||||||
|
if (data == null) {
|
||||||
|
data = new LinkedHashMap<>();
|
||||||
|
}
|
||||||
|
data.put(key, obj);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void write(OutputStream out) {
|
||||||
|
ctx = new Context();
|
||||||
|
getData().forEach(ctx::putVar);
|
||||||
|
|
||||||
|
try (InputStream input = loadTemplate();) {
|
||||||
|
JxlsHelper.getInstance().processTemplate(input, out, ctx);
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw runtimeException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,67 @@
|
|||||||
|
package cokr.xit.base.file.xls;
|
||||||
|
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.io.OutputStream;
|
||||||
|
import java.text.SimpleDateFormat;
|
||||||
|
import java.util.Date;
|
||||||
|
|
||||||
|
import org.springframework.core.io.ClassPathResource;
|
||||||
|
|
||||||
|
import cokr.xit.foundation.AbstractComponent;
|
||||||
|
|
||||||
|
/**엑셀 스프레드시트의 읽기나 쓰기를 돕는 유틸리티
|
||||||
|
* @author mjkhan
|
||||||
|
*/
|
||||||
|
public abstract class XLS extends AbstractComponent {
|
||||||
|
/**엑셀 파일(*.xlsx)의 mime type */
|
||||||
|
public static final String MIME_TYPE = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";
|
||||||
|
|
||||||
|
private String
|
||||||
|
template,
|
||||||
|
filename;
|
||||||
|
|
||||||
|
/**템플릿 파일경로를 반환한다.
|
||||||
|
* @return 템플릿 파일경로
|
||||||
|
*/
|
||||||
|
public String getTemplate() {
|
||||||
|
return template;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected InputStream loadTemplate() throws Exception {
|
||||||
|
if (isEmpty(template))
|
||||||
|
return null;
|
||||||
|
return new ClassPathResource(template).getInputStream();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**템플릿 파일경로를 설정한다.
|
||||||
|
* @param template 템플릿 파일경로
|
||||||
|
* @return 현재 XLS
|
||||||
|
*/
|
||||||
|
public XLS setTemplate(String template) {
|
||||||
|
this.template = template;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**저장할 파일이름을 반환한다.
|
||||||
|
* 디폴트는 'yyyyMMdd-HHmmss.xlsx'
|
||||||
|
* @return 저장할 파일이름
|
||||||
|
*/
|
||||||
|
public String getFilename() {
|
||||||
|
return ifEmpty(filename, () -> new SimpleDateFormat("yyyyMMdd-HHmmss").format(new Date()) + ".xlsx");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**저장할 파일이름을 설정한다.
|
||||||
|
* 디폴트는 'yyyyMMdd-HHmmss.xlsx'
|
||||||
|
* @param filename 저장할 파일이름
|
||||||
|
* @return 현재 XLS
|
||||||
|
*/
|
||||||
|
public XLS setFilename(String filename) {
|
||||||
|
this.filename = filename;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**설정된 데이터를 엑셀 파일 포맷으로 out에 저장한다.
|
||||||
|
* @param out OutputStream
|
||||||
|
*/
|
||||||
|
public abstract void write(OutputStream out);
|
||||||
|
}
|
@ -0,0 +1,728 @@
|
|||||||
|
package cokr.xit.base.file.xls;
|
||||||
|
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.io.OutputStream;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.Date;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.function.Consumer;
|
||||||
|
|
||||||
|
import org.apache.poi.ss.usermodel.BorderStyle;
|
||||||
|
import org.apache.poi.ss.usermodel.CellStyle;
|
||||||
|
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.xssf.streaming.SXSSFCell;
|
||||||
|
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.XSSFWorkbook;
|
||||||
|
|
||||||
|
/**대용량 데이터를 엑셀 파일로 저장하는 유틸리티.
|
||||||
|
* XLSWriter는 엑셀 템플릿 파일을 사용하도록 할 수 있다.
|
||||||
|
* <pre><code> XLSWriter xlsx = new XLSWriter().setTemplate("...");</code></pre>
|
||||||
|
* XLSWriter가 데이터를 저장한 엑셀 파일을 다운로드할 때 사용할 이름을 지정할 수 있다.
|
||||||
|
* <pre><code> XLSWriter xlsx = new XLSWriter()
|
||||||
|
* .setTemplate("...")
|
||||||
|
* .setFilename("...");</code></pre>
|
||||||
|
* XLSWriter가 데이터를 엑셀로 저장하려면 워크시트와 작업셀을 지정해야 한다.
|
||||||
|
* <pre><code> xlsx.worksheet(0) //워크시트 설정
|
||||||
|
* .row(0) //첫번째 행
|
||||||
|
* .col(0); //첫번째 열의 셀을 작업셀로 설정</code></pre>
|
||||||
|
* 엑셀로 저장할 데이터를 준비한다.
|
||||||
|
* <pre><code> List<DataObject> dataset = ...;</code></pre>
|
||||||
|
* XLSWriter에 데이터를 설정한다.
|
||||||
|
* <pre><code> xlsx.values(dataset);</code></pre>
|
||||||
|
* 위 코드는 dataset의 모든 필드값들을 설정한다.
|
||||||
|
* dataset의 특정 필드의 값들을 원하는 순서대로 설정하려면 해당 필드들의 이름을 순서대로 나열한다.
|
||||||
|
* <pre><code> xlsx.values(dataset, "RCPT_ID", "RCPT_DT", "PAYER_NM", "RCPT_AMT");</code></pre>
|
||||||
|
* dataset의 특정 필드의 값들에 스타일을 적용하려면 {@link KeyStyle}을 표시한다.
|
||||||
|
* <pre><code> CellStyle
|
||||||
|
* datetime = xlsx.yyyy_mm_dd_hh_mm_ss(),
|
||||||
|
* numeric = xlsx.n_nn0();
|
||||||
|
* xlsx.values(dataset, "RCPT_ID", xlsx.keyStyle("RCPT_DT", datetime), "PAYER_NM", xlsx.keyStyle("RCPT_AMT", numeric));</code></pre>
|
||||||
|
* @author mjkhan
|
||||||
|
*/
|
||||||
|
public class XLSWriter extends XLS {
|
||||||
|
private int rowAccessWindowSize = 128;
|
||||||
|
private SXSSFWorkbook workbook;
|
||||||
|
private SXSSFSheet worksheet;
|
||||||
|
private SXSSFRow row;
|
||||||
|
private SXSSFCell cell;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public XLSWriter setTemplate(String template) {
|
||||||
|
super.setTemplate(template);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public XLSWriter setFilename(String filename) {
|
||||||
|
super.setFilename(filename);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void write(OutputStream out) {
|
||||||
|
try {
|
||||||
|
workbook.write(out);
|
||||||
|
workbook.dispose();
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw runtimeException(e);
|
||||||
|
} finally {
|
||||||
|
clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private SXSSFWorkbook getWorkbook() {
|
||||||
|
if (workbook != null)
|
||||||
|
return workbook;
|
||||||
|
|
||||||
|
try {
|
||||||
|
InputStream template = loadTemplate();
|
||||||
|
if (template != null) {
|
||||||
|
XSSFWorkbook xssf = new XSSFWorkbook(template);
|
||||||
|
workbook = new SXSSFWorkbook(xssf, rowAccessWindowSize);
|
||||||
|
} else {
|
||||||
|
workbook = new SXSSFWorkbook(rowAccessWindowSize);
|
||||||
|
}
|
||||||
|
workbook.setCompressTempFiles(true);
|
||||||
|
return workbook;
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw runtimeException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**지정한 인덱스의 워크시트를 반환한다.
|
||||||
|
* 워크시트가 없으면 해당 인덱스로 워크시트를 생성 후 반환한다.
|
||||||
|
* @param index 워크시트 인덱스(0부터 시작)
|
||||||
|
* @return 워크시트
|
||||||
|
*/
|
||||||
|
public XLSWriter worksheet(int index) {
|
||||||
|
try {
|
||||||
|
worksheet = getWorkbook().getSheetAt(index);
|
||||||
|
} catch (Exception e) {
|
||||||
|
worksheet = getWorkbook().createSheet();
|
||||||
|
}
|
||||||
|
worksheet.setRandomAccessWindowSize(rowAccessWindowSize);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**지정한 이름의 워크시트를 반환한다.
|
||||||
|
* 워크시트가 없으면 해당 이름의 워크시트를 생성 후 반환한다.
|
||||||
|
* @param name 워크시트 이름
|
||||||
|
* @return 워크시트
|
||||||
|
*/
|
||||||
|
public XLSWriter worksheet(String name) {
|
||||||
|
try {
|
||||||
|
SXSSFWorkbook wb = getWorkbook();
|
||||||
|
worksheet = ifEmpty(wb.getSheet(name), () -> wb.createSheet(name));
|
||||||
|
worksheet.setRandomAccessWindowSize(rowAccessWindowSize);
|
||||||
|
return this;
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw runtimeException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**지정한 인덱스의 행(row)을 작업행으로 설정한다.
|
||||||
|
* 해당 행이 없으면 생성 후 작업행으로 설정한다.
|
||||||
|
* @param index 행 인덱스(0부터 시작)
|
||||||
|
* @return 현재 XLSWriter
|
||||||
|
*/
|
||||||
|
public XLSWriter row(int index) {
|
||||||
|
row = ifEmpty(worksheet.getRow(index), () -> worksheet.createRow(index));
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**현재 작업행의 지정한 인덱스의 열(column)을 작업셀로 설정한다.
|
||||||
|
* 해당 셀이 없으면 생성 후 작업셀로 설정한다.
|
||||||
|
* @param index 열 인덱스(0부터 시작)
|
||||||
|
* @return 현재 XLSWriter
|
||||||
|
*/
|
||||||
|
public XLSWriter col(int index) {
|
||||||
|
cell = ifEmpty(row.getCell(index), () -> row.createCell(index));
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**지정한 행과 열 인덱스의 셀을 작업셀로 설정한다.
|
||||||
|
* @param row 행 인덱스
|
||||||
|
* @param col 열 인덱스
|
||||||
|
* @return 현재 XLSWriter
|
||||||
|
*/
|
||||||
|
public XLSWriter cell(int row, int col) {
|
||||||
|
return row(row).col(col);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**지정한 값을 현재 작업셀에 설정하고 스타일을 적용한다.
|
||||||
|
* @param val 설정값
|
||||||
|
* @param style 적용할 스타일(CellStyle, Styler, 또는 KeyStyle)
|
||||||
|
* @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);
|
||||||
|
|
||||||
|
setCellStyle(style);
|
||||||
|
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**지정한 값을 현재 작업셀에 설정한다.
|
||||||
|
* @param val 설정값
|
||||||
|
* @return 현재 XLSWriter
|
||||||
|
*/
|
||||||
|
public XLSWriter value(Object val) {
|
||||||
|
return value(val, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**지정한 값들을 현재 작업셀부터 행으로 순서대로 설정한다.<br />
|
||||||
|
* 값이 설정된 셀에 스타일을 적용하려면 해당값의 바로 뒤에 스타일을 지정한다.<br />
|
||||||
|
* 다음은 사용례다.
|
||||||
|
* <pre><code> XLSWriter xlsx = new XLSWriter()
|
||||||
|
* .setTemplate("...") // 템플릿 사용 시 지정
|
||||||
|
* .setFilename("...") // 다운로드 시 파일이름 지정
|
||||||
|
* .worksheet(0) // 워크시트 지정
|
||||||
|
* .cell(0, 0) // 작업셀 지정
|
||||||
|
* .rowValues(List.of("하나", 10000, new Date()));</code></pre>
|
||||||
|
* 두번째 값에는 숫자포맷을, 세번째 값에는 날짜포맷을 지정하려면 다음과 같이 한다.
|
||||||
|
* <pre><code> CellStyle numeric = xlsx.n_nn0(); //{@link #cellStyle(Styler)} 참고
|
||||||
|
* CellStyle datetime = xlsx.yyyy_mm_dd_hh_mm_ss();
|
||||||
|
* ...
|
||||||
|
* xlsx.rowValues(List.of("하나", 10000, numeric, new Date(), datetime));</code></pre>
|
||||||
|
* @param vals 설정값(스타일 포함)
|
||||||
|
* @return 현재 XLSWriter
|
||||||
|
*/
|
||||||
|
public XLSWriter rowValues(Iterable<?> vals) {
|
||||||
|
if (!isEmpty(vals)) {
|
||||||
|
int start = cell.getColumnIndex(),
|
||||||
|
x = start;
|
||||||
|
for (Object val: vals) {
|
||||||
|
if (val instanceof Styler) {
|
||||||
|
setCellStyle(val);
|
||||||
|
} else if (val instanceof CellStyle) {
|
||||||
|
setCellStyle(val);
|
||||||
|
} else if (val instanceof KeyStyle) {
|
||||||
|
setCellStyle(val);
|
||||||
|
} else {
|
||||||
|
col(x).value(val);
|
||||||
|
++x;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
col(start);
|
||||||
|
}
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setCellStyle(Object obj) {
|
||||||
|
Styler styler = null;
|
||||||
|
CellStyle style = null;
|
||||||
|
|
||||||
|
if (obj instanceof CellStyle) {
|
||||||
|
style = (CellStyle)obj;
|
||||||
|
} else if (obj instanceof Styler) {
|
||||||
|
styler = (Styler)obj;
|
||||||
|
} else if (obj instanceof KeyStyle) {
|
||||||
|
KeyStyle keyStyle = (KeyStyle)obj;
|
||||||
|
styler = keyStyle.styler;
|
||||||
|
style = keyStyle.style;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (styler != null) {
|
||||||
|
style = cellStyle(styler);
|
||||||
|
if (styler.width != null) {
|
||||||
|
if (styler.width < 256)
|
||||||
|
worksheet.setColumnWidth(cell.getColumnIndex(), styler.width * 256);
|
||||||
|
else
|
||||||
|
worksheet.autoSizeColumn(cell.getColumnIndex());
|
||||||
|
}
|
||||||
|
if (styler.height != null)
|
||||||
|
row.setHeight(styler.height);
|
||||||
|
}
|
||||||
|
if (style != null)
|
||||||
|
cell.setCellStyle(style);
|
||||||
|
}
|
||||||
|
|
||||||
|
private Iterable<?> vals(Map<?, ?> map, Object[] keysAndStyles) {
|
||||||
|
if (isEmpty(map))
|
||||||
|
return Collections.emptyList();
|
||||||
|
|
||||||
|
if (isEmpty(keysAndStyles))
|
||||||
|
return map.values();
|
||||||
|
|
||||||
|
ArrayList<Object> vals = new ArrayList<>();
|
||||||
|
for (Object obj: keysAndStyles) {
|
||||||
|
if (obj instanceof KeyStyle) {
|
||||||
|
KeyStyle keyStyle = (KeyStyle)obj;
|
||||||
|
Object val = map.get(keyStyle.key);
|
||||||
|
vals.add(val);
|
||||||
|
vals.add(keyStyle);
|
||||||
|
} else {
|
||||||
|
vals.add(map.get(obj));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return vals;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**지정한 map의 값들을 현재 작업셀부터 행으로 설정한다.<br />
|
||||||
|
* 설정할 값과 순서를 정하려면 해당 값들의 키를 지정한다.<br />
|
||||||
|
* 값이 설정된 셀에 스타일을 적용하려면 {@link KeyStyle}로 키와 스타일을 지정한다.<br />
|
||||||
|
* 다음은 map의 모든 값들을 설정하는 예다.
|
||||||
|
* <pre><code> DataObject rec = new DataObject().set("NO", 1).set("PAYER", "홍길동").set("RCPT_AMT", 10000).set("RCPT_DT", new Date());
|
||||||
|
* XLSWriter xlsx = new XLSWriter()
|
||||||
|
* .setTemplate("...") // 템플릿 사용 시 지정
|
||||||
|
* .setFilename("...") // 다운로드 시 파일이름 지정
|
||||||
|
* .worksheet(0) // 워크시트 지정
|
||||||
|
* .cell(0, 0) // 작업셀 지정
|
||||||
|
* .rowValues(rec);</code></pre>
|
||||||
|
* 설정할 값들을 지정하려면 다음과 같이 한다.
|
||||||
|
* <pre><code> xlsx.rowValues(rec, "PAYER", "RCPT_AMT", "RCPT_DT");</code></pre>
|
||||||
|
* RCPT_AMT, RCPT_DT에 숫자포맷과 날짜포맷을 적용하려면 다음과 같이 한다.
|
||||||
|
* <pre><code> CellStyle numeric = xlsx.n_nn0(); //{@link #cellStyle(Styler)} 참고
|
||||||
|
* CellStyle datetime = xlsx.yyyy_mm_dd_hh_mm_ss();
|
||||||
|
* ...
|
||||||
|
* xlsx.rowValues(rec, "PAYER", xlsx.keyStyle("RCPT_AMT", numeric), xlsx.keyStyle("RCPT_DT", datetime));</code></pre>
|
||||||
|
* @param map 맵
|
||||||
|
* @param keysAndStyles 셀에 설정할 값들의 키, 또는 {@link KeyStyle 키와 스타일}
|
||||||
|
* @return 현재 XLSWriter
|
||||||
|
*/
|
||||||
|
public XLSWriter rowValues(Map<?, ?> map, Object... keysAndStyles) {
|
||||||
|
return rowValues(vals(map, keysAndStyles));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**지정한 데이터셋의 값들을 현재 작업셀부터 행과 열로 설정한다.
|
||||||
|
* 설정할 값과 순서를 정하려면 해당 값들의 키를 지정한다.<br />
|
||||||
|
* 값이 설정된 셀에 스타일을 적용하려면 {@link KeyStyle}로 키와 스타일을 지정한다.<br />
|
||||||
|
* 다음은 데이터셋의 모든 값들을 설정하는 예다.
|
||||||
|
* <pre><code> List<DataObject> dataset = ...;
|
||||||
|
* XLSWriter xlsx = new XLSWriter()
|
||||||
|
* .setTemplate("...") // 템플릿 사용 시 지정
|
||||||
|
* .setFilename("...") // 다운로드 시 파일이름 지정
|
||||||
|
* .worksheet(0) // 워크시트 지정
|
||||||
|
* .cell(0, 0) // 작업셀 지정
|
||||||
|
* .rowValues(dataset);</code></pre>
|
||||||
|
* 설정할 값들을 지정하려면 다음과 같이 한다.
|
||||||
|
* <pre><code> xlsx.rowValues(dataset, "PAYER", "RCPT_AMT", "RCPT_DT");</code></pre>
|
||||||
|
* RCPT_AMT, RCPT_DT에 숫자포맷과 날짜포맷을 적용하려면 다음과 같이 한다.
|
||||||
|
* <pre><code> CellStyle numeric = xlsx.n_nn0(); //{@link #cellStyle(Styler)} 참고
|
||||||
|
* CellStyle datetime = xlsx.yyyy_mm_dd_hh_mm_ss();
|
||||||
|
* ...
|
||||||
|
* xlsx.rowValues(dataset, "PAYER", xlsx.keyStyle("RCPT_AMT", numeric), xlsx.keyStyle("RCPT_DT", datetime));</code></pre>
|
||||||
|
* @param dataset 데이터셋
|
||||||
|
* @param keysAndStyles 셀에 설정할 값들의 키, 또는 {@link KeyStyle 키와 스타일}
|
||||||
|
* @return 현재 XLSWriter
|
||||||
|
*/
|
||||||
|
public XLSWriter values(Iterable<? extends Map<?, ?>> dataset, Object... keysAndStyles) {
|
||||||
|
if (!isEmpty(dataset)) {
|
||||||
|
int c = cell.getColumnIndex(),
|
||||||
|
r = cell.getRowIndex();
|
||||||
|
for (Map<?, ?> rec: dataset) {
|
||||||
|
cell(r, c);
|
||||||
|
rowValues(rec, keysAndStyles);
|
||||||
|
++r;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public XLSWriter styles(Styler... stylers) {
|
||||||
|
if (!isEmpty(stylers)) {
|
||||||
|
int start = cell.getColumnIndex(),
|
||||||
|
x = start;
|
||||||
|
for (Styler styler: stylers) {
|
||||||
|
col(x);
|
||||||
|
setCellStyle(styler);
|
||||||
|
++x;
|
||||||
|
}
|
||||||
|
col(start);
|
||||||
|
}
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**스타일 정보에서 셀스타일을 생성하여 반환한다.
|
||||||
|
* @param styler 스타일 정보
|
||||||
|
* @return 셀스타일
|
||||||
|
*/
|
||||||
|
public CellStyle cellStyle(Styler styler) {
|
||||||
|
CellStyle cellStyle = workbook.createCellStyle();
|
||||||
|
styler.set(cellStyle);
|
||||||
|
if (styler.dataFormat != null) {
|
||||||
|
cellStyle.setDataFormat(workbook.createDataFormat().getFormat(styler.dataFormat));
|
||||||
|
}
|
||||||
|
return cellStyle;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**지정한 키와 셀스타일을 연결한 KeyStyle을 반환한다.
|
||||||
|
* @param key 키
|
||||||
|
* @param style 셀스타일
|
||||||
|
* @return KeyStyle
|
||||||
|
*/
|
||||||
|
public KeyStyle keyStyle(Object key, CellStyle style) {
|
||||||
|
return new KeyStyle(key, style);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**style에서 셀스타일을 생성한 후 지정한 키와 연결한 KeyStyle을 반환한다.
|
||||||
|
* @param key 키
|
||||||
|
* @param style 스타일 정보
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public KeyStyle keyStyle(Object key, Styler style) {
|
||||||
|
return keyStyle(key, cellStyle(style));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**현재 XLSWriter의 내부상태를 초기화하여 반환한다.
|
||||||
|
* @return 현재 XLSWriter
|
||||||
|
*/
|
||||||
|
public XLSWriter clear() {
|
||||||
|
cell = null;
|
||||||
|
row = null;
|
||||||
|
worksheet = null;
|
||||||
|
workbook = null;
|
||||||
|
rowAccessWindowSize = 128;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**숫자 스타일(오른쪽 정렬, 천단위 구분)을 반환한다.
|
||||||
|
* @return 숫자 스타일(오른쪽 정렬, 천단위 구분)
|
||||||
|
*/
|
||||||
|
public CellStyle n_nn0() {
|
||||||
|
return cellStyle(new Styler().alignment(HorizontalAlignment.RIGHT).dataFormat("#,###"));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**숫자 스타일(오른쪽 정렬, 천단위 구분, 소수점 2자리 표기)을 반환한다.
|
||||||
|
* @return 숫자 스타일(오른쪽 정렬, 천단위 구분, 소수점 2자리 표기)
|
||||||
|
*/
|
||||||
|
public CellStyle n_nn0_2() {
|
||||||
|
return cellStyle(new Styler().dataFormat("#,###.00").merge(Styler.RIGHT));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**날짜 포맷(yyyy-MM-dd HH:mm:ss)의 셀스타일을 반환한다.
|
||||||
|
* @return 날짜 포맷(yyyy-MM-dd HH:mm:ss)의 셀스타일
|
||||||
|
*/
|
||||||
|
public CellStyle yyyy_mm_dd_hh_mm_ss() {
|
||||||
|
return cellStyle(new Styler().dataFormat("yyyy-MM-dd HH:mm:ss").merge(Styler.CENTER));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**날짜 포맷(yyyy-MM-dd)의 셀스타일을 반환한다.
|
||||||
|
* @return 날짜 포맷(yyyy-MM-dd)의 셀스타일
|
||||||
|
*/
|
||||||
|
public CellStyle yyyy_mm_dd() {
|
||||||
|
return cellStyle(new Styler().dataFormat("yyyy-MM-dd").merge(Styler.CENTER));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**셀스타일 정보. {@link #set(CellStyle) CellStyle을 설정}하는데 사용.
|
||||||
|
* @author mjkhan
|
||||||
|
*/
|
||||||
|
public static class Styler {
|
||||||
|
/** 빈 스타일 */
|
||||||
|
public static final Styler NONE = new Styler().seal();
|
||||||
|
/** 좌측 정렬 */
|
||||||
|
public static final Styler LEFT = new Styler().alignment(HorizontalAlignment.LEFT).seal();
|
||||||
|
/** 가운데 정렬 */
|
||||||
|
public static final Styler CENTER = new Styler().alignment(HorizontalAlignment.CENTER).seal();
|
||||||
|
/** 우측 정렬 */
|
||||||
|
public static final Styler RIGHT = new Styler().alignment(HorizontalAlignment.RIGHT).seal();
|
||||||
|
|
||||||
|
private boolean sealed;
|
||||||
|
|
||||||
|
private Integer width;
|
||||||
|
private Short height;
|
||||||
|
|
||||||
|
private HorizontalAlignment horizontalAlignment;
|
||||||
|
private VerticalAlignment verticalAlignment;
|
||||||
|
|
||||||
|
private Border
|
||||||
|
borderTop,
|
||||||
|
borderRight,
|
||||||
|
borderBottom,
|
||||||
|
borderLeft;
|
||||||
|
|
||||||
|
private Short foregroundColor;
|
||||||
|
|
||||||
|
private Font font;
|
||||||
|
private String dataFormat;
|
||||||
|
|
||||||
|
/**열의 폭을 설정한다.
|
||||||
|
* @param chars 열의 폭. 한번에 보여지는 문자수
|
||||||
|
* @return 현재 Styler
|
||||||
|
*/
|
||||||
|
public Styler width(int chars) {
|
||||||
|
this.width = chars;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**행의 높이를 설정한다.
|
||||||
|
* @param height 행의 높이
|
||||||
|
* @return 현재 Styler
|
||||||
|
*/
|
||||||
|
public Styler height(short height) {
|
||||||
|
this.height = height;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**가로정렬을 설정한다.
|
||||||
|
* @param alignment 가로정렬
|
||||||
|
* @return 현재 Styler
|
||||||
|
*/
|
||||||
|
public Styler alignment(HorizontalAlignment alignment) {
|
||||||
|
ensureNotSealed();
|
||||||
|
horizontalAlignment = alignment;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**세로정렬을 설정한다.
|
||||||
|
* @param alignment 세로정렬
|
||||||
|
* @return 현재 Styler
|
||||||
|
*/
|
||||||
|
public Styler alignment(VerticalAlignment alignment) {
|
||||||
|
ensureNotSealed();
|
||||||
|
verticalAlignment = alignment;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**윗쪽 테두리 스타일을 설정한다.
|
||||||
|
* @param border 테두리 스타일 정보
|
||||||
|
* @return 현재 Styler
|
||||||
|
*/
|
||||||
|
public Styler borderTop(Border border) {
|
||||||
|
ensureNotSealed();
|
||||||
|
borderTop = border;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**오른쪽 테두리 스타일을 설정한다.
|
||||||
|
* @param border 테두리 스타일 정보
|
||||||
|
* @return 현재 Styler
|
||||||
|
*/
|
||||||
|
public Styler borderRight(Border border) {
|
||||||
|
ensureNotSealed();
|
||||||
|
borderRight = border;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**아래쪽 테두리 스타일을 설정한다.
|
||||||
|
* @param border 테두리 스타일 정보
|
||||||
|
* @return 현재 Styler
|
||||||
|
*/
|
||||||
|
public Styler borderBottom(Border border) {
|
||||||
|
ensureNotSealed();
|
||||||
|
borderBottom = border;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**왼쪽 테두리 스타일을 설정한다.
|
||||||
|
* @param border 테두리 스타일 정보
|
||||||
|
* @return 현재 Styler
|
||||||
|
*/
|
||||||
|
public Styler borderLeft(Border border) {
|
||||||
|
ensureNotSealed();
|
||||||
|
borderLeft = border;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**배경색을 설정한다.
|
||||||
|
* @param color
|
||||||
|
* @return 현재 Styler
|
||||||
|
*/
|
||||||
|
public Styler foregroundColor(short color) {
|
||||||
|
ensureNotSealed();
|
||||||
|
foregroundColor = color;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**폰트를 설정한다.
|
||||||
|
* @param font 폰트
|
||||||
|
* @return 현재 Styler
|
||||||
|
*/
|
||||||
|
public Styler font(Font font) {
|
||||||
|
ensureNotSealed();
|
||||||
|
this.font = font;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**데이터 포맷을 설정한다.
|
||||||
|
* @param dataFormat 데이터 포맷
|
||||||
|
* @return 현재 Styler
|
||||||
|
*/
|
||||||
|
public Styler dataFormat(String dataFormat) {
|
||||||
|
ensureNotSealed();
|
||||||
|
this.dataFormat = dataFormat;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**셀스타일에 현재 스타일 정보를 설정한다.
|
||||||
|
* @param style 셀스타일
|
||||||
|
*/
|
||||||
|
public void set(CellStyle style) {
|
||||||
|
if (style == null) return;
|
||||||
|
|
||||||
|
if (horizontalAlignment != null)
|
||||||
|
style.setAlignment(horizontalAlignment);
|
||||||
|
if (verticalAlignment != null)
|
||||||
|
style.setVerticalAlignment(verticalAlignment);
|
||||||
|
|
||||||
|
if (borderTop != null) {
|
||||||
|
if (borderTop.style != null)
|
||||||
|
style.setBorderTop(borderTop.style);
|
||||||
|
if (borderTop.color != null)
|
||||||
|
style.setTopBorderColor(borderTop.color);
|
||||||
|
}
|
||||||
|
if (borderRight != null) {
|
||||||
|
if (borderRight.style != null)
|
||||||
|
style.setBorderRight(borderRight.style);
|
||||||
|
if (borderRight.color != null)
|
||||||
|
style.setRightBorderColor(borderRight.color);
|
||||||
|
}
|
||||||
|
if (borderBottom != null) {
|
||||||
|
if (borderBottom.style != null)
|
||||||
|
style.setBorderBottom(borderBottom.style);
|
||||||
|
if (borderBottom.color != null)
|
||||||
|
style.setBottomBorderColor(borderBottom.color);
|
||||||
|
}
|
||||||
|
if (borderLeft != null) {
|
||||||
|
if (borderLeft.style != null)
|
||||||
|
style.setBorderLeft(borderLeft.style);
|
||||||
|
if (borderLeft.color != null)
|
||||||
|
style.setLeftBorderColor(borderLeft.color);
|
||||||
|
}
|
||||||
|
if (foregroundColor != null) {
|
||||||
|
style.setFillForegroundColor(foregroundColor);
|
||||||
|
style.setFillPattern(FillPatternType.SOLID_FOREGROUND);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (font != null)
|
||||||
|
style.setFont(font);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Styler configure(Consumer<Styler> configurer) {
|
||||||
|
ensureNotSealed();
|
||||||
|
if (configurer != null)
|
||||||
|
configurer.accept(this);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Styler merge(Styler other) {
|
||||||
|
Styler copy = new Styler();
|
||||||
|
|
||||||
|
copy.width = this.width;
|
||||||
|
copy.height = this.height;
|
||||||
|
|
||||||
|
copy.horizontalAlignment = this.horizontalAlignment;
|
||||||
|
copy.verticalAlignment = this.verticalAlignment;
|
||||||
|
|
||||||
|
copy.borderTop = this.borderTop;
|
||||||
|
copy.borderRight = this.borderRight;
|
||||||
|
copy.borderBottom = this.borderBottom;
|
||||||
|
copy.borderLeft = this.borderLeft;
|
||||||
|
|
||||||
|
copy.foregroundColor = this.foregroundColor;
|
||||||
|
copy.font = this.font;
|
||||||
|
copy.dataFormat = this.dataFormat;
|
||||||
|
|
||||||
|
if (other.width != null)
|
||||||
|
copy.width = other.width;
|
||||||
|
if (other.height != null)
|
||||||
|
copy.height = other.height;
|
||||||
|
|
||||||
|
if (other.horizontalAlignment != null)
|
||||||
|
copy.horizontalAlignment = other.horizontalAlignment;
|
||||||
|
if (other.verticalAlignment != null)
|
||||||
|
copy.verticalAlignment = other.verticalAlignment;
|
||||||
|
|
||||||
|
if (other.borderTop != null)
|
||||||
|
copy.borderTop = other.borderTop;
|
||||||
|
if (other.borderRight != null)
|
||||||
|
copy.borderRight = other.borderRight;
|
||||||
|
if (other.borderBottom != null)
|
||||||
|
copy.borderBottom = other.borderBottom;
|
||||||
|
if (other.borderLeft != null)
|
||||||
|
copy.borderLeft = other.borderLeft;
|
||||||
|
|
||||||
|
if (other.foregroundColor != null)
|
||||||
|
copy.foregroundColor = other.foregroundColor;
|
||||||
|
if (other.font != null)
|
||||||
|
copy.font = other.font;
|
||||||
|
if (other.dataFormat != null)
|
||||||
|
copy.dataFormat = other.dataFormat;
|
||||||
|
|
||||||
|
return copy;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Styler seal() {
|
||||||
|
sealed = true;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ensureNotSealed() {
|
||||||
|
if (sealed)
|
||||||
|
throw new RuntimeException("The Style is sealed and unmodifieable");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**테두리 스타일 정보
|
||||||
|
* @author mjkhan
|
||||||
|
*/
|
||||||
|
public static class Border {
|
||||||
|
private BorderStyle style;
|
||||||
|
private Short color;
|
||||||
|
|
||||||
|
/**테두리 스타일 정보를 설정한다.
|
||||||
|
* @param style 테두리 스타일 정보
|
||||||
|
* @return 현재 테두리 스타일 정보
|
||||||
|
*/
|
||||||
|
public Border style(BorderStyle style) {
|
||||||
|
this.style = style;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**테두리 색깔을 설정한다.
|
||||||
|
* @param color 테두리 색깔
|
||||||
|
* @return 현재 테두리 스타일 정보
|
||||||
|
*/
|
||||||
|
public Border color(short color) {
|
||||||
|
this.color = color;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**셀스타일을 특정키와 연결하는 정보
|
||||||
|
* @author mjkhan
|
||||||
|
*/
|
||||||
|
public static class KeyStyle {
|
||||||
|
private Object key;
|
||||||
|
private CellStyle style;
|
||||||
|
private Styler styler;
|
||||||
|
|
||||||
|
/**새 KeyStyle을 생성한다.
|
||||||
|
* @param key 키
|
||||||
|
* @param style 셀스타일
|
||||||
|
*/
|
||||||
|
KeyStyle(Object key, CellStyle style) {
|
||||||
|
this.key = notEmpty(key, "key");
|
||||||
|
this.style = style;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**새 KeyStyle을 생성한다.
|
||||||
|
* @param key 키
|
||||||
|
* @param styler 스타일러
|
||||||
|
*/
|
||||||
|
KeyStyle(Object key, Styler styler) {
|
||||||
|
this.key = notEmpty(key, "key");
|
||||||
|
this.styler = styler;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue