com.mobaijun.easyexcel.handler.ExcelDownHandler Maven / Gradle / Ivy
Show all versions of easyexcel-spring-boot-starter Show documentation
/*
* Copyright (C) 2022 [www.mobaijun.com]
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.mobaijun.easyexcel.handler;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ArrayUtil;
import cn.hutool.core.util.EnumUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.excel.metadata.FieldCache;
import com.alibaba.excel.metadata.FieldWrapper;
import com.alibaba.excel.util.ClassUtils;
import com.alibaba.excel.write.handler.SheetWriteHandler;
import com.alibaba.excel.write.metadata.holder.WriteSheetHolder;
import com.alibaba.excel.write.metadata.holder.WriteWorkbookHolder;
import com.mobaijun.common.collection.StreamUtil;
import com.mobaijun.core.exception.ServiceException;
import com.mobaijun.core.service.DictService;
import com.mobaijun.core.spring.SpringUtil;
import com.mobaijun.easyexcel.annotation.ExcelDictFormat;
import com.mobaijun.easyexcel.annotation.ExcelEnumFormat;
import com.mobaijun.easyexcel.core.DropDownOptions;
import com.mobaijun.easyexcel.util.StringUtil;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import lombok.extern.slf4j.Slf4j;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.DataValidation;
import org.apache.poi.ss.usermodel.DataValidationConstraint;
import org.apache.poi.ss.usermodel.DataValidationHelper;
import org.apache.poi.ss.usermodel.Name;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.ss.util.CellRangeAddressList;
import org.apache.poi.ss.util.WorkbookUtil;
import org.apache.poi.xssf.usermodel.XSSFDataValidation;
/**
* Description:
* Excel表格下拉选操作
* 考虑到下拉选过多可能导致Excel打开缓慢的问题,只校验前1000行
*
* 即只有前1000行的数据可以用下拉框,超出的自行通过限制数据量的形式,第二次输出
* Author: [mobaijun]
* Date: [2024/8/20 18:20]
* IntelliJ IDEA Version: [IntelliJ IDEA 2023.1.4]
*/
@Slf4j
public class ExcelDownHandler implements SheetWriteHandler {
/**
* Excel表格中的列名英文
* 仅为了解析列英文,禁止修改
*/
private static final String EXCEL_COLUMN_NAME = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
/**
* 单选数据Sheet名
*/
private static final String OPTIONS_SHEET_NAME = "options";
/**
* 联动选择数据Sheet名的头
*/
private static final String LINKED_OPTIONS_SHEET_NAME = "linkedOptions";
/**
* 下拉可选项
*/
private final List dropDownOptions;
/**
* 字典服务
*/
private final DictService dictService;
/**
* 当前单选进度
*/
private int currentOptionsColumnIndex;
/**
* 当前联动选择进度
*/
private int currentLinkedOptionsSheetIndex;
public ExcelDownHandler(List options) {
this.dropDownOptions = options;
this.currentOptionsColumnIndex = 0;
this.currentLinkedOptionsSheetIndex = 0;
this.dictService = SpringUtil.getBean(DictService.class);
}
/**
* 开始创建下拉数据
* 1.通过解析传入的@ExcelProperty同级是否标注有@DropDown选项
* 如果有且设置了value值,则将其直接置为下拉可选项
*
* 2.或者在调用ExcelUtil时指定了可选项,将依据传入的可选项做下拉
*
* 3.二者并存,注意调用方式
*/
@Override
public void afterSheetCreate(WriteWorkbookHolder writeWorkbookHolder, WriteSheetHolder writeSheetHolder) {
Sheet sheet = writeSheetHolder.getSheet();
// 开始设置下拉框 HSSFWorkbook
DataValidationHelper helper = sheet.getDataValidationHelper();
Workbook workbook = writeWorkbookHolder.getWorkbook();
FieldCache fieldCache = ClassUtils.declaredFields(writeWorkbookHolder.getClazz(), writeWorkbookHolder);
for (Map.Entry entry : fieldCache.getSortedFieldMap().entrySet()) {
Integer index = entry.getKey();
FieldWrapper wrapper = entry.getValue();
Field field = wrapper.getField();
// 循环实体中的每个属性
// 可选的下拉值
List options = new ArrayList<>();
if (field.isAnnotationPresent(ExcelDictFormat.class)) {
// 如果指定了@ExcelDictFormat,则使用字典的逻辑
ExcelDictFormat format = field.getDeclaredAnnotation(ExcelDictFormat.class);
String dictType = format.dictType();
String converterExp = format.readConverterExp();
if (StringUtil.isNotBlank(dictType)) {
// 如果传递了字典名,则依据字典建立下拉
Collection values = Optional.ofNullable(dictService.getAllDictByDictType(dictType))
.orElseThrow(() -> new ServiceException(String.format("字典 %s 不存在", dictType)))
.values();
options = new ArrayList<>(values);
} else if (StringUtil.isNotBlank(converterExp)) {
// 如果指定了确切的值,则直接解析确切的值
List strList = StringUtil.splitList(converterExp, format.separator());
options = StreamUtil.toList(strList, s -> StringUtil.split(s, "=")[1]);
}
} else if (field.isAnnotationPresent(ExcelEnumFormat.class)) {
// 否则如果指定了@ExcelEnumFormat,则使用枚举的逻辑
ExcelEnumFormat format = field.getDeclaredAnnotation(ExcelEnumFormat.class);
List