posts - 167,  comments - 30,  trackbacks - 0
           

          POI導出EXCEL經典實現

          web開發中,有一個經典的功能,就是數據的導入導出。特別是數據的導出,在生產管理或者財務系統中用的非常普遍,因為這些系統經常要做一些報表打印的工作。而數據導出的格式一般是EXCEL或者PDF,我這里就用兩篇文章分別給大家介紹下。(注意,我們這里說的數據導出可不是數據庫中的數據導出!么誤會啦^_^

          呵呵,首先我們來導出EXCEL格式的文件吧。現在主流的操作Excel文件的開源工具有很多,用得比較多的就是ApachePOIJExcelAPI。這里我們用Apache POI!我們先去Apache的大本營下載POIjar包:http://poi.apache.org/ ,我這里使用的是3.0.2版本。

          3jar包導入到classpath下,什么?忘了怎么導包?不會吧!好,我們來寫一個導出Excel的實用類(所謂實用,是指基本不用怎么修改就可以在實際項目中直接使用的!)。我一直強調做類也好,做方法也好,一定要通用性和靈活性強。下面這個類就算基本貫徹了我的這種思想。那么,熟悉許老師風格的人應該知道,這時候該要甩出一長串代碼了。沒錯,大伙請看:

          package org.leno.export.util;

          import java.util.Date;

          public class Student {

             private long id;

             private String name;

             private int age;

             private boolean sex;

             private Date birthday;

             public Student() {

                super();

                // TODO Auto-generated constructor stub

             }

             public Student(long id, String name, int age, boolean sex, Date birthday) {

                super();

                this.id = id;

                this.name = name;

                this.age = age;

                this.sex = sex;

                this.birthday = birthday;

             }

             public long getId() {

                return id;

             }

             public void setId(long id) {

                this.id = id;

             }

             public String getName() {

                return name;

             }

             public void setName(String name) {

                this.name = name;

             }

             public int getAge() {

                return age;

             }

             public void setAge(int age) {

                this.age = age;

             }

             public boolean getSex() {

                return sex;

             }

             public void setSex(boolean sex) {

                this.sex = sex;

             }

             public Date getBirthday() {

                return birthday;

             }

             public void setBirthday(Date birthday) {

                this.birthday = birthday;

             }

          }

          package org.leno.export.util;

          public class Book {

             private int bookId;

             private String name;

             private String author;

             private float price;

             private String isbn;

             private String pubName;

             private byte[] preface;

             public Book() {

                super();

             }

             public Book(int bookId, String name, String author, float price,

                   String isbn, String pubName, byte[] preface) {

                super();

                this.bookId = bookId;

                this.name = name;

                this.author = author;

                this.price = price;

                this.isbn = isbn;

                this.pubName = pubName;

                this.preface = preface;

             }

             public int getBookId() {

                return bookId;

             }

             public void setBookId(int bookId) {

                this.bookId = bookId;

             }

             public String getName() {

                return name;

             }

             public void setName(String name) {

                this.name = name;

             }

             public String getAuthor() {

                return author;

             }

             public void setAuthor(String author) {

                this.author = author;

             }

             public float getPrice() {

                return price;

             }

             public void setPrice(float price) {

                this.price = price;

             }

             public String getIsbn() {

                return isbn;

             }

             public void setIsbn(String isbn) {

                this.isbn = isbn;

             }

             public String getPubName() {

                return pubName;

             }

             public void setPubName(String pubName) {

                this.pubName = pubName;

             }

             public byte[] getPreface() {

                return preface;

             }

             public void setPreface(byte[] preface) {

                this.preface = preface;

             }

          }

          上面這兩個類一目了然,就是兩個簡單的javabean風格的類。再看下面真正的重點類:

          package org.leno.export.util;

          import java.io.*;

          import java.lang.reflect.*;

          import java.util.*;

          import java.util.regex.Matcher;

          import java.util.regex.Pattern;

          import java.text.SimpleDateFormat;

          import javax.swing.JOptionPane;

          import org.apache.poi.hssf.usermodel.*;

          import org.apache.poi.hssf.util.HSSFColor;

          /**

           * 利用開源組件POI3.0.2動態導出EXCEL文檔

           * 轉載時請保留以下信息,注明出處!

           * @author leno

           * @version v1.0

           * @param <T> 應用泛型,代表任意一個符合javabean風格的類

           * 注意這里為了簡單起見,boolean型的屬性xxxget器方式為getXxx(),而不是isXxx()

           * byte[]jpg格式的圖片數據

           */

          public class ExportExcel<T> {

             public void exportExcel(Collection<T> dataset, OutputStream out) {

                exportExcel("測試POI導出EXCEL文檔", null, dataset, out, "yyyy-MM-dd");

             }

             public void exportExcel(String[] headers, Collection<T> dataset,

                   OutputStream out) {

                exportExcel("測試POI導出EXCEL文檔", headers, dataset, out, "yyyy-MM-dd");

             }

             public void exportExcel(String[] headers, Collection<T> dataset,

                   OutputStream out, String pattern) {

                exportExcel("測試POI導出EXCEL文檔", headers, dataset, out, pattern);

             }

             /**

              * 這是一個通用的方法,利用了JAVA的反射機制,可以將放置在JAVA集合中并且符號一定條件的數據以EXCEL 的形式輸出到指定IO設備上

              *

              * @param title

              *            表格標題名

              * @param headers

              *            表格屬性列名數組

              * @param dataset

              *            需要顯示的數據集合,集合中一定要放置符合javabean風格的類的對象。此方法支持的

              *            javabean屬性的數據類型有基本數據類型及String,Date,byte[](圖片數據)

              * @param out

              *            與輸出設備關聯的流對象,可以將EXCEL文檔導出到本地文件或者網絡中

              * @param pattern

              *            如果有時間數據,設定輸出格式。默認為"yyy-MM-dd"

              */

             @SuppressWarnings("unchecked")

             public void exportExcel(String title, String[] headers,

                   Collection<T> dataset, OutputStream out, String pattern) {

                // 聲明一個工作薄

                HSSFWorkbook workbook = new HSSFWorkbook();

                // 生成一個表格

                HSSFSheet sheet = workbook.createSheet(title);

                // 設置表格默認列寬度為15個字節

                sheet.setDefaultColumnWidth((short) 15);

                // 生成一個樣式

                HSSFCellStyle style = workbook.createCellStyle();

                // 設置這些樣式

                style.setFillForegroundColor(HSSFColor.SKY_BLUE.index);

                style.setFillPattern(HSSFCellStyle.SOLID_FOREGROUND);

                style.setBorderBottom(HSSFCellStyle.BORDER_THIN);

                style.setBorderLeft(HSSFCellStyle.BORDER_THIN);

                style.setBorderRight(HSSFCellStyle.BORDER_THIN);

                style.setBorderTop(HSSFCellStyle.BORDER_THIN);

                style.setAlignment(HSSFCellStyle.ALIGN_CENTER);

                // 生成一個字體

                HSSFFont font = workbook.createFont();

                font.setColor(HSSFColor.VIOLET.index);

                font.setFontHeightInPoints((short) 12);

                font.setBoldweight(HSSFFont.BOLDWEIGHT_BOLD);

                // 把字體應用到當前的樣式

                style.setFont(font);

                // 生成并設置另一個樣式

                HSSFCellStyle style2 = workbook.createCellStyle();

                style2.setFillForegroundColor(HSSFColor.LIGHT_YELLOW.index);

                style2.setFillPattern(HSSFCellStyle.SOLID_FOREGROUND);

                style2.setBorderBottom(HSSFCellStyle.BORDER_THIN);

                style2.setBorderLeft(HSSFCellStyle.BORDER_THIN);

                style2.setBorderRight(HSSFCellStyle.BORDER_THIN);

                style2.setBorderTop(HSSFCellStyle.BORDER_THIN);

                style2.setAlignment(HSSFCellStyle.ALIGN_CENTER);

                style2.setVerticalAlignment(HSSFCellStyle.VERTICAL_CENTER);

                // 生成另一個字體

                HSSFFont font2 = workbook.createFont();

                font2.setBoldweight(HSSFFont.BOLDWEIGHT_NORMAL);

                // 把字體應用到當前的樣式

                style2.setFont(font2);

                // 聲明一個畫圖的頂級管理器

                HSSFPatriarch patriarch = sheet.createDrawingPatriarch();

                // 定義注釋的大小和位置,詳見文檔

                HSSFComment comment = patriarch.createComment(new HSSFClientAnchor(0, 0, 0, 0, (short) 4, 2, (short) 6, 5));

                // 設置注釋內容

                comment.setString(new HSSFRichTextString("可以在POI中添加注釋!"));

                // 設置注釋作者,當鼠標移動到單元格上是可以在狀態欄中看到該內容.

                comment.setAuthor("leno");

                //產生表格標題行

                HSSFRow row = sheet.createRow(0);

                for (short i = 0; i < headers.length; i++) {

                   HSSFCell cell = row.createCell(i);

                   cell.setCellStyle(style);

                   HSSFRichTextString text = new HSSFRichTextString(headers[i]);

                   cell.setCellValue(text);

                }

                //遍歷集合數據,產生數據行

                Iterator<T> it = dataset.iterator();

                int index = 0;

                while (it.hasNext()) {

                   index++;

                   row = sheet.createRow(index);

                   T t = (T) it.next();

                   //利用反射,根據javabean屬性的先后順序,動態調用getXxx()方法得到屬性值

                   Field[] fields = t.getClass().getDeclaredFields();

                   for (short i = 0; i < fields.length; i++) {

                      HSSFCell cell = row.createCell(i);

                      cell.setCellStyle(style2);

                      Field field = fields[i];

                      String fieldName = field.getName();

                      String getMethodName = "get"

                             + fieldName.substring(0, 1).toUpperCase()

                             + fieldName.substring(1);

                      try {

                          Class tCls = t.getClass();

                          Method getMethod = tCls.getMethod(getMethodName,

                                new Class[] {});

                          Object value = getMethod.invoke(t, new Object[] {});

                          //判斷值的類型后進行強制類型轉換

                          String textValue = null;

          //              if (value instanceof Integer) {

          //                 int intValue = (Integer) value;

          //                 cell.setCellValue(intValue);

          //              } else if (value instanceof Float) {

          //                 float fValue = (Float) value;

          //                 textValue = new HSSFRichTextString(

          //                       String.valueOf(fValue));

          //                 cell.setCellValue(textValue);

          //              } else if (value instanceof Double) {

          //                 double dValue = (Double) value;

          //                 textValue = new HSSFRichTextString(

          //                       String.valueOf(dValue));

          //                 cell.setCellValue(textValue);

          //              } else if (value instanceof Long) {

          //                 long longValue = (Long) value;

          //                 cell.setCellValue(longValue);

          //              }

                          if (value instanceof Boolean) {

                             boolean bValue = (Boolean) value;

                             textValue = "";

                             if (!bValue) {

                                textValue ="";

                             }

                          } else if (value instanceof Date) {

                             Date date = (Date) value;

                             SimpleDateFormat sdf = new SimpleDateFormat(pattern);

                              textValue = sdf.format(date);

                          } else if (value instanceof byte[]) {

                             // 有圖片時,設置行高為60px;

                             row.setHeightInPoints(60);

                             // 設置圖片所在列寬度為80px,注意這里單位的一個換算

                             sheet.setColumnWidth(i, (short) (35.7 * 80));

                             // sheet.autoSizeColumn(i);

                             byte[] bsValue = (byte[]) value;

                             HSSFClientAnchor anchor = new HSSFClientAnchor(0, 0,

                                   1023, 255, (short) 6, index, (short) 6, index);

                             anchor.setAnchorType(2);

                             patriarch.createPicture(anchor, workbook.addPicture(

                                   bsValue, HSSFWorkbook.PICTURE_TYPE_JPEG));

                          } else{

                             //其它數據類型都當作字符串簡單處理

                             textValue = value.toString();

                          }

                          //如果不是圖片數據,就利用正則表達式判斷textValue是否全部由數字組成

                          if(textValue!=null){

                             Pattern p = Pattern.compile("^""d+("".""d+)?$");  

                            Matcher matcher = p.matcher(textValue);

                             if(matcher.matches()){

                                //是數字當作double處理

                                cell.setCellValue(Double.parseDouble(textValue));

                             }else{

                                HSSFRichTextString richString = new HSSFRichTextString(textValue);

                                HSSFFont font3 = workbook.createFont();

                                font3.setColor(HSSFColor.BLUE.index);

                                richString.applyFont(font3);

                                cell.setCellValue(richString);

                             }

                          }

                      } catch (SecurityException e) {

                          // TODO Auto-generated catch block

                          e.printStackTrace();

                      } catch (NoSuchMethodException e) {

                          // TODO Auto-generated catch block

                          e.printStackTrace();

                      } catch (IllegalArgumentException e) {

                          // TODO Auto-generated catch block

                          e.printStackTrace();

                      } catch (IllegalAccessException e) {

                          // TODO Auto-generated catch block

                          e.printStackTrace();

                      } catch (InvocationTargetException e) {

                          // TODO Auto-generated catch block

                          e.printStackTrace();

                      } finally {

                          //清理資源

                      }

                   }

                }

                try {

                   workbook.write(out);

                } catch (IOException e) {

                   // TODO Auto-generated catch block

                   e.printStackTrace();

                }

             }

             public static void main(String[] args) {

                // 測試學生

                ExportExcel<Student> ex = new ExportExcel<Student>();

                String[] headers = { "學號", "姓名", "年齡", "性別", "出生日期" };

                List<Student> dataset = new ArrayList<Student>();

                dataset.add(new Student(10000001, "張三", 20, true, new Date()));

                dataset.add(new Student(20000002, "李四", 24, false, new Date()));

                dataset.add(new Student(30000003, "王五", 22, true, new Date()));

                // 測試圖書

                ExportExcel<Book> ex2 = new ExportExcel<Book>();

                String[] headers2 = { "圖書編號", "圖書名稱", "圖書作者", "圖書價格", "圖書ISBN",

                      "圖書出版社", "封面圖片" };

                List<Book> dataset2 = new ArrayList<Book>();

                try {

                   BufferedInputStream bis = new BufferedInputStream(

                          new FileInputStream("book.jpg"));

                   byte[] buf = new byte[bis.available()];

                   while ((bis.read(buf)) != -1) {

                      //

                   }

                   dataset2.add(new Book(1, "jsp", "leno", 300.33f, "1234567",

                          "清華出版社", buf));

                   dataset2.add(new Book(2, "java編程思想", "brucl", 300.33f, "1234567",

                          "陽光出版社", buf));

                   dataset2.add(new Book(3, "DOM藝術", "lenotang", 300.33f, "1234567",

                          "清華出版社", buf));

                   dataset2.add(new Book(4, "c++經典", "leno", 400.33f, "1234567",

                          "清華出版社", buf));

                   dataset2.add(new Book(5, "c#入門", "leno", 300.33f, "1234567",

                          "湯春秀出版社", buf));

                   OutputStream out = new FileOutputStream("E:""a.xls");

                   OutputStream out2 = new FileOutputStream("E:""b.xls");

                   ex.exportExcel(headers, dataset, out);

                   ex2.exportExcel(headers2, dataset2, out2);

                   out.close();

                   JOptionPane.showMessageDialog(null, "導出成功!");

                   System.out.println("excel導出成功!");

                } catch (FileNotFoundException e) {

                   // TODO Auto-generated catch block

                   e.printStackTrace();

                } catch (IOException e) {

                   // TODO Auto-generated catch block

                   e.printStackTrace();

                }

             }

          }

          不行,頭有點暈^_^。呵呵,又是泛型,又是反射,又是正則表達式,又是重載,還有多參數列表和POI API。一下子蹦出來,實在讓人吃不消。不管了,頂住看效果先。在本地運行后,我們發現在E:""下生成了兩份excel文件:學生記錄和圖書記錄,并且中文,數字,顏色,日期,圖片等等一且正常。恩,太棒了。有人看到這里開始苦臉了:喂,我怎么一運行就報錯啊!呵呵,看看什么錯吧!哦,找不到文件,也就是說你沒有book.jpg嘛。好,拷貝一張小巧的圖書圖片命名為book.jpg放置到當前工程下吧。注意,您千萬別把張桌面大小的圖片丟進去了^_^!看到效果了吧。現在我們再來簡單梳理一下代碼,實際上上面就做了一個導出excel的方法和一個本地測試main()方法。并且代碼的結構也很清晰,只是涉及的知識點稍微多一點。大家細心看看注釋,結合要完成的功能,應該沒有太大問題的。好啦,吃杯茶,擦把汗,總算把這個類消化掉,你又進步了。咦,你不是說是在WEB環境下導出的嗎?別急,因為導出就是一個下載的過程。我們只需要在服務器端寫一個Jsp或者Servlet組件完成輸出excel到瀏覽器客戶端的工作就好了。我們以Servlet為例,還是看代碼吧:

          package org.leno.export.util;

          import java.io.*;

          import java.util.ArrayList;

          import java.util.List;

          import javax.servlet.ServletException;

          import javax.servlet.http.HttpServletRequest;

          import javax.servlet.http.HttpServletResponse;

           /**

           * @author leno

           * 使用servlet導出動態生成的excel文件,數據可以來源于數據庫

           * 這樣,瀏覽器客戶端就可以訪問該servlet得到一份用java代碼動態生成的excel文件

           */

          public class Export extends javax.servlet.http.HttpServlet{

             static final long serialVersionUID = 1L;

             protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

                File file = new File(getServletContext().getRealPath("WEB-INF/book.jpg"));

                response.setContentType("octets/stream");

                response.addHeader("Content-Disposition", "attachment;filename=test.xls");

                //測試圖書

                ExportExcel<Book> ex = new ExportExcel<Book>();

                String[] headers = { "圖書編號", "圖書名稱", "圖書作者", "圖書價格", "圖書ISBN",

                      "圖書出版社", "封面圖片" };

                List<Book> dataset = new ArrayList<Book>();

                try {

                   BufferedInputStream bis = new BufferedInputStream(

                         new FileInputStream(file));

                   byte[] buf = new byte[bis.available()];

                   while ((bis.read(buf)) != -1) {

                      //將圖片數據存放到緩沖數組中

                   }

                   dataset.add(new Book(1, "jsp", "leno", 300.33f, "1234567",

                          "清華出版社", buf));

                   dataset.add(new Book(2, "java編程思想", "brucl", 300.33f, "1234567",

                          "陽光出版社", buf));

                   dataset.add(new Book(3, "DOM藝術", "lenotang", 300.33f, "1234567",

                          "清華出版社", buf));

                   dataset.add(new Book(4, "c++經典", "leno", 400.33f, "1234567",

                          "清華出版社", buf));

                   dataset.add(new Book(5, "c#入門", "leno", 300.33f, "1234567",

                          "湯春秀出版社", buf));

                   OutputStream out = response.getOutputStream();

                   ex.exportExcel(headers, dataset, out);

                   out.close();

                   System.out.println("excel導出成功!");

                } catch (FileNotFoundException e) {

                   // TODO Auto-generated catch block

                   e.printStackTrace();

                } catch (IOException e) {

                   // TODO Auto-generated catch block

                   e.printStackTrace();

                }

             } 

             protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

                doGet(request, response);

             }             

          }

          寫完之后,如果您不是用eclipse工具生成的Servlet,千萬別忘了在web.xml上注冊這個Servelt。而且同樣的,拷貝一張小巧的圖書圖片命名為book.jpg放置到當前WEB根目錄的/WEB-INF/下。部署好web工程,用瀏覽器訪問Servlet看下效果吧!是不是下載成功了。呵呵,您可以將下載到本地的excel報表用打印機打印出來,這樣您就大功告成了。完事了我們就思考:我們發現,我們做的方法,不管是本地調用,還是在WEB服務器端用Servlet調用;不管是輸出學生列表,還是圖書列表信息,代碼都幾乎一樣,而且這些數據我們很容器結合后臺的DAO操作數據庫動態獲取。恩,類和方法的通用性和靈活性開始有點感覺了。好啦,祝您學習愉快!

          本文來自CSDN博客,轉載請標明出處:http://blog.csdn.net/lenotang/archive/2008/08/24/2823230.aspx

          posted on 2010-11-24 09:32 David1228 閱讀(1071) 評論(0)  編輯  收藏

          只有注冊用戶登錄后才能發表評論。


          網站導航:
           

          <2010年11月>
          31123456
          78910111213
          14151617181920
          21222324252627
          2829301234
          567891011

          常用鏈接

          留言簿(4)

          隨筆分類

          隨筆檔案

          文章檔案

          新聞分類

          新聞檔案

          相冊

          收藏夾

          Java

          Linux知識相關

          Spring相關

          云計算/Linux/虛擬化技術/

          友情博客

          多線程并發編程

          開源技術

          持久層技術相關

          搜索

          •  

          積分與排名

          • 積分 - 359311
          • 排名 - 154

          最新評論

          閱讀排行榜

          評論排行榜

          主站蜘蛛池模板: 三江| 崇阳县| 若羌县| 瓮安县| 白玉县| 宜兴市| 邹城市| 平陆县| 腾冲县| 浑源县| 泰州市| 项城市| 漳平市| 江北区| 宝鸡市| 龙游县| 合肥市| 庄河市| 苍南县| 耿马| 安平县| 天气| 佛学| 阳高县| 汶川县| 定安县| 抚顺县| 宾川县| 建昌县| 万山特区| 石城县| 微博| 芜湖县| 柳江县| 屯门区| 邵武市| 抚州市| 孟村| 临漳县| 禹城市| 夹江县|