EasyExcel——自定义注解、实现动态获取下拉框内容

问题场景

在使用EasyExcel进行导出时,有时候需要根据数据库表内容,为导出数据列单元格做内容下拉框,通常在下载导入模板时使用,这样可有将导出的模板作为导入数据的表单,实现对用户输入的一个合法限制,效果大致如下:

代码实现

EasyExcel工具的使用这里就不赘述了,这里主要展示了在导出过程中是如何从数据库表获取动态下拉框内容,以及和固定下拉框内容的对比。

导出实体类

import com.alibaba.excel.annotation.ExcelProperty;

import com.alibaba.excel.annotation.format.DateTimeFormat;
import com.alibaba.excel.annotation.write.style.*;
import com.alibaba.excel.enums.poi.HorizontalAlignmentEnum;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.util.Date;

@Data
@AllArgsConstructor
@NoArgsConstructor

@HeadRowHeight(value = 25) // 头部行高
@ContentRowHeight(value = 15) // 内容行高
@ColumnWidth(value = 20) // 列宽
@HeadStyle(horizontalAlignment = HorizontalAlignmentEnum.CENTER) // 表头样式
@HeadFontStyle(fontName = "黑体")
@ContentStyle(horizontalAlignment = HorizontalAlignmentEnum.CENTER) // 内容样式

//添加自定关注解,将导出信息增加下拉框判断

public class EmpDo {

//    private String source = "";
//    private MyExcelSelected excelSelected

    @ExcelProperty("姓名")
    @ColumnWidth(10)
    private String name;

    /**
     * 性别: 1:男  0:女
     */
    @ExcelSelected(source = {"男","女"})
    @ExcelProperty(value = "性别", converter = GenderConverter.class)
    @ColumnWidth(10)
    private Integer gender;

    @ExcelProperty("年龄")
    @ColumnWidth(10)

    private Integer age;

    @ExcelProperty("电话")
    @ColumnWidth(25)
    private String tel;

    @ExcelProperty("邮箱")
    @ColumnWidth(25)
    private String email;
    /**
     * 对照部门表
     * 1-开发部  2-运维部  3-开发一部  4-开发二部  5-开发三部  6-运维一部  7-运维二部
     */
    //动态获取下拉框内容
    @ExcelSelected(sourceClass = DeptSelected.class)
    @ExcelProperty(value = "部门", converter = DeptConverter.class)
    @ColumnWidth(10)
    private String deptId;

    @ExcelProperty(value = "入职时间")
    @ColumnWidth(25)
    @DateTimeFormat("yyyy-MM-dd")
    private Date hireDate;

    /**
     * 工作状态(0:在职、1:离职、2:复职、3:外部人员、4:退休人员)
     */
    @ExcelSelected(source = {"在职","离职","复职","外部人员","退休人员"})
    @ExcelProperty(value = "工作状态", converter = JobStatusConverter.class)
    @ColumnWidth(20)
    private Integer jobStatus;

    /**
     * 是否党员(0:党员 1:非党员)
     */
    @ExcelSelected(source = {"党员","非党员"})
    @ExcelProperty(value = "是否党员", converter = IspartyConverter.class)
    @ColumnWidth(20)
    private Integer isParty;
}

这里演示的是部门列动态获取下拉框内容,性别、工作状态以及是否党员状态值固定,所以直接在导入导出转换器内写成固定的了。 

自定义注解

(1)

@Documented
@Target({ElementType.FIELD})//用此注解用在属性上。
@Retention(RetentionPolicy.RUNTIME)//注解不仅被保存到class文件中,jvm加载class文件之后,仍然存在;
public @interface ExcelSelected {
    /**
     * 固定下拉内容
     */
    String[] source() default {};

    /**
     * 动态下拉内容
     */
    Class<? extends ExcelDynamicSelect>[] sourceClass() default {};

    /**
     * 设置下拉框的起始行,默认为第二行
     */
    int firstRow() default 1;

    /**
     * 设置下拉框的结束行,默认为最后一行
     */
    int lastRow() default 0x10000;
}

