easyexcel导出使用注解设置下拉选数据

maven依赖

<!-- easy excel -->
<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>easyexcel</artifactId>
    <version>3.0.5</version>
</dependency>

获取下拉数据接口类, 下拉数据需实现此接口类

public interface ExcelSelectorService {

    /**
     * 获取下拉数据
     *
     * @return java.lang.String[]
     * @author SunLingDa
     * @date 2022/9/20 16:50
     */
    String[] getSelectorData();

    /**
     * 根据字典key获取下拉数据
     *
     * @param dictKeyValue 字典key
     * @return java.lang.String[]
     * @author SunLingDa
     * @date 2022/9/20 16:50
     */
    String[] getSelectorData(String dictKeyValue);
}

下拉选的注解类, 可以固定数据, 也可以根据字典获取数据, 根据自己的业务处理

public @interface ExcelSelector {

    /**
     * 固定数据
     */
    String[] fixedSelector() default {};

    /**
     * 字典key
     */
    String dictKeyValue() default "";

    /**
     * 服务类
     */
    Class<? extends ExcelSelectorService>[] serviceClass() default {};
}

下拉选处理类, 方法resolveExcelSelector获取下拉数据

@Data
@Slf4j
public class ExcelSelectorResolve {

    /**
     * 下拉选起始行
     */
    private int startRow = 0;

    /**
     * 下拉选结束行
     */
    private int endRow = 500;

    /**
     * 下拉数据集
     */
    private String[] selectorData;

    /**
     * 解决Excel注解的下拉选数据获取
     *
     * @param excelSelector Excel下拉选
     * @return java.lang.String[]
     * @author SunLingDa
     * @date 2022/9/20 16:58
     */
    public String[] resolveExcelSelector(ExcelSelector excelSelector) {
        if (excelSelector == null) {
            return null;
        }

        String[] fixedSelector = excelSelector.fixedSelector();
        if (ArrayUtil.isNotEmpty(fixedSelector)) {
            return fixedSelector;
        }
        String[] selectorData = null;
        Class<? extends ExcelSelectorService>[] serviceClass = excelSelector.serviceClass();
        if (ArrayUtil.isNotEmpty(serviceClass)) {
            try {
                ExcelSelectorService excelSelectorService = serviceClass[0].newInstance();
                if (StrUtil.isBlank(excelSelector.dictKeyValue())) {
                    selectorData = excelSelectorService.getSelectorData();
                } else {
                    selectorData = excelSelectorService.getSelectorData(excelSelector.dictKeyValue());
                }
            } catch (InstantiationException | IllegalAccessException e) {
                log.error(e.getMessage(), e);
            }
        }
        return selectorData;
    }
}

数据写入的处理器类

@Data
public class ExcelSelectorDataWriteHandler implements SheetWriteHandler {

    private final Map<Integer, ExcelSelectorResolve> selectedMap;

    @Override
    public void afterSheetCreate(WriteWorkbookHolder writeWorkbookHolder, WriteSheetHolder writeSheetHolder) {
        Sheet sheet = writeSheetHolder.getSheet();
        DataValidationHelper helper = sheet.getDataValidationHelper();
        if (CollUtil.isEmpty(selectedMap)) {
            return;
        }
        selectedMap.forEach((k, v) -> {
            // 下拉 首行 末行 首列 末列
            CellRangeAddressList list = new CellRangeAddressList(v.getStartRow(), v.getEndRow(), k, k);
            // 下拉值
            DataValidationConstraint constraint = helper.createExplicitListConstraint(v.getSelectorData());
            DataValidation validation = helper.createValidation(constraint, list);
            validation.setErrorStyle(DataValidation.ErrorStyle.STOP);
            validation.setShowErrorBox(true);
            validation.setSuppressDropDownArrow(true);
            validation.createErrorBox("提示", "请输入下拉选项中的内容");
            sheet.addValidationData(validation);
        });
    }
}

Excel数据监听类

@Data
@Slf4j
public class ExcelCellDataListener<T> implements ReadListener<T> {

    /**
     * 数据集合
     */
    private List<T> data = CollUtil.newArrayList();

    private Map<Integer, ExcelFailRecord> failMap = CollUtil.newHashMap(16);

    @Override
    public void invoke(T bean, AnalysisContext context) {
        boolean emptyRow = true;
        List<Field> fieldList = getFieldList(bean.getClass());
        for (Field field : fieldList) {
            field.setAccessible(true);
            try {
                Object fieldValue = field.get(bean);
                if (fieldValue instanceof String) {
                    if (StrUtil.isNotBlank((String) fieldValue)) {
                        emptyRow = false;
                        break;
                    }
                }
                if (ObjectUtil.isNotNull(fieldValue)) {
                    emptyRow = false;
                    break;
                }
            } catch (IllegalAccessException e) {
                log.error(e.getMessage(), e);
            }
        }
        if (!emptyRow) {
        	// 不处理空数据行
            data.add(bean);
            ReadRowHolder readRowHolder = context.readRowHolder();
            log.info("rowIndex: {}, rowType: {}", readRowHolder.getRowIndex(), readRowHolder.getRowType());
        }
    }

