zoukankan      html  css  js  c++  java
  • JAVA实现导出Excel

            用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教程。我也对其进行了参考学习。

  • 相关阅读:
    页面可视化搭建工具前生今世
    16、Redis手动创建集群
    15、Redis的集群
    14、Redis的复制
    13、Redis的发布订阅模式
    12、Redis的事务
    11、Redis的持久化(RDB、AOF)
    9、Redis处理过期keys的机制
    8、Redis中sort命令详解
    7、Redis中对ZSet类型的操作命令
  • 原文地址:https://www.cnblogs.com/chenghao1/p/7803932.html
Copyright © 2011-2022 走看看