使用ApachePOI创建带图片的Excel
最近一个项目中使用到了列表数据导出为Excel表格的功能,项目中是使用了Apache的POI来生成Excel文件。
由于使用到的技术有一定的复杂度,我在此特别列出一些实现上的细节作为记录和备忘。
首先我们要用到的jar包是POI,我使用的是项目框架中的,版本可能有一些老,不过功能还算完整。
我先把代码贴一些出来,并解释一下:
1 package test; 2 3 import java.awt.image.BufferedImage; 4 import java.io.ByteArrayOutputStream; 5 import java.io.File; 6 import java.io.FileOutputStream; 7 import java.net.URL; 8 9 import javax.imageio.ImageIO; 10 import javax.swing.filechooser.FileSystemView; 11 12 import org.apache.poi.hssf.usermodel.HSSFClientAnchor; 13 import org.apache.poi.hssf.usermodel.HSSFPatriarch; 14 import org.apache.poi.hssf.usermodel.HSSFSheet; 15 import org.apache.poi.hssf.usermodel.HSSFWorkbook; 16 17 // 测试Apache POI 18 public class Main{ 19 public static void main(String[] args){ 20 // 第一步:拿到图片资源 21 BufferedImage bi = null; // 声明图片 22 // 1.从网络获取图片资源(下面的图片为百度首页图片) 23 //URL url = new URL("http://www.baidu.com/img/shouye_b5486898c692066bd2cbaeda86d74448.gif"); 24 //bi = ImageIO.read(url); 25 // 2.从物理存储设备获取图片资源(以下示例为从笔者桌面获取图片) 26 File f = new File(FileSystemView.getFileSystemView().getHomeDirectory() + "/baidu.gif"); 27 bi = ImageIO.read(f); 28 29 // 第二步:处理图片(很多时候失败原因就是没有处理图片) 30 ByteArrayOutputStream bos = new ByteArrayOutputStream(); 31 ImageIO.write(bi, "jpg", bos); 32 33 // 第三步:创建Excel并插入图片(这里就要使用POI了) 34 HSSFWorkbook wb = new HSSFWorkbook(); // 创建一个工作簿 35 HSSFSheet sheet = wb.createSheet("Sample"); // 创建一个床单-_- 36 HSSFPatriarch patriarch = sheet.createDrawingPatriarch(); // 创建一个用于画图的对象 37 // 以上部分为共用,表单Sample中所有图片的操作都应该有patriarch负责 38 HSSFClientAnchor anchor = new HSSFClientAnchor(0, 0, 0, 0, (short)0, 0, (short)1, 1); // 创建一个图片停靠信息对象 39 // anchor.setAnchorType(2); 设置这个属性是为哪个图片设置的,第一张图片不需要设置 40 patriarch.createPicture(anchor, wb.addPicture(bos.toByteArray(), HSSFWorkbook.PICTURE_TYPE_JPEG)); // 这一步就是按照上面的属性将图片插入到床单Sample中去 41 42 // 第四步:我们保存(或下载)生成的Excel(笔者保存到桌面) 43 File fo = new File(FileSystemView.getFileSystemView().getHomeDirectory() + "/sample.xls"); 44 FileOutputStream fos = null; 45 fos = new FileOutputStream(fo); 46 wb.write(fos); 47 fos.flush(); 48 fos.close(); 49 } 50 }
(上图异常未处理,因为最终我们需要将代码写得更规范,异常的处理也要更加好,上图只做参考)
我稍微解释一下,首先图片的获得一般为两种途径,网络和磁盘。我们拿到图片后的处理是必须的,因为大家可以看到,POI对图片的支持和解析并不是那么强大,我们需要使用ImageIO来提取图片的内容,并使用jpg格式写入缓冲来交给POI使用。
其次就是图片在Excel中的放置,顺便提一下Anchor的各个参数,为了方便大家理解,我先将代码运行结果贴出来给大家:
可以看到,在坐上角为0,0 右下角为1,1的网格中出现了图片,这解释了anchor的后四个参数,即图片左上角和右下角的坐标,至于为什么x坐标为short,不会不知道吧?
(所以我们没有在sheet里创建row和column来放置图片,因为在office套件里图片和文字并不是放置在一个平面的,可以这么理解:文字是放置在行、列中的格子里,而图片是沉浮在网格中的)
那么anchor的前四个参数是什么呢?其实Excel为了图片停靠地更加精细,将一个格子分成了1024x256个小格子,我们可以为图片设置它相对于左上角、右下角的横向和纵向偏移量(0-1023或0-255),看了下图大家就明白了:
(上图为anchor前四个参数设置为512,126,0,0)
(上图为anchor前四个参数设置为0,0,512,126)
(毋庸置疑,上图为anchor四个参数设置为512,126,512,126)
可以通过sheet.setColumWidth和row.setHeight设置列宽和行高。
贴上我的代码:
1 package test; 2 3 import java.awt.image.BufferedImage; 4 import java.io.ByteArrayOutputStream; 5 import java.io.File; 6 import java.io.FileNotFoundException; 7 import java.io.FileOutputStream; 8 import java.io.IOException; 9 import java.net.MalformedURLException; 10 import java.net.URL; 11 12 import javax.imageio.ImageIO; 13 import javax.swing.filechooser.FileSystemView; 14 15 import org.apache.poi.hssf.usermodel.HSSFClientAnchor; 16 import org.apache.poi.hssf.usermodel.HSSFPatriarch; 17 import org.apache.poi.hssf.usermodel.HSSFSheet; 18 import org.apache.poi.hssf.usermodel.HSSFWorkbook; 19 20 // 测试Apache POI 21 public class Main { 22 public static void main(String[] args) { 23 BufferedImage bi = null; 24 ByteArrayOutputStream bos = new ByteArrayOutputStream(); 25 HSSFWorkbook wb = new HSSFWorkbook(); 26 HSSFSheet sheet = wb.createSheet("Sample"); 27 HSSFPatriarch patriarch = sheet.createDrawingPatriarch(); 28 FileOutputStream fos = null; 29 30 try { 31 URL url = new URL("http://www.baidu.com/img/shouye_b5486898c692066bd2cbaeda86d74448.gif"); 32 bi = ImageIO.read(url); 33 34 //File f = new File(FileSystemView.getFileSystemView().getHomeDirectory() + "/baidu.gif"); 35 //bi = ImageIO.read(f); 36 37 ImageIO.write(bi, "jpg", bos); 38 HSSFClientAnchor anchor = new HSSFClientAnchor(512, 126, 512, 126, (short) 0, 39 0, (short) 1, 1); 40 // anchor.setAnchorType(2); 41 patriarch.createPicture(anchor,wb.addPicture(bos.toByteArray(), HSSFWorkbook.PICTURE_TYPE_JPEG)); 42 43 File fo = new File(FileSystemView.getFileSystemView() 44 .getHomeDirectory() + "/sample.xls"); 45 fos = new FileOutputStream(fo); 46 wb.write(fos); 47 fos.flush(); 48 fos.close(); 49 50 51 } catch (MalformedURLException e) { 52 // TODO Auto-generated catch block 53 e.printStackTrace(); 54 } catch (FileNotFoundException e) { 55 // TODO Auto-generated catch block 56 e.printStackTrace(); 57 } catch (IOException e) { 58 // TODO Auto-generated catch block 59 e.printStackTrace(); 60 } 61 } 62 }
注意:ByteArrayOutputStream与HSSFClientAnchor是一次性用品,需要在真正使用前声明,后释放(上图是一个不正规的示范,很明显,在多个图片后bos会溢出)。
anchorType从2开始,1不需要设置。
有关生成的xls从服务器下载到客户端,以后再讨论。
(最后编辑时间2013-03-27 13:46:00)