    @Override
    public void onException(Exception exception, AnalysisContext context) {
        log.error(exception.getMessage(), exception);
        if (exception instanceof ExcelDataConvertException) {
            ExcelDataConvertException e = (ExcelDataConvertException) exception;
            ExcelFailRecord excelFailRecord = new ExcelFailRecord();
            excelFailRecord.setRow(e.getRowIndex());
            excelFailRecord.setColumn(e.getColumnIndex());
            excelFailRecord.setFailMessage(e.getCause().getMessage());

            failMap.put(e.getRowIndex(), excelFailRecord);
        }
    }

    @Override
    public void doAfterAllAnalysed(AnalysisContext analysisContext) {
        log.info("Excel Deal Finish");
    }
}

导出Excel工具类

@Slf4j
public class ExcelUtil {

    /**
     * 默认的sheet名称
     */
    private static final String DEFAULT_SHEET_NAME = "Sheet1";

    /**
     * 写Excel数据
     *
     * @param response response
     * @param fileName 文件名称
     * @param data     数据
     * @param clazz    类class
     * @author SunLingDa
     * @date 2022/9/6 13:59
     */
    public static <T> void writeExcel(HttpServletResponse response, String fileName, List<T> data, Class<?> clazz) {
        writeExcel(response, fileName, DEFAULT_SHEET_NAME, data, clazz);
    }

    /**
     * 写Excel数据
     *
     * @param response  response
     * @param fileName  文件名称
     * @param sheetName sheet名称
     * @param data      数据
     * @param clazz     类class
     * @author SunLingDa
     * @date 2022/9/6 13:58
     */
    public static <T> void writeExcel(HttpServletResponse response, String fileName, String sheetName, List<T> data, Class<?> clazz) {
        OutputStream outputStream = null;
        Map<Integer, ExcelSelectorResolve> selectedMap = getSelectedMap(clazz);
        ExcelSelectorDataWriteHandler writeHandler = new ExcelSelectorDataWriteHandler(selectedMap);
        try {
            outputStream = getOutputStream(response, fileName, ExcelTypeEnum.XLSX);
            EasyExcel.write(outputStream, clazz).excelType(ExcelTypeEnum.XLSX).sheet(sheetName).registerWriteHandler(writeHandler).doWrite(data);
        } catch (Exception e) {
            log.error(e.getMessage(), e);
        } finally {
            if (outputStream != null) {
                try {
                    outputStream.close();
                } catch (IOException e) {
                    log.error(e.getMessage(), e);
                }
            }
        }
    }

    /**
     * 读取不包含头信息的Excel
     *
     * @param file  文件
     * @param clazz 类class
     * @author SunLingDa
     * @date 2022/9/6 13:20
     */
    public static <T> List<T> readExcelNotContainHeader(MultipartFile file, Class<T> clazz) throws IOException {
        return readExcel(1, file, clazz);
    }

    /**
     * 读取包含头信息的Excel
     *
     * @param file  文件
     * @param clazz 类class
     * @author SunLingDa
     * @date 2022/9/6 13:20
     */
    public static <T> List<T> readExcelContainHeader(MultipartFile file, Class<T> clazz) throws IOException {
        return readExcel(0, file, clazz);
    }

    /**
     * 读取Excel
     *
     * @param rowNum 行数
     * @param file   文件
     * @param clazz  类class
     * @author SunLingDa
     * @date 2022/9/6 13:20
     */
    public static <T> List<T> readExcel(int rowNum, MultipartFile file, Class<T> clazz) throws IOException {
        String fileName = file.getOriginalFilename();
        InputStream inputStream = file.getInputStream();
        return readExcel(rowNum, fileName, inputStream, clazz);
    }

    /**
     * 读取不包含头信息的Excel
     *
     * @param fileName    文件名称
     * @param inputStream 流
     * @param clazz       类
     * @author SunLingDa
     * @date 2022/9/6 13:16
     */
    public static <T> List<T> readExcelNotContainHeader(String fileName, InputStream inputStream, Class<T> clazz) {
        return readExcel(1, fileName, inputStream, clazz);
    }

    /**
     * 读取包含头信息的Excel
     *
     * @param fileName    文件名称
     * @param inputStream 流
     * @param clazz       类
     * @param listener    监听
     * @author SunLingDa
     * @date 2022/9/6 13:16
     */
    public static <T> List<T> readExcelContainHeader(String fileName, InputStream inputStream, Class<T> clazz, ExcelCellDataListener<T> listener) {
        return readExcel(0, fileName, inputStream, clazz);
    }

