简介
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导出的工具类
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; } }(3)设置excel的类
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的性能优化。
最后说几句
本人第一次写博客,格式或许有些不对,希望大家指出,如对代码有什么疑问的可联系我邮箱,程序有需要改进的地方请大家指出。如果大家喜欢就帮忙推荐一下~~~网友的支持和吐槽等都是我写博客的动力~~~