|
|
package com.wb.excel.api;
|
|
|
|
|
|
import com.wb.excel.api.annotation.ColumnDescription;
|
|
|
import com.wb.excel.api.datatable.WCell;
|
|
|
import com.wb.excel.api.datatable.WColumn;
|
|
|
import com.wb.excel.api.datatable.WSheet;
|
|
|
import com.wb.excel.api.enumeration.DataType;
|
|
|
import com.wb.excel.api.enumeration.Status;
|
|
|
import com.wb.excel.api.style.*;
|
|
|
import org.apache.poi.ss.usermodel.CellStyle;
|
|
|
import org.apache.poi.ss.usermodel.Font;
|
|
|
import org.apache.poi.ss.usermodel.Row;
|
|
|
import org.apache.poi.ss.usermodel.Workbook;
|
|
|
import org.apache.poi.xssf.usermodel.*;
|
|
|
|
|
|
import java.io.ByteArrayOutputStream;
|
|
|
import java.io.IOException;
|
|
|
import java.lang.reflect.Field;
|
|
|
import java.util.HashSet;
|
|
|
import java.util.Set;
|
|
|
|
|
|
/**
|
|
|
* Excel帮助类.
|
|
|
* <p/>
|
|
|
* Created on 2014/9/27.
|
|
|
*
|
|
|
* @author
|
|
|
* @since 0.1.0
|
|
|
*/
|
|
|
public class WExcel {
|
|
|
/**
|
|
|
* Excel表格
|
|
|
*/
|
|
|
private XSSFWorkbook workbook;
|
|
|
|
|
|
/**
|
|
|
* 表头样式
|
|
|
*/
|
|
|
private CellStyle headCellStyle;
|
|
|
|
|
|
/**
|
|
|
* 错误单元格的样式
|
|
|
*/
|
|
|
private CellStyle errorCellStyle;
|
|
|
|
|
|
/**
|
|
|
* 错误的数字单元格的样式(数字靠右)
|
|
|
*/
|
|
|
private CellStyle errorNumberCellStyle;
|
|
|
|
|
|
/**
|
|
|
* 普通单元格的样式
|
|
|
*/
|
|
|
private CellStyle normalCellStyle;
|
|
|
|
|
|
/**
|
|
|
* 普通数字单元格的样式
|
|
|
*/
|
|
|
private CellStyle normalNumberCellStyle;
|
|
|
|
|
|
/**
|
|
|
* 检查消息单元格的样式(最右边一列)
|
|
|
*/
|
|
|
private CellStyle checkMessageCellStyle;
|
|
|
|
|
|
/**
|
|
|
* 检查结果失败的单元格的样式
|
|
|
*/
|
|
|
private CellStyle checkFailureCellStyle;
|
|
|
|
|
|
/**
|
|
|
* 检查结果通过的单元格的样式
|
|
|
*/
|
|
|
private CellStyle checkSuccessCellStyle;
|
|
|
|
|
|
/**
|
|
|
* 正常的文字
|
|
|
*/
|
|
|
private Font normalFont;
|
|
|
|
|
|
/**
|
|
|
* 红色文字
|
|
|
*/
|
|
|
private Font redFont;
|
|
|
|
|
|
/**
|
|
|
* 初始化一个Excel文件.
|
|
|
*/
|
|
|
public void init() {
|
|
|
workbook = new XSSFWorkbook();
|
|
|
|
|
|
//---------- 创建样式 ------------------
|
|
|
headCellStyle = new HeadCellStyle(workbook).getStyle();
|
|
|
errorCellStyle = new ErrorCellStyle(workbook).getStyle();
|
|
|
errorNumberCellStyle = new ErrorNumberCellStyle(workbook).getStyle();
|
|
|
normalCellStyle = new NormalCellStyle(workbook).getStyle();
|
|
|
normalNumberCellStyle = new NormalNumberCellStyle(workbook).getStyle();
|
|
|
checkMessageCellStyle = new CheckMessageCellStyle(workbook).getStyle();
|
|
|
checkFailureCellStyle = new CheckFailureCellStyle(workbook).getStyle();
|
|
|
checkSuccessCellStyle = new CheckSuccessCellStyle(workbook).getStyle();
|
|
|
|
|
|
//----------- 创建字体 ----------------
|
|
|
normalFont = new NormalFont(workbook).getFont();
|
|
|
redFont = new RedFont(workbook).getFont();
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* 默认无参构造方法.
|
|
|
*/
|
|
|
public WExcel() {
|
|
|
init();
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* 将一个DataTable转换为Excel对象,不显示检查结果和错误消息栏.<br/>
|
|
|
* 通常用于导出报表.
|
|
|
* {@link WExcel#WExcel(boolean flag, WSheet... dataTable)}
|
|
|
*
|
|
|
* @param tables 要导出的DataTable集合
|
|
|
*/
|
|
|
public WExcel(WSheet... tables) {
|
|
|
workbook = this.initExcel(false, tables);
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* 将若干DataTable转换为Excel对象.
|
|
|
*
|
|
|
* @param flag 是否需要添加检查结果和错误消息栏(true,会添加;false,不会添加)
|
|
|
* @param tables DataTable列表
|
|
|
*/
|
|
|
public WExcel(boolean flag, WSheet... tables) {
|
|
|
workbook = this.initExcel(flag, tables);
|
|
|
}
|
|
|
|
|
|
public XSSFWorkbook initExcel(boolean flag, WSheet... tables) {
|
|
|
init();
|
|
|
Set<String> nameSet = new HashSet<>(tables.length);
|
|
|
for (WSheet table : tables) {
|
|
|
String name = table.getName();
|
|
|
int index = 1;
|
|
|
while (nameSet.contains(name)) {
|
|
|
name = table.getName() + "(" + index + ")";
|
|
|
index++;
|
|
|
}
|
|
|
nameSet.add(name);
|
|
|
|
|
|
//创建一个Sheet表
|
|
|
XSSFSheet sheet = workbook.createSheet(name);
|
|
|
sheet.setDefaultRowHeightInPoints(20);
|
|
|
Row firstRow = sheet.createRow(0); // 下标为0的行开始
|
|
|
XSSFDrawing drawing = sheet.createDrawingPatriarch();
|
|
|
|
|
|
//----------------表头--------------------
|
|
|
if (flag) {
|
|
|
// 检查结果栏
|
|
|
org.apache.poi.ss.usermodel.Cell firstCell = firstRow.createCell(0);
|
|
|
String columnName = WSheet.CHECK_STATUS_NAME;
|
|
|
firstCell.setCellStyle(headCellStyle);
|
|
|
firstCell.setCellValue(new XSSFRichTextString(columnName));
|
|
|
sheet.setColumnWidth(0, (4 + 8) * 256);
|
|
|
}
|
|
|
// 数据栏
|
|
|
int hiddenNumber = 0;
|
|
|
for (int j = 0; j < table.getColumnIndex(); j++) {
|
|
|
WColumn WColumn = table.getWColumns()[j];
|
|
|
if (WColumn.isHidden()) {
|
|
|
hiddenNumber++;
|
|
|
continue;
|
|
|
}
|
|
|
int k = j - hiddenNumber;
|
|
|
if (flag) {
|
|
|
k++;
|
|
|
}
|
|
|
org.apache.poi.ss.usermodel.Cell firstCell = firstRow.createCell(k);
|
|
|
String columnName = WColumn.getName();
|
|
|
XSSFRichTextString textString;
|
|
|
if (WColumn.isRequired()) {
|
|
|
textString = new XSSFRichTextString("*" + columnName);
|
|
|
textString.applyFont(0, 1, redFont);
|
|
|
textString.applyFont(1, textString.length(), normalFont);
|
|
|
} else {
|
|
|
textString = new XSSFRichTextString(columnName);
|
|
|
textString.applyFont(normalFont);
|
|
|
}
|
|
|
StringBuilder sb = new StringBuilder();
|
|
|
sb.append(WColumn.getDescription()).append("\n");
|
|
|
if (WColumn.getDataType() != DataType.STRING) {
|
|
|
// 如果数据类型不是字符串类型,添加特殊数据类型的说明信息。
|
|
|
Field[] fields = DataType.class.getDeclaredFields();
|
|
|
for (Field field : fields) {
|
|
|
if (field.getName().equals(WColumn.getDataType().name())) {
|
|
|
if (field.isAnnotationPresent(ColumnDescription.class)) {
|
|
|
|
|
|
// 获取声明字段上的Description信息。
|
|
|
ColumnDescription columnDescription = field.getAnnotation(ColumnDescription.class);
|
|
|
if (columnDescription.value() != null) {
|
|
|
sb.append(columnDescription.value());
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
|
|
|
// 如果填写了注释信息
|
|
|
if (sb.length() > 1) {
|
|
|
XSSFClientAnchor anchor = new XSSFClientAnchor(0, 0, 0, 0, (short) 3, 3, (short) 5, 6);
|
|
|
XSSFComment comment = drawing.createCellComment(anchor);
|
|
|
comment.setString(sb.toString());
|
|
|
firstCell.setCellComment(comment);
|
|
|
}
|
|
|
firstCell.setCellValue(textString);
|
|
|
firstCell.setCellStyle(headCellStyle);
|
|
|
sheet.setColumnWidth(k, (4 + WColumn.getCellWidth()) * 256);
|
|
|
}
|
|
|
|
|
|
// 错误消息栏
|
|
|
if (flag) {
|
|
|
org.apache.poi.ss.usermodel.Cell firstCell = firstRow.createCell(table.getColumnIndex() + 1 - hiddenNumber);
|
|
|
String columnName = WSheet.CHECK_STATUS_RESULT;
|
|
|
firstCell.setCellStyle(headCellStyle);
|
|
|
firstCell.setCellValue(new XSSFRichTextString(columnName));
|
|
|
sheet.setColumnWidth(table.getColumnIndex() + 1, (4 + 10) * 256);
|
|
|
}
|
|
|
|
|
|
// 冻结第一行
|
|
|
//sheet.createFreezePane(255,1);
|
|
|
|
|
|
//------------------数据--------------------
|
|
|
for (int i = 0; i < table.getRowIndex(); i++) {
|
|
|
Row row = sheet.createRow(i + 1);
|
|
|
boolean rowFlag = true;
|
|
|
|
|
|
//如果该行有错误
|
|
|
if (flag) {
|
|
|
org.apache.poi.ss.usermodel.Cell xssfCell = row.createCell(0);
|
|
|
if (table.getRowError(i) != null) {
|
|
|
rowFlag = false;
|
|
|
xssfCell.setCellValue("不通过");
|
|
|
xssfCell.setCellStyle(checkFailureCellStyle);
|
|
|
} else {
|
|
|
xssfCell.setCellValue("通过");
|
|
|
xssfCell.setCellStyle(checkSuccessCellStyle);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
int j = 0;
|
|
|
hiddenNumber = 0;
|
|
|
for (; j < table.getColumnIndex(); j++) {
|
|
|
WColumn WColumn = table.getWColumns()[j];
|
|
|
if (WColumn.isHidden()) {
|
|
|
hiddenNumber++;
|
|
|
continue;
|
|
|
}
|
|
|
int k = j - hiddenNumber;
|
|
|
if (flag) {
|
|
|
k++;
|
|
|
}
|
|
|
|
|
|
org.apache.poi.ss.usermodel.Cell xssfCell = row.createCell(k);
|
|
|
WCell WCell = table.getCell(i, j);
|
|
|
if (null == WCell) {
|
|
|
continue;
|
|
|
}
|
|
|
String value = WCell.getValue();
|
|
|
xssfCell.setCellValue(value);
|
|
|
|
|
|
// 如果该列是数字类型,则靠右
|
|
|
if (table.getWColumns()[j].getDataType() == DataType.DECIMAL
|
|
|
|| table.getWColumns()[j].getDataType() == DataType.NUMBER) {
|
|
|
if (flag && !WCell.getStatus().equals(Status.PASS)) {
|
|
|
xssfCell.setCellStyle(errorNumberCellStyle);
|
|
|
} else {
|
|
|
xssfCell.setCellStyle(normalNumberCellStyle);
|
|
|
}
|
|
|
} else {
|
|
|
if (flag && !WCell.getStatus().equals(Status.PASS)) {
|
|
|
xssfCell.setCellStyle(errorCellStyle);
|
|
|
} else {
|
|
|
xssfCell.setCellStyle(normalCellStyle);
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
|
|
|
if (flag && !rowFlag) {
|
|
|
org.apache.poi.ss.usermodel.Cell xssfCell = row.createCell(j + 1 - hiddenNumber);
|
|
|
xssfCell.setCellValue(table.getRowError(i));
|
|
|
xssfCell.setCellStyle(checkMessageCellStyle);
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
return workbook;
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* 得到已生成好的Excel文件的字节流信息
|
|
|
*
|
|
|
* @return 字节流信息
|
|
|
* @throws IOException
|
|
|
*/
|
|
|
public byte[] getBytes() throws IOException {
|
|
|
if (workbook != null) {
|
|
|
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
|
|
|
workbook.write(outputStream);
|
|
|
return outputStream.toByteArray();
|
|
|
}
|
|
|
return null;
|
|
|
}
|
|
|
|
|
|
//------------ getter & setter --------------------
|
|
|
public Workbook getWorkbook() {
|
|
|
return workbook;
|
|
|
}
|
|
|
|
|
|
public void setWorkbook(XSSFWorkbook workbook) {
|
|
|
this.workbook = workbook;
|
|
|
}
|
|
|
}
|