哈喽,2023大家开工大吉啊!财源滚滚!

业务需求:需要生成excel模板,且对部分列设置下拉框,进行动态赋值,效果如下:

checkbox java 生成excel java生成excel模板_ci


拿上图举例:针对省这一列,不是填写,而是选择数据,也就是说我们生成excel文件的时候需要把数据填充到下拉框的列中。

大体逻辑就是:java生成excel文件,在生成excel文件的时候将部分列是设置成下拉框,并赋值。

而在 Java 中,操作 excel 目前有两个主流框架,分别是:

apache 的 poi
Apache POI是基于DOM方式进行解析,将文件直接加载内存,速度较快,适合文件数据量不大的应用场景。它分别对不同格式的文件提供不同的文件解析:

HSSF:  操作Microsoft Excel格式。
    XSSF:  操作Microsoft Excel  OOXML格式。

HSSF主要用于解析.xls格式的Excel文件,而XSSF主要用于解析.xlsx格式的Excel文件

Java Excel
Java Excel是一开放源码项目,通过它Java开发人员可以操作Excel文件(读取,创建,更新等)。

由于其小巧 易用的特点, 逐渐已经取代了 POI-excel的地位。

HSSFWorkbook:是操作Excel2003以前(包括2003)的版本,扩展名是.xls;

XSSFWorkbook:是操作Excel2007的版本,扩展名是.xlsx。

对于不同版本的EXCEL文档要使用不同的工具类,如果使用错了,会提示如下错误信息:

org.apache.poi.openxml4j.exceptions.InvalidOperationExceptionorg.apache.poi.poifs.filesystem.OfficeXmlFileException

java生成excel文件逻辑:
1:创建excel
2:在excel中创建表格
3:在表格中输入列名
4:输入数据

代码如下

