Apache poi导出excel

一、普通类型的excel导出

1、导入相关依赖

<dependency>
            <groupId>org.apache.poi</groupId>
            <artifactId>poi</artifactId>
            <version>3.17</version>
            <exclusions>
                <exclusion>
                    <groupId>log4j</groupId>
                    <artifactId>log4j</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
        <dependency>
            <groupId>org.apache.poi</groupId>
            <artifactId>poi-ooxml</artifactId>
            <version>3.17</version>
        </dependency>
        <dependency>
            <groupId>org.apache.poi</groupId>
            <artifactId>poi-scratchpad</artifactId>
            <version>3.17</version>
        </dependency>

2、创建一个excel工作簿

//声明一个工作簿
 HSSFWorkbook workbook = new HSSFWorkbook();

3、生成一个sheet页

//生成一个表格
HSSFSheet sheet = workbook.createSheet(title);

4、如果需要生成表格的标题行可采取如下操作

 		//产生表格标题行
        HSSFRow row = sheet.createRow(0);
        for (short i=0;i<headers.length;i++){
            HSSFCell cell = row.createCell(i);
            cell.setCellStyle(headerStyle);
            HSSFRichTextString text = new HSSFRichTextString(headers[i]);
            cell.setCellValue(text);
        }

5、遍历数据集合,利用反射机制对单元格进行赋值操作

		//遍历集合数据,产生数据行
        Iterator<T> iterator = dataSet.iterator();
        int index = 0;
        while (iterator.hasNext()){
            index++;
            row = sheet.createRow(index);
            T t = (T)iterator.next();
            //利用反射,根据javabean属性的先后顺序,动态调用get方法得到属性值
            Field[] fields = t.getClass().getDeclaredFields();
            for (short i=0;i<fields.length;i++){
                HSSFCell cell = row.createCell(i);
                Field field = fields[i];
                String fieldName = field.getName();
                //get方法名
                String getMethodName = "get"+fieldName.substring(0,1).toUpperCase()+fieldName.substring(1);
                try{
                    Class cls = t.getClass();
                    Method getMethod = cls.getMethod(getMethodName,new Class[]{});
                    Object value = getMethod.invoke(t, new Object[]{});
                    //在赋值之前可以对value进行类型的判断处理
                    cell.setCellValue(value);
                }catch (NoSuchMethodException | InvocationTargetException | IllegalAccessException e){
                    e.printStackTrace();
                }
            }

6、将excel数据输出

		try {
            response.setHeader("Content-Disposition",
                    "attachment;filename=\"" + new String((fileName+".xls").getBytes(),"iso-8859-1"));
            // 执行公式(如果excel有内置公式的前提需要设置此属性)
            workbook.setForceFormulaRecalculation(true);
            workbook.write(response.getOutputStream());
        }catch (IOException e){
            e.printStackTrace();
        }

二、在一般的实际项目里面,可能我们每次导出的数据都是不一样的,列数也是动态变化,此时我们就无法使用上述Java反射的方法来处理数据。这时我们就需要每次导出时进行动态生成列以及对应的赋值操作,以下是举例说明:

1、生成workbook对象和sheet对象与第一种情况一致;

//声明一个工作簿
HSSFWorkbook workbook = new HSSFWorkbook();
//生成一个表格
HSSFSheet sheet = workbook.createSheet(title);

2、根据特殊的条件动态生成表头数据后生成表头

//此处为个人的处理表头方法,可替换
String[] headers = dealProductHeaders(productList,1);
//样式
HSSFCellStyle commonStyle = commonStyle(workbook);
        headerRow.setHeightInPoints(20);
        for (short i=0;i<headers.length;i++){
            HSSFCell headerCell = headerRow.createCell(i);
            HSSFRichTextString text = new HSSFRichTextString(headers[i]);
            headerCell.setCellValue(text);
            headerCell.setCellStyle(commonStyle);
        }

3、对需要导出的数据进行遍历,在遍历的时候循环生成行hssfRow,并对每行的每列hssfCell进行赋值以及样式的处理;

//此处可自行发挥

4、在处理数据的时候,或许我们会遇到某列设置下拉框的情况,这种情况我们有两种方式可以采取

	第一种:在对应的列直接赋值,生成下拉框,但是此种方法下拉框值的大小有限制;
 /**
     *  excel导出,有码值的数据使用下拉框展示。
     * @param str 数据
     * @param firstRow        插入下拉框开始行号
     * @param lastRow         插入下拉框结束行号
     * @param firstCol        插入下拉框开始列号
     * @param lastCol         插入下拉框结束行号
     * @return
     */
    private static HSSFDataValidation createBox(String[] str, int firstRow, int lastRow, int firstCol, int lastCol) {
         HSSFDataValidation dataValidation = null;
         //设置下拉框
         if(str.length > 0 && null != str) {
             //指定0-9行,0-0列为下拉框
             CellRangeAddressList cas = new CellRangeAddressList(firstRow , lastRow , firstCol , lastCol);
             //创建下拉数据列
             DVConstraint dvConstraint = DVConstraint.createExplicitListConstraint(str);
             //将下拉数据放入下拉框
             dataValidation = new HSSFDataValidation(cas, dvConstraint);
         }
         return dataValidation;
    }
	第二种:可以采取生成隐藏sheet数据,然后在需要生成下拉框的sheet页里面进行引用(无限制,推荐使用);
private static void createBox(HSSFWorkbook workbook,String sheetName,int sheetNameIndex,String[] sheetData,int firstRow,int lastRow,int firstCol,int lastCol){
        //将下拉框数据放到新的sheet里,然后excel通过新的sheet数据加载下拉框数据
        Sheet hidden = workbook.createSheet(sheetName);
        CellStyle cellstyle = workbook.createCellStyle();
        //创建单元格对象
        Cell cell =null;
        //遍历我们上面的数组,将数据取出来放到新sheet的单元格中
        for (int i = 0, length = sheetData.length; i < length; i++){
            //取出数组中的每个元素
            String name = sheetData[i];
            //根据i创建相应的行对象(说明我们将会把每个元素单独放一行)
            Row row = hidden.createRow(i);
            //创建每一行中的第一个单元格
            cell = row.createCell(0);
            //然后将数组中的元素赋值给这个单元格
            cell.setCellValue(name);
            cell.setCellStyle(cellstyle);
        }
        if (sheetData.length==0){
            //没有下拉数据
            workbook.setSheetHidden(sheetNameIndex, true);
        }else {
            //被引用
            // 创建名称,可被其他单元格引用
            Name namedCell = workbook.createName();
            namedCell.setNameName(sheetName);
            // 设置名称引用的公式
            namedCell.setRefersToFormula(sheetName+"!$A$1:$A$" + sheetData.length);
            //加载数据,将名称为hidden的sheet中的数据转换为List形式
            DVConstraint constraint = DVConstraint.createFormulaListConstraint(sheetName);
            // (3, 65534, 2, 2) ====> (起始行,结束行,起始列,结束列)
            CellRangeAddressList regions = new CellRangeAddressList(firstRow, lastRow, firstCol, lastCol);
            // 将设置下拉选的位置和数据的对应关系 绑定到一起
            DataValidation dataValidation = new HSSFDataValidation(regions, constraint);
            //将第二个sheet设置为隐藏
            workbook.setSheetHidden(sheetNameIndex, true);
            //将数据赋给下拉列表
            workbook.getSheetAt(0).addValidationData(dataValidation);
        }
    }

5、另外,在导出excel数据时难免遇到一些特殊情况,需要实现数据分组(即父子关系)、折叠收缩的效果,此时我们需要使用到 poi的sheet.groupRow(param1,param2)方法:

		//param1为分组的起始索引,param2为终止索引
		sheet.groupRow(param1,param2);
        //设置折叠符号在上方
        sheet.setRowSumsBelow(false);
        sheet.setRowSumsRight(false);

建议:在循环数据进行单元格赋值的同时生成分组信息Map<Integer, List<List>> map,后续只需遍历map即可实现excel分组效果,另外像组内汇总,嵌套公式都是很方便的。

map的key为层级,value为此层级所有的分组信息

警告:设置折叠符在上方发现poi自带的获取层级方法失效,因此上述建议可采纳。

6、附上部分常用方法

  • 合并单元格
   private static void commonMergedRegion(HSSFSheet sheet,int firstRow,int lastRow,int firstCol,int lastCol){
        CellRangeAddress region=new CellRangeAddress(firstRow, lastRow, firstCol, lastCol);
        sheet.addMergedRegion(region);
    }
  • 合并单元格之后边框样式处理
 /**
     * 合并单元格后添加边框
     */
    private static void setBorderStyle(CellRangeAddress region, HSSFSheet sheet) {
            RegionUtil.setBorderBottom(BorderStyle.THIN, region, sheet);
            RegionUtil.setBorderLeft(BorderStyle.THIN, region, sheet);
            RegionUtil.setBorderRight(BorderStyle.THIN, region, sheet);
            RegionUtil.setBorderTop(BorderStyle.THIN, region, sheet);
    }
  • 设置样式
public static HSSFCellStyle bodyStyle(HSSFWorkbook workbook){
        HSSFCellStyle style = workbook.createCellStyle();
        //设置样式
        //边框
        style.setBorderBottom(BorderStyle.THIN);
        style.setBorderLeft(BorderStyle.THIN);
        style.setBorderTop(BorderStyle.THIN);
        style.setBorderRight(BorderStyle.THIN);
        //居中
        style.setAlignment(HorizontalAlignment.CENTER);
        //字体
        HSSFFont font = workbook.createFont();
        font.setFontName("仿宋_GB2312");
        //字号
        font.setFontHeightInPoints((short)12);
        //是否加粗
        font.setBold(false);
        style.setFont(font);
        return style;
    }
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值