使用easyExcel导出多级表头及下拉选框选择数据

最近有个需求,要导出Excel模板。

 

这个模板需要具备多级表头以及有些列只能输入特定的字典值。

开发了一个工具类满足需求,记录一下。

一、定义一个注解,通过注解方式配置需要下拉的字段和下拉内容:


import java.lang.annotation.*;

/**
 * 标注导出的列为下拉框类型,并为下拉框设置内容
 */
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface ExcelSelected {
    /**
     * 固定下拉内容
     */
    String[] source() default {};


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

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

 二、通过反射解析注解,将数据动态添加到Class模板当中


import lombok.Data;
import lombok.extern.slf4j.Slf4j;

@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;
        }


        return null;
    }

}

import com.alibaba.excel.write.handler.SheetWriteHandler;
import com.alibaba.excel.write.metadata.holder.WriteSheetHolder;
import com.alibaba.excel.write.metadata.holder.WriteWorkbookHolder;
import lombok.AllArgsConstructor;
import lombok.Data;
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.Sheet;
import org.apache.poi.ss.util.CellRangeAddressList;

import java.util.Map;

@Data
@AllArgsConstructor
public class SelectedSheetWriteHandler implements SheetWriteHandler {

    private final Map<Integer, ExcelSelectedResolve> selectedMap;


    @Override
    public void beforeSheetCreate(WriteWorkbookHolder writeWorkbookHolder, WriteSheetHolder writeSheetHolder) {

    }


    @Override
    public void afterSheetCreate(WriteWorkbookHolder writeWorkbookHolder, WriteSheetHolder writeSheetHolder) {
        // 这里可以对cell进行任何操作
        Sheet sheet = writeSheetHolder.getSheet();
        DataValidationHelper helper = sheet.getDataValidationHelper();
        selectedMap.forEach((k, v) -> {
            // 设置下拉列表的行: 首行,末行,首列,末列
            CellRangeAddressList rangeList = new CellRangeAddressList(v.getFirstRow(), v.getLastRow(), k, k);
            // 设置下拉列表的值
            DataValidationConstraint constraint = helper.createExplicitListConstraint(v.getSource());
            // 设置约束
            DataValidation validation = helper.createValidation(constraint, rangeList);
            // 阻止输入非下拉选项的值
            validation.setErrorStyle(DataValidation.ErrorStyle.STOP);
            validation.setShowErrorBox(true);
            validation.setSuppressDropDownArrow(true);
            validation.createErrorBox("提示", "请输入下拉选项中的内容");
            sheet.addValidationData(validation);
        });
    }
}

import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.ExcelWriter;
import com.alibaba.excel.annotation.ExcelProperty;
import com.alibaba.excel.write.metadata.WriteSheet;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.util.CollectionUtils;

import javax.servlet.http.HttpServletResponse;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;
import java.nio.charset.StandardCharsets;
import java.util.*;

@Slf4j
public class EasyExcelUtil {

    public static final String member_values = "memberValues";
    public static final String source = "source";
	/**
     * 创建即将导出的sheet页(sheet页中含有带下拉框的列)
     * @param head 导出的表头信息和配置
     * @param sheetNo sheet索引
     * @param sheetName sheet名称
     * @param <T> 泛型
     * @return sheet页
     */
    public static <T> WriteSheet writeSelectedSheet(Class<T> head, Integer sheetNo, String sheetName) {
        Map<Integer, ExcelSelectedResolve> selectedMap = resolveSelectedAnnotation(head);

        return EasyExcel.writerSheet(sheetNo, sheetName)
                .head(head)
                .registerWriteHandler(new SelectedSheetWriteHandler(selectedMap))
                .build();
    }

    /**
     * 解析表头类中的下拉注解
     * @param head 表头类
     * @param <T> 泛型
     * @return Map<下拉框列索引, 下拉框内容> map
     */
    private static <T> Map<Integer, ExcelSelectedResolve> resolveSelectedAnnotation(Class<T> head) {
        Map<Integer, ExcelSelectedResolve> selectedMap = new HashMap<>();

        Field[] fields = head.getDeclaredFields();
        for (int i = 0; i < fields.length; i++){
            Field field = fields[i];
            // 解析注解信息
            ExcelSelected selected = field.getAnnotation(ExcelSelected.class);
            ExcelProperty property = field.getAnnotation(ExcelProperty.class);
            if (selected != null) {
                ExcelSelectedResolve excelSelectedResolve = new ExcelSelectedResolve();
                String[] source = excelSelectedResolve.resolveSelectedSource(selected);
                if (source != null && source.length > 0){
                    excelSelectedResolve.setSource(source);
                    excelSelectedResolve.setFirstRow(selected.firstRow());
                    excelSelectedResolve.setLastRow(selected.lastRow());
                    if (property != null && property.index() >= 0){
                        selectedMap.put(property.index(), excelSelectedResolve);
                    } else {
                        selectedMap.put(i, excelSelectedResolve);
                    }
                }
            }
        }

        return selectedMap;
    }