    /**
     * 读取Excel
     *
     * @param rowNum      行数
     * @param fileName    文件名称
     * @param inputStream 流
     * @param clazz       类
     * @author SunLingDa
     * @date 2022/9/6 13:16
     */
    public static <T> List<T> readExcel(int rowNum, String fileName, InputStream inputStream, Class<T> clazz) {
        ExcelCellDataListener<T> dataListener = new ExcelCellDataListener<>();
        try {
            ExcelReader excelReader = getExcelReader(rowNum, fileName, inputStream, clazz, dataListener);
            if (excelReader == null) {
                return null;
            }
            List<ReadSheet> sheetList = excelReader.excelExecutor().sheetList();
            for (ReadSheet sheet : sheetList) {
                excelReader.read(sheet);
            }
            excelReader.finish();
        } finally {
            try {
                inputStream.close();
            } catch (IOException e) {
                log.error(e.getMessage(), e);
            }
        }
        return dataListener.getData();
    }

    /**
     * 获取OutputStream
     *
     * @param response response
     * @param fileName 文件名称
     * @return java.io.OutputStream
     * @author SunLingDa
     * @date 2022/9/6 13:44
     */
    private static OutputStream getOutputStream(HttpServletResponse response, String fileName, ExcelTypeEnum typeEnum) throws Exception {
        fileName = URLEncoder.encode(fileName, "UTF-8");
        response.setStatus(200);
        response.setCharacterEncoding("UTF-8");
        if (ExcelTypeEnum.CSV.equals(typeEnum)) {
            response.setContentType("application/csv");
        } else {
            response.setContentType("application/vnd.ms-excel");
        }
        response.setHeader("Content-Disposition", "attachment;filename=" + fileName + typeEnum.getValue());
        return response.getOutputStream();
    }

    /**
     * 获取ExcelReader
     *
     * @param rowNum      行数
     * @param fileName    文件名称
     * @param inputStream 流
     * @param clazz       类class
     * @param listener    监听
     * @return com.alibaba.excel.ExcelReader
     * @author SunLingDa
     * @date 2022/9/6 13:19
     */
    private static ExcelReader getExcelReader(int rowNum, String fileName, InputStream inputStream, Class<?> clazz, ReadListener listener) {
        if (StrUtil.isBlank(fileName)) {
            return null;
        }
        String fileExtName = getFileExtName(fileName);
        EasyExcelTypeEnum typeEnum = EasyExcelTypeEnum.parseType(fileExtName);
        if (typeEnum == null) {
            log.info("表格类型错误");
        }

        return EasyExcel.read(inputStream, clazz, listener).headRowNumber(rowNum).build();
    }

    /**
     * 获取文件后缀名称 .xxx
     *
     * @param fileName 文件名称
     * @return java.lang.String
     * @author SunLingDa
     * @date 2022/9/6 11:23
     */
    private static String getFileExtName(String fileName) {
        if (StrUtil.isBlank(fileName)) {
            return null;
        }
        int lastIndex = fileName.lastIndexOf(StrUtil.DOT);
        if (lastIndex != -1) {
            return fileName.substring(lastIndex);
        }
        return null;
    }

    /**
     * 获取样式
     *
     * @return com.alibaba.excel.write.style.HorizontalCellStyleStrategy
     * @author SunLingDa
     * @date 2022/9/6 16:20
     */
    private static HorizontalCellStyleStrategy getStyleStrategy() {
        // 表头样式
        WriteCellStyle headStyle = new WriteCellStyle();
        // 设置表头居中对齐
        headStyle.setHorizontalAlignment(HorizontalAlignment.CENTER);
        // 内容样式
        WriteCellStyle contentStyle = new WriteCellStyle();
        // 设置内容靠左对齐
        contentStyle.setHorizontalAlignment(HorizontalAlignment.LEFT);
        return new HorizontalCellStyleStrategy(headStyle, contentStyle);
    }

    /**
     * 获取下拉的map
     *
     * @param clazz 类class
     * @return java.util.Map
     * @author SunLingDa
     * @date 2022/9/20 17:45
     */
    private static Map<Integer, ExcelSelectorResolve> getSelectedMap(Class<?> clazz) {
        Map<Integer, ExcelSelectorResolve> selectedMap = CollUtil.newHashMap();
        Field[] fields = clazz.getDeclaredFields();
        for (Field field : fields) {
            if (!field.isAnnotationPresent(ExcelSelector.class) || !field.isAnnotationPresent(ExcelProperty.class)) {
                continue;
            }
            ExcelSelector excelSelector = field.getAnnotation(ExcelSelector.class);
            ExcelProperty excelProperty = field.getAnnotation(ExcelProperty.class);
            ExcelSelectorResolve resolve = new ExcelSelectorResolve();
            String[] data = resolve.resolveExcelSelector(excelSelector);
            if (ArrayUtil.isNotEmpty(data)) {
                resolve.setSelectorData(data);
                selectedMap.put(excelProperty.index(), resolve);
            }
        }
        return selectedMap;
    }
}

