hutool导出excel支持下拉框数据超255字符

hutool导出excel支持下拉框数据超255字符

java 复制代码
import cn.hutool.core.io.IoUtil;
import cn.hutool.poi.excel.ExcelReader;
import cn.hutool.poi.excel.ExcelUtil;
import cn.hutool.poi.excel.ExcelWriter;
import cn.hutool.poi.excel.StyleSet;
import com.ibmp.common.annotation.Excel;
import com.ibmp.common.constant.ExcelConsts;
import com.ibmp.common.exception.CustomException;
import com.ibmp.common.utils.file.FileTypeUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.ss.util.CellRangeAddress;
import org.apache.poi.ss.util.CellRangeAddressList;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.lang.reflect.Field;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

/**
 * @author Mr丶s
 * @date 2021/7/26 2:18 下午
 * @description
 */
@Slf4j
public class ExcelUtils {

    /**
     * 导出
     *
     * @param mergeColumn 合并多少列
     * @param mergeText   合并单元格内文字
     * @param list        需要导出的list
     * @param excelName   导出的文件名称
     * @param clazz       实体类 对应list
     * @param response
     */
    public static void export(int mergeColumn, String mergeText, List<Map<Object, Object>> maps, List<?> list, String excelName, Class clazz, HttpServletResponse response) {
        try {
            if (!list.isEmpty()) {
                if (!list.get(0).getClass().equals(clazz)) {
                    log.error("数据类型与传入的集合数据类型不一致!数据类型:{}; 集合数据类型:{}", clazz, list.get(0).getClass());
                    throw new Exception("数据类型与传入的集合数据类型不一致!");
                } else {
                    ExcelWriter writer = ExcelUtil.getBigWriter();
                    // 获取当前类字段
                    Field[] fields = clazz.getDeclaredFields();
                    // 字段名称集合
                    List<String> fieldNames = new ArrayList<>();
                    // 字段中文名称集合(获取实体中@Excel注解name的值)
                    List<String> cnNames = new ArrayList<>();
                    for (Field field : fields) {
                        if (!field.isAccessible()) {
                            // 关闭反射访问安全检查,为了提高速度
                            field.setAccessible(true);
                        }
                        String fieldName = field.getName();
                        // 排除ID和序号
                        if (!"sid".equals(fieldName) && !"serialVersionUID".equals(fieldName) && !"ordernum".equals(fieldName)) {
                            fieldNames.add(fieldName);
                        }
                        // 判断是否有@Excel
                        boolean annotationPresent = field.isAnnotationPresent(Excel.class);
                        if (annotationPresent && !"sid".equals(fieldName)) {
                            String name = field.getAnnotation(Excel.class).name();
                            cnNames.add(name);
                        }
                    }
                    String[] fs = fieldNames.toArray(new String[0]);
                    String[] ns = cnNames.toArray(new String[0]);
                    for (int i = 0; i < ns.length; i++) {
                        // 设置表头及字段名
                        writer.addHeaderAlias(fs[i], ns[i]);
                    }
                    // 自动换行
                    Workbook workbook = writer.getWorkbook();
//                    Map<Object, Object>map1 = new HashMap<>();
//                    map1.put("cellNo",14);
//                    List<String> strings = new ArrayList<>();
//                    strings.add("cc1");
//                    strings.add("cc2");
//                    strings.add("cc3");
//                    strings.add("cc4");
//                    strings.add("cc5");
//                    map1.put("cellList", strings);
//                    maps.set(6, map1);
                    //设置下拉数据
                    if (CollectionUtils.isNotEmpty(maps)) {
                        int index = 0;
                        for (Map<Object, Object> map : maps) {
                            Integer cellNo = (int) map.get("cellNo");
                            List<Object> cellList = (List<Object>) map.get("cellList");
                            index = index + 1;
                            selectListMore("sheet00" + cellNo, index, workbook, cellNo, cellNo, cellList.toArray(new String[cellList.size()]));
                        }

                    }
                    //合并单元格
                    if (mergeColumn != -1) {
                        writer.merge(mergeColumn, mergeText);
                    }

                    CellStyle headCellStyle = writer.getCellStyle();
                    //设置内容字体
                    Font font = writer.createFont();
                    //设置字体
                    font.setFontName("宋体");
                    //加粗
                    // font.setBold(true);
                    //设置标题字体大小
                    font.setFontHeightInPoints((short) 15);
                    headCellStyle.setFont(font);

                    StyleSet styleSet = new StyleSet(workbook);
                    styleSet.setWrapText();
                    writer.setStyleSet(styleSet);

                    writer.write(list, true);
                    writer.autoSizeColumnAll();
                    //冻结行数 2-前两行
                    writer.setFreezePane(2);
                    ServletOutputStream out = response.getOutputStream();
                    try {
                        for (int i = 0; i < fieldNames.size(); i++) {
                            writer.setColumnWidth(i, 23);
                        }
                        //设置头部
                        response.setContentType(ExcelConsts.CONTENT_TYPE);

                        String ecodeFileName = URLEncoder.encode(excelName, "UTF-8");
                        response.setHeader(ExcelConsts.HEADER_S, ExcelConsts.RESPONSE_HEADER + ecodeFileName + ".xlsx");
                        writer.flush(out, true);
                        writer.close();
                        IoUtil.close(out);
                    } catch (IOException e) {
                        log.error(e.getMessage());
                        e.printStackTrace();
                    }
                }
            } else {
                log.error("数据集合为空");
                throw new Exception("数据集合为空");
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * excel下拉框
     *
     * @param sheetName
     * @param index     隐藏的sheet编号(例如1,2,3),多个下拉数据不能使用同一个
     * @param workbook
     * @param firstCol  区域中第一个单元格的列号 (下标0开始)
     * @param lastCol   区域中最后一个单元格的列号
     * @param dataArray 下拉内容
     */
    public static void selectListMore(String sheetName, Integer index, Workbook workbook, int firstCol, int lastCol, String[] dataArray) {
        //将下拉框数据放到新的sheet里,然后excle通过新的sheet数据加载下拉框数据
        Sheet hidden = workbook.createSheet(sheetName);
        //创建单元格对象
        Cell cell = null;
        //遍历我们上面的数组,将数据取出来放到新sheet的单元格中
        for (int i = 0, length = dataArray.length; i < length; i++) {
            //取出数组中的每个元素
            String name = dataArray[i];
            //根据i创建相应的行对象(说明我们将会把每个元素单独放一行)
            Row row = hidden.createRow(i);
            //创建每一行中的第一个单元格
            cell = row.createCell(0);
            //然后将数组中的元素赋值给这个单元格
            cell.setCellValue(name);
        }
        // 创建名称,可被其他单元格引用
        Name namedCell = workbook.createName();
        namedCell.setNameName(sheetName);
        // 设置名称引用的公式
        namedCell.setRefersToFormula(sheetName + "!$A$1:$A$" + dataArray.length);
        String range = sheetName + "!$A$1:$A$" + dataArray.length;
        //加载数据,将名称为hidden的sheet中的数据转换为List形式
        // DVConstraint constraint = DVConstraint.createFormulaListConstraint(sheetName);

        // 设置第一列的3-65534行为下拉列表
        // (3, 65534, 2, 2) ====> (起始行,结束行,起始列,结束列)
        CellRangeAddressList regions = new CellRangeAddressList(0, 1000000, firstCol, lastCol);
        DataValidationHelper dataValidationHelper = hidden.getDataValidationHelper();
        // 数据长度低于100正常录入 超过100 改为编写公式引用
        if (dataArray.length < 100 ) {
            // 将设置下拉选的位置和数据的对应关系 绑定到一起
            // DataValidation dataValidation = new HSSFDataValidation(regions, constraint);
            DataValidationConstraint constraint = dataValidationHelper.createExplicitListConstraint(dataArray);
            DataValidation dataValidation = dataValidationHelper.createValidation(constraint, regions);

            //将数据赋给下拉列表
            workbook.getSheetAt(0).addValidationData(dataValidation);
        }else {
            DataValidationConstraint dvConstraint = dataValidationHelper.createFormulaListConstraint(range);
            DataValidation dataValidation = dataValidationHelper.createValidation(dvConstraint, regions);
            workbook.getSheetAt(0).addValidationData(dataValidation);
        }
        //将第二个sheet设置为隐藏
        workbook.setSheetHidden(index, true);
    }


    /**
     * 导入
     *
     * @param file
     * @param sheet
     * @param clazz
     * @return
     */
    public static ExcelReader read(MultipartFile file, Integer sheet, Class clazz) {
        return readCommon(file, sheet, clazz);
    }

    /**
     * 导入
     *
     * @param file
     * @param clazz
     * @return
     */
    public static ExcelReader read(MultipartFile file, Class clazz) {
        return readCommon(file, 0, clazz);
    }

    /**
     * 导入
     *
     * @param file
     * @param clazz
     * @return
     */
    public static ExcelReader readCommon(MultipartFile file, Integer sheet, Class clazz) {
        try {
            InputStream inputStream = file.getInputStream();
            if (!isExcelFile(file)) {
                throw new CustomException("文件名格式不正确, 请使用后缀名为.xlsx的文件");
            }
            ExcelReader reader = ExcelUtil.getReader(inputStream, sheet);

            // 获取当前类字段
            Field[] fields = clazz.getDeclaredFields();
            // 字段名称集合
            List<String> fieldNames = new ArrayList<>();
            // 字段中文名称集合(获取实体中@Excel注解name的值)
            List<String> cnNames = new ArrayList<>();
            for (Field field : fields) {
                if (!field.isAccessible()) {
                    // 关闭反射访问安全检查,为了提高速度
                    field.setAccessible(true);
                }
                String fieldName = field.getName();
                // 排除ID和序号
                if (!"sid".equals(fieldName) && !"serialVersionUID".equals(fieldName) && !"ordernum".equals(fieldName)) {
                    fieldNames.add(fieldName);
                }
                // 判断是否有@Excel
                boolean annotationPresent = field.isAnnotationPresent(Excel.class);
                if (annotationPresent && !"sid".equals(fieldName)) {
                    String name = field.getAnnotation(Excel.class).name();
                    cnNames.add(name);
                }
            }
            String[] fs = fieldNames.toArray(new String[0]);
            String[] ns = cnNames.toArray(new String[0]);
            for (int i = 0; i < fs.length; i++) {
                // 设置表头及字段名
                reader.addHeaderAlias(ns[i], fs[i]);
            }
            return reader;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 读取sheet数
     *
     * @param file
     * @return
     */
    public static Workbook readExcelSheet(MultipartFile file) {
        try {
            InputStream inputStream = file.getInputStream();
            if (!isExcelFile(file)) {
                throw new CustomException("文件名格式不正确, 请使用后缀名为.xlsx的文件");
            }
            ExcelReader reader = ExcelUtil.getReader(inputStream);
            return reader.getWorkbook();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 是否为Excel文件
     *
     * @param file 表单文件
     * @return 文件格式是否正确
     */
    public static boolean isExcelFile(MultipartFile file) throws IOException {
        if (file.isEmpty()) {
            throw new CustomException("文件不能为空");
        }
        String filename = file.getOriginalFilename();
        String header = FileTypeUtils.getFileHeader(file.getInputStream());
        return (filename.endsWith(ExcelConsts.EXCEL_VERSION_XLSX) || filename.endsWith(ExcelConsts.EXCEL_VERSION_XLS)) &&
                (header.contains(ExcelConsts.XLS_HEADER) || header.contains(ExcelConsts.XLSX_HEADER));
    }


    public static Workbook getXSSFWorkbook(String sheetName, String[] title, String[][] values, Workbook wb) {
        return getXSSFWorkbook(sheetName, title, null, values, wb);
    }

    public static Workbook getXSSFWorkbook(String sheetName, String[] title, int[] width, String[][] values, Workbook wb) {

        // 第一步,创建一个HSSFWorkbook,对应一个Excel文件
        if (wb == null) {
            wb = new XSSFWorkbook();
        }

        // 第二步,在workbook中添加一个sheet,对应Excel文件中的sheet
        Sheet sheet = wb.createSheet(sheetName);
        sheet.createFreezePane(0, 1, 0, 1);
        // 第三步,在sheet中添加表头第0行,注意老版本poi对Excel的行数列数有限制
        Row row = sheet.createRow(0);

        // 第四步,创建单元格,并设置值表头 设置表头居中
        CellStyle style = wb.createCellStyle();
        Font font = wb.createFont();
        font.setBold(true);
        style.setFont(font);

        //声明列对象
        Cell cell;

        //创建标题
        for (int i = 0; i < title.length; i++) {
            cell = row.createCell(i);
            cell.setCellValue(title[i]);
            cell.setCellStyle(style);
            if (width != null) {
                sheet.setColumnWidth(i, width[i]);
            }
        }
        String s;
        //创建内容
        for (int i = 0; i < values.length; i++) {
            row = sheet.createRow(i + 1);
            for (int j = 0; j < values[i].length; j++) {
                //将内容按顺序赋给对应的列对象
                s = values[i][j];
                s = StringUtils.isBlank(s) ? "" : (StringUtils.equals("null", s) ? "" : s);
                row.createCell(j).setCellValue(s);
            }
        }
        return wb;
    }

    public static void margeCell(Sheet sheet, int startRow, int colNum) {
        String content = "";
        int index = startRow;
        for (int i = startRow; i <= sheet.getLastRowNum(); i++) {
            String value = sheet.getRow(i).getCell(colNum).getStringCellValue();
            if (!StringUtils.equals(content, value)) {
                if (i - index > 1) {
                    CellRangeAddress region = new CellRangeAddress(index, i - 1, colNum, colNum);
                    sheet.addMergedRegion(region);
                }
                index = i;
                content = value;
            } else {
                if (i == sheet.getLastRowNum() && i - index > 1) {
                    CellRangeAddress region = new CellRangeAddress(index, i, colNum, colNum);
                    sheet.addMergedRegion(region);
                }
            }
        }
    }


    /**
     * 设置 response
     *
     * @param response
     * @param fileName
     * @throws UnsupportedEncodingException
     */
    public static void setResponse(HttpServletResponse response, String fileName) throws UnsupportedEncodingException {
        // 配置文件下载
        response.setHeader("content-type", "application/octet-stream");
        response.setContentType("application/octet-stream");
        // 下载文件能正常显示中文
        String _filaName = new String((fileName + ".xlsx").getBytes("gb2312"), "iso8859-1");
        response.setHeader("Content-disposition", "attachment;filename=" + _filaName);
    }
}
相关推荐
m0_7482552643 分钟前
easyExcel导出大数据量EXCEL文件,前端实现进度条或者遮罩层
前端·excel
小张认为的测试1 小时前
Linux性能监控命令_nmon 安装与使用以及生成分析Excel图表
linux·服务器·测试工具·自动化·php·excel·压力测试
PieroPc7 小时前
Python 写的 智慧记 进销存 辅助 程序 导入导出 excel 可打印
开发语言·python·excel
不吃鱼的羊1 天前
Excel生成DBC脚本源文件
服务器·网络·excel
chenchihwen1 天前
数据分析时的json to excel 转换的好用小工具
数据分析·json·excel
lxxxxl1 天前
C#调用OpenXml,读取excel行数据,遇到空单元跳过现象处理
excel
m0_748246351 天前
前端通过new Blob下载文档流(下载zip或excel)
前端·excel
不吃鱼不吃鱼2 天前
Excel加载项入门:原理、安装卸载流程与常见问题
excel·wps
深耕AI2 天前
在Excel中绘制ActiveX控件:解决文本编辑框定位问题
java·前端·excel