@Excel若依导出异常/解决BusinessBaseEntity里面的字段不支持导出
今天发现所有实体类继承BusinessBaseEntity里面的这些通用字段不支持导出,debug时发现是这样:
导出效果
这里我把能查到的方法都汇总了,如果你也遇到这个异常,可以去逐步排查
1.先看库里有没有数据
2.看字段名是否对齐
3.所需要导出的字段是否正确加上@Excel注解
4.检查注解内部是不是被加注了type = Excel.Type.IMPORT
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
@TableField(value = "create_time", fill = FieldFill.INSERT)
@Excel(name = "创建时间", width = 30, dateFormat = "yyyy-MM-dd HH:mm:ss", type = Excel.Type.IMPORT)
private Date createTime;
因为这个type是控制数据通道的,通过详细代码可以看到这是控制此字段仅允许被导入
5.检查xml里面的SQL是否对应,因为涉及到关联表的时候,这个通用字段大家都有,如果需要查询就必须要指定是查哪个表
/** 创建时间 */
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
@TableField(value = "create_time", fill = FieldFill.INSERT)
@Excel(name = "创建时间", width = 30, dateFormat = "yyyy-MM-dd HH:mm:ss", type = Excel.Type.EXPORT)
private Date createTime;
到这里一般就可以解决了,但如果到这里还不行可以试试我下面这个方法,通过反射去获取导出的实体类的父类的带@Excel注解的字段,再把子类的值赋值上来,进行导出
这里补充一下各个用法:
属性 | 类型 | 用途 | 示例 |
name | String | 定义Excel列的名称,用于Excel表头。 | @Excel(name = "学生姓名") |
width | double | 定义列宽度,单位为字符。 | @Excel(width = 20) |
height | double | 定义行高,单位为磅。仅对导出有效。 | @Excel(height = 10) |
orderNum | String | 定义列的显示顺序。 | @Excel(orderNum = "1") |
needMerge | boolean | 表示是否需要合并单元格。 | @Excel(needMerge = true) |
mergeVertical | boolean | 表示是否纵向合并单元格。 | @Excel(mergeVertical = true) |
mergeRely | int[] | 指定合并单元格时依赖的列,数组中的数字为列的索引。 | @Excel(mergeRely = {1}) |
isImportField | String | 定义是否为导入字段,“true"或"false”。 | @Excel(isImportField = "true") |
isWrap | boolean | 定义是否自动换行。 | @Excel(isWrap = true) |
exportFormat | String | 定义导出时的格式化模式,如日期格式。 | @Excel(exportFormat = "yyyy-MM-dd") |
importFormat | String | 定义导入时的格式化模式。 | @Excel(importFormat = "yyyy-MM-dd") |
imageType | int | 定义图片类型(如1表示从文件导入,2表示从数据库导入)。 | @Excel(imageType = 1) |
suffix | String | 定义文本后缀,如在文本后添加特定的后缀。 | @Excel(suffix = "%") |
type | int | 定义字段类型(如1表示文本,2表示图片)。 | @Excel(type = 1) |
enumExportField | String | 定义枚举导出时,调用枚举字段的哪个方法获取实际的值。 | @Excel(enumExportField = "getText") |
savePath | String | 定义图片保存路径,仅对导入有效。 | @Excel(savePath = "/tmp") |
dateFormat | String | 简化的日期格式设置,简化的exportFormat/importFormat。 | @Excel(dateFormat = "yyyy-MM-dd") |
use1904windowing | boolean | 定义是否使用1904年日期窗口。 | @Excel(use1904windowing = true) |
fixedIndex | int | 指定Excel列的索引,从0开始,用于导入时准确匹配列位置。 | @Excel(fixedIndex = 0) |
groupName | String | 用于分组导出/导入时定义的组名。 | @Excel(groupName = "group1") |
dict | String | 用于指定数据字典,将数据转换为对应的文本值。 | @Excel(dict = "sex=1_男,2_女") |
replace | String[] | 定义要替换的值,用于导出时将字段值替换为指定的文本值。 | @Excel(replace = {"男_1", "女_2"}) |
statistics | boolean | 定义是否进行统计,用于对数字字段进行求和统计。 | @Excel(statistics = true) |
6.用代码,里面有判定继承关系的方法、利用类的反射,获取类的注解、获取类的父类、字段名等方法可以参考
/**
* 对list数据源将其里面的数据导入到excel表单
*
* @param response 返回数据
* @param list 导出数据集合
* @param sheetName 工作表的名称
* @return 结果
*/
public void exportExcel(HttpServletResponse response, List<T> list, String sheetName)
{
// if(list.size()>0){
// //获取父类带Excel注解的字段
// List<String> elementList=getSuperClasseExcel(list.get(0).getClass());
// for (String s : elementList) {
// list=setBusinessBaseEntity(list,s);
// }
exportExcel(response, list, sheetName, StringUtils.EMPTY);
// }
}
//把业务实体父类的指定属性赋值到子类
private List<T> setBusinessBaseEntity(List<T> list,String element) {
for (T t : list) {
try {
// 获取 T 的 createTime 字段
Field createTimeField = getDeclaredFieldIncludingSuperclasses(t.getClass(), element);
if (createTimeField != null) {
createTimeField.setAccessible(true);
// 获取父类的 createTime 字段值
Object parentValue = getFieldValueIncludingSuperclasses(t, element);
// 如果父类有 createTime 字段值,则赋值给当前对象
if (parentValue != null) {
createTimeField.set(t, parentValue);
}
}
} catch ( IllegalAccessException e) {
e.printStackTrace();
}
}
return list;
}
private static Field getDeclaredFieldIncludingSuperclasses(Class<?> clazz, String fieldName) {
while (clazz != null) {
try {
return clazz.getDeclaredField(fieldName);
} catch (NoSuchFieldException e) {
// 继续查找父类
clazz = clazz.getSuperclass();
}
}
return null;
}
private static Object getFieldValueIncludingSuperclasses(Object obj, String fieldName) throws IllegalAccessException {
Class<?> clazz = obj.getClass();
while (clazz != null) {
try {
Field field = clazz.getDeclaredField(fieldName);
field.setAccessible(true);
return field.get(obj);
} catch (NoSuchFieldException e) {
// 继续查找父类
clazz = clazz.getSuperclass();
}
}
return null;
}
//获取父类带Excel注解的字段
// private List<String> getSuperClasseExcel(Object object) {
// //先判断是否继承自BusinessBaseEntity
// List<String> elementList = new ArrayList<>();
// //再把BusinessBaseEntity中有@Excel注解的字段收集起来
//
// // 获取父类
// Class<Object> clazz = object;
//
// // 获取父类
// Class<?> superClass = clazz.getSuperclass();
//
// if (superClass != null) {
// System.out.println("有" + superClass.getSimpleName());
// } else {
// System.out.println("无");
// }
//
//
//
//
//
if (object instanceof BusinessBaseEntity) {
BusinessBaseEntity b = new BusinessBaseEntity() {};
Class<?> clazz = b.getClass();
// while (clazz != null) {
for (Field field : clazz.getDeclaredFields()) {
if (field.isAnnotationPresent(Excel.class)) {
elementList.add(field.getName());
Excel excelAnnotation = field.getAnnotation(Excel.class);
System.out.println("Field: " + field.getName()
+ " has Excel annotation with value: " + excelAnnotation.name());
}
}
// }
}
// return elementList;
// }
7.如果还是不能解决,可以排查一下是不是日期格式异常,这种情况一般会报错:org.apache.poi.ss.usermodel.Cell.setCellValue
可以建一个工具类DateFormatTransition(但注意需要alibaba导excel的包)
package com.ruoyi.common.convert;
import com.alibaba.excel.converters.Converter;
import com.alibaba.excel.enums.CellDataTypeEnum;
import com.alibaba.excel.metadata.GlobalConfiguration;
import com.alibaba.excel.metadata.data.WriteCellData;
import com.alibaba.excel.metadata.property.ExcelContentProperty;
import java.text.SimpleDateFormat;
import java.util.Date;
/**
* 日期格式转换 用于导出日期类异常
* @fly 2024-11-01 16:41:55
**/
public class DateFormatTransition implements Converter<Date> {
private static final String PATTERN_YYYY_MM_DD = "yyyy-MM-dd";
@Override
public Class<?> supportJavaTypeKey() {
return Converter.super.supportJavaTypeKey();
}
@Override
public CellDataTypeEnum supportExcelTypeKey() {
return Converter.super.supportExcelTypeKey();
}
@Override
public WriteCellData<?> convertToExcelData(Date value, ExcelContentProperty contentProperty,
GlobalConfiguration globalConfiguration) throws Exception {
SimpleDateFormat sdf = new SimpleDateFormat(PATTERN_YYYY_MM_DD);
String dateValue = sdf.format(value);
return new WriteCellData<>(dateValue);
}
}
具体使用:
@ExcelProperty(value = "创建时间",converter = DateFormatTransition.class)
private Date createTime;
8.最后记得检查一下工具类是否含有get、set方法或者使用了lombok的情况下直接在类上加上@Data注解
因为子类的toString方法虽然已经重写,内部也有基于这些通用字段的get和set方法,这是将父类的字段继承过来再进行get和set操作的,但父类是没有这些通用字段的get和set方法,就不能在导出时正常赋值,从而导致导出的excel表列数据为空