下拉获取数据实现类, 我的是获取字典数据, 根据自己业务处理

@Slf4j
@Service
public class DeviceExcelSelectorServiceImpl implements ExcelSelectorService {

    @Override
    public String[] getSelectorData() {
        return null;
    }

    @Override
    public String[] getSelectorData(String dictKeyValue) {
        IDataDictService dataDictService = SpringContextUtil.getBean(IDataDictService.class);
        List<DataDict> list = dataDictService.getDataByKey(dictKeyValue);
        if (CollUtil.isEmpty(list)) {
            return null;
        }
        return list.stream().map(DataDict::getLabel).toArray(String[]::new);
    }
}

获取上下文工具类

@Component
@Lazy(value = false)
public class SpringContextUtil implements ApplicationContextAware {

    private static ApplicationContext applicationContext;

    @Override
    public void setApplicationContext(@NonNull ApplicationContext applicationContext) throws BeansException {
        if (SpringContextUtil.applicationContext == null) {
            SpringContextUtil.applicationContext = applicationContext;
        }
    }

    /**
     * 获取ApplicationContext
     *
     * @return org.springframework.context.ApplicationContext
     * @author SunLingDa
     * @date 2022/8/22 17:05
     */
    public static ApplicationContext getApplicationContext() {
        return applicationContext;
    }

    /**
     * 根据名称获取Bean对象
     *
     * @param name 名称
     * @return T
     * @author SunLingDa
     * @date 2022/8/22 17:05
     */
    public static <T> T getBean(String name) {
        //noinspection unchecked
        return (T) applicationContext.getBean(name);
    }

    /**
     * 根据class获取Bean对象
     *
     * @param clazz class
     * @return T
     * @author SunLingDa
     * @date 2022/8/22 17:06
     */
    public static <T> T getBean(Class<T> clazz) {
        return applicationContext.getBean(clazz);
    }

    /**
     * 根据名称和class获取Bean对象
     *
     * @param name  名称
     * @param clazz class
     * @return T
     * @author SunLingDa
     * @date 2022/8/22 17:06
     */
    public static <T> T getBean(String name, Class<T> clazz) {
        return applicationContext.getBean(name, clazz);
    }

    /**
     * 获取配置文件数据
     *
     * @param key key
     * @return java.lang.String
     * @author SunLingDa
     * @date 2022/8/23 11:38
     */
    public static String getProperty(String key) {
        return applicationContext.getEnvironment().getProperty(key);
    }

    /**
     * 注册bean
     *
     * @param beanName bean名称
     * @param bean     bean
     * @author SunLingDa
     * @date 2022/8/23 11:39
     */
    public static <T> void registerBean(String beanName, T bean) {
        ConfigurableApplicationContext context = (ConfigurableApplicationContext) applicationContext;
        context.getBeanFactory().registerSingleton(beanName, bean);
    }
}

导出对应类, 固定值和获取字典值, DeviceExcelSelectorServiceImpl实现ExcelSelectorService接口

@Data
@ColumnWidth(20)
@HeadStyle(horizontalAlignment = HorizontalAlignmentEnum.CENTER)
@ContentStyle(horizontalAlignment = HorizontalAlignmentEnum.LEFT)
public class CameraExportExcel {

    @ExcelProperty(value = "设备名称", index = 0)
    private String name;

    @ExcelProperty(value = "设备编号", index = 1)
    private String deviceId;

    @ExcelIgnore
    private String commTypeCode;

    @ExcelProperty(value = "视频接入协议", index = 2)
    @ExcelSelector(serviceClass = DeviceExcelSelectorServiceImpl.class, dictKeyValue = "videoAccessProtocol")
    private String commTypeName;

	@ExcelSelector(fixedSelector = {"是", "否"})
    @ExcelProperty(value = "是否配有IM采集模块", index = 3)
    private String imName;
}

导出service类

@Override
    public void exportExcel() {
        List<CameraExportExcel> dataList = cameraMapper.getCameraExportData();
        if (CollUtil.isEmpty(dataList)) {
            return;
        }
        ExcelUtil.writeExcel(this.response, "设备列表", dataList, CameraExportExcel.class);
    }

导出就是这个样子了, 希望能帮助大家
easyexcel导出使用注解设置下拉选数据_第1张图片

你可能感兴趣的:(easyexcel导出使用注解设置下拉选数据)