    public static Class dynamicReviseAnnoParam(Class aClass, Map<String, List<String>> map) {
        Field[] declaredFields = aClass.getDeclaredFields();
        try {
            for (Field f : declaredFields) {
                if (f.isAnnotationPresent(ExcelSelected.class)) {
                    ExcelSelected annotation = f.getAnnotation(ExcelSelected.class);
                    InvocationHandler h = Proxy.getInvocationHandler(annotation);

                    Field hField = h.getClass().getDeclaredField(member_values);
                    hField.setAccessible(true);
                    Map memberValues = (Map) hField.get(h);
                    String name = f.getName();
                    if (map == null){
                        map = new HashMap<>();
                    }
                    List<String> arr = map.get(name);
                    if (CollectionUtils.isEmpty(arr)){
                        continue;
                    }
                    String[] array = arr.toArray(new String[arr.size()]);
                    memberValues.put(source, array);

                }
            }
        } catch (NoSuchFieldException | IllegalAccessException e){
            log.error("动态添加注解数据失败!");
            e.printStackTrace();

        }
        return aClass;
    }

    public static void generatorTemplateBySelected(HttpServletResponse response,String filename,
                                                   Map<String,List<String>> selectedData,
                                                   Class instance){
        try {
            if (StringUtils.isBlank(filename)){
                filename = UUID.randomUUID().toString();
            }
            filename = new String(filename.getBytes(StandardCharsets.UTF_8), StandardCharsets.ISO_8859_1);

            response.setContentType("application/vnd.ms-excel");
            response.setHeader("Content-disposition", String.format("attachment; filename=\"%s\"", filename + ".xlsx"));
            response.setHeader("Cache-Control", "no-cache");
            response.setHeader("Pragma", "no-cache");
            response.setDateHeader("Expires", -1);
            response.setCharacterEncoding("UTF-8");



            Class classs = EasyExcelUtil.dynamicReviseAnnoParam(instance,selectedData);


            ExcelWriter excelWriter = EasyExcel.write(response.getOutputStream()).build();
            WriteSheet writeSheet = EasyExcelUtil.writeSelectedSheet(classs, 0, "测试sheet");

            excelWriter.write(new ArrayList<String>(), writeSheet);
            excelWriter.finish();
        }catch (Exception e){
            e.printStackTrace();
            log.error("导出模板失败!");
        }
    }

}

三、配置导出模板


@Data
@HeadStyle(fillForegroundColor = 30)
@ColumnWidth(25)
@HeadRowHeight(20)
@ContentRowHeight(10)
public class User {

    @ExcelProperty(value = {"编号","编号"})
    private Integer id;
    @ExcelProperty(value = {"学生档案","姓名"})
    @ExcelSelected
    private String name;
    @ExcelProperty(value = {"学生档案","电话"})
    private String phone;
    @ExcelProperty(value = {"学生档案","性别"})
    @ExcelSelected(firstRow = 2)
    private String sex;
    @ExcelProperty(value = {"分组","分组"})
    @ExcelSelected
    private String group;
}

四、通过接口调用工具类导出Excel

@RestController
@Slf4j
public class exportController {

    @GetMapping("/exportSelectedExcelDemo")
    public void exportDemo(HttpServletRequest request, HttpServletResponse response){
        String [] arr = {"男","女"};
        String [] group = {"蓝队","绿队"};
        HashMap<String, List<String>> stringHashMap = new HashMap<>();
        stringHashMap.put("sex", Arrays.asList(arr));
        stringHashMap.put("group", Arrays.asList(group));
        EasyExcelUtil.generatorTemplateBySelected(response,null,stringHashMap,User.class);
    }
}

最终导出效果:

 

 

  • 4
    点赞
  • 32
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
可以使用EasyExcel来实现多级表头导出EasyExcel是一个基于Java的简单易用的Excel操作工具,支持大数据量的导入导出操作。 下面是一个示例代码,演示了如何实现多级表头导出: ```java // 创建一个excel写对象 ExcelWriter writer = EasyExcel.write("output.xlsx").build(); // 定义表头数据 List<List<String>> head = new ArrayList<>(); // 第一行表头 List<String> headRow1 = new ArrayList<>(); headRow1.add("一级表头"); headRow1.add("一级表头"); headRow1.add("一级表头"); head.add(headRow1); // 第二行表头 List<String> headRow2 = new ArrayList<>(); headRow2.add("二级表头"); headRow2.add("二级表头"); headRow2.add("二级表头"); head.add(headRow2); // 第三行表头 List<String> headRow3 = new ArrayList<>(); headRow3.add("三级表头"); headRow3.add("三级表头"); headRow3.add("三级表头"); head.add(headRow3); // 写入表头数据 Sheet sheet = new Sheet(1, 0); sheet.setHead(head); writer.write1(null, sheet); // 写入内容数据(省略) // 关闭excel写对象 writer.finish(); ``` 在上面的示例代码中,我们创建了一个ExcelWriter对象,并指定了输出文件名为"output.xlsx"。然后,我们定义了一个包含多级表头表头数据,每一级的表头都是一个List<String>。我们将这些表头数据添加到head列表中,然后使用Sheet对象将head列表设置为excel的表头。最后,调用writer的write1方法写入表头数据。 你可以根据需要修改示例代码中的表头数据,然后使用EasyExcel提供的其他方法写入内容数据。完成后,调用writer的finish方法关闭excel写对象即可。 希望对你有帮助!如果还有其他问题,请继续提问。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值