1.前言

        在java 开发过程中, EXCEL 导出大家都有遇到过。也遇到过各种问题,在这里也稍稍整理一下,算是一个这几年来对excel 导出的一些总结

2.常见的问题

        (1)excel 文字的导出目前分为两种,一种是以 xls 格式导出,其次就是以 xlsx 格式导出。

Excel版本

最大行数

最大列数

最大sheet数

2003(XLS)

65536(2的16次方)

256(IV,2的8次方)

255

2007以上(XLSX)

1048576(2的20次方)

16384(XFD,2的14次方)

无,受内存限制

表格中提到的受内存限制,那么就顺带一嘴, 如果服务器内存不够大, 一次性加载过多的数据, 在低版本的poi 中, 会出现内存溢出和性能问题。 所以在新的POI 版本中,例如:4.1.2 新增了一个专门处理大数据的 SXSSFWorkbook  对象, 这个实现的原理就是将数据直接写入到硬盘,在内存中存有少量的数据(创建对象的时候可以设置)。但是这个类也是存在弊端的。数据时写入到硬盘的,已经不再内存中, 即不能在对workbook 中数据进行操作。 要有针对性的选择 XSSFWorkbook 和  SXSSFWorkbook

        (2)poi 升级之后会遇到的问题。

如果现在项目中所用的poi 版本为 3.XX 的版本 。升级到4.1.2 之后, 会有很多方法失效的情况。 尤其是在设置excel 的样式上。

//POI 4.1.2 设置单元格属性
                CellStyle cellStyle = workbook.createCellStyle();
                 //设置单元格边框
                cellStyle.setBorderBottom(BorderStyle.THIN);
                cellStyle.setBorderTop(BorderStyle.THIN);
                cellStyle.setBorderRight(BorderStyle.THIN);
                cellStyle.setBorderLeft(BorderStyle.THIN);
                cellStyle.setAlignment(HorizontalAlignment.CENTER); //水平居中
                cellStyle.setVerticalAlignment(VerticalAlignment.CENTER); //垂直居中


                //POI 3.17 设置单元格属性
                CellStyle cellStyle = wb.createCellStyle();
    		    cellStyle.setBorderTop(CellStyle.BORDER_THIN);
    	        cellStyle.setBorderLeft(CellStyle.BORDER_THIN);
    	        cellStyle.setBorderBottom(CellStyle.BORDER_THIN);
    	        cellStyle.setBorderRight(CellStyle.BORDER_THIN);
                cellStyle.setAlignment(CellStyle.ALIGN_RIGHT);//水平位置
                cellStyle.setVerticalAlignment(CellStyle.VERTICAL_BOTTOM);

3.如何实现一个通用的,兼容各种情况的导出工具类

        之前看到的很多所谓的通用EXCEL 导出工具类。 大多需要将要合并的表头,要导出的字段,分别定义一个map。在将除了数据之外的 keyMap 和 合并表头的Map 传到工具类中进行导出。每次新增一个页面, 就需要单独写返回字段的map 和合并表头的map . 如果涉及到的表头有2行或者3行将会更不好处理。

这次我们会实现一个兼容以上这种情况的 真 · 通用导出工具类。

实现该通用EXCEL 导出工具类的前提是需要和前端做配合, 定义一个字段, 将要导出的表头用json 格式传到后台接口中。

Java的excel导出数字 java实现excel大量数据导出_Java的excel导出数字

 如上图:导出一个只有单行表头的excel 表格. 

点击导出的时候,需要传以下格式的数据:(供参考)

header: excel 导出的表头 

field 对应数据的key , 用于获取对应的数据。

rowspan : 对应是数值表明是单行表头还是复合表头

colspan:对应的数值表明合并了多少列

columns:合并列下面对应的下级标题

还可以根据具体的需求, 加入指定的属性, 例如:dataType 属性,对指定的列进行格式化,时间格式,金额,百分比等。

