
org.wuwz.poi.ExcelKit Maven / Gradle / Ivy
/**
* Copyright (c) 2017, 吴汶泽 ([email protected]).
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.wuwz.poi;
import java.io.File;
import java.io.IOException;
import java.io.OutputStream;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.servlet.http.HttpServletResponse;
import org.apache.commons.beanutils.BeanUtils;
import org.apache.commons.codec.binary.StringUtils;
import org.apache.log4j.Logger;
import org.apache.poi.hssf.usermodel.HSSFCell;
import org.apache.poi.hssf.util.HSSFColor;
import org.apache.poi.ss.usermodel.CellStyle;
import org.apache.poi.ss.usermodel.Font;
import org.apache.poi.util.StringUtil;
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.wuwz.poi.annotation.ExportConfig;
import org.wuwz.poi.convert.ExportConvert;
import org.wuwz.poi.core.POIUtils;
import org.wuwz.poi.core.XlsxReader;
import org.wuwz.poi.hanlder.ExportHandler;
import org.wuwz.poi.hanlder.ReadHandler;
import org.wuwz.poi.pojo.ExportItem;
/**
*
* ExcelKit.java : Excel快速导入导出工具
* 简单、好用且轻量级的海量Excel文件导入导出解决方案. (仅提供excel2007以及更高版本的支持)
*
*
* @author wuwz
* @since 2017年4月10日
*/
public class ExcelKit {
private static Logger log = Logger.getLogger(ExcelKit.class);
private Class> mClass = null;
private HttpServletResponse mResponse = null;
// 默认以此值填充空单元格,可通过 setEmptyCellValue(string)改变其默认值。
private String mEmptyCellValue = null;
// 分Sheet机制:每个Sheet最多多少条数据
private Integer mMaxSheetRecords = 10000;
// 缓存数据格式器实例,避免多次使用反射进行实例化
private Map mConvertInstanceCache = new HashMap();
protected ExcelKit() {}
protected ExcelKit(Class> clazz) {
this(clazz, null);
}
protected ExcelKit(Class> clazz, HttpServletResponse response) {
this.mResponse = response;
this.mClass = clazz;
}
/**
* 用于生成本地文件
*
* @param clazz
* 实体Class对象
* @return ExcelKit
*/
public static ExcelKit $Builder(Class> clazz) {
return new ExcelKit(clazz);
}
/**
* 用于浏览器导出
*
* @param clazz
* 实体Class对象
* @param response
* 原生HttpServletResponse对象
* @return ExcelKit
*/
public static ExcelKit $Export(Class> clazz, HttpServletResponse response) {
return new ExcelKit(clazz, response);
}
/**
* 用于导入数据解析
*
* @return ExcelKit
*/
public static ExcelKit $Import() {
return new ExcelKit();
}
/**
* 读取Excel时以该值填充空单元格值 (默认null)
*
* @param emptyCellValue
* 单元格值
* @return this
*/
public ExcelKit setEmptyCellValue(String emptyCellValue) {
this.mEmptyCellValue = emptyCellValue;
return this;
}
/**
* 分Sheet机制:每个Sheet最多多少条数据(默认10000)
*
* @param size
* 数据条数
* @return this
*/
public ExcelKit setMaxSheetRecords(Integer size) {
this.mMaxSheetRecords = size;
return this;
}
/**
* 导出Excel(此方式需依赖浏览器实现文件下载,故应先使用$Export()构造器)
*
* @param data
* 数据集合
* @param sheetName
* 工作表名字
* @return true-操作成功,false-操作失败
*/
public boolean toExcel(List> data, String sheetName) {
required$ExportParams();
try {
return toExcel(data, sheetName, mResponse.getOutputStream());
} catch (IOException e) {
log.error("导出Excel失败:" + e.getMessage(), e);
}
return false;
}
/**
* 针对转换方法的默认实现(提供默认样式和文件命名规则)
*
* @param data
* 数据集合
* @param sheetName
* 工作表名字
* @param out
* 输出流
* @return true-操作成功,false-操作失败
*/
public boolean toExcel(List> data, String sheetName, OutputStream out) {
return toExcel(data, sheetName, new ExportHandler() {
@Override
public CellStyle headCellStyle(SXSSFWorkbook wb) {
CellStyle cellStyle = wb.createCellStyle();
Font font = wb.createFont();
cellStyle.setFillForegroundColor((short) 12);
cellStyle.setFillPattern(CellStyle.SOLID_FOREGROUND);// 填充模式
cellStyle.setBorderTop(CellStyle.BORDER_THIN);// 上边框为细边框
cellStyle.setBorderRight(CellStyle.BORDER_THIN);// 右边框为细边框
cellStyle.setBorderBottom(CellStyle.BORDER_THIN);// 下边框为细边框
cellStyle.setBorderLeft(CellStyle.BORDER_THIN);// 左边框为细边框
cellStyle.setAlignment(CellStyle.ALIGN_LEFT);// 对齐
cellStyle.setFillForegroundColor(HSSFColor.GREEN.index);
cellStyle.setFillBackgroundColor(HSSFColor.GREEN.index);
font.setBoldweight(Font.BOLDWEIGHT_NORMAL);
// font.setFontHeightInPoints((short) 12);// 字体大小
font.setColor(HSSFColor.WHITE.index);
// 应用标题字体到标题样式
cellStyle.setFont(font);
return cellStyle;
}
@Override
public String exportFileName(String sheetName) {
return String.format("导出-%s-%s", sheetName, System.currentTimeMillis());
}
}, out);
}
public boolean toExcel(List> data, String sheetName, ExportHandler handler, OutputStream out) {
required$BuilderParams();
long begin = System.currentTimeMillis();
if (data == null || data.size() < 1) {
log.error("没有检测到数据,不执行导出操作。");
return false;
}
log.info(String.format("即将导出excel数据:%s条,请稍后..", data.size()));
// 导出列查询。
ExportConfig currentExportConfig = null;
ExportItem currentExportItem = null;
List exportItems = new ArrayList();
for (Field field : mClass.getDeclaredFields()) {
currentExportConfig = field.getAnnotation(ExportConfig.class);
if (currentExportConfig != null) {
currentExportItem = new ExportItem()
.setField(field.getName())
.setDisplay("field".equals(currentExportConfig.value()) ? field.getName() : currentExportConfig.value())
.setWidth(currentExportConfig.width())
.setConvert(currentExportConfig.convert())
.setColor(currentExportConfig.color())
.setReplace(currentExportConfig.replace());
exportItems.add(currentExportItem);
}
currentExportItem = null;
currentExportConfig = null;
}
// 创建新的工作薄。
SXSSFWorkbook wb = POIUtils.newSXSSFWorkbook();
double sheetNo = Math.ceil(data.size() / mMaxSheetRecords);// 取出一共有多少个sheet.
// =====多sheet生成填充数据=====
for (int index = 0; index <= (sheetNo == 0.0 ? sheetNo : sheetNo - 1); index++) {
SXSSFSheet sheet = POIUtils.newSXSSFSheet(wb, sheetName + (index == 0 ? "" : "_" + index));
// 创建表头
SXSSFRow headerRow = POIUtils.newSXSSFRow(sheet, 0);
for (int i = 0; i < exportItems.size(); i++) {
SXSSFCell cell = POIUtils.newSXSSFCell(headerRow, i);
POIUtils.setColumnWidth(sheet, i, exportItems.get(i).getWidth(), exportItems.get(i).getDisplay());
cell.setCellValue(exportItems.get(i).getDisplay());
CellStyle style = handler.headCellStyle(wb);
if (style != null) {
cell.setCellStyle(style);
}
}
// 产生数据行
if (data != null && data.size() > 0) {
int startNo = index * mMaxSheetRecords;
int endNo = Math.min(startNo + mMaxSheetRecords, data.size());
for (int i = startNo; i < endNo; i++) {
SXSSFRow bodyRow = POIUtils.newSXSSFRow(sheet, i + 1 - startNo);
for (int j = 0; j < exportItems.size(); j++) {
// 处理单元格值
String cellValue = exportItems.get(j).getReplace();
if ("".equals(cellValue)) {
try {
cellValue = BeanUtils.getProperty(data.get(i), exportItems.get(j).getField());
} catch (Exception e) {
log.error("获取" + exportItems.get(j).getField() + "的值失败.", e);
}
}
// 格式化单元格值
if (!"".equals(exportItems.get(j).getConvert())) {
cellValue = convertCellValue(Integer.parseInt(cellValue), exportItems.get(j).getConvert());
}
// 单元格宽度
POIUtils.setColumnWidth(sheet, j, exportItems.get(j).getWidth(), cellValue);
SXSSFCell cell = POIUtils.newSXSSFCell(bodyRow, j);
// fix: 当值为“”时,当前index的cell会失效
cell.setCellValue("".equals(cellValue) ? null : cellValue);
CellStyle style = wb.createCellStyle();
Font font = wb.createFont();
font.setColor(exportItems.get(j).getColor());
style.setFont(font);
cell.setCellStyle(style);
}
}
}
}
try {
// 生成Excel文件并下载.(通过response对象是否为空来判定是使用浏览器下载还是直接写入到output中)
POIUtils.writeByLocalOrBrowser(mResponse, handler.exportFileName(sheetName), wb, out);
} catch (Exception e) {
log.error("生成Excel文件失败:" + e.getMessage(), e);
return false;
}
log.info(String.format("Excel处理完成,共生成数据:%s行 (不包含表头),耗时:%s seconds.", (data != null ? data.size() : 0),
(System.currentTimeMillis() - begin) / 1000F));
return true;
}
/**
* 读取Excel数据(使用SAX的方式进行解析,读取所有Sheet数据)
*
* @param excelFile
* excel文件
* @param handler
* 数据处理回调
*/
public void readExcel(File excelFile, ReadHandler handler) {
this.readExcel(excelFile, -1, handler);
}
/**
* 读取Excel(使用SAX的方式进行解析,读取指定Sheet数据)
*
* @param excelFile
* excel文件
* @param sheetIndex
* sheet索引,-1为读取所有
* @param handler
* 数据处理回调
*/
public void readExcel(File excelFile, int sheetIndex, ReadHandler handler) {
long begin = System.currentTimeMillis();
String fileName = excelFile.getAbsolutePath();
XlsxReader reader = new XlsxReader(handler).setEmptyCellValue(mEmptyCellValue);
try {
if (sheetIndex >= 0) {
// 读取指定sheet
reader.process(fileName, sheetIndex);
} else {
// 读取所有sheet
reader.process(fileName);
}
} catch (Exception e) {
log.error("读取excel文件时发生异常:" + e.getMessage(), e);
}
log.info(String.format("Excel读取并处理完成,耗时:%s seconds.",(System.currentTimeMillis() - begin) / 1000F));
}
// convertCellValue: number to String (beta)
private String convertCellValue(Integer oldValue, String format) {
try {
String protocol = format.split(":")[0];
// 键值对字符串解析:s:1=男,2=女
if ("s".equalsIgnoreCase(protocol)) {
String[] pattern = format.split(":")[1].split(",");
for (String p : pattern) {
String[] cp = p.split("=");
if (Integer.parseInt(cp[0]) == oldValue) {
return cp[1];
}
}
}
// 使用处理类进行处理:c:org.wuwz.poi.test.GradeCellFormat
if ("c".equalsIgnoreCase(protocol)) {
String clazz = format.split(":")[1];
ExportConvert export = mConvertInstanceCache.get(clazz);
if (export == null) {
export = (ExportConvert) Class.forName(clazz).newInstance();
mConvertInstanceCache.put(clazz, export);
}
if (mConvertInstanceCache.size() > 10)
mConvertInstanceCache.clear();
return export.handler(oldValue);
}
} catch (Exception e) {
log.error("出现问题,可能是@ExportConfig.format()的值不规范导致。", e);
}
return String.valueOf(oldValue);
}
private void required$BuilderParams() {
if (mClass == null) {
throw new IllegalArgumentException("请先使用org.wuwz.poi.ExcelKit.$Builder(Class>)构造器初始化参数。");
}
}
private void required$ExportParams() {
if (mClass == null || mResponse == null) {
throw new IllegalArgumentException(
"请先使用org.wuwz.poi.ExcelKit.$Export(Class>, HttpServletResponse)构造器初始化参数。");
}
}
}