(2)

public interface ExcelDynamicSelect {
    /**
     * 获取动态生成的下拉框可选数据
     * @return 动态生成的下拉框可选数据
     */
    String[] getSource();
}

自定义注解解析类

/**
 * 自定义注解解析类
 */
@Data
@Slf4j
public class ExcelSelectedResolve {
    /**
     * 下拉内容
     */
    private String[] source;

    /**
     * 设置下拉框的起始行,默认为第二行
     */
    private int firstRow;

    /**
     * 设置下拉框的结束行,默认为最后一行
     */
    private int lastRow;

    public String[] resolveSelectedSource(ExcelSelected excelSelected) {
        if (excelSelected == null) {
            return null;
        }

        // 获取固定下拉框的内容
        String[] source = excelSelected.source();
        if (source.length > 0) {
            return source;
        }

        // 获取动态下拉框的内容
        Class<? extends ExcelDynamicSelect>[] classes = excelSelected.sourceClass();
        if (classes.length > 0) {
            try {
                ExcelDynamicSelect excelDynamicSelect = classes[0].newInstance();
                String[] dynamicSelectSource = excelDynamicSelect.getSource();
                if (dynamicSelectSource != null && dynamicSelectSource.length > 0) {
                    return dynamicSelectSource;
                }
            } catch (InstantiationException | IllegalAccessException e) {
                log.error("解析动态下拉框数据异常", e);
            }
        }
        return null;
    }

}

动态下拉列数据配置类 

这个类的作用是获取数据库中所有的部门信息,并返回作为部门列的下拉框内容。

如果有其他列也许要制作动态内容下拉框,以此类推创建对应的类实现相同接口即可。

//动态下拉框中的数据配置类
public class DeptSelected implements ExcelDynamicSelect{

    @Override
    public String[] getSource() {
        //查询下拉框中需要的数据  部门信息
        SysDeptDao sysDeptDao = SpringContextUtil.getBean(SysDeptDao.class);
        List<SysDeptEntity> sysDeptEntities = sysDeptDao.selectList(null);
        List<String> nameList = new ArrayList<>();
        //获取部门名称填入集合
        for (SysDeptEntity dept : sysDeptEntities) {
            nameList.add(dept.getName());
        }
        //将部门名称集合转换为数组返回 作为下拉框内容
        return nameList.toArray(new String[]{});
    }
}

这里返回的数据将作为导出实体类中的部门列下拉框内容:

转换器

部门转换器

这里的转换Map集合对照内容是从数据库获取的,作用是将人员信息中的部门id导出时转换为部门名称。

/**
 * @Description: 部门转换器
 */
public class DeptConverter implements Converter<String> {

    private final SysDeptDao sysDeptDao = SpringContextUtil.getBean(SysDeptDao.class);
    private final List<SysDeptEntity> deptList = sysDeptDao.selectList(null);

    @Override
    public Class<?> supportJavaTypeKey() {
        //实体类对象属性类型
        return String.class;
    }

    @Override
    public CellDataTypeEnum supportExcelTypeKey() {
        //excel中对应的单元格属性类型
        return CellDataTypeEnum.STRING;
    }

    /**
     * 将单元格中数据转化为java对象属性 
     * @param context
     * @return
     * @throws Exception
     */
    @Override
    public String convertToJavaData(ReadConverterContext<?> context) throws Exception {
        //创建集合用于存储部门id和名称对应关系
        Map<String,String> mapToJavaData = new HashMap<>();
        //遍历部门列表将部门id和名称放入map
        for (SysDeptEntity sysDeptEntity : deptList) {
            mapToJavaData.put(sysDeptEntity.getName(),sysDeptEntity.getId());
        }
        //从cellData中读取数据 转换为实体类中的对象数值
        return mapToJavaData.get(context.getReadCellData().getStringValue());
    }