//导出标头信息
    List<String> headers = Arrays.asList("客户姓名", "客户联系方式", "服务对象", "联系方式", "性别", "出生日期(yyyy-MM-dd)", "身份证号", "关系", "健康状况", "省", "市", "区", "服务地址详情", "一级来源渠道", "二级来源渠道", "首洽日期(yyyy-MM-dd)");
    
   // 创建workbook;可以理解为excel
    HSSFWorkbook hssfWorkbook = new HSSFWorkbook();
    
   //创建sheet:可以理解为在excel中创建表格
    HSSFSheet sheet = hssfWorkbook.createSheet();
    
   // 创建表头,供用户输入:可以理解为为表格输入列名
    initHeaders(hssfWorkbook, sheet, headers);
	
	//对性别做下拉处理;由标头可知性别位于第五列(下标从0开始,也就是4代表性别)
   String sexType = "sex";
    Map<String, String> sexMap = new HashMap<>();
    //key放性别的字段,value逗号拼接性别的所有值
    sexMap.put(sexType, "男,女,未知");
    // 1000表示该列填充1000行
    HSSFDataValidation sexValidation = ExcelUtil.createBox(sexType, sexMap, 1, 1000, 4, 4);
    if (sexValidation != null) {
        sheet.addValidationData(sexValidation);
    }

    String relationType = "relation";
    Map<String, String> relationTypeMap = new HashMap<>();
    relationTypeMap.put(relationType, relationName);
    HSSFDataValidation relationValidation = ExcelUtil.createBox(relationType, relationTypeMap, 1, 1000, 7, 7);
    if (relationValidation != null) {
        sheet.addValidationData(relationValidation);
    }

	//省市区三级联动处理
    SysCity cityParam = new SysCity();
    List<SysCity> araeList = sysCityMapper.selectSysCityList(cityParam);

    //所有省级信息:去除ID为36的请选择信息
    List<SysCity> proList = araeList.stream().filter(model -> "1".equals(model.getType().toString()) && !"36".equals(model.getId().toString())).collect(Collectors.toList());
    
    HSSFSheet mapSheet = hssfWorkbook.createSheet("MAP");
    hssfWorkbook.setSheetHidden(hssfWorkbook.getSheetIndex(mapSheet), false);
    //所有一级
    List<String> mapOneList = new ArrayList<String>();
    //市区关系
    Map<String, List<String>> map = new HashMap<String, List<String>>();


    proList.stream().forEach(model -> {
        mapOneList.add(model.getCityname());
        //获取对应市级名称信息
        List<String> cityNameList = araeList.stream().filter(as -> (as.getPid().toString()).equals(model.getId().toString())).map(ma -> ma.getCityname()).collect(Collectors.toList());
        map.put(model.getCityname(), cityNameList);
        //获取市级信息
        List<SysCity> cityList = araeList.stream().filter(as -> (as.getPid().toString()).equals(model.getId().toString())).collect(Collectors.toList());
        cityList.stream().forEach(city -> {
            //获取对应市级名称信息
            List<String> conturyNameList = araeList.stream().filter(as -> (as.getPid().toString()).equals(city.getId().toString())).map(ma -> ma.getCityname()).collect(Collectors.toList());
            map.put(city.getCityname(), conturyNameList);
        });


    });

    // 3.写入数据 将数据写入sheet中并做好关联关系
    writeData(hssfWorkbook, mapSheet, mapOneList, map);
    // 4.设置数据有效性
    setDataValid(hssfWorkbook, sheet, mapOneList, map, "1", "so");

    /**
     *
     * 渠道来源二级联动处理
     *
     */

    List<BaseSourceChannel> channelList = new BaseSourceChannel();
    //一级线索
    List<String> fatherMap = new ArrayList<String>();
    //二级线索
    Map<String, List<String>> sonMap = new HashMap<String, List<String>>();
    //一级线索
    List<BaseSourceChannel> parentSourceList = channelList.stream().filter(x -> "1".equals(x.getType())).collect(Collectors.toList());

    parentSourceList.stream().forEach(source -> {
        fatherMap.add(source.getSourceName());
        //一级对应的二级线索
        List<String> sonSourceList = channelList.stream().filter(x -> x.getPid().equals(source.getId())).map(y -> y.getSourceName()).collect(Collectors.toList());

        sonMap.put(source.getSourceName(), sonSourceList);

    });
    HSSFSheet sourceSheet = hssfWorkbook.createSheet("sourceMap");
    writeData(hssfWorkbook, sourceSheet, fatherMap, sonMap);
    setDataValid(hssfWorkbook, sheet, fatherMap, sonMap, "2", "source");


    String filename = UUID.randomUUID().toString() + "_测试模板.xlsx";

    String downloadPath = Global.getDownloadPath() + filename;
    File desc = new File(downloadPath);
    if (!desc.getParentFile().exists()) {
        desc.getParentFile().mkdirs();
    }
    FileOutputStream out = null;
    try {
        out = new FileOutputStream(downloadPath);
        hssfWorkbook.write(out);
    } catch (Exception e) {
        e.printStackTrace();
    } finally {
        if (out != null) {
            try {
                out.close();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
    return AjaxResult.success(filename);

好了,代码已经提供,有什么不明白的欢迎互相讨论。

createBox 方法如下

/**
     *  excel导出,有码值的数据使用下拉框展示。
     * @param col             列名
     * @param boxMap          码值集合
     * @param firstRow        插入下拉框开始行号
     * @param lastRow         插入下拉框结束行号
     * @param firstCol        插入下拉框开始列号
     * @param lastCol         插入下拉框结束行号
     * @return
     */
    public static HSSFDataValidation createBox(String col, Map<String, String> boxMap, int firstRow, int lastRow, int firstCol, int lastCol) {
        HSSFDataValidation dataValidation = null;
        //查询码值表
        String cols = "";
        if(null != boxMap.get(col)) {
            cols = boxMap.get(col);
        }
        //设置下拉框
        if(cols.length() > 0 && null != cols) {
            String str[] = cols.split(",");
            //指定行,列为下拉框
            CellRangeAddressList cas = new CellRangeAddressList(firstRow , lastRow , firstCol , lastCol);
            //创建下拉数据列
            DVConstraint dvConstraint = DVConstraint.createExplicitListConstraint(str);
            //将下拉数据放入下拉框
            dataValidation = new HSSFDataValidation(cas, dvConstraint);
        }
        return dataValidation;
    }

生成页面表头方法:initHeaders

/**
 * 生成主页面表头
 *
 * @param wb
 * @param mainSheet
 * @param headers
 */
private void initHeaders(HSSFWorkbook wb, HSSFSheet mainSheet, List<String> headers) {
    //表头样式
    HSSFCellStyle style = wb.createCellStyle();
    style.setAlignment(HorizontalAlignment.CENTER); // 创建一个居中格式
    //字体样式
    HSSFFont fontStyle = wb.createFont();
    fontStyle.setFontName("微软雅黑");
    fontStyle.setFontHeightInPoints((short) 12);
    style.setFont(fontStyle);
    //生成主内容
    HSSFRow rowFirst = mainSheet.createRow(0);//第一个sheet的第一行为标题
    mainSheet.createFreezePane(0, 1, 0, 1); //冻结第一行
    //写标题
    for (int i = 0; i < headers.size(); i++) {
        HSSFCell cell = rowFirst.createCell(i); //获取第一行的每个单元格
        mainSheet.setColumnWidth(i, 4000); //设置每列的列宽
        cell.setCellStyle(style); //加样式
        cell.setCellValue(headers.get(i)); //往单元格里写数据
    }
}