[{
	"name": "",
	"visible": true,
	"header": "序号",
	"rowspan": 1
}, {
	"header": "商品名称",
	"name": "pName",
	"field": "pName",
	"visible": true
}, {
	"header": "订单ID",
	"name": "orderId",
	"field": "orderId",
	"visible": true
}, {
	"header": "订单描述",
	"name": "orderDesc",
	"field": "orderDesc",
	"visible": true
}, {
	"header": "年度",
	"name": "year",
	"field": "year",
	"visible": true
}, {
	"header": "截止日期",
	"name": "jzrq",
	"field": "jzrq",
	"visible": true
}, {
	"header": "创建人",
	"name": "cjr",
	"field": "cjr",
	"visible": true
}, {
	"header": "创建日期",
	"name": "cjrq",
	"field": "cjrq",
	"visible": true
}]

序号

基本信息

附加信息

备注

名字

年龄

地址

电话

爱好

XX

XX

 此表格对应的数据格式看下方JSON 数据

[{
		"name": "",
		"header": "序号",
		"rowspan": 2
	},
	{
		"name": "",
		"header": "基本信息",
		"colspan": 4,
		"columns": [{
				"header": "名字",
				"name": "name",
				"field": "name"
			},
			{
				"header": "年龄",
				"name": "age",
				"field": "age"
			},
			{
				"header": "地址",
				"name": "add",
				"field": "add"
			},
			{
				"header": "电话",
				"name": "tel",
				"field": "tel"
			}
		]
	},
	{
		"name": "",
		"header": "附加信息",
		"colspan": 3,
		"columns": [{
				"header": "爱好",
				"name": "aih",
				"field": "aih"
			},
			{
				"header": "xx",
				"name": "xx",
				"field": "xx"
			},
			{
				"header": "xx",
				"name": "xx",
				"field": "xx"
			}
		]
	}
]
public class GeneralExportUtil {

    //Excel 导出, 每100W数据放入一个sheet页
    private static final Integer MAX_SEND = 10000000;

