java动态导出excel头

java根据动态头导出excel文件

一、需求背景

用户可选择列表中列展示,当选择好之后点击导出,excel中只导出用户选择列的数据

1、调用接口将表头传给给后端

在这里插入图片描述

2、请求结果展示

在这里插入图片描述

3、核心代码

pom包
在这里插入图片描述

1、工具类,注意异常抛出类如报错,需自定义异常类
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.lang.reflect.Field;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.text.DecimalFormat;
import java.text.NumberFormat;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

import cn.hutool.core.util.ReflectUtil;
import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.EasyExcelFactory;
import com.alibaba.excel.ExcelWriter;
import com.alibaba.excel.write.metadata.WriteSheet;
import com.alibaba.excel.write.metadata.fill.FillConfig;
import com.mbcloud.cloud.commons.exception.ApiException;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;

import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.springframework.stereotype.Component;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;

@Component
@Slf4j
public class ExcelUtil {

    /**
     * 从 sheet 中获取指定行列的单元格值
     *
     * @param sheet        表单
     * @param rowNumber    行号
     * @param columnNumber 列号
     * @return 统一返回字符串类型,null 表示找不到
     */
    public static String getCellValue(Sheet sheet, int rowNumber, int columnNumber) {

        Row row = sheet.getRow(rowNumber);
        if (null == row) {
            return null;
        }
        Cell cell = row.getCell(columnNumber);
        if (null == cell) {
            return null;
        }

        // 只处理数字、文本、公式结果为数字、文本的,其余认为错误
        switch (cell.getCellTypeEnum()) {
            case NUMERIC:
                // 保留两位小数,并处理科学计数法
                DecimalFormat df = new DecimalFormat("0.00");
                return df.format(cell.getNumericCellValue());
            case STRING:
                return cell.getStringCellValue();
            case FORMULA:
                switch (cell.getCachedFormulaResultTypeEnum()) {
                    case STRING:
                        return cell.getStringCellValue();
                    case NUMERIC:
                        NumberFormat nf = NumberFormat.getInstance();
                        nf.setGroupingUsed(false);
                        return String.valueOf(nf.format(cell.getNumericCellValue()));
                    default:
                        return null;
                }
            default:
                return null;
        }
    }

    /**
     * 根据模板导出数据 单个sheet
     *
     * @param response     返回对象
     * @param dataList     导出的数据集合
     * @param object       填充对象
     * @param fileName     文件名称
     * @param templateName 模板名称
     * @throws Exception
     */
    public void exportTemplateExcel(HttpServletResponse response, List<?> dataList, Object object,
                                    String fileName, String templateName) throws Exception {
        InputStream inputStream = this.getClass().getResourceAsStream(templateName);
        FillConfig fillConfig = FillConfig.builder().forceNewRow(Boolean.TRUE).build();
        ExcelWriter excelWriter = EasyExcelFactory.write(getOutputStream(fileName, response)).withTemplate(inputStream).build();
        WriteSheet writeSheet0 = EasyExcelFactory.writerSheet(0).build();
        excelWriter.fill(object, fillConfig, writeSheet0);
        excelWriter.fill(dataList, fillConfig, writeSheet0);
        excelWriter.finish();
    }

    /**
     * 构建输出流
     *
     * @param fileName 文件名称
     * @param response 输出流
     * @return
     * @throws Exception
     */
    private OutputStream getOutputStream(String fileName, HttpServletResponse response) throws Exception {
        URLEncoder.encode(fileName, StandardCharsets.UTF_8.name());
        response.setContentType("application/vnd.ms-excel");
        response.setCharacterEncoding(StandardCharsets.UTF_8.name());
        response.setHeader("Content-Disposition", "attachment;filename=" + fileName + ".xlsx");
        return response.getOutputStream();
    }

    /**
     * 文件格式校验
     *
     * @param file 文件
     */
    public  void checkFile(MultipartFile file) throws ApiException{
        if (file == null) {
            throw new ApiException("500", "文件不能为空");
        }
        String filename = file.getOriginalFilename();
        if (StringUtils.isEmpty(filename)) {
            throw new ApiException("500", "文件不能为空");
        }
        if (!filename.endsWith(".xls") && !filename.endsWith(".xlsx")) {
            throw new ApiException("500", "请上传.xls文件或者.xlsx文件");
        }
    }

    /**
     * 动态表头生成excel
     * @param headers 要生成的表头
     * @param dataList 数据
     * @param response
     * @param fileName 文件名称
     * @param titleName title名称
     * @param <T>
     */
    public static <T> void dynamicExportExcel(List<ExcelHeader> headers, List<T> dataList, HttpServletResponse response, String fileName, String titleName) {
        long startTime = System.currentTimeMillis();
        List<List<T>> allList = new ArrayList<>();
        for (T detail : dataList) {
            allList.addAll(dataList(headers, detail));
        }
        try (ServletOutputStream outputStream = response.getOutputStream()) {
            String name = com.sun.deploy.net.URLEncoder.encode(fileName, "UTF-8").replaceAll("\\+", "%20");
            response.setContentType("application/vnd.ms-excel");
            response.setCharacterEncoding("utf-8");
            response.setHeader("Content-disposition", "inline; " + name + ".xlsx");//设置响应头
            //response.setHeader("mime","application/vnd.ms-excel");
            EasyExcel.write(outputStream).head(headers(headers))
                    //表格标题占位
                    .relativeHeadRowIndex(1)
                    //文件样式
                    .registerWriteHandler(new CustomTitleWriteHandler(headers.size(),titleName))
                    .registerWriteHandler(new CellStyle())
                    .sheet(fileName).doWrite(allList);
        } catch (IOException e) {
            log.error("生成动态EXL失败,字段", e);
        }
        long endTime = System.currentTimeMillis();
        log.info("动态导出耗时:{}", endTime - startTime);
    }

