问题现象
1、对于日期类型
excel做筛选后应该支持按年、月、日筛选,而easyexcel 按注解 @DateTimeFormat(“yyyy-MM-dd”) 实现后虽然呈现格式上没问题,但是单元格格式还是存在问题导致筛选后不正常,具体如图效果:
1.1 excel对日期类型筛选后正常现象
1.2 easyexcel导出后对日期类型筛选后异常现象
补充现象:
easyexcel 导出后默认是未双击效果,上面得筛选结果就是未双击这版格式
如果鼠标左键双击后,excel就会自动转换正常得日期格式,就能筛选了。
本次咱们通过程序解决这个问题。
PS:即使在excel手动设置单元格格式也不生效,所以只能程序解决!
2、对于金额类型
呈现效果类似上面日期问题,也是导出默认得格式不是真正得数值类型,做合计得时候无法合计。
PS:即使在excel手动设置单元格格式也不生效,所以只能程序解决!
2.1 程序解决方案
实现一个注册一个自定义handler,implements CellWriteHandler 即
.registerWriteHandler(new OrderCellHandler())
/**
* 导出 Excel :一个 sheet,带表头.
*
* @param response HttpServletResponse
* @param data 数据 list,每个元素为一个 BaseRowModel
* @param fileName 导出的文件名
* @param sheetName 导入文件的 sheet 名
* @param clazz 映射实体类,Excel 模型
* @throws Exception 异常
*/
public static <T> void writeExcelWithColumnNames(HttpServletResponse response, String fileName, String sheetName, List<T> data, Class<T> clazz, List<String> columnNames) throws Exception {
// 这里注意 有同学反应使用swagger 会导致各种问题,请直接用浏览器或者用postman
try {
response.setContentType("application/vnd.ms-excel");
response.setCharacterEncoding("utf-8");
response.setHeader("Content-disposition", "attachment;filename=" + fileName + ".xlsx");
// 这里需要设置不关闭流
EasyExcelFactory.write(response.getOutputStream(), clazz)
.registerWriteHandler(new OrderCellHandler())
.includeColumnFiledNames(columnNames)
.autoCloseStream(Boolean.FALSE)
.sheet(sheetName)
.doWrite(data);
} catch (Exception e) {
String message = "下载文件失败" + e.getMessage();
log.error(message, e);
}
}
2.2 实现类 OrderCellHandler.java
package com.fawm.base.config.easy.excel.write.handler;
import com.alibaba.excel.metadata.CellData;
import com.alibaba.excel.metadata.Head;
import com.alibaba.excel.write.handler.CellWriteHandler;
import com.alibaba.excel.write.metadata.holder.WriteSheetHolder;
import com.alibaba.excel.write.metadata.holder.WriteTableHolder;
import com.fawm.base.utils.CommonDateUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.poi.ss.usermodel.*;
import java.text.ParseException;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
/**
* 订单导出处理日期格式与金额类
*
* @author liumingxing
*/
public class OrderCellHandler implements CellWriteHandler {
@Override
public void beforeCellCreate(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, Row row, Head head, Integer columnIndex, Integer relativeRowIndex, Boolean isHead) {
}
@Override
public void afterCellCreate(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, Cell cell, Head head, Integer relativeRowIndex, Boolean isHead) {
}
@Override
public void afterCellDispose(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, List<CellData> cellDataList, Cell cell, Head head, Integer relativeRowIndex, Boolean isHead) {
boolean columnTwoFlag = cell.getColumnIndex() == 2;
boolean otherDateFlag = cell.getColumnIndex() >= 65 && cell.getColumnIndex() <= 71;
boolean dateFlag = columnTwoFlag || otherDateFlag;
int[] moneyColumnIndex = {8, 9, 10, 11, 51, 52, 53, 55, 57, 59, 61, 62, 64};
int matchMoney = Arrays.stream(moneyColumnIndex).filter(item -> item == cell.getColumnIndex()).findAny().orElse(-1);
boolean moneyColumnFlag = matchMoney != -1;
boolean finalFlag = dateFlag || moneyColumnFlag;
if (!isHead && finalFlag) {
Workbook workbook = writeSheetHolder.getSheet().getWorkbook();
CellStyle cellStyle = workbook.createCellStyle();
String stringCellValue = cell.getStringCellValue();
try {
CreationHelper createHelper = workbook.getCreationHelper();
if (StringUtils.isNotBlank(stringCellValue) && dateFlag) {
String[] patterns = {"yyyy-MM-dd HH:mm:ss", "yyyy-MM-dd"};
Date date = CommonDateUtils.parseDate(stringCellValue, patterns);
if (columnTwoFlag) {
//订单生成日期
cellStyle.setDataFormat(createHelper.createDataFormat().getFormat("m/d/yy h:mm:ss"));
} else {
//其他日期列
cellStyle.setDataFormat(createHelper.createDataFormat().getFormat("m/d/yy"));
}
cell.setCellStyle(cellStyle);
cell.setCellValue(date);
} else if (StringUtils.isNotBlank(stringCellValue) && moneyColumnFlag) {
//其他金额列
Float money = Float.parseFloat(stringCellValue);
cellStyle.setDataFormat(createHelper.createDataFormat().getFormat("#,##0.00"));
cell.setCellStyle(cellStyle);
cell.setCellValue(money);
}
} catch (ParseException e) {
e.printStackTrace();
}
}
}
}
3、导出超过500条与导出后显示文件损毁问题
当实现上面的功能后,经过测试验证,偶发的出现下面这个问题,显示文件损毁而不能打开
。后来经过排查主要是两方面原因:
- 一是对日期、金额类型的列做转换时是按照列 index 索引指定处理转换的。而在我这个项目中,每个用户角色列头权限不一样,所以固定指 index 就会出现把非日期的列转为日期类型,非数值的列转为数值类型,进而导致 excel 格式损坏;
- 二是此方法实现转换时,数据量超过500时,会会自动 flush 刷新缓存,表头会丢失,进而报错。
下面针对这两种情况进行处理(最后付全部代码,先单独解释)
3.1 index 索引定向指定,取消 index 指向方式
很简单,通过列名判断,而不是 index 判断(不是最好的方法,但是可以解决诉求了而且不会出问题)
/**
* 需要处理日期和金额的列名
*/
String[] moneyColumns = {"保证金", "市场指导价", "员工购车价", "员工支付价", "开发票金额", "销售方案总金额", "购置税", "交强险", "车船税",
"商业险", "精品", "汽油费", "其他费用"};
/**
* 需要处理的日期+时间列名
*/
String[] dateTimeColumns = {"订单生成时间"};
/**
* 需要出列的日期列名
*/
String[] dateColumns = {"订单日期", "保证金到账日期", "首付款/全款到账时间", "尾款到账时间", "开票日期", "初次配车日期", "实际出库日期"};
//是否是日期加时间
boolean columnTwoFlag = StringUtils.isNotBlank(Arrays.stream(dateTimeColumns).filter(item -> item.equals(columnName)).findAny().orElse(""));
//是否是日期
boolean otherDateFlag = StringUtils.isNotBlank(Arrays.stream(dateColumns).filter(item -> item.equals(columnName)).findAny().orElse(""));
boolean dateFlag = columnTwoFlag || otherDateFlag;
//是否是金额
boolean moneyColumnFlag = StringUtils.isNotBlank(Arrays.stream(moneyColumns).filter(item -> item.equals(columnName)).findAny().orElse(""));
boolean finalFlag = dateFlag || moneyColumnFlag;
3.2 数据量超过500时,刷新缓存表头会丢失问题处理
方案: 先缓存一下所有列头
/**
* 列名存储列表
* 数据量超过500时,会刷新缓存,表头会丢失,所以要存一下,以便查找
*/
private static final List<String> COLUMNS = new ArrayList<>();
/**
* 初始化参数
*/
public OrderCellHandler() {
COLUMNS.clear();
dateTimeStyle = null;
dateStyle = null;
moneyStyle = null;
}
if (isHead != null && isHead) {
//获取表头,存储起来
COLUMNS.add(cell.getStringCellValue());
} else if (isHead != null) {
// 结合第一步定义的需要处理的列名 moneyColumns、dateTimeColumns、dateColumns 动态判断
String columnName = COLUMNS.get(cell.getColumnIndex());
}
3.3 附最新全部代码 OrderCellHandler.java
package com.fawm.base.config.easy.excel.write.handler;
import com.alibaba.excel.metadata.CellData;
import com.alibaba.excel.metadata.Head;
import com.alibaba.excel.write.handler.CellWriteHandler;
import com.alibaba.excel.write.metadata.holder.WriteSheetHolder;
import com.alibaba.excel.write.metadata.holder.WriteTableHolder;
import com.fawm.base.utils.CommonDateUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.time.DateUtils;
import org.apache.poi.ss.usermodel.*;
import java.text.ParseException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
/**
* 订单导出处理日期格式与金额类
*
* @author liumingxing
*/
@Slf4j
public class OrderCellHandler implements CellWriteHandler {
/**
* 需要处理日期和金额的列名
*/
String[] moneyColumns = {"保证金", "市场指导价", "员工购车价", "员工支付价", "开发票金额", "销售方案总金额", "购置税", "交强险", "车船税",
"商业险", "精品", "汽油费", "其他费用"};
/**
* 需要处理的日期+时间列名
*/
String[] dateTimeColumns = {"订单生成时间"};
/**
* 需要出列的日期列名
*/
String[] dateColumns = {"订单日期", "保证金到账日期", "首付款/全款到账时间", "尾款到账时间", "开票日期", "初次配车日期", "实际出库日期"};
/**
* 列名存储列表
* 数据量超过500时,会刷新缓存,表头会丢失,所以要存一下,以便查找
*/
private static final List<String> COLUMNS = new ArrayList<>();
/**
* 时间+日期样式存储
* 一个excel的sheet页,最多可以创建64000个样式,频繁创建会倒是程序报错
*/
private CellStyle dateTimeStyle;
/**
* 时间样式存储
* 一个excel的sheet页,最多可以创建64000个样式,频繁创建会倒是程序报错
*/
private CellStyle dateStyle;
/**
* 金额样式存储
* 一个excel的sheet页,最多可以创建64000个样式,频繁创建会倒是程序报错
*/
private CellStyle moneyStyle;
/**
* 初始化参数
*/
public OrderCellHandler() {
COLUMNS.clear();
dateTimeStyle = null;
dateStyle = null;
moneyStyle = null;
}
@Override
public void beforeCellCreate(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, Row row, Head head, Integer columnIndex, Integer relativeRowIndex, Boolean isHead) {
}
@Override
public void afterCellCreate(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, Cell cell, Head head, Integer relativeRowIndex, Boolean isHead) {
}
@Override
public void afterCellDispose(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, List<CellData> cellDataList, Cell cell, Head head, Integer relativeRowIndex, Boolean isHead) {
//获取表头,存储起来
if (isHead != null && isHead) {
COLUMNS.add(cell.getStringCellValue());
} else if (isHead != null) {
String columnName = COLUMNS.get(cell.getColumnIndex());
//是否是日期加时间
boolean columnTwoFlag = StringUtils.isNotBlank(Arrays.stream(dateTimeColumns).filter(item -> item.equals(columnName)).findAny().orElse(""));
//是否是日期
boolean otherDateFlag = StringUtils.isNotBlank(Arrays.stream(dateColumns).filter(item -> item.equals(columnName)).findAny().orElse(""));
boolean dateFlag = columnTwoFlag || otherDateFlag;
//是否是金额
boolean moneyColumnFlag = StringUtils.isNotBlank(Arrays.stream(moneyColumns).filter(item -> item.equals(columnName)).findAny().orElse(""));
boolean finalFlag = dateFlag || moneyColumnFlag;
if (finalFlag) {
Workbook workbook = writeSheetHolder.getSheet().getWorkbook();
String stringCellValue = cell.getStringCellValue();
try {
CreationHelper createHelper = workbook.getCreationHelper();
if (StringUtils.isNotBlank(stringCellValue) && dateFlag) {
String[] patterns = {"yyyy-MM-dd HH:mm:ss", "yyyy-MM-dd"};
Date date = DateUtils.parseDate(stringCellValue, patterns);
if (columnTwoFlag) {
//订单生成日期
if (dateTimeStyle == null) {
dateTimeStyle = workbook.createCellStyle();
}
dateTimeStyle.setDataFormat(createHelper.createDataFormat().getFormat("yyyy/mm/dd hh:mm:ss"));
cell.setCellStyle(dateTimeStyle);
} else {
//其他日期列
if (dateStyle == null) {
dateStyle = workbook.createCellStyle();
}
dateStyle.setDataFormat(createHelper.createDataFormat().getFormat("yyyy/mm/dd"));
cell.setCellStyle(dateStyle);
}
cell.setCellValue(date);
} else if (StringUtils.isNotBlank(stringCellValue) && moneyColumnFlag) {
//其他金额列
double money = Double.parseDouble(stringCellValue);
if (moneyStyle == null) {
moneyStyle = workbook.createCellStyle();
}
moneyStyle.setDataFormat(createHelper.createDataFormat().getFormat("0.00"));
cell.setCellStyle(moneyStyle);
cell.setCellValue(money);
}
} catch (ParseException e) {
log.info("导出订单信息时出现错误:值:{},行:{},列:{}", stringCellValue, cell.getRow().getRowNum(), cell.getColumnIndex());
cell.setCellValue("");
}
}
}
}
}
4、抽出公共handler避免一个功能写一个handler
前面写的方案局限性在于一个handler只能给一个导出功能使用,如果系统中存在多个业务模块有导出功能,就得写多个handler,很不方便,这里我把handler抽象出来,调用端仅需要对需要处理的字段传入即可。
另外对数值类型转换报错原因补充:只有dto中定义的数值字段为string类型时,excel导出才会有格式问题,如果dto中定义的字段为double或integer则不需要转换,easyexcel会按正常格式导出。所以大家传入需要转换的列名时需要判断一下dto里的类型是否是string类型(我程序中也做兼容了,不过最好还是人为判断一下,不然后台一直在吞异常)
4.1 调用端组装需要转换的参数 map 传入
/**
* 导出发车明细列表
*
* @param response
* @param query
*/
@ApiOperation("导出发车明细列表")
@GetMapping(path = "export/departDetail")
public void exportDepartDetail(HttpServletResponse response, StatisticalQuery query) {
List<DepartDetailStatisticsDto> departDetailList = planBillboardService
.departDetail(query, null);
try {
/**
* dateTimeColumns:将需要转换单元格格式的日期、数值类型传入 handler(仅需要对导出的 excel 日期筛选以及数值合计有问题的列传入即可,没问题的列可以不用传入)
* dateColumns:此功能导出的都待时间,没有导年月日的,不用处理
* numberColumns:此功能 dto 中定义的数值类型都是 double ,不是string, 所以导出后正常不用特人数处理
*/
Map<String, Object> map = new HashMap<>(3);
map.put("dateTimeColumns", new String[]{"入库日期","倒运日期","PDI日期","交钥匙日期","交合格证日期","实车出库日期"});
map.put("dateColumns", new String[]{});
map.put("numberColumns", new String[]{});
EasyExcelUtil.writeCommonExcel(response, "" + System.currentTimeMillis(), CommonConst.SHEET,
departDetailList, DepartDetailStatisticsDto.class, map);
} catch (Exception e) {
e.printStackTrace();
}
}
4.2 工具类 EasyExcelUtil.writeCommonExcel()取map并注册公共handler
.registerWriteHandler(new CommonExcelCellHandler(map))
- 1、传入dto calzz 方式
/**
* 导出 Excel :一个 sheet,带日期、数值类型单元格转换.
* @param response
* @param fileName
* @param sheetName
* @param data
* @param clazz
* @param map
* @param <T>
* @throws Exception
*/
public static <T> void writeCommonExcel(HttpServletResponse response, String fileName, String sheetName, List<T> data, Class<T> clazz,
Map<String, Object> map) throws Exception {
// 这里注意 有同学反应使用swagger 会导致各种问题,请直接用浏览器或者用postman
try {
response.setContentType("application/vnd.ms-excel");
response.setCharacterEncoding("utf-8");
response.setHeader("Content-disposition", "attachment;filename=" + fileName + ".xlsx");
// 没有传入特殊处理的列,避免 handler 初始化报错
if (map == null || map.size() == 0){
map.put("dateTimeColumns", new String[0]);
map.put("dateColumns", new String[0]);
map.put("numberColumns", new String[0]);
}
EasyExcel.write(response.getOutputStream(), clazz)
.registerWriteHandler(
new CommonExcelCellHandler(map))
.autoCloseStream(Boolean.FALSE)
.sheet(sheetName)
.doWrite(data);
} catch (Exception e) {
String message = "下载文件失败" + e.getMessage();
log.error(message, e);
}
}
- 2、传入列名集合方式
/**
* 导出数据到请求当中,含格式转换handler
* @param response
* @param data 数据对象
* @param sheetName sheet 页名称
* @param map 需要转换的列名集合,分三类
*/
public static void exportWithHandler(HttpServletResponse response, List<String[]> data, String sheetName, Map<String, Object> map) {
try {
response.setContentType("application/vnd.ms-excel");
response.setCharacterEncoding("utf-8");
response.setHeader("Content-disposition", "attachment;filename=" + System.currentTimeMillis() + EXCEL_SUFFIX);
EasyExcelDataVo easyExcelDataVo = new EasyExcelDataVo(data).invoke();
List<List<String>> headList = easyExcelDataVo.getHeadList();
List<List<String>> dataList = easyExcelDataVo.getDataList();
if (StringUtils.isEmpty(sheetName)) {
sheetName = DEFAULT_SHEET_NAME;
}
EasyExcelFactory.write(response.getOutputStream())
.registerWriteHandler(new CommonExcelCellHandler(map))
.head(headList)
.sheet(sheetName)
.doWrite(dataList);
} catch (Exception e) {
if (e.getCause() instanceof ClientAbortException) {
log.warn("创建Excel文件过程中,客户端中断了链接");
return;
}
log.error(CommonConst.UNKNOWN_EXCEPTION, e);
throw new ApiException(InfoCode.FAIL, "创建Excel文件过程中发生未知错误");
}
}
4.3 公共handler代码(含对列宽的处理)
package com.fawm.base.config.easy.excel.write.handler;
import com.alibaba.excel.metadata.CellData;
import com.alibaba.excel.metadata.Head;
import com.alibaba.excel.write.handler.CellWriteHandler;
import com.alibaba.excel.write.metadata.holder.WriteSheetHolder;
import com.alibaba.excel.write.metadata.holder.WriteTableHolder;
import com.fawm.base.exception.ApiException;
import java.text.ParseException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.Map;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.time.DateUtils;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.CellStyle;
import org.apache.poi.ss.usermodel.CreationHelper;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Workbook;
/**
* Excel 导出处理日期格式与数值类型 调用端需要将三个参数 dateColumns、dateTimeColumns、numberColumns 传进来,构造方法进行初始化 注意:仅需要对导出的
* excel 日期筛选以及数值合计有问题的列传入即可,没问题的列可以不用传入 数值类型有问题的,主要原因是 dto 里定义的是 String 类型导致,如果是 double 与 Integer
* 类型则正常导出不需要传入处理
*
* @author liumingxing
*/
@Slf4j
public class CommonExcelCellHandler implements CellWriteHandler {
/**
* 列名存储列表 数据量超过500时,会刷新缓存,表头会丢失,所以要存一下,以便查找
*/
private static final List<String> COLUMNS = new ArrayList<>();
/**
* 时间+日期样式存储 一个excel的sheet页,最多可以创建64000个样式,频繁创建会倒是程序报错
*/
private CellStyle dateTimeStyle;
/**
* 时间样式存储 一个excel的sheet页,最多可以创建64000个样式,频繁创建会倒是程序报错
*/
private CellStyle dateStyle;
/**
* 金额样式存储 一个excel的sheet页,最多可以创建64000个样式,频繁创建会倒是程序报错 数值类型有问题的,主要原因是 dto 里定义的是 String 类型导致,如果是
* double 与 Integer 类型则正常导出不需要传入处理
*/
private CellStyle numberStyle;
/**
* 需要处理日期列名
*/
private Object dateColumns;
/**
* 需要处理日期含时间的列名
*/
private Object dateTimeColumns;
/**
* 需要处理数值的列名
*/
private Object numberColumns;
/**
* 列宽时需要乘256
*/
private Integer widthCommon = 256;
/**
* 初始化参数 注意:数值类型传入前提是列dto里数值类型的字段定义的是字符串类型(如果定义的是double或intger则不需要转换)
*
* @param map 传入需要特殊处理的三个类型 dateColumns、dateTimeColumns、numberColumns
*/
public CommonExcelCellHandler(Map<String, Object> map) {
COLUMNS.clear();
dateTimeStyle = null;
dateStyle = null;
numberStyle = null;
this.dateColumns = map.get("dateColumns");
this.dateTimeColumns = map.get("dateTimeColumns");
this.numberColumns = map.get("numberColumns");
}
@Override
public void beforeCellCreate(WriteSheetHolder writeSheetHolder,
WriteTableHolder writeTableHolder, Row row, Head head, Integer columnIndex,
Integer relativeRowIndex, Boolean isHead) {
}
@Override
public void afterCellCreate(WriteSheetHolder writeSheetHolder,
WriteTableHolder writeTableHolder, Cell cell, Head head, Integer relativeRowIndex,
Boolean isHead) {
}
@Override
public void afterCellDispose(WriteSheetHolder writeSheetHolder,
WriteTableHolder writeTableHolder, List<CellData> cellDataList, Cell cell, Head head,
Integer relativeRowIndex, Boolean isHead) {
// 列宽
int width = 20;
if (isHead != null && isHead) {
//获取表头,存储起来,否则但数据超过500时会 flush 导致列名丢失报错
COLUMNS.add(cell.getStringCellValue());
} else if (isHead != null) {
// 当前列名
String columnName = COLUMNS.get(cell.getColumnIndex());
//是否是日期加时间
boolean dateTimeFlag = StringUtils.isNotBlank(Arrays.stream(
(String[]) dateTimeColumns).filter(item -> item.equals(columnName)).findAny()
.orElse(""));
//是否是日期
boolean dateFlag = StringUtils.isNotBlank(
Arrays.stream((String[]) dateColumns).filter(item -> item.equals(columnName))
.findAny().orElse(""));
//是否是数值(前提:要处理的列dto里得是字符串类型)
boolean numberColumnFlag = StringUtils.isNotBlank(
Arrays.stream((String[]) numberColumns).filter(item -> item.equals(columnName))
.findAny().orElse(""));
// 日期类标识
boolean dateFlags = dateTimeFlag || dateFlag;
if (dateFlags || numberColumnFlag) {
Workbook wk = writeSheetHolder.getSheet().getWorkbook();
String stringCellValue = null;
try {
stringCellValue = cell.getStringCellValue();
} catch (Exception e) {
// double或integer 类型数值不需要转换单元格格式,前端不要传入,后台直接去掉转换解决!
dateFlags = false;
}
try {
CreationHelper createHelper = wk.getCreationHelper();
if (StringUtils.isNotBlank(stringCellValue) && dateFlags) {
String[] patterns = {"yyyy-MM-dd HH:mm:ss", "yyyy-MM-dd"};
Date date = DateUtils.parseDate(stringCellValue, patterns);
if (dateTimeFlag) {
//订单生成日期
if (dateTimeStyle == null) {
dateTimeStyle = wk.createCellStyle();
}
dateTimeStyle.setDataFormat(createHelper.createDataFormat()
.getFormat("yyyy/mm/dd hh:mm:ss"));
cell.setCellStyle(dateTimeStyle);
} else {
//其他日期列
width = 15;
if (dateStyle == null) {
dateStyle = wk.createCellStyle();
}
dateStyle.setDataFormat(
createHelper.createDataFormat().getFormat("yyyy/mm/dd"));
cell.setCellStyle(dateStyle);
}
cell.setCellValue(date);
} else if (StringUtils.isNotBlank(stringCellValue) && numberColumnFlag && isNumber(stringCellValue)) {
//其他数值列(数值类型有问题的,主要原因是 dto 里定义的是 String 类型导致,如果是 double 与 Integer 类型则正常导出不需要传入处理)
width = 11;
double money = Double.parseDouble(stringCellValue);
if (numberStyle == null) {
numberStyle = wk.createCellStyle();
}
numberStyle
.setDataFormat(createHelper.createDataFormat().getFormat("0.00"));
cell.setCellStyle(numberStyle);
cell.setCellValue(money);
}
// 统一处理列宽
int columnWidth = writeSheetHolder.getSheet()
.getColumnWidth(cell.getColumnIndex());
if (columnWidth < width * widthCommon) {
writeSheetHolder.getSheet()
.setColumnWidth(cell.getColumnIndex(), width * widthCommon);
}
} catch (ParseException e) {
log.info("导出信息时出现错误:值:{},行:{},列:{}", stringCellValue,
cell.getRow().getRowNum(), cell.getColumnIndex());
cell.setCellValue("");
}
}
}
}
/**
* 判断一个字符串是否是数字。
*
* @param value
* @return
*/
public static boolean isNumber(String value) {
String regex = "^-?\\d+(\\.\\d+)?$";
Pattern pattern = Pattern.compile(regex);
return pattern.matcher(value).matches();
}
}