    /**
     * 构造数据, 生成符合导出的数据
     * @param jsonData   jQueryLogichandler 查询出来的 数据
     * @param columns    前台传过来的
     * @param sheetName
     * @param exportId  通过uuid 生成临时文件的名称, 前台通过UUID 下载文件, 和删除文件,
     */
    public static void buildDataAndExportExcel(String jsonData, String columns, String sheetName,String exportId) {

        List<JSONObject> dataList = JSONObject.parseArray(jsonData, JSONObject.class);
        List<JSONObject> columnList = JSONObject.parseArray(columns, JSONObject.class);

        List<String> col1 = new ArrayList<>(); //excel 第一行表头名称
        List<String> col2 = new ArrayList<>(); // excel 第二行表头名称
        List<String> col3 = new ArrayList<>(); // excel 第三行表头名称
        List<String> keyList = new ArrayList<>(); // 数据value 对应的key
        List<Integer[]> combinedTitle = new ArrayList<>(); //要合并的表头集合 第一行
        List<Integer[]> combinedTitleSec = new ArrayList<>(); //要合并的表头集合第二行
        List<Integer[]> combinedTitleThree = new ArrayList<>(); //要合并的表头集合第三行

        //表格中第一列是复选框的情况下,columnList 中的第一个元素需要移除
        JSONObject firstColumn = columnList.get(0);
        if (!firstColumn.containsKey("header")){
            columnList.remove(0);
        }

        //组织excel 表头信息
        int colNumIndexStart =0; // 从第一列到最后一列的下标
        for (JSONObject col : columnList) {
            int rowNumEnd=0; //合并行的结束
            int colNumIndexEnd=0;
            col1.add(col.getString("header").replace("<br>","")); //
            if (col.containsKey("rowspan")){
                rowNumEnd = col.getInteger("rowspan")-1;
            }
            if (col.containsKey("field")) {
                keyList.add(col.getString("field"));
            }

            if (col.containsKey("colspan")){//判断是否合并行
                colNumIndexEnd = colNumIndexStart+col.getInteger("colspan") - 1;
            }

            if (col.containsKey("columns")) {//判断是否合并列
                Integer[] array = {0,rowNumEnd,colNumIndexStart,colNumIndexEnd}; // 数组用于合并单元格
                combinedTitle.add(array);
                //构建第二行表头
                JSONArray secondRow = col.getJSONArray("columns");
                for (Object secCol : secondRow) {
                    colNumIndexEnd=0;
                    JSONObject jsonObject = (JSONObject) secCol;
                    col2.add(jsonObject.getString("header").replace("<br>",""));
                    if (jsonObject.containsKey("rowspan")) {
                        rowNumEnd = jsonObject.getInteger("rowspan");
                    }else{
                        rowNumEnd = 1;
                    }
                    if (jsonObject.containsKey("colspan")) { //第二行合并的表头
                        colNumIndexEnd = colNumIndexStart+jsonObject.getInteger("colspan") - 1;
                    }else{
                        colNumIndexEnd = colNumIndexStart;
                    }

                    if (jsonObject.containsKey("field")) {
                        keyList.add(jsonObject.getString("field"));
                    }

                    Integer[] array2 = {1,rowNumEnd,colNumIndexStart,colNumIndexEnd};
                    combinedTitleSec.add(array2);

                    /**
                     * 构建第三行表头
                     */
                    if (jsonObject.containsKey("columns")){

                        JSONArray secondThree = jsonObject.getJSONArray("columns");
                        for (Object threeCol : secondThree) {
                            JSONObject threeObject = (JSONObject) threeCol;
                            col3.add(threeObject.getString("header").replace("<br>",""));

                            if (threeObject.containsKey("field")) {
                                keyList.add(threeObject.getString("field"));
                            }
                            if (threeObject.containsKey("colspan")) { //第二行合并的表头
                                colNumIndexEnd = colNumIndexStart+threeObject.getInteger("colspan") - 1;
                            }else {
                                colNumIndexEnd = colNumIndexStart;
                            }

                            Integer[] array3 = {2,2,colNumIndexStart,colNumIndexEnd};
                            combinedTitleThree.add(array3);
                            colNumIndexStart++;
                        }
                    }else{
                        colNumIndexStart++;
                    }
                }

            }else{
                if (colNumIndexStart > 0 && colNumIndexEnd == 0) {
                    colNumIndexEnd = colNumIndexStart;
                }
                Integer[] array = {0,rowNumEnd,colNumIndexStart,colNumIndexEnd};
                combinedTitle.add(array);
                colNumIndexStart++;
            }


        }
        SXSSFWorkbook workbook = null;
        if (col2.size() == 0) {
            workbook = exportCellSingleTitle(sheetName, keyList, col1, dataList);
        }else if(col3.size() == 0){

            workbook = exportCellDoubleTitle(sheetName, keyList, col1, col2, dataList, combinedTitle);
        }else{
            workbook =exportCellThreeTitle(sheetName, keyList, col1, col2, col3, dataList, combinedTitle, combinedTitleSec,combinedTitleThree);
        }

        String tempPath = FxConstant.BASEPATH + "components" + File.separator + "fileio" + File.separator + "expfile";
        File outDir = new File(tempPath); // 生成本地存放临时文件的路径
        if (!outDir.exists()) {
            outDir.mkdirs();
        }
        FileOutputStream os = null;
        //临时文件生成
        try {
            os = new FileOutputStream(tempPath + File.separator + exportId+".xlsx");
            workbook.write(os);
            os.flush();
        } catch (IOException e) {
            e.printStackTrace();
        }finally {
            try {
                os.close();
                workbook.close();
                workbook.dispose();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

    }

    /**
     *
     * @param sheetName sheet 页名称
     * @param key_columns MAP 中对应的字段 key ,通过key 进行取值
     * @param value_columns1 表头合并第一行表头名称
     * @param value_columns2 第二行表头名称
     * @param datalistAll 要导出的数据
     * @param list3  要合并的表头 集合 例: 标题中如果有5个合并的表头, list3 的长度就为5  元素为数组, {0,1,0,0} 代表意思
     *               {行开始,行结束,列开始,列结束} 意为:第一列的第一行和第二行进行合并
     * @return
     */
    public static SXSSFWorkbook exportCellDoubleTitle(String sheetName, List<String> key_columns, List<String> value_columns1,
                                                 List<String> value_columns2, List<JSONObject> datalistAll, List<Integer[]> list3){

        SXSSFWorkbook workbook = null;
        Date date = new Timestamp(System.currentTimeMillis());
        System.out.println("excel开始时间:"+date.getTime());
        try {
            //XSSFWorkbook sheets = new XSSFWorkbook();
            //创建一个Excel文件
            workbook = new SXSSFWorkbook(100);
            List<List<JSONObject>> partition = ListUtils.partition(datalistAll, MAX_SEND);
            int sheetIndex=1;
            for (List<JSONObject> datalist : partition) {
                //创建一个工作表
                Sheet sheet = workbook.createSheet(sheetName+sheetIndex);
                sheetIndex++;
                //添加表头行
                Row row = sheet.createRow(0);
                //设置单元格格式
                CellStyle cellStyle = workbook.createCellStyle();
                //设置单元格边框
                cellStyle.setBorderBottom(BorderStyle.THIN);
                cellStyle.setBorderTop(BorderStyle.THIN);
                cellStyle.setBorderRight(BorderStyle.THIN);
                cellStyle.setBorderLeft(BorderStyle.THIN);
                cellStyle.setAlignment(HorizontalAlignment.CENTER); //水平居中
                cellStyle.setVerticalAlignment(VerticalAlignment.CENTER); //垂直居中

                //将字段赋值到合并的单元格中
                CellStyle titleStyle = workbook.createCellStyle();
                Font titleFont = workbook.createFont();
                titleStyle.setBorderBottom(BorderStyle.THIN);
                titleStyle.setBorderTop(BorderStyle.THIN);
                titleStyle.setBorderRight(BorderStyle.THIN);
                titleStyle.setBorderLeft(BorderStyle.THIN);
                titleStyle.setAlignment(HorizontalAlignment.CENTER); //水平居中
                titleStyle.setVerticalAlignment(VerticalAlignment.CENTER); //垂直居中
                titleFont.setBold(true);
                titleStyle.setFont(titleFont);
                if (value_columns1.size()>0){
                    Cell cell = null;
                    for (int i = 0; i < value_columns1.size(); i++) {
                        cell = row.createCell(list3.get(i)[2]);
                        cell.setCellValue(value_columns1.get(i));
                        cell.setCellStyle(titleStyle);
                    }
                }
                int secRowCellIndex=0;
                for (Integer[] index: list3){
                    if (index[0] == index[1] && index[2]<=index[3]){
                        secRowCellIndex=index[2];
                        break;
                    }
                }


                row = sheet.createRow(1);
                for (String cellName:value_columns2) {
                    //添加表头内容
                    Cell cell = row.createCell(secRowCellIndex);
                    cell.setCellValue(cellName);
                    cell.setCellStyle(titleStyle);
                    sheet.setColumnWidth(secRowCellIndex,(int)((cellName.length()<=2?4:cellName.length())*2.5+0.72)*256);
                    secRowCellIndex++;
                }
                for (Integer[] arr : list3) {//合并表头
                    if(((arr[2]>0 ||arr[3]>0) && arr[2] != arr[3]) || (arr[0]>0 || arr[1]>0)) {
                        CellRangeAddress cellAddresses = new CellRangeAddress(arr[0], arr[1], arr[2], arr[3]);
                        sheet.addMergedRegion(cellAddresses);
                        RegionUtil.setBorderBottom(BorderStyle.THIN,cellAddresses,sheet);
                        RegionUtil.setBorderLeft(BorderStyle.THIN,cellAddresses,sheet);
                        RegionUtil.setBorderRight(BorderStyle.THIN,cellAddresses,sheet);
                        RegionUtil.setBorderTop(BorderStyle.THIN,cellAddresses,sheet);
                    }
                }

                boolean isHaveIndex = true;
                //判断表格是否有序号列
                if(!value_columns1.contains("序号") && !value_columns2.contains("序号")){
                    isHaveIndex = false;
                }

                //把数据添加到excel

                int ii = 0;

                for (int i = 0; i < datalist.size(); i++) {
                    row = sheet.createRow(ii + 2);
                    if (isHaveIndex){
                        //创建单元格,并设置值
                        int j = 1;
                        Cell cell = row.createCell(0);
                        cell.setCellValue(i+1);
                        cell.setCellStyle(cellStyle);
                        for (String s : key_columns) {
                            cell = row.createCell(j);
                            cell.setCellValue(datalist.get(i).getString(s));
                            cell.setCellStyle(cellStyle);
                            j++;
                        }
                        ii++;
                    }else {
                        //创建单元格,并设置值
                        int j = 0;
                        for (String s : key_columns) {
                            Cell cell = row.createCell(j);
                            cell.setCellValue(datalist.get(i).getString(s));
                            cell.setCellStyle(cellStyle);
                            j++;
                        }
                        ii++;
                    }
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        Date date1 = new Timestamp(System.currentTimeMillis());
        System.out.println("excel导出结束时间:"+(date1.getTime()-date.getTime()));
        return workbook;
    }


    /**
     * @param sheetName sheet 页名称
     * @param key_columns MAP 中对应的字段 key ,通过key 进行取值
     * @param value_columns 表头名称
     * @param datalistAll 要导出的数据
     * @return
     */
    public static SXSSFWorkbook exportCellSingleTitle(String sheetName, List<String> key_columns, List<String> value_columns,
                                                  List<JSONObject> datalistAll){

        SXSSFWorkbook workbook = null;
        Date date = new Timestamp(System.currentTimeMillis());
        System.out.println("excel开始时间:"+date.getTime());
        try {
            //XSSFWorkbook sheets = new XSSFWorkbook();
            //创建一个Excel文件
            workbook = new SXSSFWorkbook(100);
            List<List<JSONObject>> partition = ListUtils.partition(datalistAll, MAX_SEND);
            int sheetIndex=1;
            for (List<JSONObject> datalist : partition) {
                //创建一个工作表
                Sheet sheet = workbook.createSheet(sheetName+sheetIndex);
                sheetIndex++;
                //添加表头行
                Row row = sheet.createRow(0);
                //设置单元格格式
                CellStyle cellStyle = workbook.createCellStyle();
                //设置单元格边框
                cellStyle.setBorderBottom(BorderStyle.THIN);
                cellStyle.setBorderTop(BorderStyle.THIN);
                cellStyle.setBorderRight(BorderStyle.THIN);
                cellStyle.setBorderLeft(BorderStyle.THIN);
                cellStyle.setAlignment(HorizontalAlignment.CENTER); //水平居中
                cellStyle.setVerticalAlignment(VerticalAlignment.CENTER); //垂直居中


                //将字段赋值到合并的单元格中
                CellStyle titleStyle = workbook.createCellStyle();
                Font titleFont = workbook.createFont();
                titleFont.setBold(true);
                titleStyle.cloneStyleFrom(cellStyle);
                titleStyle.setFont(titleFont);
                if (value_columns.size()>0){
                    Cell cell = null;
                    for (int i = 0; i < value_columns.size(); i++) {
                        cell = row.createCell(i);
                        cell.setCellValue(value_columns.get(i));
                        cell.setCellStyle(titleStyle);
                        //sheet.setDefaultColumnWidth(value_columns.get(i).length());
                        sheet.setColumnWidth(i,(int)((value_columns.get(i).length()<=2?4:value_columns.get(i).length())*2.5+0.72)*256);
                    }
                }
                //把数据添加到excel
                int ii = 0;

                for (int i = 0; i < datalist.size(); i++) {
                    row = sheet.createRow(ii + 1);

                    if (!value_columns.get(0).equals("序号")) {
                        //创建单元格,并设置值
                        int j = 0;
                        for (String s : key_columns) {
                            Cell cell = row.createCell(j);
                            cell.setCellValue(datalist.get(i).getString(s));
                            cell.setCellStyle(cellStyle);
                            j++;
                        }
                        ii++;
                    } else {
                        //创建单元格,并设置值
                        int j = 1;
                        Cell cell = row.createCell(0);
                        cell.setCellValue(i + 1);
                        cell.setCellStyle(cellStyle);
                        for (String s : key_columns) {
                            cell = row.createCell(j);
                            cell.setCellValue(datalist.get(i).getString(s));
                            cell.setCellStyle(cellStyle);
                            j++;
                        }
                        ii++;
                    }
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        Date date1 = new Timestamp(System.currentTimeMillis());
        System.out.println("excel导出结束时间:"+(date1.getTime()-date.getTime()));
        return workbook;
    }

    /**
     * 表头涉及到三行 包含合并单元格的导出情况
     * @param sheetName sheet 页名称
     * @param key_columns MAP 中对应的字段 key ,通过key 进行取值
     * @param value_columns1 表头合并第一行表头名称
     * @param value_columns2 第二行表头名称
     * @param datalistAll 要导出的数据
     * @param combinedTitle  要合并的表头 集合 例: 标题中如果有5个合并的表头, list3 的长度就为5  元素为数组, {0,1,0,0} 代表意思
     *               {行开始,行结束,列开始,列结束} 意为:第一列的第一行和第二行进行合并
     * @param combinedTitleSec  要合并的表头 集合 例: 标题中如果有5个合并的表头, list3 的长度就为5  元素为数组, {0,1,0,0} 代表意思
     *      *        {行开始,行结束,列开始,列结束} 意为:第一列的第一行和第二行进行合并
     * @return
     */
    public static SXSSFWorkbook exportCellThreeTitle(String sheetName, List<String> key_columns, List<String> value_columns1,
                                                 List<String> value_columns2,List<String> value_columns3,
                                                List<JSONObject> datalistAll, List<Integer[]> combinedTitle,
                                                List<Integer[]> combinedTitleSec,List<Integer[]> combinedTitleThree){

        SXSSFWorkbook workbook = null;
        Date date = new Timestamp(System.currentTimeMillis());
        System.out.println("excel下载开始时间:"+date.getTime());
        try {
            //XSSFWorkbook sheets = new XSSFWorkbook();
            //创建一个Excel文件
            workbook = new SXSSFWorkbook(100);
            List<List<JSONObject>> partition = ListUtils.partition(datalistAll, MAX_SEND);
            int sheetIndex=1;
            for (List<JSONObject> datalist : partition) {
                //创建一个工作表
                Sheet sheet = workbook.createSheet(sheetName + sheetIndex);


                //添加表头行
                Row row = sheet.createRow(0);
                //设置单元格格式
                CellStyle cellStyle = workbook.createCellStyle();
                //设置单元格边框
                cellStyle.setBorderBottom(BorderStyle.THIN);
                cellStyle.setBorderTop(BorderStyle.THIN);
                cellStyle.setBorderRight(BorderStyle.THIN);
                cellStyle.setBorderLeft(BorderStyle.THIN);
                cellStyle.setAlignment(HorizontalAlignment.CENTER); //水平居中
                cellStyle.setVerticalAlignment(VerticalAlignment.CENTER); //垂直居中

                //将字段赋值到合并的单元格中
                CellStyle titleStyle = workbook.createCellStyle();
                Font titleFont = workbook.createFont();
                titleFont.setBold(true);
                titleStyle.cloneStyleFrom(cellStyle);
                titleStyle.setFont(titleFont);
                if (value_columns1.size() > 0) {
                    Cell cell = null;
                    for (int i = 0; i < value_columns1.size(); i++) {
                        cell = row.createCell(combinedTitle.get(i)[2]);
                        cell.setCellValue(value_columns1.get(i));
                        cell.setCellStyle(titleStyle);
                    }
                }
                row = sheet.createRow(1);
                for (int i = 0; i < value_columns2.size(); i++) {
                    //添加表头内容
                    Cell cell = row.createCell(combinedTitleSec.get(i)[2]);
                    cell.setCellValue(value_columns2.get(i));
                    cell.setCellStyle(titleStyle);
                    sheet.setColumnWidth(i, (int) ((value_columns2.get(i).length() <= 2 ? 4 : value_columns2.get(i).length()) * 2.5 + 0.72) * 256);
                }
                row = sheet.createRow(2);
                for (int i = 0; i < value_columns3.size(); i++) {
                    //添加表头内容
                    Cell cell = row.createCell(combinedTitleThree.get(i)[2]);
                    cell.setCellValue(value_columns3.get(i));
                    cell.setCellStyle(titleStyle);
                    sheet.setColumnWidth(i, (int) ((value_columns3.get(i).length() <= 2 ? 4 : value_columns3.get(i).length()) * 2.5 + 0.72) * 256);
                }
                if (sheetIndex == 1) {
                    combinedTitle.addAll(combinedTitleSec);//合并表头前将要合并的放到一个集合中
                }
                for (Integer[] arr : combinedTitle) {//合并表头
                    if (((arr[2] > 0 || arr[3] > 0) && arr[2] != arr[3]) || (arr[0] > 0 || arr[1] > 0)) {
                        CellRangeAddress cellAddresses = new CellRangeAddress(arr[0], arr[1], arr[2], arr[3]);
                        sheet.addMergedRegion(cellAddresses);
                        RegionUtil.setBorderBottom(BorderStyle.THIN, cellAddresses, sheet);
                        RegionUtil.setBorderLeft(BorderStyle.THIN, cellAddresses, sheet);
                        RegionUtil.setBorderRight(BorderStyle.THIN, cellAddresses, sheet);
                        RegionUtil.setBorderTop(BorderStyle.THIN, cellAddresses, sheet);
                    }
                }
                boolean isHaveIndex = true;
                //判断表格是否有序号列
                if(!value_columns1.contains("序号") && !value_columns2.contains("序号")){
                    isHaveIndex = false;
                }
                //把数据添加到excel

                int ii = 0;

                for (int i = 0; i < datalist.size(); i++) {
                    row = sheet.createRow(ii + 3);
                    //创建单元格,并设置值
                    if (isHaveIndex){
                        //创建单元格,并设置值
                        int j = 1;
                        Cell cell = row.createCell(0);
                        cell.setCellValue(i+1);
                        cell.setCellStyle(cellStyle);
                        for (String s : key_columns) {
                            cell = row.createCell(j);
                            cell.setCellValue(datalist.get(i).getString(s));
                            cell.setCellStyle(cellStyle);
                            j++;
                        }
                        ii++;
                    }else {
                        //创建单元格,并设置值
                        int j = 0;
                        for (String s : key_columns) {
                            Cell cell = row.createCell(j);
                            cell.setCellValue(datalist.get(i).getString(s));
                            cell.setCellStyle(cellStyle);
                            j++;
                        }
                        ii++;
                    }

                }
                sheetIndex++;
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        Date date1 = new Timestamp(System.currentTimeMillis());
        System.out.println("excel导出结束时间:"+(date1.getTime()-date.getTime()));
        return workbook;
    }

}

4.总结

        图上代码兼容单行标题, 两行 和三行标题的表头格式导出.  但是此方式略显麻烦。下一章将会对此工具类进行优化, 将会采用 EasyExcel 替换掉 SXSSFWorkbook . 前端传参的方式不变. 性能方面略有提升, 将 XSSF 替换为SXSSF 之后会有明显的性能提升