    //excel表头
    public static List<List<String>> headers(List<ExcelHeader> excelHeaders) {
        List<List<String>> headers = new ArrayList<>();
        for (ExcelHeader header : excelHeaders) {
            List<String> head = new ArrayList<>();
            head.add(header.getHeadName());
            headers.add(head);
        }
        return headers;
    }

    /**
     * 要导出的字段
     *
     * @param exportFields 表头集合
     * @param obj          数据对象
     * @return 集合
     */
    @SneakyThrows
    public static <T> List<List<T>> dataList(List<ExcelHeader> exportFields, T obj) {
        List<List<T>> list = new ArrayList<>();
        List<T> data = new ArrayList<>();
        List<String> propList = exportFields.stream().map(ExcelHeader::getFieldName).collect(Collectors.toList());
        //先根据反射获取实体类的class对象
        Class<?> objClass = obj.getClass();
        //设置实体类属性的集合
        Field[] fields = ReflectUtil.getFields(objClass);
        for (String prop : propList) {
            //循环实体类对象集合
            for (Field field : fields) {
                field.setAccessible(true);
                //判断实体类属性跟特定字段集合名是否一样
                if (field.getName().equals(prop)) {
                    T object = (T) field.get(obj);
                    //获取属性对应的值
                    if(null == object){
                        object = (T) "--";
                    }else{
                        if(object instanceof LocalDate){
                            object = (T) DateUtil.localDateToString((LocalDate)object);
                        }
                        if(object instanceof LocalDateTime){
                            object = (T) DateUtil.localDateTimeToString((LocalDateTime)object);
                        }
                    }
                    data.add(object);
                }
            }
        }
        list.add(data);
        return list;
    }

}

2、标题设置类
import com.alibaba.excel.write.handler.SheetWriteHandler;
import com.alibaba.excel.write.metadata.holder.WriteSheetHolder;
import com.alibaba.excel.write.metadata.holder.WriteWorkbookHolder;
import org.apache.poi.ss.usermodel.CellStyle;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.ss.util.CellRangeAddress;

public class CustomTitleWriteHandler implements SheetWriteHandler {
    /**
     * 标题
     */
    private final String fileName;

    /**
     * 字段个数
     */
    private final Integer count;

    public CustomTitleWriteHandler(Integer count,String fileName) {
        this.fileName = fileName;
        this.count = count;
    }

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

    }

    @Override
    public void afterSheetCreate(WriteWorkbookHolder writeWorkbookHolder, WriteSheetHolder writeSheetHolder) {
        // 获取clazz所有的属性
        Workbook workbook = writeWorkbookHolder.getWorkbook();
        Sheet sheet = workbook.getSheetAt(0);
        Row row1 = sheet.createRow(0);
        row1.setHeight((short) 800);
        Cell cell = row1.createCell(0);
        //设置标题
        cell.setCellValue(fileName);
        CellStyle cellStyle = workbook.createCellStyle();
        cellStyle.setVerticalAlignment(VerticalAlignment.CENTER);
        cellStyle.setAlignment(HorizontalAlignment.CENTER);
        Font font = workbook.createFont();
        font.setBold(true);
        font.setFontHeight((short) 400);
        font.setFontName("宋体");
        cellStyle.setFont(font);
        cell.setCellStyle(cellStyle);
        sheet.addMergedRegionUnsafe(new CellRangeAddress(0, 0, 0, count-1));
    }
}

3、单元各简单设置类
import com.alibaba.excel.metadata.CellData;
import com.alibaba.excel.metadata.Head;
import com.alibaba.excel.write.metadata.holder.WriteSheetHolder;
import com.alibaba.excel.write.style.column.AbstractColumnWidthStyleStrategy;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.Sheet;

import java.util.List;

public class CellStyle extends AbstractColumnWidthStyleStrategy {

    @Override
    protected void setColumnWidth(WriteSheetHolder writeSheetHolder, List<CellData> cellDataList, Cell cell, Head head,
                                  Integer relativeRowIndex, Boolean isHead) {
        // 简单设置
        Sheet sheet = writeSheetHolder.getSheet();
        sheet.setColumnWidth(cell.getColumnIndex(), 5000);
    }

}

4、controller接收参数
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class ExcelHeader {
    /**
     * 要导出的字段名称英文
     */
    private String fieldName;

    /**
     * 要导出的表头名称中文
     */
    private String headName;
    /**
     * 排序
     */
    private Integer order;
    /**
     * 是否展示
     */
    private Boolean display;

}
  • 0
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值