簡介
Apache POI 是用Java編寫的免費開源的跨平臺的 Java API,Apache POI提供API給Java程式對Microsoft Office格式檔案讀和寫的功能。POI爲“Poor Obfuscation Implementation”的首字母縮寫,意爲“可憐的模糊實現”。
Apache POI 是創建和維護操作各種符合Office Open XML(OOXML)標準和微軟的OLE 2複合文檔格式(OLE2)的Java API。用它可以使用Java讀取和創建,修改MS Excel文件.而且,還可以使用Java讀取和創建MS Word和MSPowerPoint文件。Apache POI 提供Java操作Excel解決方案。詳情見百度百科:apache poi百度百科
實現導出excel兩種方式:1、JExcel 2、apache poi
區別:(1)JExcel是不支持xlsx格式,POI支持xls格式也支持xlsx格式。
(2)apache poi基於流的處理數據,適合大文件要求內存更少。.
我是用的apache poi
需要的jar包
(1)poi-3.13-20150929.jar--------我的是3.13版本,官方下載地址http://poi.apache.org/download.html
(2)commons-codec-1.4.jar----上面的已包含
(3)commons-io-1.4.jar-----apache提供的IO包,很好用,官方下載地 址http://commons.apache.org/proper/commons-io/download_io.cgi
java代碼
(1)先定義一個實體類
<span style="font-size:18px;">package com.sram.bean; import java.awt.image.BufferedImage; /** * * @類名: User * @描述: 將用戶信息和圖片導出到excel * @作者: chenchaoyun0 * @日期: 2016-1-28 下午10:06:23 * */ public class User { private int id; private String user_name; private String user_headSrc;//用戶頭像的路徑 private BufferedImage user_headImg;//用戶輸出頭像到excel的圖片緩衝 public User() { super(); } public User(int id, String user_name, String user_headSrc) { super(); this.id = id; this.user_name = user_name; this.user_headSrc = user_headSrc; } @Override public String toString() { return "User [id=" + id + ", user_name=" + user_name + ", user_headSrc=" + user_headSrc + ", user_headImg=" + user_headImg + "]"; } public int getId() { return id; } public void setId(int id) { this.id = id; } public String getUser_name() { return user_name; } public void setUser_name(String user_name) { this.user_name = user_name; } public String getUser_headSrc() { return user_headSrc; } public void setUser_headSrc(String user_headSrc) { this.user_headSrc = user_headSrc; } public BufferedImage getUser_headImg() { return user_headImg; } public void setUser_headImg(BufferedImage user_headImg) { this.user_headImg = user_headImg; } }</span>
(2)excel導出的工具類
(3)設置excel的類package com.sram.util; import java.io.File; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import org.apache.poi.hssf.usermodel.HSSFCell; import org.apache.poi.hssf.usermodel.HSSFCellStyle; import org.apache.poi.hssf.usermodel.HSSFFont; import org.apache.poi.hssf.usermodel.HSSFRichTextString; 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.hssf.util.Region; /** * * @類名: ExportExcel * @描述: excel工具類 * @作者: chenchaoyun0 * @日期: 2016-1-28 下午10:28:18 * */ public class ExportExcel { private HSSFWorkbook wb = null; private HSSFSheet sheet = null; /** * * <p> * 標題: * </p> * <p> * 描述: * </p> * * @param wb * @param sheet */ public ExportExcel(HSSFWorkbook wb, HSSFSheet sheet) { // super(); this.wb = wb; this.sheet = sheet; } /** * * @標題: createNormalHead * @作者: chenchaoyun0 * @描述: TODO(這裏用一句話描述這個方法的作用) * @參數: @param headString 頭部的字符 * @參數: @param colSum 報表的列數 * @返回: void 返回類型 * @拋出: */ @SuppressWarnings("deprecation") public void createNormalHead(String headString, int colSum) { HSSFRow row = sheet.createRow(0); // 設置第一行 HSSFCell cell = row.createCell(0); // row.setHeight((short) 1000); // 定義單元格爲字符串類型 cell.setCellType(HSSFCell.ENCODING_UTF_16);// 中文處理 cell.setCellValue(new HSSFRichTextString(headString)); // 指定合併區域 /** * public Region(int rowFrom, short colFrom, int rowTo, short colTo) */ sheet.addMergedRegion(new Region(0, (short) 0, 0, (short) colSum)); // 定義單元格格式,添加單元格表樣式,並添加到工作簿 HSSFCellStyle cellStyle = wb.createCellStyle(); // 設置單元格水平對齊類型 cellStyle.setAlignment(HSSFCellStyle.ALIGN_CENTER); // 指定單元格居中對齊 cellStyle.setVerticalAlignment(HSSFCellStyle.VERTICAL_CENTER);// 指定單元格垂直居中對齊 cellStyle.setWrapText(true);// 指定單元格自動換行 // 設置單元格字體 HSSFFont font = wb.createFont(); font.setBoldweight(HSSFFont.BOLDWEIGHT_BOLD); font.setFontName("宋體"); font.setFontHeight((short) 600); cellStyle.setFont(font); cell.setCellStyle(cellStyle); } /** * * @標題: createNormalTwoRow * @作者: chenchaoyun0 * @描述: 創建通用報表第二行 * @參數: @param params 二行統計條件數組 * @參數: @param colSum 需要合併到的列索引 * @返回: void 返回類型 * @拋出: */ @SuppressWarnings("deprecation") public void createNormalTwoRow(String[] params, int colSum) { // 創建第二行 HSSFRow row1 = sheet.createRow(1); row1.setHeight((short) 400); HSSFCell cell2 = row1.createCell(0); cell2.setCellType(HSSFCell.ENCODING_UTF_16); cell2.setCellValue(new HSSFRichTextString("時間:" + params[0] + "至" + params[1])); // 指定合併區域 sheet.addMergedRegion(new Region(1, (short) 0, 1, (short) colSum)); HSSFCellStyle cellStyle = wb.createCellStyle(); cellStyle.setAlignment(HSSFCellStyle.ALIGN_CENTER); // 指定單元格居中對齊 cellStyle.setVerticalAlignment(HSSFCellStyle.VERTICAL_CENTER);// 指定單元格垂直居中對齊 cellStyle.setWrapText(true);// 指定單元格自動換行 // 設置單元格字體 HSSFFont font = wb.createFont(); font.setBoldweight(HSSFFont.BOLDWEIGHT_BOLD); font.setFontName("宋體"); font.setFontHeight((short) 250); cellStyle.setFont(font); cell2.setCellStyle(cellStyle); } /** * * @標題: createColumHeader * @作者: chenchaoyun0 * @描述: 設置報表標題 * @參數: @param columHeader 標題字符串數組 * @返回: void 返回類型 * @拋出: */ public void createColumHeader(String[] columHeader) { // 設置列頭 在第三行 HSSFRow row2 = sheet.createRow(2); // 指定行高 row2.setHeight((short) 600); HSSFCellStyle cellStyle = wb.createCellStyle(); cellStyle.setAlignment(HSSFCellStyle.ALIGN_CENTER); // 指定單元格居中對齊 cellStyle.setVerticalAlignment(HSSFCellStyle.VERTICAL_CENTER);// 指定單元格垂直居中對齊 cellStyle.setWrapText(true);// 指定單元格自動換行 // 單元格字體 HSSFFont font = wb.createFont(); font.setBoldweight(HSSFFont.BOLDWEIGHT_BOLD); font.setFontName("宋體"); font.setFontHeight((short) 250); cellStyle.setFont(font); // 設置單元格背景色 cellStyle.setFillForegroundColor(HSSFColor.GREY_25_PERCENT.index); cellStyle.setFillPattern(HSSFCellStyle.SOLID_FOREGROUND); HSSFCell cell3 = null; for (int i = 0; i < columHeader.length; i++) { cell3 = row2.createCell(i); cell3.setCellType(HSSFCell.ENCODING_UTF_16); cell3.setCellStyle(cellStyle); cell3.setCellValue(new HSSFRichTextString(columHeader[i])); } } /** * * @標題: cteateCell * @作者: chenchaoyun0 * @描述: 創建內容單元格 * @參數: @param wb HSSFWorkbook * @參數: @param row HSSFRow * @參數: @param col short型的列索引 * @參數: @param align 對齊方式 * @參數: @param val 列 * @返回: void 返回類型 * @拋出: */ public void cteateCell(HSSFWorkbook wb, HSSFRow row, int col, short align, String val) { HSSFCell cell = row.createCell(col); cell.setCellType(HSSFCell.ENCODING_UTF_16); cell.setCellValue(new HSSFRichTextString(val)); HSSFCellStyle cellstyle = wb.createCellStyle(); cellstyle.setAlignment(align); cell.setCellStyle(cellstyle); } /** * * @標題: createLastSumRow * @作者: chenchaoyun0 * @描述: 創建合計行 * @參數: @param colSum 需要合併到的列索引 * @參數: @param cellValue 設定文件 * @返回: void 返回類型 * @拋出: */ @SuppressWarnings("deprecation") public void createLastSumRow(int colSum, String[] cellValue) { HSSFCellStyle cellStyle = wb.createCellStyle(); cellStyle.setAlignment(HSSFCellStyle.ALIGN_CENTER); // 指定單元格居中對齊 cellStyle.setVerticalAlignment(HSSFCellStyle.VERTICAL_CENTER);// 指定單元格垂直居中對齊 cellStyle.setWrapText(true);// 指定單元格自動換行 // 單元格字體 HSSFFont font = wb.createFont(); font.setBoldweight(HSSFFont.BOLDWEIGHT_BOLD); font.setFontName("宋體"); font.setFontHeight((short) 250); cellStyle.setFont(font); // 獲取工作表最後一行 HSSFRow lastRow = sheet.createRow((short) (sheet.getLastRowNum() + 1)); HSSFCell sumCell = lastRow.createCell(0); sumCell.setCellValue(new HSSFRichTextString("合計")); sumCell.setCellStyle(cellStyle); // 合併 最後一行的第零列-最後一行的第一列 sheet.addMergedRegion(new Region(sheet.getLastRowNum(), (short) 0, sheet.getLastRowNum(), (short) colSum));// 指定合併區域 for (int i = 2; i < (cellValue.length + 2); i++) { // 定義最後一行的第三列 sumCell = lastRow.createCell(i); sumCell.setCellStyle(cellStyle); // 定義數組 從0開始。 sumCell.setCellValue(new HSSFRichTextString(cellValue[i - 2])); } } /** * * @標題: outputExcel * @作者: chenchaoyun0 * @描述: 輸出excel下載 * @參數: @param fileName 文件名 * @返回: void 返回類型 * @拋出: */ public void outputExcel(String fileName) { FileOutputStream fos = null; try { fos = new FileOutputStream(new File(fileName)); wb.write(fos); fos.close(); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } } /** * * @返回: HSSFSheet 返回類型 */ public HSSFSheet getSheet() { return sheet; } public void setSheet(HSSFSheet sheet) { this.sheet = sheet; } /** * * @返回: HSSFWorkbook 返回類型 */ public HSSFWorkbook getWb() { return wb; } /** * */ public void setWb(HSSFWorkbook wb) { this.wb = wb; } }
package com.sram.util; import java.awt.image.BufferedImage; import java.io.BufferedOutputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.OutputStream; import java.util.List; import javax.imageio.ImageIO; import javax.servlet.http.HttpServletResponse; import org.apache.poi.hssf.usermodel.HSSFCell; import org.apache.poi.hssf.usermodel.HSSFCellStyle; import org.apache.poi.hssf.usermodel.HSSFClientAnchor; import org.apache.poi.hssf.usermodel.HSSFFont; import org.apache.poi.hssf.usermodel.HSSFPatriarch; import org.apache.poi.hssf.usermodel.HSSFRichTextString; import org.apache.poi.hssf.usermodel.HSSFRow; import org.apache.poi.hssf.usermodel.HSSFSheet; import org.apache.poi.hssf.usermodel.HSSFWorkbook; import com.sram.bean.User; /** * * @類名: ExportToExcelUtil * @描述: 設置excel'的信息 * @作者: chenchaoyun0 * @日期: 2016-1-28 下午11:19:58 * */ public class ExportToExcelUtil { public static void out(HttpServletResponse response, List<User> list) throws Exception { /** * 指定下載名 */ String fileName = "用戶數據.xls"; /** * 編碼 */ fileName = new String(fileName.getBytes("GBK"), "iso8859-1"); /** * 去除空白行 */ response.reset(); /** * 指定下載的文件名與設置相應頭 */ response.setHeader("Content-Disposition", "attachment;filename=" + fileName); /** * 下載文件類型 */ response.setContentType("application/vnd.ms-excel"); /** * 別給我緩存 */ response.setHeader("Pragma", "no-cache"); response.setHeader("Cache-Control", "no-cache"); response.setDateHeader("Expires", 0); /** * 得到輸出流,放到緩衝區 */ OutputStream output = response.getOutputStream(); BufferedOutputStream bufferedOutPut = new BufferedOutputStream(output); /** * 下面是導出的excel格式的設置 */ /*******************我是分割線**************************************/ // 定義單元格報頭 String worksheetTitle = "這是ccy的測試"; HSSFWorkbook wb = new HSSFWorkbook(); // 創建單元格樣式 HSSFCellStyle cellStyleTitle = wb.createCellStyle(); // 指定單元格居中對齊 cellStyleTitle.setAlignment(HSSFCellStyle.ALIGN_CENTER); // 指定單元格垂直居中對齊 cellStyleTitle.setVerticalAlignment(HSSFCellStyle.VERTICAL_CENTER); // 指定當單元格內容顯示不下時自動換行 cellStyleTitle.setWrapText(true); HSSFCellStyle cellStyle = wb.createCellStyle(); // 指定單元格居中對齊 cellStyle.setAlignment(HSSFCellStyle.ALIGN_CENTER); // 指定單元格垂直居中對齊 cellStyle.setVerticalAlignment(HSSFCellStyle.VERTICAL_CENTER); // 指定當單元格內容顯示不下時自動換行 cellStyle.setWrapText(true); // 設置單元格字體 HSSFFont font = wb.createFont(); font.setBoldweight(HSSFFont.BOLDWEIGHT_BOLD); font.setFontName("宋體"); font.setFontHeight((short) 200); cellStyleTitle.setFont(font); /****************wo是分割線*****************************************/ /** * 工作表列名 */ String id = "id"; String name = "用戶名"; String img = "頭像"; HSSFSheet sheet = wb.createSheet(); ExportExcel exportExcel = new ExportExcel(wb, sheet); /** * 創建報表頭部 */ exportExcel.createNormalHead(worksheetTitle, 6); // 定義第一行 HSSFRow row1 = sheet.createRow(1); HSSFCell cell1 = row1.createCell(0); /** * 第一行第一列 */ cell1.setCellStyle(cellStyleTitle); cell1.setCellValue(new HSSFRichTextString(id)); /** * 第一行第二列 */ cell1 = row1.createCell(1); cell1.setCellStyle(cellStyleTitle); cell1.setCellValue(new HSSFRichTextString(name)); /** * 第一行第三列 */ cell1 = row1.createCell(2); cell1.setCellStyle(cellStyleTitle); cell1.setCellValue(new HSSFRichTextString(img)); /********************我是分割線*********************************/ /** * 定義第二行,就是我們的數據 */ HSSFRow row = sheet.createRow(2); HSSFCell cell = row.createCell(1); /** * 便利我們傳進來的user-list */ User user =null; HSSFPatriarch patriarch = sheet.createDrawingPatriarch(); for (int i = 0; i < list.size(); i++) { user = list.get(i); /** * 從i+2行開始,因爲我們之前的表的標題和列的標題已經佔用了兩行 */ row = sheet.createRow(i + 2); //...id cell = row.createCell(0); cell.setCellStyle(cellStyle); cell.setCellValue(new HSSFRichTextString(user.getId() + "")); //....user_name cell = row.createCell(1); cell.setCellStyle(cellStyle); cell.setCellValue(new HSSFRichTextString("\n"+user.getUser_name()+"\n")); //...user_headImg short h =2;//定義圖片所在行 short l=2;//定義圖片所在列 cell = row.createCell(2); cell.setCellStyle(cellStyle); //得到user的圖片 BufferedImage image = user.getUser_headImg(); ByteArrayOutputStream byteArrayOut = new ByteArrayOutputStream(); ImageIO.write(image, "jpg", byteArrayOut); HSSFClientAnchor anchor = new HSSFClientAnchor(0, 0, 0, 0, l, i + h, (short) (l+1), (i+1) + h); anchor.setAnchorType(0); // 插入圖片 patriarch.createPicture(anchor, wb.addPicture( byteArrayOut.toByteArray(), HSSFWorkbook.PICTURE_TYPE_JPEG)); } try { /** * 輸出到瀏覽器 */ bufferedOutPut.flush(); wb.write(bufferedOutPut); bufferedOutPut.close();//關流 } catch (IOException e) { e.printStackTrace(); } finally { list.clear(); } } }
(4)Servlet類,注意看路徑,我這裏是模擬了數據庫信息,而且在服務器項目下需要有對應的圖片路徑
package com.sram.servlet; import java.awt.image.BufferedImage; import java.io.File; import java.io.IOException; import java.util.ArrayList; import java.util.List; import javax.imageio.ImageIO; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import com.sram.bean.User; import com.sram.util.ExportToExcelUtil; /** * * @類名: OutPut2ExcelServlet * @描述: 將用戶信息和圖片導出到excel * @作者: chenchaoyun0 * @日期: 2016-1-28 下午10:08:57 * */ public class OutPut2ExcelServlet extends HttpServlet { public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doPost(request, response); } public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { response.setContentType("text/html;charset=utf-8"); request.setCharacterEncoding("utf-8"); /**************我是分割線***********************/ /** * */ User user1=new User(1, "chenchaoyun0","/head/qq5.jpg"); User user2=new User(2, "呵呵噠","/head/qq1.jpg"); User user3=new User(3, "陳哈哈","/head/qq2.jpg"); User user4=new User(4, "喔喔喔","/head/qq3.jpg"); User user5=new User(5, "咳咳咳","/head/qq4.jpg"); /** * */ List<User> al=new ArrayList<User>(); al.add(user1); al.add(user2); al.add(user3); al.add(user4); al.add(user5); /** * 爲用戶設置頭像 */ for (int i = 0; i < al.size(); i++) { User user = al.get(i); String realPath = this.getServletContext().getRealPath(user.getUser_headSrc());//獲取真實圖片路徑 BufferedImage img=ImageIO.read(new File(realPath)); user.setUser_headImg(img);//爲每個user設置屬性 } /** * 把response給excel工具類,再輸出到瀏覽器 */ try { ExportToExcelUtil.out(response, al); } catch (Exception e) { e.printStackTrace(); } } }
總結
(1)這個程序需要在(服務器)tomcat下包含圖片的路徑,否則會報找不到路徑錯。我在寫二階段項目的時候是將用戶的頭像放在屬於用戶名下的文件夾下,但現在發現這個並不合理,因爲隨着用戶更換頭像,該文件夾下的圖片會越來越多,雖說也可以更新一次頭像將之前的頭像刪掉,用戶的頭像個人覺得應該以字節的存儲到數據庫較好些,讀取的時候在以字節數據轉換顯示。但是在工作中是怎麼用本人還沒有接觸過。在這裏就不作演示了。
(2)另一個弊端則是實體類多了一個屬性,如果說考略到性能方面的話,假如說把用戶的BufferedImage這個屬性幹掉的話,在excel編輯用戶信息類裏通過用戶的頭像路徑new 一個BufferedImage對象的方法去寫出圖片信息。後者這個方法我還沒有試過,有興趣的盆友可以試試。但是如果說考慮到性能優化的話在循環裏new 對象或者聲明臨時變量時不合理的。有興趣的盆友可以去了解一下java的性能優化。
最後說幾句
本人第一次寫博客,格式或許有些不對,希望大家指出,如對代碼有什麼疑問的可聯繫我郵箱,程序有需要改進的地方請大家指出。如果大家喜歡就幫忙推薦一下~~~網友的支持和吐槽等都是我寫博客的動力~~~