当前位置: 代码迷 >> 报表 >> JAVA将Excel中的表格导出为图片格式(二)实现思路
  详细解决方案

JAVA将Excel中的表格导出为图片格式(二)实现思路

热度:493   发布时间:2016-04-29 01:52:39.0
JAVA将Excel中的报表导出为图片格式(二)实现思路

接上文,一封类似于下方设计的Excel报表,如何将它指定的区域导出为样式一模一样的JPG图片呢?

要实现这个功能没有现成的解决方案,谷歌度娘了好久也没有,最终自己想了几条思路:

 

思路1:将报表中的背景、边框等截图下来作为模型图片,需要定时更新的数据通过JDBC读取Oracle中的数据绘制到模型图片上

否定原因:不具可行性,所有数据的坐标点需要有规则方便绘图时循环绘制,工程量巨大,耦合性巨高,表格数据牵一发而动全身,并且不利于扩展。

 

思路2:不需要报表原型,生成Excel报表后,使用jxl或者poi一个单元一个单元读取报表内所有单元格,包括单元格的数据和格式,边框、宽度、高度、字体前景色、背景色都要读取出来,然后通过JAVA绘图,最终生成JPG格式的报表。

否定原因:具有一定的可行性,但是代码量巨大,读取和绘制费时费力,但是有一定的优点,可以在不忙的时间里编写一个通用的程序,一劳永逸的解决所有导出问题。

 

思路3:比较奇葩,属于博主突发奇想的招式,通过WPS或者Office打开Excel,编写Robot机器人将鼠标移动到两个指定坐标所覆盖指定区域,Robot模拟敲击Ctrl+C,接着将剪贴板上的数据绘图,导出到JPG文件。

最终实现了思路3,有一定的好处也有弊端,好处是简单便捷,可操作性高,代码量低,扩展性强,换其他报表只需要提供另一组坐标参数即可

弊端是完全牺牲了JAVA的跨平台性,甚至如果运行在分辨率较低的服务器上,有可能导致复制操作无法执行

另一个弊端是线程变得不安全了,如果服务器负载较重,无法正确预计Office打开报表的时间,也有可能导致复制操作无法执行

或者多个生成报表截图的任务同时执行时,显然使用Robot会导致冲突。

 

下面提供思路3的实现代码,以后有时间会使用思路2写一个通用的程序

