??xml version="1.0" encoding="utf-8" standalone="yes"?>
Since the source code is not available directly from the Pentato website, I had no choice but to go thru some posts on the Pentaho forum one by one. It didn't take me much effor before I found the relevant post, thx god:) The source code of Kettle now is maintained in SVN of JavaForge, and anybody "can get the latest(subversion trunk) code changes with on this URL: http://svn.javaforge.com/svn/Kettle/trunk", the username is "anonymous" and password is "anon".
Besides, I had to download a SVN tool. I am using TortoiseSVN in my company, and the ux satisfied me, so I chose it again.
It taked about 30 minutes to check out all the source code (still very fast I think, my bandwidth is 2M).
When it done, I imported it as a general project into eclipse, and one thing surprised me a little bit was that, I didn't have to compile the source code or import some jars even than execute a Ant target manually as I built the source code of Spring before. Hah, Kettle is developed by using eclipse?! (you can find some eclipse project files in the trunk).
Anyway, the work was going on smoothly, no more than 40 minutes. Now I can debug the Kettle, and from my experience, in some scenarios Kettle doesn't work in good performace than I expect, and even sometimes it runs into some bugs when I do the multitudinous insert or update operations. Here I get the opportunity to look into the code and figure out the problem.
Keep moving forward...
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.Statement;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Combo;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.TabFolder;
import org.eclipse.swt.widgets.Table;
import org.eclipse.swt.widgets.TableColumn;
import org.eclipse.swt.widgets.TableItem;
import org.eclipse.swt.widgets.Text;
import com.swtdesigner.SWTResourceManager;
import org.eclipse.swt.widgets.TabItem;
public class tanzhang {
/**
* Launch the application
* @param args
*/
private static Table table;
private static TableItem newItemTableItem;
public static void main(String[] args) {
final Display display = Display.getDefault();
final Shell shell = new Shell();
shell.setImage(SWTResourceManager.getImage(tanzhang.class, "/org/eclipse/ui/internal/forms/widgets/progress.gif"));
shell.setSize(774, 514);
shell.setText("宣城供电局消弧U圈台帐");
............
............
............
final Combo combo_1 = new Combo(composite, SWT.READ_ONLY);
combo_1.addSelectionListener(new SelectionAdapter() {
public void widgetSelected(SelectionEvent arg0) {
String str=combo_1.getText();
try{
String dbUrl = "jdbc:odbc:test";
Class.forName("sun.jdbc.odbc.JdbcOdbcDriver");
Connection conn = DriverManager.getConnection(dbUrl, "", "");
Statement stmt=conn.createStatement();
String sql="SELECT * from test where 单元名称="+str;
ResultSet rs=stmt.executeQuery(sql);
if(rs.next()){
for(int i=0;i<=4;i++){
newItemTableItem.setText(i,rs.getString(i+1));
}
rs.close();
stmt.close();
conn.close();
}
}catch(Exception e){}
}
});
............
............
............
table = new Table(composite_1, SWT.VIRTUAL | SWT.FULL_SELECTION | SWT.BORDER | SWT.HIDE_SELECTION);
table.setLinesVisible(true);
table.setHeaderVisible(true);
table.setBounds(0, 0, 678, 80);
............
............
............
刚开始是用final修饰table和newItemTableItemQ但是“newItemTableItem.setText(i,rs.getString(i+1));”这行(代码中兰色那句)会报错,~译器提C“无法解析newItemTableItem”。我的第一反应是监听器的位|放得不寏V翻了一下书Q说SWT/JFace事g代码中要讉KcM变量有三U方法:Q?Q加finalQ(2Q将变量变ؓcȝ实例变量Q(3Q将事g代码写成命名内部c,然后通过构造函数的参数来传入?br /> 想了惛_象只有第三种Ҏ值得试试Q但是后来想hnewItemTableItem是个对象Q传入以后却不知道怎么转换cdQ呆?..
最后做了个新的E序试了试,在新E序里是成功的,是要把newItemTableItem在main函数外申明其为private staticQ但是在旧的E序中,~译器是通过了,但是q行q接数据库查询的时候,出现“Fatal Exception...”的错误Q当时一下就蒙掉了!Q完全一LQ怎么会不成功?br /> 百般无奈以后Q?---当然之前肯定是深思熟?---l于脑v中闪Z传说中的“灵感”!于是马上把table也定义ؓprivate static......OKQ 胜利L来得那么H然Q那瞬间的感觉就?0分钟打进的金?..
当然到现在,我还没找到确切的原因。只能用自己的话ȝ一下:Q?Q匿名内部类中的Ҏ是不能访问其他方法中定义的变量的Q包括实例对象)Q要讉K必须在类中将其定义ؓstaticcd。(2QTableItem是Table的子控gQ要定义TableItem为static也要同时把Table定义为staticcd?br />
l自׃个Q务:研究JAVA的内部类机制Q研ISWT中父子控件关pȝ机制Q?br />
看看《Thinking in JAVA》或怼是个不错的选择Q当然还有?a border="0">The Definitive Guide to SWT and JFace》?/p>
本系列的上一期文章(请参?参考资?/a> 中的链接Q,我们介绍?Ajax 应用E序Q考察了推?Ajax 应用E序的基本概c其中的核心是很多您可能已经了解的技术:JavaScript、HTML ?XHTML、一点动?HTML 以及 DOMQ文档对象模型)。本文将攑֤其中的一点,把目光放到具体的 Ajax l节上?/p>
本文中,您将开始接触最基本和基性的有关 Ajax 的全部对象和~程ҎQXMLHttpRequest 对象。该对象实际上仅仅是一个跨所?Ajax 应用E序的公qE,您可能已l预料到Q只有彻底理解该对象才能充分发挥~程的潜力。事实上Q有时您会发玎ͼ要正地使用 XMLHttpRequestQ显然不?使用 XMLHttpRequest。这到底是怎么回事呢? 在深入研I代码之前首先看看最q的观点 —?一定要十分清楚 Web 2.0 q个概念。听?Web 2.0 q个词的时候,应该首先问一?“Web 1.0 是什么??虽然很少听h提到 Web 1.0Q实际上它指的就是具有完全不同的h和响应模型的传统 Web。比如,?Amazon.com |站上点M个按钮或者输入搜索项。就会对服务器发送一个请求,然后响应再返回到览器。该h不仅仅是图书和书目列表,而是另一个完整的 HTML 面。因此当 Web 览器用新的 HTML 面重绘Ӟ可能会看到闪烁或抖动。事实上Q通过看到的每个新面可以清晰地看到请求和响应?/p>
Web 2.0Q在很大E度上)消除了这U看得见的往复交互。比如访?Google Maps ?Flickr q样的站点(到这些支?Web 2.0 ?Ajax 站点的链接请参阅 参考资?/a>Q。比如在 Google Maps 上,您可以拖动地图,攑֤和羃,只有很少的重l操作。当然这里仍然有h和响应,只不q都藏到了幕后。作为用P体验更加舒适,感觉很像桌面应用E序。这U新的感受和范型是当有人提?Web 2.0 时您所体会到的?/p>
需要关心的是如何ɘq些新的交互成ؓ可能。显Ӟ仍然需要发求和接收响应Q但正是针对每次h/响应交互?HTML 重绘造成了缓慢、笨拙的 Web 交互的感受。因此很清楚Q我们需要一U方法发送的h和接收的响应?包含需要的数据而不是整?HTML 面。惟一需要获得整个新 HTML 面的时候就是希望用L?新页面的时候?/p>
但多C互都是在已有面上增加细节、修改主体文本或者覆盖原有数据。这些情况下QAjax ?Web 2.0 Ҏ允许在不 更新整个 HTML 面的情况下发送和接收数据。对于那些经怸|的人,q种能力可以让您的应用程序感觉更快、响应更及时Q让他们不时地光您的网站?/p>
![]() ![]() |
![]()
|
要真正实现这U绚丽的奇迹Q必非常熟悉一?JavaScript 对象Q即 XMLHttpRequest。这个小的对象实际上已l在几种览器中存在一D|间了Q它是本专栏今后几个月中要介l的 Web 2.0、Ajax 和大部分其他内容的核心。ؓ了让您快速地大体了解它,下面l出要用于该对象的很少的几?Ҏ和属性?/p>
如果不了解这些(或者其中的M 一个)Q您也不用担心,后面几篇文章中我们将介绍每个Ҏ和属性。现在应?了解的是Q明用 XMLHttpRequest 做什么。要注意q些Ҏ和属性都与发送请求及处理响应有关。事实上Q如果看?XMLHttpRequest 的所有方法和属性,׃发现它们?与非常简单的h/响应模型有关。显Ӟ我们不会遇到特别新的 GUI 对象或者创建用户交互的某种极秘的方法,我们用非常简单的h和非常简单的响应。听hg没有多少吸引力,但是用好该对象可以彻底改变您的应用程序?/p>
首先需要创Z个新变量q赋l它一?XMLHttpRequest 对象实例。这?JavaScript 中很单,只要对该对象名?new 关键字即可,?清单 1 所C?/p>
清单 1. 创徏新的 XMLHttpRequest 对象
<script language="javascript" type="text/javascript"> var request = new XMLHttpRequest(); </script> |
不难吧?CQJavaScript 不要求指定变量类型,因此不需要像 清单 2 那样做(?Java 语言中可能需要这P?/p>
清单 2. 创徏 XMLHttpRequest ?Java 伪代?/a>
XMLHttpRequest request = new XMLHttpRequest(); |
因此?JavaScript 中用 var 创徏一个变量,l它一个名字(?“request”)Q然后赋l它一个新?XMLHttpRequest 实例。此后就可以在函C使用该对象了?/p>
在实际上各种事情都可能出错,而上面的代码没有提供M错误处理。较好的办法是创对象Qƈ在出现问题时优雅地退出。比如,M较早的浏览器Q不论您是否怿Q仍然有人在使用老版本的 Netscape NavigatorQ都不支?XMLHttpRequestQ您需要让q些用户知道有些地方Z问题?a >清单 3 说明如何创徏该对象,以便在出现问题的时候发?JavaScript 警告?/p>
清单 3. 创徏h错误处理能力?XMLHttpRequest
<script language="javascript" type="text/javascript"> var request = false; try { request = new XMLHttpRequest(); } catch (failed) { request = false; } if (!request) alert("Error initializing XMLHttpRequest!"); </script> |
一定要理解q些步骤Q?/p>
代码非常单,对大多数 JavaScript ?Web 开发h员来_真正理解它要比读写代码花更长的时间。现在已l得C一D带有错误检查的 XMLHttpRequest 对象创徏代码Q还可以告诉您哪儿出了问题?/p>
看v来似乎一切良好,臛_在用 Internet Explorer 试验q些代码之前是这L。如果这栯验的话,׃看到 ?1 所C的p糕情Ş?/p>
?1. Internet Explorer 报告错误
昄有什么地方不对劲Q?Internet Explorer 很难说是一U过时的览器,因ؓ全世界有 70% 在?Internet Explorer。换句话_如果不支?Microsoft ?Internet Explorer ׃会受?Web 世界的欢q!因此我们需要采用不同的Ҏ处理 Microsoft 览器?/p>
l验证发?Microsoft 支持 AjaxQ但是其 XMLHttpRequest 版本有不同的U呼。事实上Q它其UCؓ几种 不同的东ѝ如果用较新版本的 Internet ExplorerQ则需要用对?Msxml2.XMLHTTPQ而较老版本的 Internet Explorer 则?Microsoft.XMLHTTP。我们需要支持这两种对象cdQ同时还要支持非 Microsoft 览器)。请看看 清单 4Q它在前qC码的基础上增加了?Microsoft 的支持?/p>
清单 4. 增加?Microsoft 览器的支持
<script language="javascript" type="text/javascript"> var request = false; try { request = new XMLHttpRequest(); } catch (trymicrosoft) { try { request = new ActiveXObject("Msxml2.XMLHTTP"); } catch (othermicrosoft) { try { request = new ActiveXObject("Microsoft.XMLHTTP"); } catch (failed) { request = false; } } } if (!request) alert("Error initializing XMLHttpRequest!"); </script> |
很容易被q些花括可住了眼睛Q因此下面分别介l每一步:
q样修改代码之后再?Internet Explorer 试验Q就应该看到已经创徏的表单(没有错误消息Q。我实验的结果如 ?2 所C?/p>
?2. Internet Explorer 正常工作
再看一看清?1?a >3 ?4Q注意,所有这些代码都直接嵌套?script 标记中。像q种不放到方法或函数体中?JavaScript 代码UCؓ静?JavaScript。就是说代码是在面昄l用户之前的某个时候运行。(虽然Ҏ规范不能完全_?知道q些代码何时q行Ҏ览器有什么媄响,但是可以保证q些代码在用戯够与面交互之前q行。)q也是多?Ajax E序员创?XMLHttpRequest 对象的一般方式?/p>
是_也可以像 清单 5 那样这些代码放在一个方法中?/p>
清单 5. ?XMLHttpRequest 创徏代码Ud到方法中
<script language="javascript" type="text/javascript"> var request; function createRequest() { try { request = new XMLHttpRequest(); } catch (trymicrosoft) { try { request = new ActiveXObject("Msxml2.XMLHTTP"); } catch (othermicrosoft) { try { request = new ActiveXObject("Microsoft.XMLHTTP"); } catch (failed) { request = false; } } } if (!request) alert("Error initializing XMLHttpRequest!"); } </script> |
如果按照q种方式~写代码Q那么在处理 Ajax 之前需要调用该Ҏ。因此还需?清单 6 q样的代码?/p>
清单 6. 使用 XMLHttpRequest 的创建方?/a>
<script language="javascript" type="text/javascript"> var request; function createRequest() { try { request = new XMLHttpRequest(); } catch (trymicrosoft) { try { request = new ActiveXObject("Msxml2.XMLHTTP"); } catch (othermicrosoft) { try { request = new ActiveXObject("Microsoft.XMLHTTP"); } catch (failed) { request = false; } } } if (!request) alert("Error initializing XMLHttpRequest!"); } function getCustomerInfo() { createRequest(); // Do something with the request variable } </script> |
此代码惟一的问题是推迟了错误通知Q这也是多数 Ajax E序员不采用q一Ҏ的原因。假设一个复杂的表单?10 ?15 个字Dc选择框等Q当用户在第 14 个字D(按照表单序从上CQ输入文本时要激zL?Ajax 代码。这时候运?getCustomerInfo() 试创徏一?XMLHttpRequest 对象Q但Q对于本例来_p|了。然后向用户昄一条警告,明确地告诉他们不能用该应用E序。但用户已经p了很多时间在表单中输入数据!q是非常令h讨厌的,而讨厌显然不会吸引用户再ơ访问您的网站?/p>
如果使用静?JavaScriptQ用户在点击面的时候很快就会看到错误信息。这样也很烦人,是不是?可能令用户错误地认ؓ您的 Web 应用E序不能在他的浏览器上运行。不q,当然要比他们p?10 分钟输入信息之后再显C同L错误要好。因此,我徏议编写静态的代码Q让用户可能早地发现问题?/p>
![]() ![]() |
![]()
|
得到h对象之后可以进入请?响应循环了。记住,XMLHttpRequest 惟一的目的是让您发送请求和接收响应。其他一切都?JavaScript、CSS 或页面中其他代码的工作:改变用户界面、切换图像、解释服务器q回的数据。准备好 XMLHttpRequest 之后Q就可以向服务器发送请求了?/p>
Ajax 采用一U沙安全模型。因此,Ajax 代码Q具体来说就?XMLHttpRequest 对象Q只能对所在的同一个域发送请求。以后的文章中将q一步介l安全和 AjaxQ现在只要知道在本地机器上运行的代码只能Ҏ地机器上的服务器端脚本发送请求。如果让 Ajax 代码?www.breakneckpizza.com 上运行,则必?www.breakneck.com 中运行的脚本发送请求?/p>
首先要确定连接的服务器的 URL。这q不?Ajax 的特D要求,但仍然是建立q接所必需的,昄现在您应该知道如何构?URL 了。多数应用程序中都会l合一些静态数据和用户处理的表单中的数据来构造该 URL。比如,清单 7 中的 JavaScript 代码获取电话L字段的值ƈ用其构?URL?/p>
清单 7. 建立h URL
<script language="javascript" type="text/javascript"> var request = false; try { request = new XMLHttpRequest(); } catch (trymicrosoft) { try { request = new ActiveXObject("Msxml2.XMLHTTP"); } catch (othermicrosoft) { try { request = new ActiveXObject("Microsoft.XMLHTTP"); } catch (failed) { request = false; } } } if (!request) alert("Error initializing XMLHttpRequest!"); function getCustomerInfo() { var phone = document.getElementById("phone").value; var url = "/cgi-local/lookupCustomer.php?phone=" + escape(phone); } </script> |
q里没有难懂的地斏V首先,代码创徏了一个新变量 phoneQƈ?ID ?“phone?的表单字D늚Dl它?a >清单 8 展示了这个表单的 XHTMLQ其中可以看?phone 字段及其 id 属性?/p>
清单 8. Break Neck Pizza 表单
<body> <p><img src="breakneck-logo_4c.gif" alt="Break Neck Pizza" /></p> <form action="POST"> <p>Enter your phone number: <input type="text" size="14" name="phone" id="phone" onChange="getCustomerInfo();" /> </p> <p>Your order will be delivered to:</p> <div id="address"></div> <p>Type your order in here:</p> <p><textarea name="order" rows="6" cols="50" id="order"></textarea></p> <p><input type="submit" value="Order Pizza" id="submit" /></p> </form> </body> |
q要注意Q当用户输入电话L或者改变电话号码时Q将触发 清单 8 所C的 getCustomerInfo() Ҏ。该Ҏ取得电话Lq构造存储在 url 变量中的 URL 字符丌Ӏ记住,׃ Ajax 代码是沙型的,因而只能连接到同一个域Q实际上 URL 中不需要域名。该例中的脚本名?/cgi-local/lookupCustomer.php。最后,电话L作ؓ GET 参数附加到该脚本中:"phone=" + escape(phone)?/p>
如果以前没用见过 escape() ҎQ它用于转义不能用明文正发送的M字符。比如,电话L中的I格被转换成字W?%20Q从而能够在 URL 中传递这些字W?/p>
可以Ҏ需要添加Q意多个参数。比如,如果需要增加另一个参敎ͼ只需要将光加到 URL 中ƈ?“与”(&Q字W分开 [W一个参数用问号Q?Q和脚本名分开]?/p>
![]() |
|
有了要连接的 URL 后就可以配置h了。可以用 XMLHttpRequest 对象?open() Ҏ来完成。该Ҏ有五个参敎ͼ
通常使用其中的前三个参数。事实上Q即佉K要异步连接,也应该指定第三个参数?“true”。这是默认|但坚持明指定请求是异步的还是同步的更容易理解?/p>
这些结合v来,通常会得?清单 9 所C的一行代码?/p>
清单 9. 打开h
function getCustomerInfo() { var phone = document.getElementById("phone").value; var url = "/cgi-local/lookupCustomer.php?phone=" + escape(phone); request.open("GET", url, true); } |
一旦设|好?URLQ其他就单了。多数请求?GET 够了(后面的文章中看到需要?POST 的情况)Q再加上 URLQ这是使用 open() Ҏ需要的全部内容了?/p>
本系列的后面一文章中Q我用很多旉~写和用异步代码,但是您应该明白ؓ什?open() 的最后一个参数这么重要。在一般的h/响应模型中,比如 Web 1.0Q客hQ浏览器或者本地机器上q行的代码)向服务器发出h。该h是同步的Q换句话_客户机等待服务器的响应。当客户机等待的时候,臛_会用某种形式通知您在{待Q?/p>
q正?Web 应用E序让h感到W拙或缓慢的原因 —?~Z真正的交互性。按下按钮时Q应用程序实际上变得不能使用Q直到刚刚触发的h得到响应。如果请求需要大量服务器处理Q那么等待的旉可能很长Q至在q个多处理器、DSL 没有{待的世界中是如此)?/p>
而异步请求不 {待服务器响应。发送请求后应用E序l箋q行。用户仍然可以在 Web 表单中输入数据,甚至d表单。没有旋转的皮球或者沙漏,应用E序也没有明昄ȝ。服务器悄悄地响应请求,完成后告诉原来的h者工作已l结束(具体的办法很快就会看刎ͼ。结果是Q应用程序感觉不 那么q钝或者缓慢,而是响应q速、交互性强Q感觉快多了。这仅仅?Web 2.0 的一部分Q但它是很重要的一部分。所有老套?GUI lg?Web 设计范型都不能克服缓慢、同步的h/响应模型?/p>
一旦用 open() 配置好之后,可以发送请求了。幸q的是,发送请求的Ҏ的名U要?open() 适当Q它是 send()?/p>
send() 只有一个参敎ͼ是要发送的内容。但是在考虑q个Ҏ之前Q回想一下前面已l通过 URL 本n发送过数据了:
var url = "/cgi-local/lookupCustomer.php?phone=" + escape(phone); |
虽然可以使用 send() 发送数据,但也能通过 URL 本n发送数据。事实上QGET hQ在典型?Ajax 应用中大U占 80%Q中Q用 URL 发送数据要Ҏ得多。如果需要发送安全信息或 XMLQ可能要考虑使用 send() 发送内容(本系列的后箋文章中将讨论安全数据?XML 消息Q。如果不需要通过 send() 传递数据,则只要传?null 作ؓ该方法的参数卛_。因此您会发现在本文中的例子中只需要这样发送请求(参见 清单 10Q?/p>
清单 10. 发送请?/a>
function getCustomerInfo() { var phone = document.getElementById("phone").value; var url = "/cgi-local/lookupCustomer.php?phone=" + escape(phone); request.open("GET", url, true); request.send(null); } |
现在我们所做的只有很少一Ҏ新的、革命性的或异步的。必L认,open() Ҏ?“true?q个小的关键字建立了异步请求。但是除此之外,q些代码与用 Java servlet ?JSP、PHP ?Perl ~程没有什么两栗那?Ajax ?Web 2.0 最大的U密是什么呢Q秘密就在于 XMLHttpRequest 的一个简单属?onreadystatechange?/p>
首先一定要理解q些代码中的程Q如果需要请回顾 清单 10Q。徏立其h然后发出h。此外,因ؓ是异步请求,所?JavaScript ҎQ例子中?getCustomerInfo()Q不会等待服务器。因此代码将l箋执行Q就是说Q将退Ҏ而把控制q回l表单。用户可以l输入信息,应用E序不会{待服务器?/p>
q就提出了一个有的问题Q服务器完成了请求之后会发生什么?{案是什么也不发生,臛_对现在的代码而言如此Q显然这样不行,因此服务器在完成通过 XMLHttpRequest 发送给它的h处理之后需要某U指C明怎么做?/p>
![]() |
|
现在 onreadystatechange 属性该d了。该属性允许指定一个回调函数。回调允许服务器Q猜得到吗?Q反向调?Web 面中的代码。它也给了服务器一定程度的控制权,当服务器完成h之后Q会查看 XMLHttpRequest 对象Q特别是 onreadystatechange 属性。然后调用该属性指定的MҎ。之所以称为回调是因ؓ服务器向|页发v调用Q无论网|w在做什么。比方说Q可能在用户坐在椅子上手没有键盘的时候调用该ҎQ但是也可能在用戯入、移动鼠标、滚动屏q或者点L钮时调用该方法。它q不兛_用户在做什么?/p>
q就是称之ؓ异步的原因:用户在一层上操作表单Q而在另一层上服务器响应请求ƈ触发 onreadystatechange 属性指定的回调Ҏ。因此需要像 清单 11 一样在代码中指定该Ҏ?/p>
清单 11. 讄回调Ҏ
function getCustomerInfo() { var phone = document.getElementById("phone").value; var url = "/cgi-local/lookupCustomer.php?phone=" + escape(phone); request.open("GET", url, true); request.onreadystatechange = updatePage; request.send(null); } |
需要特别注意的是该属性在代码中设|的位置 —?它是在调?send() 之前 讄的。发送请求之前必设|该属性,q样服务器在回答完成h之后才能查看该属性。现在剩下的只有编?updatePage() Ҏ了,q是本文最后一节要讨论的重炏V?/p>
![]() ![]() |
![]()
|
发送请求,用户高兴C?Web 表单Q同时服务器在处理请求)Q而现在服务器完成了请求处理。服务器查看 onreadystatechange 属性确定要调用的方法。除此以外,可以您的应用程序看作其他应用程序一P无论是否异步。换句话_不一定要采取Ҏ的动作编写响应服务器的方法,只需要改变表单,让用戯问另一?URL 或者做响应服务器需要的M事情。这一节我们重点讨论对服务器的响应和一U典型的动作 —?x改变用户看到的表单中的一部分?/p>
现在我们已经看到如何告诉服务器完成后应该做什么:?XMLHttpRequest 对象?onreadystatechange 属性设|ؓ要运行的函数名。这P当服务器处理完请求后׃自动调用该函数。也不需要担心该函数的Q何参数。我们从一个简单的Ҏ开始,?清单 12 所C?/p>
清单 12. 回调Ҏ的代?/a>
<script language="javascript" type="text/javascript"> var request = false; try { request = new XMLHttpRequest(); } catch (trymicrosoft) { try { request = new ActiveXObject("Msxml2.XMLHTTP"); } catch (othermicrosoft) { try { request = new ActiveXObject("Microsoft.XMLHTTP"); } catch (failed) { request = false; } } } if (!request) alert("Error initializing XMLHttpRequest!"); function getCustomerInfo() { var phone = document.getElementById("phone").value; var url = "/cgi-local/lookupCustomer.php?phone=" + escape(phone); request.open("GET", url, true); request.onreadystatechange = updatePage; request.send(null); } function updatePage() { alert("Server is done!"); } </script> |
它仅仅发Z些简单的警告Q告诉您服务器什么时候完成了d。在自己的网中试验q些代码Q然后在览器中打开Q如果希望查看该例中?XHTMLQ请参阅 清单 8Q。输入电话号码然后离开该字D,看C个弹出的警告H口Q如 ?3 所C)Q但是点?OK 又出C…?/p>
?3. 弹出警告?Ajax 代码
Ҏ览器的不同Q在表单停止弹出警告之前会看Cơ、三ơ甚臛_ơ警告。这是怎么回事呢?原来我们q没有考虑 HTTP qA状态,q是h/响应循环中的一个重要部分?/p>
前面提到Q服务器在完成请求之后会?XMLHttpRequest ?onreadystatechange 属性中查找要调用的Ҏ。这是真的,但还不完整。事实上Q每?HTTP qA状态改变时它都会调用该Ҏ。这意味着什么呢Q首先必ȝ?HTTP qA状态?/p>
HTTP qA状态表C求的状态或情Ş。它用于定该请求是否已l开始、是否得C响应或者请?响应模型是否已经完成。它q可以帮助确定读取服务器提供的响应文本或数据是否安全。在 Ajax 应用E序中需要了解五U就l状态:
与大多数跨浏览器问题一Pq些qA状态的使用也不一致。您也许期望dqA状态从 0 ?1?? 再到 4Q但实际上很是q种情况。一些浏览器从不报告 0 ?1 而直接从 2 开始,然后?3 ?4。其他浏览器则报告所有的状态。还有一些则多次报告qA状?1。在上一节中看到Q服务器多次调用 updatePage()Q每ơ调用都会弹告框 —?可能和预期的不同Q?/p>
对于 Ajax ~程Q需要直接处理的惟一状态就是就l状?4Q它表示服务器响应已l完成,可以安全C用响应数据了。基于此Q回调方法中的第一行应该如 清单 13 所C?/p>
清单 13. 查就l状?/a>
function updatePage() { if (request.readyState == 4) alert("Server is done!"); } |
修改后就可以保证服务器的处理已经完成。尝试运行新版本?Ajax 代码Q现在就会看C预期的一P只显CZơ警告信息了?/p>
虽然 清单 13 中的代码看v来似乎不错,但是q有一个问?—?如果服务器响应请求ƈ完成了处理但是报告了一个错误怎么办?要知道,服务器端代码应该明白它是?Ajax、JSP、普?HTML 表单或其他类型的代码调用的,但只能用传l的 Web 专用Ҏ报告信息。而在 Web 世界中,HTTP 代码可以处理h中可能发生的各种问题?/p>
比方_您肯定遇到过输入了错误的 URL h而得?404 错误码的情ŞQ它表示该页面不存在。这仅仅?HTTP h能够收到的众多错误码中的一U(完整的状态码列表请参?参考资?/a> 中的链接Q。表C所讉K数据受到保护或者禁止访问的 403 ?401 也很常见。无论哪U情况,q些错误码都是从完成的响?得到的。换句话_服务器行了hQ即 HTTP qA状态是 4Q但是没有返回客h预期的数据?/p>
因此除了qA状态外Q还需要检?HTTP 状态。我们期望的状态码?200Q它表示一切顺利。如果就l状态是 4 而且状态码?200Q就可以处理服务器的数据了,而且q些数据应该是要求的数据(而不是错误或者其他有问题的信息)。因此还要在回调Ҏ中增加状态检查,?清单 14 所C?/p>
清单 14. ?HTTP 状态码
function updatePage() { if (request.readyState == 4) if (request.status == 200) alert("Server is done!"); } |
Z增加更健壮的错误处理q尽量避免过于复杂,可以增加一两个状态码查,L一?清单 15 中修改后?updatePage() 版本?/p>
清单 15. 增加一炚w误检?/a>
function updatePage() { if (request.readyState == 4) if (request.status == 200) alert("Server is done!"); else if (request.status == 404) alert("Request URL does not exist"); else alert("Error: status code is " + request.status); } |
现在?getCustomerInfo() 中的 URL 改ؓ不存在的 URL 看看会发生什么。应该会看到警告信息说明要求?URL 不存?—?好极了!很难处理所有的错误条gQ但是这一小的改变能够涵盖典?Web 应用E序?80% 的问题?/p>
现在可以保h已经处理完成Q通过qA状态)Q服务器l出了正常的响应Q通过状态码Q,最后我们可以处理服务器q回的数据了。返回的数据保存?XMLHttpRequest 对象?responseText 属性中?/p>
关于 responseText 中的文本内容Q比如格式和长度Q有意保持含p。这h务器可以将文本讄成Q何内宏V比方说Q一U脚本可能返回逗号分隔的|另一U则使用道W(?| 字符Q分隔的|q有一U则q回长文本字W串。何M从由服务器决定?/p>
在本文用的例子中,服务器返回客L上一个订单和客户地址Q中间用道W分开。然后用订单和地址讄表单中的元素|清单 16 l出了更新显C内容的代码?/p>
清单 16. 处理服务器响?/a>
function updatePage() { if (request.readyState == 4) { if (request.status == 200) { var response = request.responseText.split("|"); document.getElementById("order").value = response[0]; document.getElementById("address").innerHTML = response[1].replace(/\n/g, " |
首先Q得?responseText q?JavaScript split() Ҏ从管道符分开。得到的数组攑ֈ response 中。数l中的第一个?—?上一个订?—??response[0] 讉KQ被讄?ID ?“order?的字D늚倹{第二个?response[1]Q即客户地址Q则需要更多一点处理。因为地址中的行用一般的行分隔符Q“\n”字W)分隔Q代码中需要用 XHTML 风格的行分隔W?<br /> 来代ѝ替换过E?replace() 函数和正则表辑ּ完成。最后,修改后的文本作ؓ HTML 表单 div 中的内部 HTML。结果就是表单突然用客户信息更新了,如图 4 所C?/p>
?4. 收到客户数据后的 Break Neck 表单
l束本文之前Q我q要介绍 XMLHttpRequest 的另一个重要属?responseXML。如果服务器选择使用 XML 响应则该属性包含(也许您已l猜刎ͼXML 响应。处?XML 响应和处理普通文本有很大不同Q涉及到解析、文对象模型(DOMQ和其他一些问题。后面的文章中将q一步介l?XML。但是因?responseXML 通常?responseText 一赯论,q里有必要提一提。对于很多简单的 Ajax 应用E序 responseText 够了,但是您很快就会看到通过 Ajax 应用E序也能很好地处?XML?/p>
![]() ![]() |
![]()
|
您可能对 XMLHttpRequest 感到有点厌倦了Q我很少看到一整篇文章讨论一个对象,特别是这U简单的对象。但是您在使用 Ajax ~写的每个页面和应用E序中反复用该对象。坦白地_关于 XMLHttpRequest q真有一些可说的内容。下一期文章中介l如何在h中?POST ?GETQ来讄h中的内容头部和从服务器响应读取内容头部,理解如何在请?响应模型中编码请求和处理 XML?/p>
再往后我们将介绍常见 Ajax 工具。这些工L实际上隐藏了本文所q的很多l节Q?Ajax ~程更容易。您也许会想Q既然有q么多工LZq要对底层的l节~码。答案是Q如果不知道应用E序在做什么,很隑֏现应用程序中的问题?/p>
因此不要忽略q些l节或者简单地览一下,如果便捷华丽的工L出现了错误,您就不必挠头或者发送邮件请求支持了。如果了解如何直接?XMLHttpRequestQ就会发现很Ҏ调试和解x奇怪的问题。只有让其解x的问题,工具才是好东西?/p>
因此L?XMLHttpRequest 吧。事实上Q如果您有用工L?Ajax 代码Q可以尝试?XMLHttpRequest 对象及其属性和Ҏ重新改写。这是一U不错的l习Q可以帮助您更好地理解其中的原理?/p>
前一节中我们单介l了一?/span> Action 。其实所谓的 Action 是一个最常用的事Ӟ举个例子来说Q对于一个按钮来说它可以有多个事Ӟ比如按键Q焦点,鼠标Q等{等{吧Q但是实际上在用程序的时候,我们最兛_的,是按下去这个按钮会发生什么,q个其实是所谓的 Action 。如果大家以前做q?/span> swing/awt 变成的话Q应该对 Action 不会陌生?/span>
?/span> JFace 里面Q一?/span> Action 可以对应多个 GUI 对象Q这些对象就是所谓的 Contribution Item 。比如我们在一般程序里面很常见的“文件”菜单,下面都会有“新建”,“保存”等{。同时我们可以在工具条上攄相应的按钮,那么q些都是有相同的功能Q在 JFace 里面我们可以只写一?/span> Action Q然后把它映到不同?/span> ContributionItem 去,而不必ؓ每个部g都写一串处理事件?/span>
我们下面q是通过一个简单的例子来说明,?/span> JFace 中怎么使用菜单和工hq两U最基本也是最有用?/span> Contribution Item ?/span>
我们q个E序写得很傻Q就是一个光U秃的窗口上做了一个菜单和工具条按钮,功能也只有一个,是每次点一下,弹Z个输入框来问你名字是什么,然后昄一?/span> Hello, xxx 之类的?/span>
首先我们q是来写一?/span>
Action
c:
代码D?/span>
17
q只是一个很单的 Action c,没有太多可说的?/span>
然后我们创徏一?/span>
ApplicationWindow
c:
代码D?/span> 18
大家可能已经注意CQ在q里面我们重载了
createMenuManager
?/span>
createToolBarManager
两个ҎQ它们的用途就和名字一P一个是用来创徏菜单的,一个是用来创徏工具条的。重载了q两个方法以后,通过在构造函C调用
addMenuBar
?/span>
addToolBar
让工h和菜单显C出来?/span>
q里值得一提的?/span>
MenuManager
?/span>
ToolBarManager
c,如果大家M?/span>
API
文的话会发现它们都是所谓的
contribution manager
Q实C
IConntributionManager
接口Q,你可以通过q些
contribution manager
来实现对特定lg的管理(d删除{等Q?/span>
具体到菜单的创徏Q看了我们上面的代码很明白了,q接调用相?/span>
MenuManager
?/span>
add
Ҏ?/span>
action
d上就可以了?/span>
JFace
会自动找到这?/span>
Action
?/span>
getText
Ҏ讄菜单的文字。如果是有好几层菜单Q那么只要在重新
new
一?/span>
MenuManager
d到已有的
MenuManager
里面可以了。就象前面代码中的:
至于工具条就更简单了Q创Z?/span>
ToolBarManager
然后直接
add
对应?/span>
Action
可以了?/span>
如果菜单只是文字q没有什么,如果你的工具条都是文字是不是会显得干巴巴的?其实只要我们?/span>
Action
讄
ImageDescriptor
可以了Q比如你可以自己M个图标保存到
Action
的包下面Q我M一?/span>
hi.gif
Q,然后?/span>
Action
的构造函数改写成q样Q?br />
大家注意最后一句话Q就是ؓ
action
讄图标的。然后再q行一下就会发现菜单和工具栏都有图标了?/span>
大家好,因ؓ工作的事情搞了一个多月,现在l于暂时安定下来了。这一pd的文章我也会l箋往下写?/span>
在这一节中Q我会向大家介绍
JFace
中的事g模式。其实我怿q篇文章的读者应该大部分都会接触
eclipse
Q这样可能也会接触过
eclipse
的插件开发。就是没有接触过Q大家也可能会有?/span>
eclipse
里面新徏工程的时候出于各U原因(比如好奇心)点了
plug-in project
的时候吧。其实作Z个程序员来讲Q保持好奇是很重要的。如果你大概看过一?/span>
plug-in project
的结构,虽然可能不能全部理解Q但是我怿也应该对
Action
之类有一些了解。我们这一节主要就是围l?/span>
Action
来写的。ؓ了增加可L,我们首先介绍几个名词Q这些名词都可以?/span>
eclipse
的文中扑ֈ?/span>
JFace
中的一?/span>
Action
可以单地理解成一?span style="COLOR: blue">命o。那么它?span style="COLOR: blue">事g有什么关pdQ比如说我点了一个菜单,那么点击本n是一个事Ӟ但是q个事g的媄响就是相应的命o被执行了。大家日怋用的一些Y件比?/span>
Office
都是有菜单和工具栏的Q而一个菜单项和一个工h可能执行的是同一个命令。比?/span>
Word
里面要新Z个文档的话可以通过
?/span>
文g
?/span>
菜单下的
?/span>
新徏
?/span>
实现Q也可以通过点击工具栏上相应的图标实现。这个新建地功能本n?/span>
JFace
里面是可以?/span>
Action
来实现的?/span>
?/span>
JFace
里面Q?/span>
Action
可以兌到菜单,工具条,以及按钮Q也是
Button
Q。当然关于如何关联,我们会在后面向大家详l介l?/span>
Action ?/span> JFace 里面的定义是一个接?/span> org.eclipse.jface.action.IAction 。当然实际上你写E序的时候必自己来实现q个接口Q写q Action cL?/span>
IAction 里面最重要的方法是 run() Q它也是事g触发以后执行的代码。其他的Ҏ都是一些辅助性的ҎQ不是我们要x的重炏Vؓ了能够将_֊集中在我们所x的事情上Q通常我们不是实现 IAction 接口Q而是通过l承 org.eclipse.jface.action.Action q个抽象cL实现 Action 。下面我们通过一个例子来说明 Action 的用法?/span>
Hello,Action!
首先我们先不用L面,先定义一个最单的 Action cR?/span>
代码D?/span>
1
5
q段代码其实应该q是很好L的。带参的构造函数带q来一?/span> Shell 实例Q?/span> run() Ҏ说明了这?/span> Action 的功能就是显CZ个对话框。第 5 行中的代码调用了父类的构造函敎ͼ其中W一个参数是 Action 对应的文本,前面?/span> & W号表明?/span> H 是热键,而第二个参数则是一个风格参数。如果大家l向后看的话Q就会发现这?/span> Action 被附加在了一个按钮上面,而按钮上昄的文本就?/span> Hello Q如果你定义的风g?/span> AS_PUSH_BUTTON 而是 AS_RADIO_BUTTON 的话׃发现按钮已经不是一个纯_的按钮了,而是一个单选钮。相应的其他风格可以参照 Javadoc?br />
代码D?/span>
16
和前面一节的代码相比Q我们只是修改了
createContents
Ҏ。首先创Z一?/span>
HelloAction
的实例,然后又创Z一?/span>
ActionContributionItem
的实例,最后调用了q个实例?/span>
fill
Ҏ按钮添加到H口中,q就是全部了。是不是很简单呢Q程序运行出来的效果如下图:
?/span> 1 6
可能看了q个例子Q你会认?/span>
ActionContributionItem
q个c表C的是一个按钮了。但是实际上q不是的Q它在图形界面上表示成什么样子,随着不同?/span>
fill
调用又有不同。在下一节中Q我会向大家深入介绍
Contribution Item
以及
JFace
中的菜单Q工h{的应用。这一节就到这里结束了Q因为刚刚换了工作环境,有很多事情需要去做,所以写得比较短Q请大家见谅Q)?/span>