    /**
     * 将java对象转化为excel单元格数据  
     * @param context
     * @return
     * @throws Exception
     */
    @Override
    public WriteCellData<?> convertToExcelData(WriteConverterContext<String> context) throws Exception {

        Map<String,String> mapToExcelData = new HashMap<>();

        for (SysDeptEntity sysDeptEntity : deptList) {
            mapToExcelData.put(sysDeptEntity.getId(),sysDeptEntity.getName());
        }


        //将java属性转换为excel对应属性类型
        return new WriteCellData<>(mapToExcelData.get(context.getValue()));
    }
}

性别转换器

性别只有男、女两种选择,所以这里直接固定了Map集合的内容,直接将存储的值转换为名称导出。其他固定下拉内容的列同理。

public class GenderConverter implements Converter<Integer> {

    @Override
    public Class<?> supportJavaTypeKey() {
        //实体类中对象属性类型
        return Integer.class;
    }
    @Override
    public CellDataTypeEnum supportExcelTypeKey() {
        //Excel中对应的cellData(单元格数据)属性类型
        return CellDataTypeEnum.STRING;
    }

    /**
     * 将单元格数据转化为java对象,男-1,女-0,用于导入时识别转化为实体类相应类型字段
     * @param context
     * @return
     * @throws Exception
     */
    @Override
    public Integer convertToJavaData(ReadConverterContext<?> context) throws Exception {

        Map<String,Integer> mapToJavaData = new HashMap<>();
        mapToJavaData.put("男",1);
        mapToJavaData.put("女",0);

        // 从CellData中读取数据,判断Excel中的值,将其转换为预期的数值
        return mapToJavaData.get(context.getReadCellData().getStringValue());
    }

    /**
     * 将java对象转为单元格数据,也就是0转成女,1转成男,用于导出excel时对性别字段进行转换
     * @param context
     * @return
     * @throws Exception
     */
    @Override
    public WriteCellData<?> convertToExcelData(WriteConverterContext<Integer> context) throws Exception {

        Map<Integer,String> mapToExcelData = new HashMap<>();
        mapToExcelData.put(1,"男");
        mapToExcelData.put(0,"女");

        // 判断实体类中获取的值,转换为Excel预期的值,并封装为CellData对象
        return new WriteCellData<>(mapToExcelData.get(context.getValue()));
    }
}

测试结果

数据库部门表信息

导出Excel表部门下拉框内容

注: 内容为本人参考其他博主分享,结合自身需求学习实践产生,参考博客为:

Easyexcel生成excel并通过自定义注解实现下拉框以及动态下拉框(将数据库中的数据显示在excel下拉框中)-CSDN博客

EasyExcel中,可以通过注解自定义样式。下面是一个示例: 首先,定义一个样式的类,例如: ```java public class ExcelStyle { @ContentStyle(fillPatternType = FillPatternType.SOLID_FOREGROUND, fillForegroundColor = IndexedColors.YELLOW) private String contentStyle; @HeadStyle(fillPatternType = FillPatternType.SOLID_FOREGROUND, fillForegroundColor = IndexedColors.GREY_25_PERCENT) private String headStyle; // 省略getter和setter方法 } ``` 然后,在需要导出Excel的实体类中使用该样式注解,例如: ```java public class Student { @ExcelProperty(value = "姓名", index = 0) @CellStyleAnnotation(ExcelStyle.class) // 使用自定义样式注解 private String name; @ExcelProperty(value = "年龄", index = 1) private Integer age; // 省略getter和setter方法 } ``` 最后,在导出Excel的方法中,使用`EasyExcel.write().sheet().doWrite()`方法导出数据,例如: ```java public void exportExcel(List<Student> studentList) { // 创建ExcelWriter对象 ExcelWriter excelWriter = EasyExcel.write("student.xlsx").build(); // 创建Sheet对象,并指定表头和实体类 WriteSheet writeSheet = EasyExcel.writerSheet("学生信息").head(Student.class).build(); // 写入数据 excelWriter.write(studentList, writeSheet); // 关闭资源 excelWriter.finish(); } ``` 这样,在生成的Excel文件中,名字列的内容将会使用自定义样式。你可以根据需要修改`ExcelStyle`类中的样式属性,以达到自定义样式的效果。
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值