package com.newflypig.excel;import java.awt.Graphics;import java.awt.Image;import java.awt.Robot;import java.awt.Toolkit;import java.awt.datatransfer.DataFlavor;import java.awt.datatransfer.Transferable;import java.awt.event.InputEvent;import java.awt.event.KeyEvent;import java.awt.image.BufferedImage;import java.io.File;import java.text.SimpleDateFormat;import java.util.Date;import javax.imageio.ImageIO;public class OpenExcelDemo {    public static void main(String[] args) throws Exception {        openExcel("d:\\新增积分月报表.xlsx");        copyRectByPix(37, 207, 1215, 665); //给定两个坐标点的数据,圈定截图范围        createImageFileFromClip("d:/" + getTimeStr() + ".jpg");        closeExcel((int)Toolkit.getDefaultToolkit().getScreenSize().getWidth() - 15, 12);    //需要模拟关闭事件,将Excel关闭,以便下次能正确打开报表        }    private static void closeExcel(int i, int j) throws Exception {        Robot robot = new Robot();        robot.delay(500);        robot.mouseMove(i,j);        robot.delay(500);        robot.mousePress(InputEvent.BUTTON1_MASK);        robot.delay(500);        robot.mouseRelease(InputEvent.BUTTON1_MASK);        robot.delay(500);        robot.keyPress(KeyEvent.VK_ENTER);    }    public static void openExcel(String dir) throws Exception {        Runtime.getRuntime().exec("cmd /k " + dir + "");    }    public static void copyRectByPix(int fromX, int fromY, int toX, int toY)            throws Exception {        Robot robot = new Robot();        robot.delay(3000); // 延时3000毫秒        robot.mouseMove(fromX, fromY);        robot.delay(500);        robot.mousePress(InputEvent.BUTTON1_MASK);        robot.delay(500);        robot.mouseMove(toX, toY);        robot.delay(500);        robot.mouseRelease(InputEvent.BUTTON1_MASK);        robot.setAutoDelay(200);        robot.keyPress(KeyEvent.VK_CONTROL);        robot.keyPress(KeyEvent.VK_C);        robot.keyRelease(KeyEvent.VK_CONTROL);        robot.keyRelease(KeyEvent.VK_C);    }    public static void createImageFileFromClip(String dir) throws Exception {        Transferable t = Toolkit.getDefaultToolkit().getSystemClipboard()                .getContents(null);        if (null != t && t.isDataFlavorSupported(DataFlavor.imageFlavor)) {            Image image = (Image) t.getTransferData(DataFlavor.imageFlavor);            savePic(image, dir);        }    }    public static String savePic(Image iamge, String dir) throws Exception {        int w = iamge.getWidth(null);        int h = iamge.getHeight(null);        // 首先创建一个BufferedImage变量,因为ImageIO写图片用到了BufferedImage变量。        BufferedImage bi = new BufferedImage(w, h, BufferedImage.TYPE_3BYTE_BGR);        // 再创建一个Graphics变量,用来画出来要保持的图片,及上面传递过来的Image变量        Graphics g = bi.getGraphics();        g.drawImage(iamge, 0, 0, null);        // 将BufferedImage变量写入文件中。        ImageIO.write(bi, "jpg", new File(dir));        return dir;    }    public static String getTimeStr() {        String time = new SimpleDateFormat("yyyyMMddHHmmss").format(new Date());        return time;    }}

 

2楼╰︶赖床专业户こ
html和execl可以想换转换的,你改下尾缀就可以。,JAVA我之前看到篇文章,可以直接使用html代码转换成图片;其中:http://my.oschina.net/longniao/blog/84236,,,ps:, StringBuffer sbf=new StringBuffer ();, sbf.append(quot;, lt;htmlgt;,lt;headgt;,lt;titlegt;测试lt;/titlegt;,lt;/headgt;,lt;bodygt;,lt;tablegt;,lt;trgt;,lt;tdgt;,1111,lt;/tdgt;,lt;tdgt;,22222,lt;/tdgt;,lt;/trgt;,lt;/tablegt;,lt;/bodygt;,lt;/htmlgt;,quot;);,,转成图片:,HtmlImageGenerator imageGenerator = new HtmlImageGenerator();,imageGenerator.loadHtml(sbf.toString());,imageGenerator.getBufferedImage();,imageGenerator.saveAsImage(quot;d:/hello-world.pngquot;);,这样会在d盘生成图片,下载execl:,out.write(sbf.toString());,response.setContentType(quot;application/vnd.ms-excel;charset=utf-8quot;); ,String fileName = now; ,fileName = new String(fileName.getBytes(quot;GB2312quot;),quot;ISO8859-1quot;); ,response.setHeader(quot;Content-dispositionquot;,quot;attachment; filename=\quot;quot; + fileName + quot;.xls\quot;quot;);,,,如有问题,请提出
Re: 丁丁#183;中国电信
@╰︶赖床专业户こ,问题是excel不用生成啊,本地由另一套程序通过poi已经生成好excel了,再将excel用html展现?
Re: 丁丁#183;中国电信
@╰︶赖床专业户こ,再说,HTML转化成图片貌似不可能太丰富吧,CSS渲染,JS的DOM动态生成,等等,每个浏览器解析HTML都有差异,怎么保证用JAVA将HTML绘图就能正确呢?
Re: 丁丁#183;中国电信
@╰︶赖床专业户こ,Excel的结构挺复杂的,并不是纯粹的td tr,有合并的单元格,有函数计算的值,有单元格边框、字体、背景、前景等各种格式,现在有可以将服务器本地的excel文件用浏览器完美展现的技术吗。
1楼╰︶赖床专业户こ
html--gt;转成图片;, html--gt;转成execl;,,公用html代码,你把这部分写在后台拼接。,先用java把html搞成图片保存,再用html设置response.setContentType(quot;application/vnd.ms-excel;charset=utf-8quot;); ,这个感觉应该可以的
Re: 丁丁#183;中国电信
@╰︶赖床专业户こ,跟HTML无关,有可能运行在static void main中,不一定是web应用,有可能是j2se,仅仅是将本地excel指定区域导出为图片,保留完全的报表格式。即使是web应用,你说的方式我也没太明白,能不能详细点。
  相关解决方案