一、Web服務元數據
二、腳本語言支持
三、嵌入式數據庫
四、在Java SE6(Mustang)中使用Desktop API
五、使用Compiler API
六、輕量級Http Server
七、用Console開發控制臺程序
一、Web服務元數據 top
.Net的Web Services元數據
早在.Net Framework 1.0中,微軟就用元數據功能(.net的attribute特性)來標注要暴露成Web Service的方法,下面是用C#演示的利用.net的元數據功能暴露Web Service方法的代碼片斷.
public class TestWS{
[WebMethod]
public String sayHi(){
return "Hi!";
}
public int add(int d1,int d2){
return d1+d2;
}
}
上面的[WebMethod]是加在方法sayHi上面的元數據,用來告訴Web Services引擎(一般是ASP.NET Runtime), 我這個方法需要暴露為一個Web Service,你需要幫我生成相應的WSDL描述及相關支持文件.而另一個方法add沒有加這個元數據,所以Web Services引擎就不會為該方法生成WSDL及相關支持文件
Java的Web Services元數據
Java 里的Web服務元數據跟微軟的方案基本沒有語義上的區別,自從JDK5添加了元數據功能(Annotation)之后,SUN幾乎重構了整個J2EE體 系, 由于變化很大,干脆將名字也重構為Java EE, Java EE(當前版本為5.0)將元數據納入很多規范當中,這其中就包括Web Services的相關規范, 加入元數據之后的Web Services服務器端編程模型就跟上面看到的C#片斷差不多了, 這顯然比以前的JAX-RPC編程模型簡單(當然, Axis的編程模型也很簡單).這里要談的Web服務元數據(JSR 181)只是Java Web 服務規范中的一個,它跟Common Annotations, JAXB2, StAX, SAAJ和JAX-WS等共同構成Java EE 5的Web Services技術堆棧.
JSR-181的元數據清單
下面介紹JSR-181里面各個元數據的相關參數及用途
Annotation Retention Target Description
WebService Runtime Type
標注要暴露為Web Services的類或接口
WebParam Runtime Parameter 自定義服務方法參數到WSDL的映射
WebResult Runtime Method 自定義服務方法返回值到WSDL的映射
WebMethod Runtime Method 自定義單個服務方法到WSDL的映射
Oneway Runtime Method 必須與@WebMethod連用,表明被標注方法只有輸入沒有輸出,這就要求被標注方法不能有返回值,也不能聲明checked exception
HandlerChain Runtime Type,Method,Field 將Web服務與外部Handler chain關聯起來
SOAPBinding Runtime Type,Method 自定義SOAPBinding
JSR-181元數據使用示例
package WebServices;
import java.io.File;
import java.io.IOException;
import javax.jws.Oneway;
import javax.jws.WebMethod;
import javax.jws.WebParam;
import javax.jws.WebResult;
import javax.jws.WebService;
import javax.xml.ws.Endpoint;
/**
* @author chinajash
*/
@WebService(targetNamespace="public class WSProvider {
@WebResult(name="Greetings")//自定義該方法返回值在WSDL中相關的描述
@WebMethod
public String sayHi(@WebParam(name="MyName") String name){
return "Hi,"+name; //@WebParam是自定義參數name在WSDL中相關的描述
}
@Oneway //表明該服務方法是單向的,既沒有返回值,也不應該聲明檢查異常
@WebMethod(action="printSystemTime",operationName="printSystemTime")//自定義該方法在WSDL中相關的描述
public void printTime(){
System.out.println(System.currentTimeMillis());
}
public static void main(String[] args) {
Thread wsPublisher = new Thread(new WSPublisher());
wsPublisher.start();
}
private static class WSPublisher implements Runnable{
public void run() {
//發布WSProvider到http://localhost:8888/chinajash/WSProvider這個地址,之前必須調用wsgen命令
//生成服務類WSProvider的支持類,命令如下:
//wsgen -cp . WebServices.WSProvider
Endpoint.publish("http://localhost:8888/chinajash/WSProvider",new WSProvider());
}
}
}
如果想看到Web Services Engine生成的WSDL文件是否遵守上面的元數據, 我們沒有必要將上面的WSProvider部署到支持JSR-181的應用服務器或Servlet形式的Web Services Engine,現在JDK6已經提供了一個很簡單的機制可以用來測試和發布Web Services,下面講講如何在JDK6環境下發布Web Services和查看生成的WSDL
1.將<JDK_HOME>/bin加入path環境變量
2.在命令行下切換當前目錄到WSProvider的class文件所在的目錄,運行下面命令
wsgen -cp . WebServices.WSProvider
在這個例子中會生成以下3個類的源代碼文件及class文件
SayHi
SayHiResponse
PrintTime
3.執行如下代碼發布WSProvider到http://localhost:8888/chinajash/WSProvider,在這里可以執行WSProvider類的main方法就可以
Endpoint.publish("http://localhost:8888/chinajash/WSProvider",new WSProvider());
4.在瀏覽器輸入http://localhost:8888/chinajash/WSProvider?wsdl就可以看到生成的WSDL文件,為了節省篇幅,這里就不把生成的WSDL文件貼上了,大家可以自己動手試試.
--------------------------------------------------------------------------------------------------------
二、腳本語言支持 top
JDK6增加了對腳本語言的支持(JSR 223),原理上是將腳本語言編譯成bytecode,這樣腳本語言也能享用Java平臺的諸多優勢,包括可移植性,安全等,另外,由于現在是編譯成bytecode后再執行,所以比原來邊解釋邊執行效率要高很多。加入對腳本語言的支持后,對Java語言也提供了以下好處。
1、許多腳本語言都有動態特性,比如,你不需要用一個變量之前先聲明它,你可以用一個變量存放完全不同類型的對象,你不需要做強制類型轉換,因為轉換都是自動的。現在Java語言也可以通過對腳本語言的支持間接獲得這種靈活性。
2、 可以用腳本語言快速開發產品原型,因為現在可以Edit-Run,而無需Edit-Compile-Run,當然,因為Java有非常好的IDE支持,我 們完全可以在IDE里面編輯源文件,然后點擊運行(隱含編譯),以此達到快速開發原型的目的,所以這點好處基本上可以忽略。
3、通過引入腳本語言可以輕松實現Java應用程序的擴展和自定義,我們可以把原來分布在在Java應用程序中的配置邏輯,數學表達式和業務規則提取出來,轉用JavaScript來處理。
Sun的JDK6實現包含了一個基于Mozilla Rhino的 腳本語言引擎,支持JavaScript,這并不是說明JDK6只支持JavaScript,任何第三方都可以自己實現一個JSR-223兼容的腳本引擎 使得JDK6支持別的腳本語言,比如,你想讓JDK6支持Ruby,那你可以自己按照JSR 223的規范實現一個Ruby的腳本引擎類,具體一點,你需要實現javax.script.ScriptEngine(簡單起見,可以繼承javax.script.AbstractScriptEngine)和javax.script.ScriptEngineFactory兩個接口。當然,在你實現自己的腳本語言引擎之前,先到scripting.dev.java.net project 這里看看是不是有人已經幫你做了工作,這樣你就可以直接拿來用就行。
Scripting API
Scripting API是用于在Java里面編寫腳本語言程序的API, 在Javax.script中可以找到Scripting API,我們就是用這個API來編寫JavaScript程序,這個包里面有一個ScriptEngineManager類,它是使用Scripting API的入口,ScriptEngineManager可以通過jar服務發現(service discovery)機制尋找合適的腳本引擎類(ScriptEngine),使用Scripting API的最簡單方式只需下面三步
1、創建一個ScriptEngineManager對象
2、通過ScriptEngineManager獲得ScriptEngine對象
3、用ScriptEngine的eval方法執行腳本
下面是一個Hello World程序
/** * @author chinajash */public class HelloScript {public static void main(String[] args) throws Exception { ScriptEngineManager factory = new ScriptEngineManager();//step 1 ScriptEngine engine = factory.getEngineByName("JavaScript");//Step 2 engine.eval("print('Hello, Scripting')");//Step 3 } }運行上面程序,控制臺會輸出Hello, Scripting上面這個簡單的Scripting程序演示了如何在Java里面運行腳本語言,除此之外,我們還可以利用Scripting API實現以下功能1、暴露Java對象為腳本語言的全局變量2、在Java中調用腳本語言的方法3、腳本語言可以實現Java的接口4、腳本語言可以像Java一樣使用JDK平臺下的類下面的類演示了以上4種功能package Scripting;import java.io.File;import javax.script.Invocable;import javax.script.ScriptEngine;import javax.script.ScriptEngineManager;import javax.script.ScriptException;/** * @author chinajash */public class ScriptingAPITester { public static void main(String[] args) throws Exception { ScriptEngineManager manager = new ScriptEngineManager(); ScriptEngine engine = manager.getEngineByName("JavaScript"); testScriptVariables(engine);//演示如何暴露Java對象為腳本語言的全局變量 testInvokeScriptMethod(engine);//演示如何在Java中調用腳本語言的方法 testScriptInterface(engine);//演示腳本語言如何實現Java的接口 testUsingJDKClasses(engine);//演示腳本語言如何使用JDK平臺下的類 } public static void testScriptVariables(ScriptEngine engine) throws ScriptException{ File file = new File("test.txt"); engine.put("f", file); engine.eval("println('Total Space:'+f.getTotalSpace())"); } public static void testInvokeScriptMethod(ScriptEngine engine) throws Exception{ String script = "function hello(name) { return 'Hello,' + name;}"; engine.eval(script); Invocable inv = (Invocable) engine; String res = (String)inv.invokeFunction("hello", "Scripting" ); System.out.println("res:"+res); } public static void testScriptInterface(ScriptEngine engine) throws ScriptException{ String script = "var obj = new Object(); obj.run = function() { println('run method called'); }"; engine.eval(script); Object obj = engine.get("obj"); Invocable inv = (Invocable) engine; Runnable r = inv.getInterface(obj,Runnable.class); Thread th = new Thread(r); th.start(); } public static void testUsingJDKClasses(ScriptEngine engine) throws Exception{ //Packages是腳本語言里的一個全局變量,專用于訪問JDK的package String js = "function doSwing(t){var f=new Packages.javax.swing.JFrame(t);f.setSize(400,300);f.setVisible(true);}"; engine.eval(js); Invocable inv = (Invocable) engine; inv.invokeFunction("doSwing", "Scripting Swing" ); }}Scripting Tool
SUN提供的JDK6中有一個命令行工具??jrunscript,你可以在<JDK6_Home>/bin下面找到這個工具,jrunscript是一個腳本語言的解釋程序,它獨立于腳本語言,但默認是用JavaScript,我們可以用jrunscript來測試自己寫的腳本語言是否正確,下面是一個在命令行運行jrunscript的簡單例子
jrunscript
js>println("Hello,JrunScript");
Hello,JrunScript
js>9*8
72.0
js>
--------------------------------------------------------------------------------------------------------
三、嵌入式數據庫Derby top
Derby并不是一個新的數據庫產品,它是由IBM捐獻給Apache的DB項目的一個純Java數據庫,JDK6.0里面帶的這個Derby的版本是10.2.1.7,支持存儲過程和觸發器;有兩種運行模式,一種是作為嵌入式數據庫,另一種是作為網絡數據庫,前者的數據庫服務器和客戶端都在同一個JVM里面運行,后者允許數據庫服務器端和客戶端不在同一個JVM里面,而且允許這兩者在不同的物理機器上.值得注意的是JDK6里面的這個Derby支持JDK6的新特性JDBC 4.0規范(JSR 221),現在我們如果要練習JDBC的用法,沒有必要單獨裝一個數據庫產品了,直接用Derby就行.安裝完JDK6.0后,Derby會被安裝到<JDK6_HOME>/db下面,在<JDK6_HOME>/db/demo/programs下面還有一些示例程序,演示了如何啟動,連接Derby數據庫以及JDBC API的使用.下面分兩種情況演示一下如何用代碼操作Derby數據庫,一種是嵌入式數據庫,一種是網絡數據庫.
一.嵌入式數據庫
/**
* @author chinajash
*/
public class EmbeddedDerbyTester {
public static void main(String[] args) {
String driver = "org.apache.derby.jdbc.EmbeddedDriver";//在derby.jar里面
String dbName="EmbeddedDB";
String dbURL = "jdbc:derby:"+dbName+";create=true";//create=true表示當數據庫不存在時就創建它
try {
Class.forName(driver);
Connection conn = DriverManager.getConnection(dbURL);//啟動嵌入式數據庫
Statement st = conn.createStatement();
st.execute("create table foo (FOOID INT NOT NULL,FOONAME VARCHAR(30) NOT NULL)");//創建foo表
st.executeUpdate("insert into foo(FOOID,FOONAME) values (1,'chinajash')");//插入一條數據
ResultSet rs = st.executeQuery("select * from foo");//讀取剛插入的數據
while(rs.next()){
int id = rs.getInt(1);
String name = rs.getString(2);
System.out.println("id="+id+";name="+name);
}
} catch(Exception e){
e.printStackTrace();
}
}
}
運行上面程序后,會在當前目錄生成名為EmbeddedDB的文件夾,既是EmbeddedDB數據庫的數據文件存放的地方,控制臺將輸出
id=1;name=chinajash
二.網絡數據庫
/**
* @author chinajash
*/
public class NetworkServerDerbyTester {
public static void main(String[] args) {
String driver = "org.apache.derby.jdbc.ClientDriver";//在derbyclient.jar里面
String dbName="NetworkDB";
String connectionURL = "jdbc:derby://localhost:1527/" + dbName + ";create=true";
try {
/*
創建Derby網絡服務器,默認端口是1527,也可以通過運行
<Derby_Home>\frameworks\NetworkServer\bin\startNetworkServer.bat
來創建并啟動Derby網絡服務器,如果是Unix,用startNetworkServer.ksh
*/
NetworkServerControl derbyServer = new NetworkServerControl();//NetworkServerControl類在derbynet.jar里面
PrintWriter pw = new PrintWriter(System.out);//用系統輸出作為Derby數據庫的輸出
derbyServer.start(pw);//啟動Derby服務器
Class.forName(driver);
DriverManager.getConnection(connectionURL);
//do something
derbyServer.shutdown();//關閉Derby服務器
} catch (Exception ex) {
ex.printStackTrace();
}
}
}
運行上面程序后,會在當前目錄生成名為NetworkDB的文件夾
關于Derby的詳細情況,請參考http://db.apache.org/derby
----------------------------------------------------------------------------------------------------
四、在Java SE6(Mustang)中使用Desktop API top
伴隨著默認的圖形用戶界面(GUI)的外觀,打印和性能,Java平臺在縮小平臺差異和整合本地程序與Java程序的道路上已經走了很長一段路。
Java平臺標準版(Java SE)第6版,代號為Mustang(野馬),繼續用新增的系統托盤功能,對JTable更好的打印支持和現在的Desktop API
(java.awt.Desktop)來填補這個空隙。本文描述了新的Desktop API,它們允許Java程序來和主機平臺與特定文件類型相關聯的默認應用程序進
行交互。為了更有效地描述這些API,本文也展示了一個簡單的應用程序DesktopDemo。
Desktop 概述
這個新功能是由java.awt.Desktop類提供的。這個API取自桌面綜合組件(JDIC)項目。這個項目的目標是“使以Java技術為基礎的應用程序成為
桌面的一級公民”,實現無縫整合。特別的,新的Desktop API允許Java應用程序實現以下功能:
1.通過一個指定的統一資源定位符(URI)啟動主機系統的默認瀏覽器
2.啟動主機系統的默認郵件客戶端
3.啟動應用程序來打開,編輯或打印和這些應用程序相關聯的文件
Desktop API使用主機操作系統的文件關聯來啟動和特定文件類型相關聯的應用程序。例如,如果OpenDocument text(.odt)文件擴展名與
OpenOffice Writer應用程序相關聯,你的Java應用程序就能夠根據這個關聯啟動OpenOffice Writer來打開,編輯或者甚至輸出.odt文件。依
靠你的主機系統,不同的應用程序可能會和不同的動作相關聯。
運行DesktopDemo應用程序
DesktopDemo是使用Mustang的Desktop API的一個簡單應用程序。這個程序有一個展示了完整API的主窗口,允許你做三件事:
1.通過一個指定的URI啟動默認的瀏覽器
2.通過一個郵件接收者啟動默認的郵件客戶端
3.啟動相關聯的應用程序來打開,編輯或打印一個文件
圖1顯示了用戶界面(UI)

你可以通過下載源程序和JAR文件來運行這個應用程序,把控制臺轉到工程的dist目錄,在Mustang JDK環境下用以下的命令來運行:
java -jar DesktopDemo.jar
判定對Desktop API的支持
在啟動瀏覽器,郵件客戶端或者任何應用程序之前,DesktopDemo必須判定你的平臺是否支持Desktop API。首先,DesktopDemo會禁用所有的文
本域和按鈕。它會在判定你的平臺支持它們以后再激活它們。
在展示了用戶界面以后,應用程序的構造函數很快地用如下所示的代碼禁用了這個應用程序的組件。
public DesktopDemo() {
// Initiate all GUI components.
initComponents();
// Disable buttons that launch browser and email client.
// Disable buttons that open, edit, and print files.
disableActions();
...
}
/**
* Disable all graphical components until we know
* whether their functionality is supported.
*/
private void disableActions() {
txtBrowserURI.setEnabled(false);
btnLaunchBrowser.setEnabled(false);
txtMailTo.setEnabled(false);
btnLaunchEmail.setEnabled(false);
rbEdit.setEnabled(false);
rbOpen.setEnabled(false);
rbPrint.setEnabled(false);
txtFile.setEnabled(false);
btnLaunchApplication.setEnabled(false);
}
...
public javax.swing.JTextField txtBrowserURI;
public javax.swing.JButton btnLaunchBrowser;
public javax.swing.JTextField txtMailTo;
public javax.swing.JButton btnLaunchEmail;
public javax.swing.JRadioButton rbEdit;
public javax.swing.JRadioButton rbOpen;
public javax.swing.JRadioButton rbPrint;
public javax.swing.JTextField txtFile;
public javax.swing.JButton btnLaunchApplication;
用Desktop.isDesktopSupported()方法判定Desktop API是否可用。在Solaris操作系統和Linux平臺上,這個API依賴于Gnome庫。如果這些庫不
可用,這個方法會返回false。在判定了系統支持Desktop API,也就是isDesktopSupported()方法返回true時,應用程序就會使用一個靜態
(static)方法getDesktop()重新獲得一個Desktop實例。
Desktop desktop = null;
// Before more Desktop API is used, first check
// whether the API is supported by this particular
// virtual machine (VM) on this particular host.
if (Desktop.isDesktopSupported()) {
desktop = Desktop.getDesktop();
...
如果你的應用程序沒有在調用getDesktop()方法之前用isDesktopSupported()方法檢查系統對API的支持,那就必須準備捕捉
UnsupportedOperationException異常,該異常會在你的應用程序請求一個Desktop實例而平臺不支持的時候拋出。另外,如果你的應用程序在
一個沒有鍵盤,鼠標或者監聽器的環境(一個“無領導者”的環境)中運行,getdesktop()方法會拋出一個java.awt.HeadlessException異常。
一旦重新獲得,Desktop實例允許你的應用程序瀏覽,發郵件,打開、編輯甚至打印文件或者URI,只要重新獲得的Desktop實例支持這些動作。
每個這種動作被稱為一個action,而每一個Desktop.Action枚舉實例代表一個action:
BROWSE:代表一個通過主機瀏覽器執行的瀏覽動作
MAIL:代表一個通過默認郵件客戶端執行的發郵件動作
OPEN:代表一個通過相關聯的應用程序打開一種特定文件類型的打開動作
EDIT:代表一個通過相關聯的應用程序編輯一種特定文件類型的編輯動作
PRINT:代表一個通過相關聯的應用程序打印一種特定文件類型的打印動作
在調用這些動作之前,應用程序應該判定Desktop實例是否支持它們。這和判定Desktop實例是否可用是不同的。Desktop.isDesktopSupported
()方法告訴我們能否創建一個實例。一旦獲得了一個Desktop對象,你可以查詢這個實例來找出支持哪些特定的動作。如果Desktop對象不支持
特定的動作,或者Desktop API本身不被支持,DesktopDemo會簡單地禁用受影響的那些圖形組件。如圖2所展示的,在禁用狀態下這些組件不能
被用來調用Desktop功能。

使用一個新的Desktop實例,下面的代碼檢查了每個Desktop.Action的支持情況并且激活了適當的圖形組件:
public DesktopDemo() {
...
// Before more Desktop API is used, first check
// whether the API is supported by this particular
// VM on this particular host.
if (Desktop.isDesktopSupported()) {
desktop = Desktop.getDesktop();
// Now enable buttons for actions that are supported.
enableSupportedActions();
}
...
}
/**
* Enable actions that are supported on this host.
* The actions are the following: open browser,
* open email client, and open, edit, and print
* files using their associated application.
*/
private void enableSupportedActions() {
if (desktop.isSupported(Desktop.Action.BROWSE)) {
txtBrowserURI.setEnabled(true);
btnLaunchBrowser.setEnabled(true);
}
if (desktop.isSupported(Desktop.Action.MAIL)) {
txtMailTo.setEnabled(true);
btnLaunchEmail.setEnabled(true);
}
if (desktop.isSupported(Desktop.Action.OPEN)) {
rbOpen.setEnabled(true);
}
if (desktop.isSupported(Desktop.Action.EDIT)) {
rbEdit.setEnabled(true);
}
if (desktop.isSupported(Desktop.Action.PRINT)) {
rbPrint.setEnabled(true);
}
if (rbEdit.isEnabled() || rbOpen.isEnabled() || rbPrint.isEnabled()) {
txtFile.setEnabled(true);
btnLaunchApplication.setEnabled(true);
}
}
一旦應用程序判定了可支持的動作,它會激活適當的圖形組件。如果所有組件都被激活,用戶界面應該如圖3所示:

打開瀏覽器
調用下面的實例方法會打開主機的默認瀏覽器:
public void browse(URI uri) throws IOException
因為DesktopDemo的用戶界面組件只有在Desktop.Action被支持的情況下才會被激活,所以這個簡單的示例程序不需要在調用browse()方法之前
再次檢查支持情況。然而,在實際應用程序中,在每個調用之前檢查支持情況可能會使程序更加健壯:
if (desktop.isSupported(Desktop.Action.BROWSE)) {
// launch browser
...
}
DesktopDemo為每個按鈕添加了java.awt.event.ActionListener。當被激活時,Launch Browser按鈕會通過它的ActionListener調用如下方法
:
private void onLaunchBrowser(java.awt.event.ActionEvent evt) {
URI uri = null;
try {
uri = new URI(txtBrowserURI.getText());
desktop.browse(uri);
}
catch(IOException ioe) {
ioe.printStackTrace();
}
catch(URISyntaxException use) {
use.printStackTrace();
}
...
}
browse()方法會拋出多種異常,包括當URI為空時拋出的NullPointerException,當BROWSE動作不被支持時拋出的
UnsupportedOperationException,當默認瀏覽器或者應用程序無法找到或者啟動時拋出的IOException,以及當安全管理器拒絕調用時拋出的
SecurityException。
如果進展順利,監聽器會從圖4中所示的相關聯的文本域中重新獲得文本,創建一個URI,然后調用browse()方法。上面的代碼啟動了你系統上
默認的瀏覽器來加載URI,如圖5所示。


發送郵件
如果動作被支持的話,應用程序能夠啟動主機的默認郵件客戶端,通過調用Desktop的實例方法:
public void mail(URI uri) throws IOException
DesktopDemo有一個Launch Mail按鈕的ActionListener。在這種情況下,監聽器調用如下方法:
private void onLaunchMail(java.awt.event.ActionEvent evt) {
String mailTo = txtMailTo.getText();
URI uriMailTo = null;
try {
if (mailTo.length() > 0) {
uriMailTo = new URI("mailto", mailTo, null);
desktop.mail(uriMailTo);
} else {
desktop.mail();
}
}
catch(IOException ioe) {
ioe.printStackTrace();
}
catch(URISyntaxException use) {
use.printStackTrace();
}
...
}
onLaunchMail()方法重新獲得和文本域相關的郵件接收者,如果接收者存在就使用mailto模式參數創建URI,然后調用mail()方法。mail()方法
已經被重載,因此你可以通過使用或者不使用代表mailto接收者的URI來調用它(見圖6)。

你可以不僅僅使用一個簡單郵件接收者來創建URI。mailto模式也支持CC,BCC,SUBJECT和BODY字段。例如,下面的文本可以被用來創建一個
mailto URI。
mailto:duke@sun.com?SUBJECT=Happy New Year!&BODY=Happy New Year, Duke!
圖7顯示了結果:

當然,你也可以不使用參數調用mail()方法。在這種情況下,你的郵件客戶端將會啟動一個新的沒有指定接收者、主題或者主體的郵件窗口。
打開,編輯和打印一個文件
Java應用程序可以分別使用Desktop對象的open()、edit()、print()方法通過和文件相關聯的應用程序打開、編輯和打印文件。(見圖8)而且,
DesktopDemo只有在Desktop實例支持的情況下允許這些動作,因此在這個應用程序的設定中,沒有必要再檢查這些支持情況。

每個DesktopDemo的單選按鈕也都有它們自己的ActionListener。在這種情況下,每個監聽器設置一個實例變量的值來代表最近選擇的按鈕相關
聯的Desktop.Action:
Desktop.Action action;
private void onPrintAction(java.awt.event.ActionEvent evt) {
action = Desktop.Action.PRINT;
}
private void onEditAction(java.awt.event.ActionEvent evt) {
action = Desktop.Action.EDIT;
}
private void onOpenAction(java.awt.event.ActionEvent evt) {
action = Desktop.Action.OPEN;
}
當你按下Launch Default Application按鈕時,它觸發它自己的監聽器,調用如下方法:
private void onLaunchDefaultApplication(java.awt.event.ActionEvent evt) {
String fileName = txtFile.getText();
File file = new File(fileName);
try {
switch(action) {
case OPEN:
desktop.open(file);
break;
case EDIT:
desktop.edit(file);
break;
case PRINT:
desktop.print(file);
break;
}
}
catch (IOException ioe) {
ioe.printStackTrace();
}
...
}
這個方法判定哪個Desktop.Action被選擇并且調用適當的Desktop的實例方法,open(),edit()或者print()。每個方法要求一個File參數用來
執行被請求的動作。
有趣的是,在相同的文件類型上的不同動作可能會被注冊為不同的應用程序。例如,Firefox瀏覽器可能會執行OPEN操作,Emacs執行EDIT操作
,另一種不同的應用程序執行PRINT操作。你的主機桌面的關聯用來決定應該調用哪個應用程序。這種操作桌面文件關聯的能力對目前存在的
Mustang中的Desktop API來說還不可能,這樣這些關聯就只能通過與平臺相關的工具來創建或改變了。
摘要
桌面整合是一個重要的Mustang主題。Mustang支持這個主題的一種方法是通過java.awt.Desktop API。這個API允許Java應用程序啟動主機的默
認的瀏覽器和郵件客戶端。另外,Java應用程序能夠啟動和文件相關的應用程序來打開、編輯和打印文件。盡管Java應用程序不能操作、創建
或者改變文件關聯,Desktop API允許Java應用程序啟動默認的相關聯的應用程序。這篇文章提供了一個示范這些API的示例程序,你可以從站
點上下載這個程序。
注意:任何Java SE平臺規范的增加或改進由JSR 270專家組回顧和正式批準。
原文地址:http://java.sun.com/developer/technicalArticles/J2SE/Desktop/mustang/desktop_api/
-----------------------------------------------------------------------------------------
五、使用Compiler API top
現在我們可以用JDK6 的Compiler API(JSR 199)去動態編譯Java源文件,Compiler API結合反射功能就可以實現動態的產生Java代碼并編譯執行這些代碼,有點動態語言的特征。這個特性對于某些需要用到動態編譯的應用程序相當有用, 比如JSP Web Server,當我們手動修改JSP后,是不希望需要重啟Web Server才可以看到效果的,這時候我們就可以用Compiler API來實現動態編譯JSP文件,當然,現在的JSP Web Server也是支持JSP熱部署的,現在的JSP Web Server通過在運行期間通過Runtime.exec或ProcessBuilder來調用javac來編譯代碼,這種方式需要我們產生另一個進程去做編譯工作,不夠優雅而且容易使代碼依賴與特定的操作系統;Compiler API通過一套易用的標準的API提供了更加豐富的方式去做動態編譯,而且是跨平臺的。 下面代碼演示了Compiler API的使用
public class CompilerAPITester {
private static String JAVA_SOURCE_FILE = "DynamicObject.java";
private static String JAVA_CLASS_FILE = "DynamicObject.class";
private static String JAVA_CLASS_NAME = "DynamicObject";
public static void main(String[] args) {
JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
StandardJavaFileManager fileManager = compiler.getStandardFileManager(null, null, null);
generateJavaClass();
try {
//將產生的類文件拷貝到程序的ClassPath下面,下面這一行代碼是特定于Windows+IntelliJ IDEA 6.0項目,不具有移植性
Runtime.getRuntime().exec("cmd /c copy "+JAVA_CLASS_FILE+" classes\\production\\JDK6Features");
Iterable<? extends JavaFileObject> sourcefiles = fileManager.getJavaFileObjects(JAVA_SOURCE_FILE);
compiler.getTask(null, fileManager, null, null, null, sourcefiles).call();
fileManager.close();
Class.forName(JAVA_CLASS_NAME).newInstance();//創建動態編譯得到的DynamicObject類的實例
} catch (Exception ex) {
ex.printStackTrace();
}
}
public static void generateJavaClass(){
try {
FileWriter fw = new FileWriter(JAVA_SOURCE_FILE);
BufferedWriter bw = new BufferedWriter(fw);
bw.write("public class "+JAVA_CLASS_NAME+"{");
bw.newLine();
bw.write("public "+JAVA_CLASS_NAME+"(){System.out.println(\"In the constructor of DynamicObject\");}}");
bw.flush();
bw.close();
} catch (IOException ex) {
ex.printStackTrace();
}
}
}
程序運行后,會產生DynamicObject.java和DynamicObject.class兩個文件,并在控制臺輸出
In the constructor of DynamicObject
--------------------------------------------------------------------------------
六、輕量級Http Server top
JDK6提供了一個簡單的Http Server API,據此我們可以構建自己的嵌入式Http Server,它支持Http和Https協議,提供了HTTP1.1的部分實現,沒有被實現的那部分可以通過擴展已有的Http Server API來實現,程序員必須自己實現HttpHandler接口,HttpServer會調用HttpHandler實現類的回調方法來處理客戶端請求,在這里,我們把一個Http請求和它的響應稱為一個交換,包裝成HttpExchange類,HttpServer負責將HttpExchange傳給HttpHandler實現類的回調方法.下面代碼演示了怎樣創建自己的Http Server
/**
* Created by IntelliJ IDEA.
* User: Chinajash
* Date: Dec 30, 2006
*/
public class HTTPServerAPITester {
public static void main(String[] args) {
try {
HttpServer hs = HttpServer.create(new InetSocketAddress(8888),0);//設置HttpServer的端口為8888
hs.createContext("/chinajash", new MyHandler());//用MyHandler類內處理到/chinajash的請求
hs.setExecutor(null); // creates a default executor
hs.start();
} catch (IOException e) {
e.printStackTrace();
}
}
}
class MyHandler implements HttpHandler {
public void handle(HttpExchange t) throws IOException {
InputStream is = t.getRequestBody();
String response = "<h3>Happy New Year 2007!--Chinajash</h3>";
t.sendResponseHeaders(200, response.length());
OutputStream os = t.getResponseBody();
os.write(response.getBytes());
os.close();
}
}
運行程序后,在瀏覽器內輸入http://localhost:8888/chinajash,瀏覽器輸出
Happy New Year 2007!--Chinajash
-------------------------------------------------------------------------------------------
七、用Console開發控制臺程序 top
JDK6中提供了java.io.Console類專用來訪問基于字符的控制臺設備. 你的程序如果要與Windows下的cmd或者Linux下的Terminal交互,就可以用Console類代勞. 但我們不總是能得到可用的Console, 一個JVM是否有可用的Console依賴于底層平臺和JVM如何被調用. 如果JVM是在交互式命令行(比如Windows的cmd)中啟動的,并且輸入輸出沒有重定向到另外的地方,那么就可以得到一個可用的Console實例. 下面代碼演示了Console類的用法:
/**
* @author chinajash
*/
public class ConsoleTest {
public static void main(String[] args) {
Console console = System.console();//獲得Console實例
if(console!=null){//判斷console是否可用
String user = new String(console.readLine("Enter user:")); //讀取整行字符
String pwd = new String(console.readPassword("Enter passowrd:")); //讀取密碼,密碼輸入時不會顯示
console.printf("User is:"+user+"\n");
console.printf("Password is:"+pwd+"\n");
}else{
System.out.println("Console is unavailable");
}
}
}
如果在NetBean5.5里面運行上面程序,會輸出
Console is unavailable
表示Console不可獲得,那是因為JVM不是在命令行中被調用的或者輸入輸出被重定向了. 但是如果我們在命令行中運行上面程序(java ConsoleTest),程序能夠獲得Console實例,并執行如下:
Enter user:chinajash
Enter passowrd:
User is:chinajash
Password is:chinajash
在這里可以看到輸入密碼時,控制臺時不顯示這些密碼字符的,但是程序可以得到輸入的密碼字符串,這與Linux下面輸入密碼的情況是一樣的