excel工具类对poi的封装,所以需要导入poi的依赖,我用的是4.1.0版本,如果是4以下,工具里面的poi的相关api需要改变;
导入/导出支持:一对多合并(不限制层级数,但每个类只能有一个子集)、必填字段检测(读取的时候能用到)、排序(导出能用到)、动态隐藏字段(导入导出会忽略该字段)
<dependencies>
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi</artifactId>
<version>4.1.0</version>
</dependency>
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-ooxml</artifactId>
<version>4.1.0</version>
</dependency>
name : 用作excel列名
isSon :用作判断是否是子集(默认false,如果有子集,在子集成员变量上标注: @IExcel(isSon = true))
hiddenField :隐藏字段(默认为:false,当为true时,导入导出会忽略该字段,用法: IExcelUtils.hideColumn( clazz,columnName, target),参数依次为:需要修改的class对象、需要修改的字段名、修改的值,也就是true/false),
注意 :IExcelUtils.hideColumn()方法需要用在导入导出前才有效
sortNo : 排序号(默认为0,不进行排序,如果需要排序,在字段上标注@IExcel(sortNo=正整数),从1开始排序)
注意:如果有子集,子集也是从1开始排序
isNotBlank : 设置字段不为空(默认false;在导入时,如果希望某个字段必填不然该条数据就不要读取,就需要在该字段上标注:@IExcel(isNotBlank=true);如需要获取没有读取的字段信息,用 IExcelUtils.getErrRowInfo()方法可以获取到)
booleanFormatter :布尔类型字段转换(处理布尔值的转换,注意:请将表示true的标识写在分割符"|“的左边,表示false的标识写在分割符“|”的右边 ;默认"是|否”)
dateFormat :日期转换(默认:“yyyy/MM/dd”;导入导出时,日期格式化)
package com.ph.excel.annotation;
import com.ph.excel.IExcelUtils;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* excel
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface IExcel {
/**
* 列名称,不能重复
* @return
*/
String name() default "";
/**
* 是否是子集
* @return
*/
boolean isSon() default false;
/**
* 隐藏字段
* @return
*/
boolean hiddenField() default false;
/**
* 排序号
* @return
*/
int sortNo() default 0;
/**
* 字段必填,不为空
* @return
*/
boolean isNotBlank() default false;
//处理布尔值的转换,注意:请将表示true的标识写在分割符"|"的左边,表示false的标识写在分割符“|”的右边 ;默认"是|否"
String booleanFormatter() default "是|否";
/**
* 日期格式化
* @return
*/
String dateFormat() default IExcelUtils.IEXCEL_DATE_DEFAULT_FORMAT;
}
package com.ph.excel;
import com.ph.excel.annotation.IExcel;
import com.sun.istack.internal.NotNull;
import org.apache.poi.hssf.usermodel.HSSFDateUtil;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.ss.util.CellRangeAddress;
import org.apache.poi.xssf.usermodel.*;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.lang.reflect.*;
import java.math.BigDecimal;
import java.net.URLEncoder;
import java.text.DecimalFormat;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicReference;
import java.util.stream.Collectors;
import java.util.stream.Stream;
/**
* @ClassName: IExcelUtils
* @Description: 读取或导出excel工具类
* @Date: 2023/6/1 9:57
* @author: ph9527
* @version: 1.0
*/
public class IExcelUtils {
/**
* 获取获取大标题行数时循环的行数
*/
private final static Integer FIND_TITLE_SIZE = 10;
/**
* IExcel与当前exceldate类型共有的日期格式
*/
public final static String IEXCEL_DATE_DEFAULT_FORMAT = "yyyy/MM/dd";
/**
* 处理布尔值的转换,注意:请将表示true的标识写在分割符"|"的左边,表示false的标识写在分割符“|”的右边 ;默认"是|否"
*/
public final static String IEXCEL_BOOLEAN_TRUE_DEFAULT_FLAG = "\\|";
/**
* 默认标题合并列
*/
public final static int Excel_DEFAULT_TITLE_MERGERNUM = 6;
/**
* 因缺失必填字段为读取的数据信息
*/
private static List<BlankRowInfo> errRowInfo;
/**
* excel映射顶级对象class
*/
private static Class clazz;
static class ClassVoIExcelEntity {
/**
* 当前所属对象class
*/
private Class clazz;
private Class parentClass;
//当前等级
private Integer levelIndex;
/**
* 所有标注IExcel注解的各属性值
*/
private List<ClassVoFieldIExcel> fields;
/**
* 标注IExcel的子集
*/
private ClassVoIExcelEntity sonClassVo;
}
static class ClassVoFieldIExcel {
private String classVoFieldName;
private IExcel iExcel;
}
private static class CellTitleValueEntity {
private String cellTitleName;
private Integer cellIndex;
//在当前行字段对应对象的第一个元素
private boolean isExcelObjFirstField;
//在当前行字段对应对象的最后一个元素
private boolean isExcelObjLastField;
}
private static class MergedRowInfo {
private Boolean isMerge;
private Integer firstRow;
private Integer lastRow;
}
public static class BlankRowInfo {
//缺失信息的行号
public Long rowNo;
//当前对象级别
public Integer objLevel;
//缺失信息的列名
public List<String> blankTitleNames;
}
private static class ExportColumn {
private String excelColumnName;
private String value;
}
private static class ExportRow {
private List<ExportColumn> values;
private List<ExportRow> sons;
private Integer levelIndex;
private Integer mergeNum;
}
private static class TitleEntity {
private String name;
private Integer sortNo;
}
/**
* 读取excel文件
*
* @param inputStream 前端上传到后端的文件用的是MultipartFile接收,免得转File,就用inputStream做参数
* @param fileName 文件名,必填,需要根据文件名判断是否是excel文件以及判断是xlsx或者xls,直接用file.getName()就行了
* @param sourceClass
* @param
* @return
*/
public static <T> List<T> readExcel(@NotNull InputStream inputStream, @NotNull String fileName, @NotNull Class<T> sourceClass) {
//初始化
clazz = null;
List<T> data = new ArrayList<>();
Workbook wb = null;
try {
//检测是否是excel文件
if (!isExcelFile(fileName)) {
throw new RuntimeException("当前文件不是excel文件");
}
//检测是否是xlsx,如果文件名为空,则默认xlsx
wb = isXlsx(fileName) ? new XSSFWorkbook(inputStream) : new HSSFWorkbook(inputStream);
} catch (Exception e) {
data = new ArrayList<>();
throw new RuntimeException("excel文件解析错误:" + e);
}
if (wb != null) {
//给顶级对象赋值
clazz = sourceClass;
errRowInfo = new ArrayList<>();
Sheet sheet0 = wb.getSheetAt(0);
int lastRowNum = sheet0.getLastRowNum();
//总行数小于等于标题行则代表没有数据,直接返回;
int rowCount = lastRowNum + 1;
//获取映射对象字段值
List<String> iExcelNames = new ArrayList<>();
ClassVoIExcelEntity classVoIExcelEntity = new ClassVoIExcelEntity();
classVoIExcelEntity.clazz = clazz;
classVoIExcelEntity.levelIndex = 0;
setAllClassVoIExcelEntity(classVoIExcelEntity, iExcelNames);
int titleCount = getTitleCount(iExcelNames, sheet0);
if (rowCount <= titleCount) {
return data;
}
//读取数据
try {
readData(sheet0, titleCount, classVoIExcelEntity, data);
} catch (Exception e) {
throw new RuntimeException("读取excel数据错误:" + e);
}
}
return data;
}
/**
* 导出excel
*
* @param fileName
* @param titleName
* @param response
* @param data
* @param sourceClass
*/
public static void exportExcel(@NotNull String fileName, @NotNull String titleName, @NotNull HttpServletResponse response, @NotNull List data, Class sourceClass) throws FileNotFoundException {
int rowIndex = 0;
Workbook workbook = null;
OutputStream outputStream = null;
try {
// 创建一个Excel工作簿
workbook = new XSSFWorkbook();
// 创建一个工作表
XSSFSheet sheet = (XSSFSheet) workbook.createSheet();
clazz = sourceClass;
//获取映射对象字段值
ClassVoIExcelEntity classVoIExcelEntity = new ClassVoIExcelEntity();
classVoIExcelEntity.clazz = clazz;
classVoIExcelEntity.levelIndex = 0;
setAllClassVoIExcelEntity(classVoIExcelEntity, new ArrayList<>());
//获取排序好的所有列名
List<String> iExcelNames = new ArrayList<>();
getIexcelNames(classVoIExcelEntity, iExcelNames);
//获取最后的层级,从0开始的
Integer lastIndex = getLastLevel(classVoIExcelEntity);
sheet.setDefaultColumnWidth(15);
//设置大标题
if (strIsNotBlank(titleName)) {
createBigTitle(sheet, iExcelNames, titleName, rowIndex);
rowIndex++;
}
if (listIsNotEmpty(iExcelNames)) {
//设置小标题
createSmallTitles(sheet, iExcelNames, rowIndex);
rowIndex++;
if (listIsNotEmpty(data)) {
List<ExportRow> exportRows = new ArrayList<>();
//设置数据与ExportRow的对应关系
setExportDataMapping(classVoIExcelEntity, data, exportRows);
//设置数据合并行数
setMergeRowForExportRow(exportRows, lastIndex);
//将数据输入到excel表格中
setDataToExcel(exportRows, sheet, iExcelNames, rowIndex);
}
}
// 告诉浏览器用什么软件可以打开此文件
response.setHeader("content-Type", "application/octet-stream;charset=utf-8");
// 下载文件的默认名称
response.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(fileName + ".xlsx", "utf-8"));
outputStream = response.getOutputStream();
workbook.write(outputStream);
} catch (Exception e) {
e.printStackTrace();
} finally {
if (outputStream != null) {
try {
outputStream.close();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
if (workbook != null) {
try {
workbook.close();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
}
private static void setDataToExcel(List<ExportRow> exportRows, XSSFSheet sheet, List<String> iExcelNames, int startRowIndex) {
for (ExportRow exportRow : exportRows) {
Integer mergeNum = exportRow.mergeNum;
List<ExportColumn> values = exportRow.values;
XSSFRow row = nextRow(sheet, startRowIndex);
int cellIndex = 0;
boolean mergeFlag = !(mergeNum == 0 || mergeNum == 1);
for (; cellIndex < values.size(); cellIndex++) {
XSSFCell cell = row.createCell(cellIndex);
cell.setCellValue(getValueFromExportColumn(iExcelNames.get(cellIndex), values));
if (mergeFlag) {
int endIndex = startRowIndex + mergeNum - 1;
sheet.addMergedRegion(new CellRangeAddress(startRowIndex, endIndex, cellIndex, cellIndex));
}
}
List<ExportRow> sons = exportRow.sons;
if (listIsNotEmpty(sons)) {
setSonDataToExcel(sons, sheet, iExcelNames, startRowIndex, cellIndex);
}
if (mergeFlag) {
startRowIndex += mergeNum;
} else {
startRowIndex += 1;
}
}
}
/**
* 设置子集的值到excel中
*
* @param sons
* @param sheet
* @param startRowIndex
* @param startCellIndex
*/
private static void setSonDataToExcel(List<ExportRow> sons, XSSFSheet sheet, List<String> iExcelNames, int startRowIndex, int startCellIndex) {
Integer rowIndex = startRowIndex;
for (ExportRow exportRow : sons) {
Integer cellIndex = startCellIndex;
Integer mergeNum = exportRow.mergeNum;
List<ExportColumn> values = exportRow.values;
XSSFRow row = null;
if (sheet.getRow(rowIndex) == null) {
row = nextRow(sheet, rowIndex);
} else {
row = sheet.getRow(rowIndex);
}
Integer endCellIndex = values.size() + startCellIndex;
//合并标识
boolean mergeFlag = !(mergeNum == 0 || mergeNum == 1);
for (; cellIndex < endCellIndex; cellIndex++) {
XSSFCell cell = row.createCell(cellIndex);
cell.setCellValue(getValueFromExportColumn(iExcelNames.get(cellIndex), values));
if (mergeFlag) {
int endIndex = rowIndex + mergeNum - 1;
sheet.addMergedRegion(new CellRangeAddress(rowIndex, endIndex, cellIndex, cellIndex));
}
}
List<ExportRow> sons1 = exportRow.sons;
if (mergeFlag) {
rowIndex += mergeNum;
} else {
rowIndex += 1;
}
if (listIsNotEmpty(sons1)) {
setSonDataToExcel(sons1, sheet, iExcelNames, row.getRowNum(), startCellIndex + values.size());
}
}
}
/**
* 根据列名获取值
*
* @param name
* @param values
* @return
*/
private static String getValueFromExportColumn(String name, List<ExportColumn> values) {
for (ExportColumn exportColumn : values) {
if (name.equals(exportColumn.excelColumnName)) {
return exportColumn.value;
}
}
return null;
}
/**
* 获取最后的层级数
*
* @param classVoIExcelEntity
* @return
*/
private static Integer getLastLevel(ClassVoIExcelEntity classVoIExcelEntity) {
ClassVoIExcelEntity sonClassVo = classVoIExcelEntity.sonClassVo;
if (sonClassVo == null) {
return classVoIExcelEntity.levelIndex;
} else {
return getLastLevel(sonClassVo);
}
}
/**
* 设置合并行数
*
* @param exportRows
* @param lastIndex
*/
private static void setMergeRowForExportRow(List<ExportRow> exportRows, Integer lastIndex) {
for (ExportRow exportRow : exportRows) {
List<ExportRow> sons = exportRow.sons;
if (lastIndex == 0) {
exportRow.mergeNum = 1;
} else {
exportRow.mergeNum = getMergeNum(sons, lastIndex);
if (listIsNotEmpty(sons)) {
setMergeRowForExportRow(sons, lastIndex);
}
}
}
}
private static int getMergeNum(List<ExportRow> sons, Integer lastIndex) {
if (listIsNotEmpty(sons)) {
ExportRow exportRow = sons.get(0);
if (exportRow.levelIndex == lastIndex - 1) {
AtomicInteger count = new AtomicInteger();
sons.forEach(item -> {
List<ExportRow> sons1 = item.sons;
if (listIsNotEmpty(sons1)) {
count.addAndGet(sons1.size());
}
});
return count.get();
} else if (exportRow.levelIndex == lastIndex) {
return sons.size();
} else {
AtomicInteger flag = new AtomicInteger();
sons.forEach(item -> {
flag.addAndGet(getMergeNum(item.sons, lastIndex));
});
return flag.get();
}
}
return 0;
}
/**
* 获取所有excel列名,并按顺序排列
*
* @param classVoIExcelEntity
* @return
*/
private static void getIexcelNames(ClassVoIExcelEntity classVoIExcelEntity, List<String> names) {
if (classVoIExcelEntity != null) {
List<ClassVoFieldIExcel> fields = classVoIExcelEntity.fields;
ClassVoIExcelEntity sonClassVo = classVoIExcelEntity.sonClassVo;
if (listIsNotEmpty(fields)) {
List<IExcel> excelsSorted = new ArrayList<>();
List<IExcel> excels = new ArrayList<>();
for (int i = 0; i < fields.size(); i++) {
ClassVoFieldIExcel classVoFieldIExcel = fields.get(i);
IExcel iExcel = classVoFieldIExcel.iExcel;
if (iExcel != null && !iExcel.isSon()) {
if (iExcel.sortNo() == 0) {
excels.add(iExcel);
} else {
excelsSorted.add(iExcel);
}
}
}
//合并
List<String> newNames = Stream.concat(
excelsSorted.stream().sorted(Comparator.comparingInt(IExcel::sortNo)).map(item -> item.name()),
excels.stream().map(item -> item.name())
).collect(Collectors.toList());
names.addAll(newNames);
}
//是否是有集
if (sonClassVo != null) {
getIexcelNames(classVoIExcelEntity.sonClassVo, names);
}
}
}
/**
* 设置数据与excel每列的对应关系
*
* @param classVoIExcelEntity
* @param data
* @param exportRows
*/
private static void setExportDataMapping(ClassVoIExcelEntity classVoIExcelEntity, List data, List<ExportRow> exportRows) {
for (int i = 0; i < data.size(); i++) {
ExportRow exportRow = new ExportRow();
List<ExportRow> sonExportRow = null;
Object obj = data.get(i);
Class<?> objClass = obj.getClass();
ClassVoIExcelEntity classEntity = getClassEntityByClass(classVoIExcelEntity, objClass);
if (classEntity != null) {
List<ClassVoFieldIExcel> fieldIExcels = classEntity.fields;
List<ExportColumn> columnList = new ArrayList<>();
fieldIExcels.forEach(fieldIExcel -> {
try {
if (!fieldIExcel.iExcel.isSon()) {
Field field = objClass.getDeclaredField(fieldIExcel.classVoFieldName);
if (field != null) {
field.setAccessible(true);
ExportColumn exportColumn = new ExportColumn();
exportColumn.value = getFieldValue(obj, field, fieldIExcel.iExcel);
exportColumn.excelColumnName = fieldIExcel.iExcel.name();
columnList.add(exportColumn);
}
}
} catch (Exception e) {
throw new RuntimeException(e);
}
});
exportRow.values = columnList;
exportRow.levelIndex = classEntity.levelIndex;
ClassVoIExcelEntity sonClassVo = classEntity.sonClassVo;
if (sonClassVo != null) {
sonExportRow = new ArrayList<>();
List sonData = getSonData(obj);
if (listIsNotEmpty(sonData)) {
setExportDataMapping(classVoIExcelEntity, sonData, sonExportRow);
exportRow.sons = sonExportRow;
}
}
exportRows.add(exportRow);
}
}
}
/**
* 获取对象的属性值
*
* @param obj
* @param
* @return
*/
private static <T> String getFieldValue(Object obj, Field field, IExcel annotation) throws Exception {
String value = null;
field.setAccessible(true);
if (field.getType() == Boolean.class || field.getType() == boolean.class) {
if (annotation != null) {
String s = annotation.booleanFormatter();
String[] split = s.split(IEXCEL_BOOLEAN_TRUE_DEFAULT_FLAG);
Object o = field.get(obj);
if (o != null) {
Boolean aBoolean = (Boolean) field.get(obj);
value = aBoolean ? split[0] : split[1];
} else {
value = "";
}
}
} else if (field.getType() == Date.class) {
if (annotation != null) {
String dateForMatter = annotation.dateFormat();
Object o = field.get(obj);
if (o != null) {
Date date = (Date) field.get(obj);
SimpleDateFormat simpleDateFormat = new SimpleDateFormat(dateForMatter);
value = simpleDateFormat.format(date);
} else {
value = "";
}
}
} else {
Object o = field.get(obj);
value = o != null ? o.toString() : "";
}
return value;
}
/**
* 获取子集
*
* @param obj
* @return
*/
private static List getSonData(Object obj) {
Field[] declaredFields = obj.getClass().getDeclaredFields();
for (Field field : declaredFields) {
Class<?> type = field.getType();
if (type == List.class) {
IExcel annotation = field.getAnnotation(IExcel.class);
if (annotation != null && annotation.isSon()) {
try {
field.setAccessible(true);
return (List) field.get(obj);
} catch (IllegalAccessException e) {
throw new RuntimeException(e);
}
}
}
}
return null;
}
/**
* 根据class获取对应的classVoIExcelEntity
*
* @param classVoIExcelEntity
* @param aClass
* @return
*/
private static ClassVoIExcelEntity getClassEntityByClass(ClassVoIExcelEntity classVoIExcelEntity, Class<?> aClass) {
if (classVoIExcelEntity == null) return null;
Class clazz1 = classVoIExcelEntity.clazz;
if (clazz1.getTypeName().equals(aClass.getTypeName())) return classVoIExcelEntity;
ClassVoIExcelEntity sonClassVo = classVoIExcelEntity.sonClassVo;
return getClassEntityByClass(sonClassVo, aClass);
}
/**
* 创建大标题样式
*
* @param wb
* @return
*/
public static XSSFCellStyle createBigTitleCellStyle(XSSFWorkbook wb) {
// 标题样式(加粗,垂直居中)
XSSFCellStyle titleCellStyle = wb.createCellStyle();
titleCellStyle.setAlignment(HorizontalAlignment.CENTER);//水平居中
titleCellStyle.setVerticalAlignment(VerticalAlignment.CENTER);//垂直居中
XSSFFont fontStyle = wb.createFont();
fontStyle.setBold(true); //加粗
fontStyle.setFontHeightInPoints((short) 16); //设置标题字体大小
titleCellStyle.setFont(fontStyle);
return titleCellStyle;
}
/**
* 创建小标题样式
*
* @param wb
* @return
*/
public static XSSFCellStyle createSmallTitleCellStyle(XSSFWorkbook wb) {
//设置表头样式,表头居中
XSSFCellStyle style = wb.createCellStyle();
//设置单元格样式
style.setAlignment(HorizontalAlignment.CENTER);
style.setVerticalAlignment(VerticalAlignment.CENTER);
//设置字体
XSSFFont font = wb.createFont();
font.setFontHeightInPoints((short) 14);
style.setFont(font);
return style;
}
/**
* 设置大标题
*
* @param sheet
* @param iExcelNames
* @param titleName
* @param rowIndex
*/
private static void createBigTitle(XSSFSheet sheet, List<String> iExcelNames, String titleName, int rowIndex) {
XSSFCellStyle style = createBigTitleCellStyle(sheet.getWorkbook());
XSSFRow rowBigTitle = nextRow(sheet, rowIndex);
//大标题
XSSFCell cell = rowBigTitle.createCell(0);
cell.setCellValue(titleName);
cell.setCellStyle(style);
sheet.addMergedRegion(new CellRangeAddress(0, 0, 0, listIsNotEmpty(iExcelNames) ? iExcelNames.size() - 1 : Excel_DEFAULT_TITLE_MERGERNUM));
}
/**
* 设置小标题
*
* @param sheet
* @param iExcelNames
* @param rowIndex
*/
private static void createSmallTitles(XSSFSheet sheet, List<String> iExcelNames, int rowIndex) {
XSSFCellStyle style = createSmallTitleCellStyle(sheet.getWorkbook());
XSSFRow rowSmallTitle = nextRow(sheet, rowIndex);
for (int i = 0; i < iExcelNames.size(); i++) {
XSSFCell cell = rowSmallTitle.createCell(i);
cell.setCellValue(iExcelNames.get(i));
cell.setCellStyle(style);
}
}
/**
* 获取下一行
*
* @param sheet
* @param rowIndex
* @return
*/
private static XSSFRow nextRow(XSSFSheet sheet, int rowIndex) {
XSSFRow row = sheet.createRow(rowIndex);
return row;
}
/**
* 读取数据
*
* @param sheet
* @param titleCount
* @param classVoIExcelEntity
* @param data
* @param
*/
private static <T> void readData(Sheet sheet, Integer titleCount, ClassVoIExcelEntity classVoIExcelEntity, List<T> data) throws Exception {
//定义一个数组,存放各个层级的当前对象
List levelsObjs = new ArrayList();
//获取excel的所有小标题
List<CellTitleValueEntity> cellTitles = getCellTitles(sheet, titleCount);
if (listIsNotEmpty(cellTitles)) {
//设置哪些是当前行的第一个元素
setFirstAndLastField(cellTitles, classVoIExcelEntity);
//开始读取数据
int startDataIndex = titleCount + 1;
int allRowNums = sheet.getLastRowNum() + 1;
try {
//循环excel每一行
for (int i = startDataIndex; i < allRowNums; i++) {
Row row = sheet.getRow(i);
if (row != null && checkRowDataIsNotBlank(cellTitles, row)) {
for (int j = 0; j < cellTitles.size(); j++) {
CellTitleValueEntity cellTitleValueEntity = cellTitles.get(j);
Integer nowCellIndex = cellTitleValueEntity.cellIndex;
Cell cell = row.getCell(nowCellIndex);
if (cell == null) {
cell = row.createCell(nowCellIndex);
}
String cellValue = getCellValue(cell);
//获取当前字段的所属class
ClassVoIExcelEntity classVoIExcelEntityNow = getClassVoExcelEntityByExcelCellTitle(cellTitleValueEntity.cellTitleName, classVoIExcelEntity);
Integer levelIndex = classVoIExcelEntityNow.levelIndex;
if (classVoIExcelEntityNow != null) {
//当前单元格是否为第一个字段
boolean isExcelObjFirstField = cellTitleValueEntity.isExcelObjFirstField;
boolean isExcelObjLastFieldField = cellTitleValueEntity.isExcelObjLastField;
//获取合并信息
MergedRowInfo mergedRowInfo = getMergedRowInfo(cell, sheet);
Boolean isMerge = mergedRowInfo.isMerge;
Integer firstRow = mergedRowInfo.firstRow;
Integer lastRow = mergedRowInfo.lastRow;
//判断是否需要新建对象
if (isExcelObjFirstField && (!isMerge || i == firstRow)) {
if (!listIsNotEmpty(levelsObjs) || levelsObjs.size() < levelIndex + 1) {
levelsObjs.add(classVoIExcelEntityNow.clazz.newInstance());
} else {
levelsObjs.set(levelIndex, classVoIExcelEntityNow.clazz.newInstance());
}
}
//获取当前对象
Object nowObj = levelsObjs.get(classVoIExcelEntityNow.levelIndex);
//获取当前单元格对应对象的字段名
String fieldName = getFieldNameByCellTitleName(cellTitleValueEntity.cellTitleName, classVoIExcelEntityNow);
//给属性设置值
if (strIsNotBlank(cellValue)) {
setCellValueToObjField(nowObj, fieldName, cellValue);
}
//获取当前对象的上级对象
Object parentObj = getParentObj(classVoIExcelEntityNow, levelsObjs);
List sonList = getSonListByParentObj(parentObj);
//判断当前单元格是否是所属对象最后的一个对应,借此判断当前行当前对象是否填充完成
if (isExcelObjLastFieldField && (!isMerge || i == lastRow)) {
//判断必填字段是否都有值
BlankRowInfo blankRowInfo = checkObjIsNotBlankField(classVoIExcelEntityNow, nowObj, (long) (i + 1));
if (blankRowInfo == null) {
if (parentObj != null) {
sonList.add(nowObj);
} else {
data.add((T) nowObj);
}
} else {
errRowInfo.add(blankRowInfo);
setSonFieldValueToNull(nowObj);
break;
}
}
}
}
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
/**
* 获取未被读取的错误信息
*
* @return
*/
public static List<BlankRowInfo> getErrRowInfo() {
return errRowInfo;
}
/**
* 设置子集值为空
*
* @param nowObj
*/
private static void setSonFieldValueToNull(Object nowObj) {
if (nowObj != null) {
Class<?> parentObjClass = nowObj.getClass();
Field[] declaredFields = parentObjClass.getDeclaredFields();
for (Field field : declaredFields) {
IExcel annotation = field.getAnnotation(IExcel.class);
if (annotation != null) {
if (annotation.isSon()) {
field.setAccessible(true);
Class<?> type = field.getType();
if (type == List.class) {
try {
field.set(nowObj, null);
} catch (IllegalAccessException e) {
throw new RuntimeException(e);
}
}
}
}
}
}
}
/**
* 检查当前对象必填字段是否都有值
*
* @param classVoIExcelEntityNow
* @param nowObj
*/
private static BlankRowInfo checkObjIsNotBlankField(ClassVoIExcelEntity classVoIExcelEntityNow, Object nowObj, Long rowNo) {
AtomicReference<BlankRowInfo> blankRowInfo = new AtomicReference<>();
List<ClassVoFieldIExcel> fields = classVoIExcelEntityNow.fields;
if (nowObj != null && listIsNotEmpty(fields)) {
Class<?> clazz = nowObj.getClass();
Field[] declaredFields = clazz.getDeclaredFields();
Arrays.stream(declaredFields).forEach(field -> {
field.setAccessible(true);
try {
Object fieldValueObj = field.get(nowObj);
IExcel iExcel = field.getAnnotation(IExcel.class);
if (fieldValueObj == null && iExcel != null && iExcel.isNotBlank()) {
if (blankRowInfo.get() == null) {
blankRowInfo.set(new BlankRowInfo());
blankRowInfo.get().rowNo = rowNo;
blankRowInfo.get().objLevel = classVoIExcelEntityNow.levelIndex;
blankRowInfo.get().blankTitleNames = new ArrayList<>();
}
blankRowInfo.get().blankTitleNames.add(iExcel.name());
}
} catch (IllegalAccessException e) {
throw new RuntimeException(e);
}
});
}
return blankRowInfo.get();
}
/**
* 获取上级对象的子集
*
* @param parentObj
* @return
*/
private static List getSonListByParentObj(Object parentObj) {
if (parentObj != null) {
Class<?> parentObjClass = parentObj.getClass();
Field[] declaredFields = parentObjClass.getDeclaredFields();
for (Field field : declaredFields) {
IExcel annotation = field.getAnnotation(IExcel.class);
if (annotation != null) {
if (annotation.isSon()) {
field.setAccessible(true);
Class<?> type = field.getType();
if (type == List.class) {
try {
Object son = field.get(parentObj);
if (son != null) {
return (List) son;
}
List sonList = new ArrayList<>();
field.set(parentObj, sonList);
return sonList;
} catch (IllegalAccessException e) {
throw new RuntimeException(e);
}
}
}
}
}
}
return null;
}
/**
* 获取父级对象
*
* @param classVoIExcelEntityNow
* @param levelsObjs
* @return
*/
private static Object getParentObj(ClassVoIExcelEntity classVoIExcelEntityNow, List levelsObjs) {
Object parentObj = null;
Class parentClass = classVoIExcelEntityNow.parentClass;
if (parentClass != null) {
String typeName = parentClass.getTypeName();
for (Object item : levelsObjs) {
if (typeName.equals(item.getClass().getTypeName())) {
parentObj = item;
break;
}
}
}
return parentObj;
}
/**
* 获取当前单元格对应对象的字段名
*
* @param cellTitleName
* @param classVoIExcelEntityNow
* @return
*/
private static String getFieldNameByCellTitleName(String cellTitleName, ClassVoIExcelEntity classVoIExcelEntityNow) {
List<ClassVoFieldIExcel> fields = classVoIExcelEntityNow.fields;
for (ClassVoFieldIExcel classVoFieldIExcel : fields) {
if (classVoFieldIExcel.iExcel.name().equals(cellTitleName)) {
return classVoFieldIExcel.classVoFieldName;
}
}
return null;
}
/**
* 给属性设置值
*
* @param obj
* @param filedName
* @param cellValue
* @param
*/
private static <T> void setCellValueToObjField(Object obj, String filedName, Object cellValue) throws Exception {
Class<?> clazz = obj.getClass();
Field declaredField = clazz.getDeclaredField(filedName);
declaredField.setAccessible(true);
Class<?> type = declaredField.getType();
if (type == Integer.class || type == int.class) {
declaredField.set(obj, Integer.parseInt(cellValue.toString()));
} else if (type == Long.class || type == long.class) {
declaredField.set(obj, Long.parseLong(cellValue.toString()));
} else if (type == boolean.class || type == Boolean.class) {
IExcel annotation = declaredField.getAnnotation(IExcel.class);
String s = annotation.booleanFormatter();
String[] split = s.split(IEXCEL_BOOLEAN_TRUE_DEFAULT_FLAG);
declaredField.set(obj, split[0].trim().equals(cellValue.toString().trim()) ? true : false);
} else if (type == Date.class) {
IExcel annotation = declaredField.getAnnotation(IExcel.class);
String s = annotation.dateFormat();
SimpleDateFormat format = new SimpleDateFormat(s);
declaredField.set(obj, format.parse(cellValue.toString()));
} else if (type == Double.class || type == double.class) {
declaredField.set(obj, Double.valueOf(cellValue.toString()));
} else if (type == List.class) {
declaredField.set(obj, cellValue);
} else if (type == BigDecimal.class) {
BigDecimal bigDecimal = BigDecimal.valueOf(Long.valueOf(cellValue.toString()));
declaredField.set(obj, bigDecimal);
} else {
declaredField.set(obj, cellValue);
}
}
/**
* 设置哪些是当前行的第一个元素和最后一个元素 (注意:这里要求不能出现重复的列名)
*
* @param cellTitles
* @param classVoIExcelEntity
*/
private static void setFirstAndLastField(List<CellTitleValueEntity> cellTitles, ClassVoIExcelEntity classVoIExcelEntity) {
final ClassVoIExcelEntity[] previousClassVo = {null};
for (int i = 0; i < cellTitles.size(); i++) {
CellTitleValueEntity item = cellTitles.get(i);
String cellTitleName = item.cellTitleName;
ClassVoIExcelEntity nowClassVoEntity = getClassEntityByCellTitleName(cellTitleName, classVoIExcelEntity);
if (nowClassVoEntity != null) {
//设置是否是第一个元素
if (previousClassVo[0] == null) {
item.isExcelObjFirstField = true;
previousClassVo[0] = nowClassVoEntity;
} else if (!previousClassVo[0].clazz.getTypeName().equals(nowClassVoEntity.clazz.getTypeName())) {
item.isExcelObjFirstField = true;
previousClassVo[0] = nowClassVoEntity;
}
//设置是否是最后一个元素
if (i < cellTitles.size() - 1) {
CellTitleValueEntity nextItem = cellTitles.get(i + 1);
String nextCellTitleName = nextItem.cellTitleName;
ClassVoIExcelEntity nextClassVoEntity = getClassEntityByCellTitleName(nextCellTitleName, classVoIExcelEntity);
if (nextClassVoEntity != null) {
if (!nowClassVoEntity.clazz.getTypeName().equals(nextClassVoEntity.clazz.getTypeName())) {
item.isExcelObjLastField = true;
}
}
}
if (i == cellTitles.size() - 1) {
item.isExcelObjLastField = true;
}
}
}
}
/**
* 根据列名获取 ClassVoIExcelEntity
*
* @param cellTitleName
* @param classVoIExcelEntity
* @return
*/
private static ClassVoIExcelEntity getClassEntityByCellTitleName(String cellTitleName, ClassVoIExcelEntity classVoIExcelEntity) {
List<ClassVoFieldIExcel> fields = classVoIExcelEntity.fields;
for (ClassVoFieldIExcel item : fields) {
IExcel iExcel = item.iExcel;
String name = iExcel.name();
if (name.equals(cellTitleName)) {
return classVoIExcelEntity;
}
}
ClassVoIExcelEntity sonClassVo = classVoIExcelEntity.sonClassVo;
if (sonClassVo != null) {
return getClassEntityByCellTitleName(cellTitleName, sonClassVo);
}
return null;
}
/**
* 获取当前字段所属excel映射对象
*
* @param cellTitleName
* @param classVoIExcelEntity
* @return
*/
private static ClassVoIExcelEntity getClassVoExcelEntityByExcelCellTitle(String cellTitleName, ClassVoIExcelEntity classVoIExcelEntity) {
ClassVoIExcelEntity rsClassVoIExcelEntity = null;
List<ClassVoFieldIExcel> fields = classVoIExcelEntity.fields;
for (ClassVoFieldIExcel classVoFieldIExcel : fields) {
IExcel iExcel = classVoFieldIExcel.iExcel;
String name = iExcel.name();
if (name.equals(cellTitleName)) {
rsClassVoIExcelEntity = classVoIExcelEntity;
break;
}
}
if (rsClassVoIExcelEntity == null && classVoIExcelEntity.sonClassVo != null) {
rsClassVoIExcelEntity = getClassVoExcelEntityByExcelCellTitle(cellTitleName, classVoIExcelEntity.sonClassVo);
}
return rsClassVoIExcelEntity;
}
/**
* 获取标题总行数
* iExcelNames
*
* @param sheet0
* @return
*/
private static int getTitleCount(List<String> iExcelNames, Sheet sheet0) {
for (int i = 0; i < FIND_TITLE_SIZE; i++) {
Row row = sheet0.getRow(i);
if (row != null) {
int lastCellNum = row.getLastCellNum();
for (int j = 0; j < lastCellNum; j++) {
Cell cell = row.getCell(j);
String cellValue = getCellValue(cell);
if (strIsNotBlank(cellValue) && iExcelNames.contains(cellValue)) {
return i;
}
}
}
}
return 0;
}
/**
* 获取合并行信息
*
* @param cell
* @param sheet
* @return
*/
private static MergedRowInfo getMergedRowInfo(Cell cell, Sheet sheet) {
MergedRowInfo mergedRowInfo = new MergedRowInfo();
for (CellRangeAddress region : sheet.getMergedRegions()) {
if (region.isInRange(cell.getRowIndex(), cell.getColumnIndex())) {
mergedRowInfo.isMerge = true;
mergedRowInfo.firstRow = region.getFirstRow();
mergedRowInfo.lastRow = region.getLastRow();
return mergedRowInfo;
}
}
mergedRowInfo.isMerge = false;
return mergedRowInfo;
}
/**
* 检查当前行不是空的
*
* @param cellTitles
* @param row
* @return
*/
private static boolean checkRowDataIsNotBlank(List<CellTitleValueEntity> cellTitles, Row row) {
AtomicInteger flag = new AtomicInteger();
for (CellTitleValueEntity title : cellTitles) {
Integer cellIndex = title.cellIndex;
Cell cell = row.getCell(cellIndex);
if (cell != null) {
MergedRowInfo mergedRowInfo = getMergedRowInfo(cell, row.getSheet());
if (mergedRowInfo != null && mergedRowInfo.isMerge) {
return true;
}
if (strIsNotBlank(getCellValue(cell))) {
flag.getAndIncrement();
}
}
}
return flag.get() > 0;
}
/**
* 获取所有小标题
*
* @param sheet
* @param titleCount
* @return
*/
private static List<CellTitleValueEntity> getCellTitles(Sheet sheet, Integer titleCount) {
List<CellTitleValueEntity> cellTitles = new ArrayList<>();
Row cellTitleRow = sheet.getRow(titleCount);
if (cellTitleRow != null) {
int lastCellNum = cellTitleRow.getLastCellNum();
for (int i = 0; i < lastCellNum; i++) {
Cell cell = cellTitleRow.getCell(i);
String cellValue = getCellValue(cell);
if (strIsNotBlank(cellValue)) {
CellTitleValueEntity cellTitleEntity = new CellTitleValueEntity();
cellTitleEntity.cellTitleName = cellValue;
cellTitleEntity.cellIndex = i;
cellTitles.add(cellTitleEntity);
}
}
}
return cellTitles;
}
/**
* 获取excel表格单元格的值
*
* @param cell
* @return
*/
private static String getCellValue(Cell cell) {
String cellvalue = "";
if (cell != null) {
// 判断当前Cell的Type
switch (cell.getCellType()) {
// 如果当前Cell的Type为NUMERIC
case NUMERIC:
case FORMULA: {
// 判断当前的cell是否为Date
if (HSSFDateUtil.isCellDateFormatted(cell)) {
Date date = cell.getDateCellValue();
SimpleDateFormat sdf = new SimpleDateFormat(IEXCEL_DATE_DEFAULT_FORMAT);
cellvalue = sdf.format(date);
}
// 如果是纯数字
else {
// 取得当前Cell的数值
cellvalue = new DecimalFormat("0").format(cell.getNumericCellValue());
}
break;
}
// 如果当前Cell的Type为STRIN
case STRING:
// 取得当前的Cell字符串
cellvalue = cell.getRichStringCellValue().getString();
break;
// 默认的Cell值
default:
cellvalue = " ";
}
} else {
cellvalue = "";
}
return cellvalue;
}
/**
* 设置所有iexcel注解与目标对象的映射字段名和值
*
* @param classVoIExcelEntity classVoIExcelEntity.clazz必须有值
* @param iExcelNames
*/
private static void setAllClassVoIExcelEntity(ClassVoIExcelEntity classVoIExcelEntity, List<String> iExcelNames) {
AtomicBoolean isSonFlag = new AtomicBoolean(false);
Class nowClazz = classVoIExcelEntity.clazz;
List<ClassVoFieldIExcel> classVoFields = new ArrayList<>();
Field[] declaredFields = nowClazz.getDeclaredFields();
Arrays.stream(declaredFields).forEach(field -> {
IExcel iExcel = field.getAnnotation(IExcel.class);
if (iExcel != null && !iExcel.hiddenField()) {
ClassVoFieldIExcel classVoFieldIExcel = new ClassVoFieldIExcel();
if (iExcel.isSon() && !isSonFlag.get()) {
//处理子集
Class sonClass = getGenericClassForList(field);
if (sonClass != null) {
ClassVoIExcelEntity sonClassVoIExcel = new ClassVoIExcelEntity();
sonClassVoIExcel.clazz = sonClass;
sonClassVoIExcel.parentClass = classVoIExcelEntity.clazz;
sonClassVoIExcel.levelIndex = classVoIExcelEntity.levelIndex + 1;
setAllClassVoIExcelEntity(sonClassVoIExcel, iExcelNames);
classVoIExcelEntity.sonClassVo = sonClassVoIExcel;
isSonFlag.set(true);
}
} else {
iExcelNames.add(iExcel.name());
}
classVoFieldIExcel.classVoFieldName = field.getName();
classVoFieldIExcel.iExcel = iExcel;
classVoFields.add(classVoFieldIExcel);
}
});
classVoIExcelEntity.fields = classVoFields;
}
/**
* 获取List的泛型类型
*
* @param field
* @return
*/
private static Class getGenericClassForList(Field field) {
Class clazz = null;
if (field.getType() == List.class) {
Type genericType = field.getGenericType();
if (genericType != null && genericType instanceof ParameterizedType) {
ParameterizedType pt = (ParameterizedType) genericType;
clazz = (Class<?>) pt.getActualTypeArguments()[0];
}
}
return clazz;
}
/**
* 判断是否是excel文件
*
* @param fileName
* @return
*/
private static boolean isExcelFile(String fileName) {
if (!strIsNotBlank(fileName)) {
return false;
}
String fileNameSuffix = getFileNameSuffix(fileName);
if (fileNameSuffix.toLowerCase().equals("xlsx") || fileNameSuffix.toLowerCase().equals("xls")) {
return true;
} else {
return false;
}
}
/**
* 检测excel类型,如果fileName为空,则默认为xlsx
*
* @param fileName
* @return
*/
private static boolean isXlsx(String fileName) {
if (!strIsNotBlank(fileName)) {
return true;
}
String fileNameSuffix = getFileNameSuffix(fileName);
if (fileNameSuffix.toLowerCase().equals("xlsx")) {
return true;
} else {
return false;
}
}
/**
* 获取文件后缀名
*
* @param fileName
* @return
*/
private static String getFileNameSuffix(String fileName) {
String[] split = fileName.split("\\u002E");
String fileNameSuffix = split[split.length - 1];
return fileNameSuffix;
}
/**
* 检测字符串不为空
*
* @param str
* @return
*/
private static boolean strIsNotBlank(String str) {
return !(str == null || str.trim().equals(""));
}
/**
* 判断list不为空
*
* @param list
* @return
*/
private static boolean listIsNotEmpty(List list) {
return list != null && list.size() > 0;
}
/**
* 隐藏字段
* @param clazz
* @param columnName
* @param target
* @throws Exception
*/
public static void hideColumn(Class<?> clazz, String columnName, Boolean target) throws Exception {
if (!strIsNotBlank(columnName)) {
throw new NullPointerException("传入的属性列名为空");
}
if (target == null) {
target = true;
}
//获取目标对象的属性值
Field field = clazz.getDeclaredField(columnName);
//获取注解反射对象
IExcel excelAnion = field.getAnnotation(IExcel.class);
//获取代理
InvocationHandler invocationHandler = Proxy.getInvocationHandler(excelAnion);
Field excelField = invocationHandler.getClass().getDeclaredField("memberValues");
excelField.setAccessible(true);
Map memberValues = (Map) excelField.get(invocationHandler);
memberValues.put("hiddenField", target);
}
}
package com.ph.excel.vo;
import com.ph.excel.annotation.IExcel;
import java.util.Date;
import java.util.List;
/**
* @ClassName: OrderModel
* @Description: TODO
* @Date: 2023/6/2 14:31
* @author: ph9527
* @version: 1.0
*/
public class OrderModel {
private Long id;
@IExcel(name = "订单号",isNotBlank = true)
private String orderNo;
@IExcel(name = "订单时间", sortNo = 2)
private Date orderTime;
@IExcel(name = "购买人", sortNo = 1)
private String buyUser;
@IExcel(isSon = true)
private List<DetailModel> details;
public OrderModel() {
}
public OrderModel(Long id, String orderNo, Date orderTime, String buyUser, Integer buyNum, List<DetailModel> details) {
this.id = id;
this.orderNo = orderNo;
this.orderTime = orderTime;
this.buyUser = buyUser;
this.details = details;
}
@Override
public String toString() {
return "OrderModel{" +
"id=" + id +
", orderNo='" + orderNo + '\'' +
", orderTime=" + orderTime +
", buyUser='" + buyUser + '\'' +
", details=" + details +
'}';
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getOrderNo() {
return orderNo;
}
public void setOrderNo(String orderNo) {
this.orderNo = orderNo;
}
public Date getOrderTime() {
return orderTime;
}
public void setOrderTime(Date orderTime) {
this.orderTime = orderTime;
}
public String getBuyUser() {
return buyUser;
}
public void setBuyUser(String buyUser) {
this.buyUser = buyUser;
}
public List<DetailModel> getDetails() {
return details;
}
public void setDetails(List<DetailModel> details) {
this.details = details;
}
}
DetailModel:
package com.ph.excel.vo;
import com.ph.excel.annotation.IExcel;
import java.util.Date;
import java.util.List;
/**
* @ClassName: DetailModel
* @Description: TODO
* @Date: 2023/6/2 14:31
* @author: ph9527
* @version: 1.0
*/
public class DetailModel {
private Long id;
private Long orderId;
@IExcel(name = "商品名")
private String goodName;
@IExcel(name = "商品码", isNotBlank = true, sortNo = 2)
private String goodCode;
@IExcel(name = "购买数量", sortNo = 1)
private Integer buyNum;
@IExcel(isSon = true)
private List<CodeModel> codes;
@Override
public String toString() {
return "DetailModel{" +
"id=" + id +
", orderId=" + orderId +
", goodName='" + goodName + '\'' +
", goodCode='" + goodCode + '\'' +
", buyNum=" + buyNum +
", codes=" + codes +
'}';
}
public DetailModel() {
}
public DetailModel(Long id, Long orderId, String goodName, String goodCode, Integer buyNum, List<CodeModel> codes) {
this.id = id;
this.orderId = orderId;
this.goodName = goodName;
this.goodCode = goodCode;
this.buyNum = buyNum;
this.codes = codes;
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public Long getOrderId() {
return orderId;
}
public void setOrderId(Long orderId) {
this.orderId = orderId;
}
public String getGoodName() {
return goodName;
}
public void setGoodName(String goodName) {
this.goodName = goodName;
}
public String getGoodCode() {
return goodCode;
}
public void setGoodCode(String goodCode) {
this.goodCode = goodCode;
}
public Integer getBuyNum() {
return buyNum;
}
public void setBuyNum(Integer buyNum) {
this.buyNum = buyNum;
}
public List<CodeModel> getCodes() {
return codes;
}
public void setCodes(List<CodeModel> codes) {
this.codes = codes;
}
}
CodeModel :
package com.ph.excel.vo;
import com.ph.excel.annotation.IExcel;
/**
* @ClassName: CodeModel
* @Description: TODO
* @Date: 2023/6/2 14:31
* @author: ph9527
* @version: 1.0
*/
public class CodeModel {
private Long id;
private Long detailId;
@IExcel(name = "追溯码",isNotBlank = true)
private String code;
@Override
public String toString() {
return "CodeModel{" +
"id=" + id +
", detailId=" + detailId +
", code='" + code + '\'' +
'}';
}
public CodeModel() {
}
public CodeModel(Long id, Long detailId, String code) {
this.id = id;
this.detailId = detailId;
this.code = code;
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public Long getDetailId() {
return detailId;
}
public void setDetailId(Long detailId) {
this.detailId = detailId;
}
public String getCode() {
return code;
}
public void setCode(String code) {
this.code = code;
}
}
b :测试读取excel
读取用到的excel为:
/**
* 读取excel测试
*
* @return
*/
@GetMapping("/read")
public JSONObject readExcel() throws FileNotFoundException {
JSONObject rs = new JSONObject();
File file = new File("D:\\PH\\Desktop\\test.xlsx");
FileInputStream inputStream = new FileInputStream(file);
//读取数据
List<OrderModel> orders = IExcelUtils.readExcel(inputStream, file.getName(), OrderModel.class);
//获取因必填项没填写,未读取的数据信息
List<IExcelUtils.BlankRowInfo> errRowInfos = IExcelUtils.getErrRowInfo();
rs.put("读取的数据orders", orders);
rs.put("错误的数据errRowInfo", errRowInfos);
return rs;
}
d :读取excel的结果:
e:测试导出excel
我导出测试的数据直接读取的exel,下面是读取的excel图
f : 导出测试代码:
/**
* 导出测试
* @param response
* @throws Exception
*/
@GetMapping("/export")
public void export(HttpServletResponse response) throws Exception {
//创建测试数据
List<OrderModel> data = createExportData();
//导出excel
IExcelUtils.exportExcel("订单", "订单信息", response, data, OrderModel.class);
}