本文说到的是用PHP-Java-Bridge技术实现JasperReport web报表的输出。

JasperReport(http://jasperforge.org/),是一个强大、灵活的报表生成工具,能够展示丰富的页面内容,并将之转换成PDF,HTML,或者XML格式。该库完全由Java写成,可以用于在各种Java应用程序,包括J2EE,Web应用程序中生成动态内容。

附带报表设计工具是iReport(免费的),该工具可以实现可视化报表设计,可以输出PDF,HTML,WORD的常用格式报表,保存后的文件为.jrxml后缀,需要Java环境才可以正常运行,PHP不能直接调用。

既然PHP不能直接调用,这就不得不借助于PHP-Java-Bridge技术。具体可以参考http://php-java-bridge.sourceforge.net/pjb/index.php

1、安装tomcat,如果是选择exe安装版,安装的时候会自动安装jre环境,如果是压缩版tomcat,需要另外安装java环境,配置也更繁琐,推荐用安装版的tomcat。

把tomcat的端口配置6000,默认的8080端口被占用,站点根目录为tomcat下面的webapps

2、下载php-java-bridge包,地址http://php-java-bridge.sourceforge.net/pjb/download.php,下载后解压,里面有一个JavaBridge.war的文件,将这个文件拷贝到tomcat的webapps,运行http://localhost:6000/JavaBridge/之后,会在webapps生成一个JavaBridge的目录。

3、安装ireport3.0(有更新的版本) 拷贝C:\Program Files\JasperSoft\iReport-3.0.0\lib 中的所有内容,拷贝到tomcat的webapps/JavaBridge/WEB-INF/lib/下,这些包需要能被JavaBridge找得到才行。

4、从生成的JavaBridge目录下拷贝java目录到PHP站点下(或者找到php.ini这个文件,将里面的allow_url_include参数改为on,直接引用JavaBridge下的java/java.inc)。下载报表文件http://www.rjohnson.id.au/download/jasper/test.jrxml放在PHP站点下。

然后在PHP站点下建立一个PHP文件

ireport.php(代码中涉及到端口的,需要根据个人情况更改)

View Code
  1 <?php
2
3 /**
4 * see if the java extension was loaded.
5 */
6 function checkJavaExtension()
7 {
8 if(!extension_loaded('java'))
9 {
10 $sapi_type = php_sapi_name();
11
12 //$port = (isset($_SERVER['SERVER_PORT']) && (($_SERVER['SERVER_PORT'])>1024)) ? $_SERVER['SERVER_PORT'] : '6000';
13 //echo $port;
14 $port = 6000;
15 if ($sapi_type == "cgi" || $sapi_type == "cgi-fcgi" || $sapi_type == "cli")
16 {
17 if(!(PHP_SHLIB_SUFFIX=="so" && @dl('java.so'))&&!(PHP_SHLIB_SUFFIX=="dll" && @dl('php_java.dll'))&&!(@include_once("java/Java.inc"))&&!(require_once("http://127.0.0.1:$port/JavaBridge/java/Java.inc")))
18 {
19 return "java extension not installed.";
20 }
21 }
22 else
23 {
24 if(!(@include_once("java/Java.inc")))
25 {
26
27 require_once("http://127.0.0.1:$port/JavaBridge/java/Java.inc");
28 }
29 }
30 }
31 if(!function_exists("java_get_server_name"))
32 {
33 return "The loaded java extension is not the PHP/Java Bridge";
34 }
35
36 return true;
37 }
38
39 /**
40 * convert a php value to a java one...
41 * @param string $value
42 * @param string $className
43 * @returns boolean success
44 */
45 function convertValue($value, $className)
46 {
47 // if we are a string, just use the normal conversion
48 // methods from the java extension...
49 try
50 {
51 if ($className == 'java.lang.String')
52 {
53 $temp = new Java('java.lang.String', $value);
54 return $temp;
55 }
56 else if ($className == 'java.lang.Boolean' ||
57 $className == 'java.lang.Integer' ||
58 $className == 'java.lang.Long' ||
59 $className == 'java.lang.Short' ||
60 $className == 'java.lang.Double' ||
61 $className == 'java.math.BigDecimal')
62 {
63 $temp = new Java($className, $value);
64 return $temp;
65 }
66 else if ($className == 'java.sql.Timestamp' ||
67 $className == 'java.sql.Time')
68 {
69 $temp = new Java($className);
70 $javaObject = $temp->valueOf($value);
71 return $javaObject;
72 }
73 }
74 catch (Exception $err)
75 {
76 echo ( 'unable to convert value, ' . $value .
77 ' could not be converted to ' . $className);
78 return false;
79 }
80
81 echo ( 'unable to convert value, class name '.$className.
82 ' not recognised');
83 return false;
84 }
85
86
87 checkJavaExtension();
88
89 $compileManager = new JavaClass("net.sf.jasperreports.engine.JasperCompileManager");
90 $report = $compileManager->compileReport(realpath("test.jrxml"));
91
92 $fillManager = new JavaClass("net.sf.jasperreports.engine.JasperFillManager");
93
94 $params = new Java("java.util.HashMap");
95 $params->put("text", "This is a test string");
96 $params->put("number", 3.00);
97 $params->put("date", convertValue("2007-12-31 0:0:0", "java.sql.Timestamp"));
98
99 $emptyDataSource = new Java("net.sf.jasperreports.engine.JREmptyDataSource");
100 $jasperPrint = $fillManager->fillReport($report, $params, $emptyDataSource);
101
102 $outputPath = realpath(".")."/"."output.pdf";
103
104 $exportManager = new JavaClass("net.sf.jasperreports.engine.JasperExportManager");
105 $exportManager->exportReportToPdfFile($jasperPrint, $outputPath);
106
107 header("Content-type: application/pdf");
108 readfile($outputPath);
109
110 unlink($outputPath);
111
112 ?>

5、访问PHP站点,http://localhost:8080/ireport.php,就可以输出PDF文档。

posted @ 2011-10-27 16:17 相随心 阅读(795) 评论(0) 编辑
摘要: 用现实生活中打比方:TCP就好比打电话,必须双发的手机连接之后才能通电话,拨打用户拨通之后,被拨打用户必须有一个接听的动作,必须确保双发都连接成功UDP就好比发短信,只需要输入对方手机号发送就OK了。TCP和UDP在概念上来说是这样的TCP:(Transmission Control Protocol,传输控制协议)是基于连接的协议,也就是说,在正式收发数据前,必须和对方建立可靠的连接。TCP协议能为应用程序提供可靠的通信连接,使一台计算机发出的字节流无差错地发往网络上的其他计算机,对可靠性要求高的数据通信系统往往使用TCP协议传输数据。UDP:(User Data Protocol,用户数据阅读全文
posted @ 2011-07-22 10:03 相随心 阅读(60) 评论(0) 编辑
摘要: 原则1 减少HTTP请求数构造请求、等待响应需要时间,因此请求数量越少越好。减少请求的总体思路就是合并资源,减少显示一个页面需要的文件数。1. Image Map通过设置<img>标签的usemap属性与使用<map>标签可以在一幅图片上切分出多个区域,指向不同的链接。比起使用多幅图片分别构造链接减少了请求数。2. CSS Sprite(CSS贴图整合/贴图拼合/贴图定位)通过设置元素的background-position样式做到。一般用于界面图标。典型的可以参考TinyMCE编辑器上方的那些小按钮。多个小图实质 是从一个统一的大图通过不同的偏移量裁剪而来,这样加载界阅读全文
posted @ 2011-07-20 10:34 相随心 阅读(152) 评论(0) 编辑

实际应用当初将数据表格导出为Excel很是常见,当然从后台数据处理后当初到Excel最为常见,但是有的时候总是显得不是很方便。

下面就是我最近用到的一个方法,当然也是从网上学习到的(表示感谢下,呵呵),在这里想和大家分享下,希望能帮助到一些朋友

1、Web页面中不管用什么方法,不管是Asp.net中的GridView还是Ajax取数据构造,最终呈现在页面中的数据列表,基本上我想都是Table形势的,本人用到是flexigrid生产的数据列表,分析其结构为列头和数据不在一个Table中,分别在flexigrid_head(只有列头)和flexigrid_dotNetFlexGrid1(只有数据Ttody)两个个Table中。

2、最后通过页面中的按钮事件调用即可 getXlsFromTbl('flexigrid_head', 'flexigrid_dotNetFlexGrid1', null, "合同列表");

3、具体JS代码如下

function getXlsFromTbl(intTheadID, inTblId, inWindow, fileName) {

    try {
        var allStr = "";
        var curStr = "";
        if (inTblId != null && inTblId != "" && inTblId != "null") {
            curStr = getTblData(intTheadID, inTblId, inWindow);
        }
        if (curStr != null) {
            allStr += curStr;
        }
        else {
            alert("你要导出的表不存在!");
            return;
        }
        var fileName = getExcelFileName(fileName);
        doFileExport(fileName, allStr);
    }

    catch (e) {
        alert("导出发生异常:" + e.name + "->" + e.description + "!");
    }
}


//填充数据 inTblHead表示列头所在Table的ID,inTbl表示数据所在Table的ID,inWindow表示两个Table所在区域

//说明下:如果数据和列头在一个Table中更好,只需对下面的代码稍微改变下(橙色部分可以去掉,当然inTblHead这个参数就无效了)
function getTblData(inTblHead, inTbl, inWindow) {

    var rows = 0;
    var tblDocument = document;
    if (!!inWindow && inWindow != "") {
        if (!document.all(inWindow)) {
            return null;
        }
        else {
            tblDocument = eval(inWindow).document;
        }
    }

    var curTblHead = tblDocument.getElementById(inTblHead);
    var curTbl = tblDocument.getElementById(inTbl);
    var outStr = "";
    if (curTblHead != null) {//表头
        for (var i = 0; i < curTblHead.rows[0].cells.length; i++) {
            if (i == 0 && rows > 0) {
                outStr += " \t";
                rows -= 1;
            }
            outStr += curTblHead.rows[0].cells[i].innerText.toString() + "\t";
            if (curTblHead.rows[0].cells[i].colSpan > 1) {
                for (var k = 0; k < curTblHead.rows[j].cells[i].colSpan - 1; k++) {
                    outStr += " \t";
                }
            }
            if (i == 0) {
                if (rows == 0 && curTblHead.rows[0].cells[i].rowSpan > 1) {
                    rows = curTblHead.rows[0].cells[i].rowSpan - 1;
                }
            }
        }
        outStr += "\r\n";
    }

    if (curTbl != null) { //表数据行
        for (var j = 0; j < curTbl.rows.length; j++) {
            for (var i = 0; i < curTbl.rows[j].cells.length; i++) {
                if (i == 0 && rows > 0) {
                    outStr += " \t";
                    rows -= 1;
                }
                outStr += curTbl.rows[j].cells[i].innerText.toString() + "\t";
                if (curTbl.rows[j].cells[i].colSpan > 1) {
                    for (var k = 0; k < curTbl.rows[j].cells[i].colSpan - 1; k++) {
                        outStr += " \t";
                    }
                }
                if (i == 0) {
                    if (rows == 0 && curTbl.rows[j].cells[i].rowSpan > 1) {
                        rows = curTbl.rows[j].cells[i].rowSpan - 1;
                    }
                }
            }
            outStr += "\r\n";
        }
    }
    else {
        outStr = null;
        alert(inTbl + "不存在!");
    }
    return outStr;
}



//设置导出文件名
function getExcelFileName(myName) {
    var d = new Date();
    var curYear = d.getYear();
    var curMonth = "" + (d.getMonth() + 1);
    var curDate = "" + d.getDate();
    var curHour = "" + d.getHours();
    var curMinute = "" + d.getMinutes();
    var curSecond = "" + d.getSeconds();
    if (curMonth.length == 1) {
        curMonth = "0" + curMonth;
    }
    if (curDate.length == 1) {
        curDate = "0" + curDate;
    }
    if (curHour.length == 1) {
        curHour = "0" + curHour;
    }
    if (curMinute.length == 1) {
        curMinute = "0" + curMinute;
    }
    if (curSecond.length == 1) {
        curSecond = "0" + curSecond;
    }
    var fileName = myName + "_" + curYear + curMonth + curDate + "_"
 + curHour + curMinute + curSecond + ".csv";
    //alert(fileName);  
    return fileName;

}


//导出
function doFileExport(inName, inStr) {
    var xlsWin = null;
    if (!!document.all("glbHideFrm")) {
        xlsWin = glbHideFrm;
    }
    else {
        var width = 6;
        var height = 4;
        var openPara = "left=" + (window.screen.width / 2 - width / 2)
 + ",top=" + (window.screen.height / 2 - height / 2)
 + ",scrollbars=no,width=" + width + ",height=" + height;
        xlsWin = window.open("", "_blank", openPara);

    }
    xlsWin.document.write(inStr);
    xlsWin.document.close();
    xlsWin.document.execCommand('Saveas', true, inName);
    xlsWin.close();
}
posted @ 2011-05-14 12:40 相随心 阅读(1123) 评论(6) 编辑

在一些常见的管理软件,例如HR软件,经常需要展示一个集团或者公司的组织架构情况。

此控件为SilverLight 4开发的一个控件,采用XML作为数据源,包含缩略图、缩放、打印、全部展开和收缩、显示负责人照片等功能

效果图如下:

posted @ 2011-04-13 17:11 相随心 阅读(747) 评论(16) 编辑