JAVA实现导出Excel表

来源:互联网 发布:c语言源小程序代码大全 编辑:程序博客网 时间:2024/05/19 23:56

        用java完成将数据导出到Excel中的功能,首先去了解一下有哪些Java ExcelAPI。

Java Aspose Cells

        Java Aspose Cells 是一种纯粹的Java授权的Excel API,开发和供应商Aspose发布。这个API的最新版本是8.1.2,发布于2014年7月,是一个丰富而厚重的API(普通Java类和AWT类的组合)设计,可以读、写和操纵电子表格Excel的组件。此API常见用途如下:

  • Excel报表,建立动态Excel报表
  • 高保真的Excel渲染和打印
  • 从Excel电子表格中导入和导出数据
  • 生成,编辑,转换和电子表格

JXL

        JXL是一款专为Selenium第三方框架,支持基于Web浏览器(数据是Web浏览器自动更新)数据驱动的自动化。然而,它也被用来作为JExcel API的一个共同的支持库,因为它的基本功能是可创建,读取和写入电子表格。基本特征如下:

  • 生成Excel文件
  • 从工作簿和电子表格导入数据
  • 获得行和列的总数
  • 注意:JXL只支持xls档案格式,并且不能处理大数据量。

JExcel

        JExcel是由Team Dev开发提供纯行货API。利用这一点程序员可以很容易地读取,写入,显示和修改Excel工作簿中的两种格式:.xls和.XLSX。这个API可以很容易地嵌入Java的Swing和AWT。这个API的最新版本是Jexcel-2.6.12,发布于2009年,主要特点如下:

  • 自动化Excel应用程序,工作簿,工作表等
  • 在Java Swing应用程序作为普通的Swing组件嵌入到工作簿
  • 事件侦听器添加到工作簿和电子表格
  • 添加事件处理程序来处理的工作簿和电子表格事件的行为
  • 添加本地对等开发定制功能

Apache POI

        Apache POI是Apache软件基金会提供的100%开源库。大多数中小规模的应用程序开发主要依赖于Apache POI(HSSF+ XSSF)。它支持Excel 库的所有基本功能; 然而,呈现和文本提取是它的主要特点。


        这次我用到的是最后一种Apache POI。首先是一个总的方法exportExcel_2007,传入4个主要参数,分别是: sheetName 工作表的名称;dataset 数据源;fieldMap 类的英文属性和Excel中的中文列名的对应关系;sheetSize 每个工作表中记录的最大个数。
代码如下:

/**   * @param sheetName 工作表的名称   * @param dataset 数据源   * @param fieldMap 类的英文属性和Excel中的中文列名的对应关系   * @param sheetSize 每个工作表中记录的最大个数   * @return   * @throws Exception   */  public <T> Workbook exportExcel_2007(String sheetName, List<T> dataset,                                             LinkedHashMap<String, String> fieldMap, int sheetSize, List<ModelAttr> modelAttrs) throws Exception {    if(dataset==null || dataset.size()==0) {      throw new RuntimeException("没有任何数据");    }    SXSSFWorkbook wb = new SXSSFWorkbook(1000);    //1.计算一共有多少个工作表    double sheetNum = Math.ceil(dataset.size()/new Integer(sheetSize).doubleValue());    //2.创建相应的工作表,并向其中填充数据    for(int i=0; i<sheetNum; i++){      //如果只有一个工作表的情况      if(1==sheetNum){        Sheet sheet = wb.createSheet(sheetName);        fillSheet(sheet, dataset, fieldMap, 0, dataset.size()-1,modelAttrs);        setColumnBorderAndColor(wb,sheet);        //有多个工作表的情况      }else{        Sheet sheet = wb.createSheet(sheetName+(i+1));        //获取开始索引和结束索引        int firstIndex=i*sheetSize;        int lastIndex=(i+1)*sheetSize-1>dataset.size()-1 ? dataset.size()-1 : (i+1)*sheetSize-1;        //填充工作表        fillSheet(sheet, dataset, fieldMap, firstIndex, lastIndex,modelAttrs);        setColumnBorderAndColor(wb,sheet);      }    }    return wb;  }



        将工作表创建出来,就需要对表头和表体进行填充。因为我这里的表头是动态的,因此多传入了一个参数进行相关判断。填充表头和表体的函数是fillSheet。

代码如下:

/**   * @MethodName  : fillSheet   * @Description : 向工作表中填充数据   * @param sheet       工作表   * @param list        数据源   * @param fieldMap    中英文字段对应关系的Map   * @param firstIndex  开始索引   * @param lastIndex   结束索引   */  private <T> void fillSheet(          Sheet sheet,          List<T> list,          LinkedHashMap<String,String> fieldMap,          int firstIndex,          int lastIndex,          List<ModelAttr> modelAttrs  )throws Exception{    //定义存放英文字段名和中文字段名的数组    String[] enFields=new String[fieldMap.size()];    String[] cnFields=new String[fieldMap.size()];    //填充数组    int count=0;    for(Map.Entry<String,String> entry:fieldMap.entrySet()){      enFields[count]=entry.getKey();      cnFields[count]=entry.getValue();      count++;    }    //填充表头    Row firstRow = sheet.createRow(0);    for(int i=0;i<cnFields.length;i++){      firstRow.createCell(i).setCellValue(cnFields[i]);    }    //填充内容    int rowNo=1;    for(int index=firstIndex;index<=lastIndex;index++){      Row row = sheet.createRow(rowNo);      //获取单个对象      Map<String,Object> item= (Map<String, Object>) list.get(index);      for(int i=0;i<enFields.length;i++){        ModelAttrType type = null;        for(ModelAttr modelAttr : modelAttrs){          if(enFields[i].equals(modelAttr.getAttrCode())){              type = modelAttr.getAttrType();          }        }        String value = getFieldValueByNameSequence(enFields[i], item,type);        String fieldValue=value==null ? "" : value;        row.createCell(i).setCellValue(fieldValue);      }      rowNo++;    }    //设置自动列宽    setColumnAutoSize(sheet, 512);  }

        首先将表头的数据放入两个数组中,一个是中文表头,一个是英文code,用来匹配表体。然后中文表体填充到新建的firstRow中。

        在表头完成后,根据数据源填充表体,因为数据源是一个复杂的mapList,所以需要对填充的value进行提取处理。我这里写了几个方法,其中针对不同类型的数据处理写了一个感知器,感知器的不用类型处理的代码太多,就不贴了。总之能把你想要放的数据取出来就可以,不用写很复杂。


代码如下:

/**   * @MethodName  : getFieldValueByNameSequence   * @Description :   * 根据属性名获取属性值   *   * @param fieldNameSequence  简单属性名   * @param o 对象   * @return  属性值   * @throws Exception   */  private String getFieldValueByNameSequence(String fieldNameSequence, Map<String,Object> o,ModelAttrType type) throws Exception{    String value=null;    return value = getFieldValueByName(fieldNameSequence,o,type);  }/**   * @MethodName  : getFieldValueByName   * @Description : 根据字段名获取字段值   * @param fieldName 字段名   * @param o 对象   * @return  字段值   */  private String getFieldValueByName(String fieldName, Map<String,Object> o,ModelAttrType type) throws Exception{    Object value=null;    value=getFieldByName(fieldName, o);    String valueStr = insAttrValueAwareProcessor.convertToExcel(type, value);    return valueStr;  }  /**   * @MethodName  : getFieldByName   * @Description : 根据字段名获取字段   * @param fieldName 字段名   * @param   * @return 字段   */  private static Object getFieldByName(String fieldName, Map<String,Object>  o){    if(o == null){      return null;    }    return o.get(fieldName);  }



        填充完数据后,就需要简单设置一下工作表的样式,具体看实际情况。


代码如下:

  /**   * @MethodName  : setColumnAutoSize   * @Description : 设置工作表自动列宽和首行加粗   * @param ws   */  private static void setColumnAutoSize(Sheet ws,int extraWith){    //获取本列的最宽单元格的宽度    for(int i=0;i<ws.getRow(0).getPhysicalNumberOfCells();i++){      int colWith=0;      for(int j=0;j<ws.getLastRowNum();j++){        String content=ws.getRow(j).getCell(i).getStringCellValue();        int cellWith=content.length();        if(colWith<cellWith){          colWith=cellWith;        }      }      //设置单元格的宽度为最宽宽度+额外宽度      ws.setColumnWidth(i, colWith*extraWith);    }  }  /**   * 设置工作表单元格边框和首行背景色   * @param wb   * @param ws   */  private static void setColumnBorderAndColor(SXSSFWorkbook wb,Sheet ws){    XSSFCellStyle cellBorderStyle = (XSSFCellStyle)wb.createCellStyle();    XSSFCellStyle cellColorStyle = (XSSFCellStyle)wb.createCellStyle();    for(int i=0;i<ws.getPhysicalNumberOfRows();i++){      Row row = ws.getRow(i);      for(int j=0;j<ws.getRow(0).getPhysicalNumberOfCells();j++){        Cell cell = row.getCell(j);        Cell cellFirst = ws.getRow(0).getCell(j);        //给单元格设置边框        cellBorderStyle.setBorderBottom(BorderStyle.THIN);        cellBorderStyle.setBorderTop(BorderStyle.THIN);        cellBorderStyle.setBorderLeft(BorderStyle.THIN);        cellBorderStyle.setBorderRight(BorderStyle.THIN);        //给第一行设置边框和背景        cellColorStyle.setFillForegroundColor(IndexedColors.AQUA.getIndex());        cellColorStyle.setFillPattern(FillPatternType.SOLID_FOREGROUND);        cellColorStyle.setBorderBottom(BorderStyle.THIN);        cellColorStyle.setBorderTop(BorderStyle.THIN);        cellColorStyle.setBorderLeft(BorderStyle.THIN);        cellColorStyle.setBorderRight(BorderStyle.THIN);        cell.setCellStyle(cellBorderStyle);        cellFirst.setCellStyle(cellColorStyle);      }    }  }

        有想深入了解学习Apache POI的,可以看看这篇教程Apache POI教程。我也对其进行了参考学习。