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教程。我也對其進行了參考學習。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM