Struts2匯出Excel步驟及問題彙總 poi分頁(一)

dawn009發表於2014-06-04

最近開發專案中遇到了很多問題,終於可以在空閒的時候總結一下,今天要彙總的是Excel下載匯出等相關問題,主要涉及到問題,如下:

   1. 生成Excel

   2. 大資料Excel匯出(支援多個sheet,親測可以匯出30W資料,再大程式報記憶體溢位)

   3. 下載檔案,及中文檔名下載亂碼,為空等問題

工具/原料

poi-3.8.jar
poi-ooxml-3.8.jar

方法/步驟

  1. 新增Excel標題物件


    /**
    * 用來儲存Excel標題的物件,透過該物件可以獲取標題和方法的對應關係

    * @author monkey

    */
    public class ExcelHeader implements Comparable {
       

       /**
        * excel的標題名稱
        */
       private String title;
       /**
        * 每一個標題的順序
        */
       private int order;
       /**
        * 說對應方法名稱
        */
       private String methodName;

       public String getTitle() {
           return title;
       }

       public void setTitle(String title) {
           this.title = title;
       }

       public int getOrder() {
           return order;
       }

       public void setOrder(int order) {
           this.order = order;
       }

       public String getMethodName() {
           return methodName;
       }

       public void setMethodName(String methodName) {
           this.methodName = methodName;
       }

       public int compareTo(ExcelHeader o) {
           return order > o.order ? 1 : (order < o.order ? -1 : 0);
       }

       public ExcelHeader(String title, int order, String methodName) {
           super();
           this.title = title;
           this.order = order;
           this.methodName = methodName;
       }

       @Override
       public String toString() {
           return "ExcelHeader [title=" + title + ", order=" + order
                   + ", methodName=" + methodName + "]";
       }

    }

  2. 定義annotation類,可以透過該類設定匯出相應的屬性,標題及排序


    import java.lang.annotation.Retention;
    import java.lang.annotation.RetentionPolicy;


    /**
    * 用來在物件的get方法上加入的annotation,透過該annotation說明某個屬性所對應的標題
    * @author Administrator
    *
    */
    @Retention(RetentionPolicy.RUNTIME)
    public @interface ExcelResources {
       /**
        * 屬性的標題名稱
        * @return
        */
       String title();
       /**
        * 在excel的順序
        * @return
        */
       int order() default 9999;
    }

  3. 操作Excel,設定Excel標題樣式,sheet名稱,sheet每頁顯示條數等資訊


    import java.io.FileNotFoundException;
    import java.io.FileOutputStream;
    import java.io.IOException;
    import java.lang.reflect.Method;
    import java.util.ArrayList;
    import java.util.Collections;
    import java.util.List;

    import org.apache.commons.beanutils.BeanUtils;
    import org.apache.commons.lang3.StringUtils;
    import org.apache.poi.hssf.usermodel.HSSFCell;
    import org.apache.poi.hssf.usermodel.HSSFCellStyle;
    import org.apache.poi.hssf.usermodel.HSSFRow;
    import org.apache.poi.hssf.usermodel.HSSFSheet;
    import org.apache.poi.hssf.usermodel.HSSFWorkbook;
    import org.apache.poi.hssf.util.HSSFColor;
    import org.apache.poi.ss.usermodel.Cell;
    import org.apache.poi.ss.usermodel.CellStyle;
    import org.apache.poi.ss.usermodel.Font;
    import org.apache.poi.ss.usermodel.Workbook;

    /**
    * Excel 操作類

    * @author houzhiqing

    */
    @SuppressWarnings("unchecked")
    public class ExcelUtil {

       private static final String POSITION_TITLE = "title";

       private static final String POSITION_BODY = "body";

       private static ExcelUtil eu = new ExcelUtil();

       private ExcelUtil() {
       }

       public static ExcelUtil getInstance() {
           return eu;
       }

       /**
        * 匯出物件到Excel,不是基於模板的,直接新建一個Excel完成匯出,基於路徑的匯出
        * 
        * @param outPath
        *            輸出路徑
        * @param objs
        *            資料來源
        * @param clz
        *            類
        * @param sheetName
        *            分sheet匯出是sheet的名字 , 如 “sheet” -> sheet1,sheet2...
        * @param pageSize
        *            每個sheet要顯示多少條資料
        */
       public void exportObj2Excel(String outPath, List objs, Class clz,
               String sheetName, int pageSize) {
           Workbook wb = handleObj2Excel(objs, clz, sheetName, pageSize);
           FileOutputStream fos = null;
           try {
               fos = new FileOutputStream(outPath);
               wb.write(fos);
           } catch (FileNotFoundException e) {
               e.printStackTrace();
           } catch (IOException e) {
               e.printStackTrace();
           } finally {
               try {
                   if (fos != null)
                       fos.close();
               } catch (IOException e) {
                   e.printStackTrace();
               }
           }
       }

       /**
        * 匯出物件到Excel,不是基於模板的,直接新建一個Excel完成匯出,基於路徑的匯出
        * 
        * @param outPath
        *            輸出路徑
        * @param objs
        *            資料來源
        * @param clz
        *            類
        * @param sheetName
        *            分sheet匯出是sheet的名字 , 如 “sheet” -> sheet1,sheet2...
        * @param pageSize
        *            每個sheet要顯示多少條資料
        */
       public HSSFWorkbook handleObj2Excel(List objs, Class clz, String sheetName,
               int pageSize) {
           HSSFWorkbook wb = null;
           try {
               wb = new HSSFWorkbook();
               // TODO 獲取表頭
               List headers = getHeaderList(clz);
               Collections.sort(headers);

               if (null != objs && objs.size() > 0) {

                   int sheetCount = objs.size() % pageSize == 0 ? objs.size()
                           / pageSize : objs.size() / pageSize + 1;

                   for (int i = 1; i <= sheetCount; i++) {

                       HSSFSheet sheet = null;
                       if(!StringUtils.isEmpty(sheetName)) {
                           sheet = wb.createSheet(sheetName + i);
                       } else {
                           sheet = wb.createSheet();
                       }
                       
                       HSSFRow row = sheet.createRow(0);

                       // 寫標題
                       CellStyle titleStyle = setCellStyle(wb, POSITION_TITLE);
                       for (int m = 0; m < headers.size(); m++) {
                           HSSFCell cell = row.createCell(m);
                           cell.setCellStyle(titleStyle);
                           cell.setCellValue(headers.get(m).getTitle());
                           sheet.setColumnWidth(m, 5000); // 設定每列的寬度
                       }

                       // 寫資料
                       Object obj = null;
                       CellStyle bodyStyle = setCellStyle(wb, POSITION_BODY);
                       int begin = (i - 1) * pageSize;
                       int end = (begin + pageSize) > objs.size() ? objs.size()
                               : (begin + pageSize);

                       System.out.println("begin:" + begin + ",end=" + end);

                       int rowCount = 1;
                       for (int n = begin; n < end; n++) {
                           row = sheet.createRow(rowCount);
                           rowCount++;
                           obj = objs.get(n);
                           for (int x = 0; x < headers.size(); x++) {
                               Cell cell = row.createCell(x);
                               cell.setCellStyle(bodyStyle);
                               cell.setCellValue(BeanUtils.getProperty(obj,
                                       getMethodName(headers.get(x))));
                           }
                       }

                   }
               }

           } catch (Exception e) {
               e.printStackTrace();
               throw new RuntimeException("生成excel失敗");
           }
           return wb;
       }

       /**
        * 根據標題獲取相應的方法名稱
        * 
        * @param eh
        * @return
        */
       private String getMethodName(ExcelHeader eh) {
           String mn = eh.getMethodName().substring(3);
           mn = mn.substring(0, 1).toLowerCase() + mn.substring(1);
           return mn;
       }

       /**
        * 獲取excel標題列表
        * 
        * @param clz
        * @return
        */
       private List getHeaderList(Class clz) {
           List headers = new ArrayList();
           Method[] ms = clz.getDeclaredMethods();
           for (Method m : ms) {
               String mn = m.getName();
               if (mn.startsWith("get")) {
                   if (m.isAnnotationPresent(ExcelResources.class)) {
                       ExcelResources er = m.getAnnotation(ExcelResources.class);
                       headers.add(new ExcelHeader(er.title(), er.order(), mn));
                   }
               }
           }
           return headers;
       }

       /**
        * 設定單元格樣式
        * 
        * @param position
        *            ["body","title"]
        */
       private static CellStyle setCellStyle(Workbook workBook, String position) {

           CellStyle cellStyle = workBook.createCellStyle();
           cellStyle.setAlignment(HSSFCellStyle.ALIGN_CENTER);
           cellStyle.setVerticalAlignment(HSSFCellStyle.VERTICAL_CENTER);
           // 設定單元格字型
           Font headerFont = workBook.createFont(); // 字型
           if (POSITION_TITLE.equals(position)) {
               headerFont.setFontHeightInPoints((short) 12);
           } else {
               headerFont.setFontHeightInPoints((short) 10);
           }
           headerFont.setFontName("宋體");
           if (POSITION_TITLE.equals(position))
               headerFont.setBoldweight((short) 10);
           cellStyle.setFont(headerFont);
           cellStyle.setWrapText(true);

           cellStyle.setFillBackgroundColor(HSSFCellStyle.THICK_FORWARD_DIAG);
           // 設定單元格邊框及顏色
           cellStyle.setBorderBottom((short) 1);
           cellStyle.setBorderLeft((short) 1);
           cellStyle.setBorderRight((short) 1);
           cellStyle.setBorderTop((short) 1);
           cellStyle.setWrapText(true);

           cellStyle.setLeftBorderColor(HSSFColor.BLACK.index); // 設定邊框顏色
           cellStyle.setRightBorderColor(HSSFColor.BLACK.index);
           cellStyle.setTopBorderColor(HSSFColor.BLACK.index);
           cellStyle.setBottomBorderColor(HSSFColor.BLACK.index);

           return cellStyle;
       }
    }

  4. 匯出物件實體類,實際專案中這個類可以有更多的屬性


    import java.io.Serializable;
    import java.util.Date;

    import com.monkey.poi.util.ExcelResources;


    public class ProductCard implements Serializable {

       private static final long serialVersionUID = -70571478472359104L;
       
       private Integer id;
       
       private String code;
       
       private String codePwd;
       
       public Integer getId() {
           return id;
       }

       public void setId(Integer id) {
           this.id = id;
       }
       
       @ExcelResources(title="卡號", order=1)
       public String getCode() {
           return code;
       }

       public void setCode(String code) {
           this.code = code;
       }
       
       @ExcelResources(title="密碼", order=2)
       public String getCodePwd() {
           return codePwd;
       }

       public void setCodePwd(String codePwd) {
           this.codePwd = codePwd;
       }
       
    }

  5. junit測試


       @Test
       public void test002() {
           List pcList = new ArrayList();
           for (int i = 0; i < 300000; i++) {
               ProductCard p = new ProductCard();
               p.setCode(DateUtils.formatDate(DateUtils.DATE_PATTERN_PLAIN,new Date()));
               p.setCodePwd("123456" + i);
               
               pcList.add(p);
           }
           
           ExcelUtil.getInstance().exportObj2Excel("d:/product-1.xls", pcList,
                   ProductCard.class, "我的sheet", 10000);
       }

    END

注意事項

  • Excel樣式部分我是按照我們專案中的所用的格式匯出,各位在自己專案中可以自己定義

  • Excel可以分開單獨顯示不同的

  • 下載部分請查考下一篇文章

-------------------&gt>轉載於:

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/29119536/viewspace-1175698/,如需轉載,請註明出處,否則將追究法律責任。

相關文章