hyq0077

             :: 首頁 ::  ::  :: 聚合  :: 管理 ::
            2 隨筆 :: 4 文章 :: 0 評(píng)論 :: 0 Trackbacks

           
          一、Web服務(wù)元數(shù)據(jù)
          二、
          腳本語言支持
          三、
          嵌入式數(shù)據(jù)庫(kù)
          四、
          在Java SE6(Mustang)中使用Desktop API
          五、
          使用Compiler API
          六、
          輕量級(jí)Http Server
          七、用Console開發(fā)控制臺(tái)程序



          一、Web服務(wù)元數(shù)據(jù)    top

          .Net的Web Services元數(shù)據(jù)
          早在.Net  Framework 1.0中,微軟就用元數(shù)據(jù)功能(.net的attribute特性)來標(biāo)注要暴露成Web Service的方法,下面是用C#演示的利用.net的元數(shù)據(jù)功能暴露Web Service方法的代碼片斷.
          public class TestWS{
              [WebMethod]
              public String sayHi(){
                    return "Hi!";
              }   
              public int add(int d1,int d2){
                    return d1+d2;
              }
          }
          上面的[WebMethod]是加在方法sayHi上面的元數(shù)據(jù),用來告訴Web Services引擎(一般是ASP.NET Runtime), 我這個(gè)方法需要暴露為一個(gè)Web Service,你需要幫我生成相應(yīng)的WSDL描述及相關(guān)支持文件.而另一個(gè)方法add沒有加這個(gè)元數(shù)據(jù),所以Web Services引擎就不會(huì)為該方法生成WSDL及相關(guān)支持文件

          Java的Web Services元數(shù)據(jù)
          Java 里的Web服務(wù)元數(shù)據(jù)跟微軟的方案基本沒有語義上的區(qū)別,自從JDK5添加了元數(shù)據(jù)功能(Annotation)之后,SUN幾乎重構(gòu)了整個(gè)J2EE體 系, 由于變化很大,干脆將名字也重構(gòu)為Java EE, Java EE(當(dāng)前版本為5.0)將元數(shù)據(jù)納入很多規(guī)范當(dāng)中,這其中就包括Web Services的相關(guān)規(guī)范, 加入元數(shù)據(jù)之后的Web Services服務(wù)器端編程模型就跟上面看到的C#片斷差不多了, 這顯然比以前的JAX-RPC編程模型簡(jiǎn)單(當(dāng)然, Axis的編程模型也很簡(jiǎn)單).這里要談的Web服務(wù)元數(shù)據(jù)(JSR 181)只是Java Web 服務(wù)規(guī)范中的一個(gè),它跟Common Annotations, JAXB2, StAX, SAAJ和JAX-WS等共同構(gòu)成Java EE 5的Web Services技術(shù)堆棧.

          JSR-181的元數(shù)據(jù)清單
          下面介紹JSR-181里面各個(gè)元數(shù)據(jù)的相關(guān)參數(shù)及用途
          Annotation Retention Target Description
           WebService  Runtime Type
           標(biāo)注要暴露為Web Services的類或接口
           WebParam  Runtime Parameter 自定義服務(wù)方法參數(shù)到WSDL的映射
           WebResult  Runtime Method 自定義服務(wù)方法返回值到WSDL的映射
           WebMethod  Runtime Method 自定義單個(gè)服務(wù)方法到WSDL的映射
           Oneway  Runtime Method 必須與@WebMethod連用,表明被標(biāo)注方法只有輸入沒有輸出,這就要求被標(biāo)注方法不能有返回值,也不能聲明checked exception
           
           HandlerChain  Runtime Type,Method,Field 將Web服務(wù)與外部Handler chain關(guān)聯(lián)起來
           SOAPBinding  Runtime Type,Method 自定義SOAPBinding

          JSR-181元數(shù)據(jù)使用示例

          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中相關(guān)的描述   
              @WebMethod
              public String sayHi(@WebParam(name="MyName") String name){
                  return "Hi,"+name;
          //@WebParam是自定義參數(shù)name在WSDL中相關(guān)的描述
              }   
              @Oneway //表明該服務(wù)方法是單向的,既沒有返回值,也不應(yīng)該聲明檢查異常
              @WebMethod(action="printSystemTime",operationName="printSystemTime")//自定義該方法在WSDL中相關(guān)的描述
              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() {
                      //發(fā)布WSProvider到http://localhost:8888/chinajash/WSProvider這個(gè)地址,之前必須調(diào)用wsgen命令
                      //生成服務(wù)類WSProvider的支持類,命令如下:
                      //wsgen -cp . WebServices.WSProvider
                      Endpoint.publish("http://localhost:8888/chinajash/WSProvider",new WSProvider());
                  }       
              }
          }

          如果想看到Web Services Engine生成的WSDL文件是否遵守上面的元數(shù)據(jù), 我們沒有必要將上面的WSProvider部署到支持JSR-181的應(yīng)用服務(wù)器或Servlet形式的Web Services Engine,現(xiàn)在JDK6已經(jīng)提供了一個(gè)很簡(jiǎn)單的機(jī)制可以用來測(cè)試和發(fā)布Web Services,下面講講如何在JDK6環(huán)境下發(fā)布Web Services和查看生成的WSDL
          1.將<JDK_HOME>/bin加入path環(huán)境變量
          2.在命令行下切換當(dāng)前目錄到WSProvider的class文件所在的目錄,運(yùn)行下面命令
          wsgen -cp . WebServices.WSProvider
          在這個(gè)例子中會(huì)生成以下3個(gè)類的源代碼文件及class文件
          SayHi
          SayHiResponse
          PrintTime
          3.執(zhí)行如下代碼發(fā)布WSProvider到http://localhost:8888/chinajash/WSProvider,在這里可以執(zhí)行WSProvider類的main方法就可以
          Endpoint.publish("http://localhost:8888/chinajash/WSProvider",new WSProvider());
          4.在瀏覽器輸入http://localhost:8888/chinajash/WSProvider?wsdl就可以看到生成的WSDL文件,為了節(jié)省篇幅,這里就不把生成的WSDL文件貼上了,大家可以自己動(dòng)手試試.


          --------------------------------------------------------------------------------------------------------

          二、腳本語言支持    top

          JDK6增加了對(duì)腳本語言的支持(JSR 223),原理上是將腳本語言編譯成bytecode,這樣腳本語言也能享用Java平臺(tái)的諸多優(yōu)勢(shì),包括可移植性,安全等,另外,由于現(xiàn)在是編譯成bytecode后再執(zhí)行,所以比原來邊解釋邊執(zhí)行效率要高很多。加入對(duì)腳本語言的支持后,對(duì)Java語言也提供了以下好處。
          1、許多腳本語言都有動(dòng)態(tài)特性,比如,你不需要用一個(gè)變量之前先聲明它,你可以用一個(gè)變量存放完全不同類型的對(duì)象,你不需要做強(qiáng)制類型轉(zhuǎn)換,因?yàn)檗D(zhuǎn)換都是自動(dòng)的。現(xiàn)在Java語言也可以通過對(duì)腳本語言的支持間接獲得這種靈活性。
          2、 可以用腳本語言快速開發(fā)產(chǎn)品原型,因?yàn)楝F(xiàn)在可以Edit-Run,而無需Edit-Compile-Run,當(dāng)然,因?yàn)镴ava有非常好的IDE支持,我 們完全可以在IDE里面編輯源文件,然后點(diǎn)擊運(yùn)行(隱含編譯),以此達(dá)到快速開發(fā)原型的目的,所以這點(diǎn)好處基本上可以忽略。
          3、通過引入腳本語言可以輕松實(shí)現(xiàn)Java應(yīng)用程序的擴(kuò)展和自定義,我們可以把原來分布在在Java應(yīng)用程序中的配置邏輯,數(shù)學(xué)表達(dá)式和業(yè)務(wù)規(guī)則提取出來,轉(zhuǎn)用JavaScript來處理。

          Sun的JDK6實(shí)現(xiàn)包含了一個(gè)基于Mozilla Rhino的 腳本語言引擎,支持JavaScript,這并不是說明JDK6只支持JavaScript,任何第三方都可以自己實(shí)現(xiàn)一個(gè)JSR-223兼容的腳本引擎 使得JDK6支持別的腳本語言,比如,你想讓JDK6支持Ruby,那你可以自己按照J(rèn)SR 223的規(guī)范實(shí)現(xiàn)一個(gè)Ruby的腳本引擎類,具體一點(diǎn),你需要實(shí)現(xiàn)javax.script.ScriptEngine(簡(jiǎn)單起見,可以繼承javax.script.AbstractScriptEngine)和javax.script.ScriptEngineFactory兩個(gè)接口。當(dāng)然,在你實(shí)現(xiàn)自己的腳本語言引擎之前,先到scripting.dev.java.net project 這里看看是不是有人已經(jīng)幫你做了工作,這樣你就可以直接拿來用就行。

          Scripting API

          Scripting API是用于在Java里面編寫腳本語言程序的API, 在Javax.script中可以找到Scripting API,我們就是用這個(gè)API來編寫JavaScript程序,這個(gè)包里面有一個(gè)ScriptEngineManager類,它是使用Scripting API的入口,ScriptEngineManager可以通過jar服務(wù)發(fā)現(xiàn)(service discovery)機(jī)制尋找合適的腳本引擎類(ScriptEngine),使用Scripting API的最簡(jiǎn)單方式只需下面三步
          1、創(chuàng)建一個(gè)ScriptEngineManager對(duì)象
          2、通過ScriptEngineManager獲得ScriptEngine對(duì)象
          3、用ScriptEngine的eval方法執(zhí)行腳本

          下面是一個(gè)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    }    }運(yùn)行上面程序,控制臺(tái)會(huì)輸出Hello, Scripting上面這個(gè)簡(jiǎn)單的Scripting程序演示了如何在Java里面運(yùn)行腳本語言,除此之外,我們還可以利用Scripting API實(shí)現(xiàn)以下功能1、暴露Java對(duì)象為腳本語言的全局變量2、在Java中調(diào)用腳本語言的方法3、腳本語言可以實(shí)現(xiàn)Java的接口4、腳本語言可以像Java一樣使用JDK平臺(tái)下的類下面的類演示了以上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對(duì)象為腳本語言的全局變量         testInvokeScriptMethod(engine);//演示如何在Java中調(diào)用腳本語言的方法         testScriptInterface(engine);//演示腳本語言如何實(shí)現(xiàn)Java的接口         testUsingJDKClasses(engine);//演示腳本語言如何使用JDK平臺(tái)下的類    }        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是腳本語言里的一個(gè)全局變量,專用于訪問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中有一個(gè)命令行工具??jrunscript,你可以在<JDK6_Home>/bin下面找到這個(gè)工具,jrunscript是一個(gè)腳本語言的解釋程序,它獨(dú)立于腳本語言,但默認(rèn)是用JavaScript,我們可以用jrunscript來測(cè)試自己寫的腳本語言是否正確,下面是一個(gè)在命令行運(yùn)行jrunscript的簡(jiǎn)單例子
          jrunscript
          js>println("Hello,JrunScript");
          Hello,JrunScript
          js>9*8
          72.0
          js>

          --------------------------------------------------------------------------------------------------------

          三、嵌入式數(shù)據(jù)庫(kù)Derby    top


          Derby并不是一個(gè)新的數(shù)據(jù)庫(kù)產(chǎn)品,它是由IBM捐獻(xiàn)給Apache的DB項(xiàng)目的一個(gè)純Java數(shù)據(jù)庫(kù),JDK6.0里面帶的這個(gè)Derby的版本是10.2.1.7,支持存儲(chǔ)過程和觸發(fā)器;有兩種運(yùn)行模式,一種是作為嵌入式數(shù)據(jù)庫(kù),另一種是作為網(wǎng)絡(luò)數(shù)據(jù)庫(kù),前者的數(shù)據(jù)庫(kù)服務(wù)器和客戶端都在同一個(gè)JVM里面運(yùn)行,后者允許數(shù)據(jù)庫(kù)服務(wù)器端和客戶端不在同一個(gè)JVM里面,而且允許這兩者在不同的物理機(jī)器上.值得注意的是JDK6里面的這個(gè)Derby支持JDK6的新特性JDBC 4.0規(guī)范(JSR 221),現(xiàn)在我們?nèi)绻毩?xí)JDBC的用法,沒有必要單獨(dú)裝一個(gè)數(shù)據(jù)庫(kù)產(chǎn)品了,直接用Derby就行.安裝完JDK6.0后,Derby會(huì)被安裝到<JDK6_HOME>/db下面,在<JDK6_HOME>/db/demo/programs下面還有一些示例程序,演示了如何啟動(dòng),連接Derby數(shù)據(jù)庫(kù)以及JDBC API的使用.下面分兩種情況演示一下如何用代碼操作Derby數(shù)據(jù)庫(kù),一種是嵌入式數(shù)據(jù)庫(kù),一種是網(wǎng)絡(luò)數(shù)據(jù)庫(kù).

          一.嵌入式數(shù)據(jù)庫(kù)

           /**
           * @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表示當(dāng)數(shù)據(jù)庫(kù)不存在時(shí)就創(chuàng)建它
                  try {           
                      Class.forName(driver);
                      Connection conn = DriverManager.getConnection(dbURL);//啟動(dòng)嵌入式數(shù)據(jù)庫(kù)
                      Statement st = conn.createStatement();
                      st.execute("create table foo (FOOID INT NOT NULL,FOONAME VARCHAR(30) NOT NULL)");//創(chuàng)建foo表
                      st.executeUpdate("insert into foo(FOOID,FOONAME) values (1,'chinajash')");//插入一條數(shù)據(jù)
                      ResultSet rs = st.executeQuery("select * from foo");//讀取剛插入的數(shù)據(jù)
                      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();
                  }
              }
          }

          運(yùn)行上面程序后,會(huì)在當(dāng)前目錄生成名為EmbeddedDB的文件夾,既是EmbeddedDB數(shù)據(jù)庫(kù)的數(shù)據(jù)文件存放的地方,控制臺(tái)將輸出

          id=1;name=chinajash

          二.網(wǎng)絡(luò)數(shù)據(jù)庫(kù)

          /**
           * @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 {
                      /*
                       創(chuàng)建Derby網(wǎng)絡(luò)服務(wù)器,默認(rèn)端口是1527,也可以通過運(yùn)行
                       <Derby_Home>\frameworks\NetworkServer\bin\startNetworkServer.bat
                       來創(chuàng)建并啟動(dòng)Derby網(wǎng)絡(luò)服務(wù)器,如果是Unix,用startNetworkServer.ksh
                      */
                      NetworkServerControl derbyServer = new NetworkServerControl();//NetworkServerControl類在derbynet.jar里面
                      PrintWriter pw = new PrintWriter(System.out);//用系統(tǒng)輸出作為Derby數(shù)據(jù)庫(kù)的輸出
                      derbyServer.start(pw);//啟動(dòng)Derby服務(wù)器
                      Class.forName(driver);
                      DriverManager.getConnection(connectionURL);
                      //do something
                      derbyServer.shutdown();//關(guān)閉Derby服務(wù)器
                  } catch (Exception ex) {
                      ex.printStackTrace();
                  }
              }
          }

           運(yùn)行上面程序后,會(huì)在當(dāng)前目錄生成名為NetworkDB的文件夾

          關(guān)于Derby的詳細(xì)情況,請(qǐng)參考http://db.apache.org/derby


          ----------------------------------------------------------------------------------------------------

          四、在Java SE6(Mustang)中使用Desktop API    top

          伴隨著默認(rèn)的圖形用戶界面(GUI)的外觀,打印和性能,Java平臺(tái)在縮小平臺(tái)差異和整合本地程序與Java程序的道路上已經(jīng)走了很長(zhǎng)一段路。

          Java平臺(tái)標(biāo)準(zhǔn)版(Java SE)第6版,代號(hào)為Mustang(野馬),繼續(xù)用新增的系統(tǒng)托盤功能,對(duì)JTable更好的打印支持和現(xiàn)在的Desktop API

          (java.awt.Desktop)來填補(bǔ)這個(gè)空隙。本文描述了新的Desktop API,它們?cè)试SJava程序來和主機(jī)平臺(tái)與特定文件類型相關(guān)聯(lián)的默認(rèn)應(yīng)用程序進(jìn)

          行交互。為了更有效地描述這些API,本文也展示了一個(gè)簡(jiǎn)單的應(yīng)用程序DesktopDemo。
          Desktop 概述
          這個(gè)新功能是由java.awt.Desktop類提供的。這個(gè)API取自桌面綜合組件(JDIC)項(xiàng)目。這個(gè)項(xiàng)目的目標(biāo)是“使以Java技術(shù)為基礎(chǔ)的應(yīng)用程序成為

          桌面的一級(jí)公民”,實(shí)現(xiàn)無縫整合。特別的,新的Desktop API允許Java應(yīng)用程序?qū)崿F(xiàn)以下功能:
          1.通過一個(gè)指定的統(tǒng)一資源定位符(URI)啟動(dòng)主機(jī)系統(tǒng)的默認(rèn)瀏覽器
          2.啟動(dòng)主機(jī)系統(tǒng)的默認(rèn)郵件客戶端
          3.啟動(dòng)應(yīng)用程序來打開,編輯或打印和這些應(yīng)用程序相關(guān)聯(lián)的文件

          Desktop API使用主機(jī)操作系統(tǒng)的文件關(guān)聯(lián)來啟動(dòng)和特定文件類型相關(guān)聯(lián)的應(yīng)用程序。例如,如果OpenDocument text(.odt)文件擴(kuò)展名與

          OpenOffice Writer應(yīng)用程序相關(guān)聯(lián),你的Java應(yīng)用程序就能夠根據(jù)這個(gè)關(guān)聯(lián)啟動(dòng)OpenOffice Writer來打開,編輯或者甚至輸出.odt文件。依

          靠你的主機(jī)系統(tǒng),不同的應(yīng)用程序可能會(huì)和不同的動(dòng)作相關(guān)聯(lián)。

          運(yùn)行DesktopDemo應(yīng)用程序
          DesktopDemo是使用Mustang的Desktop API的一個(gè)簡(jiǎn)單應(yīng)用程序。這個(gè)程序有一個(gè)展示了完整API的主窗口,允許你做三件事:
          1.通過一個(gè)指定的URI啟動(dòng)默認(rèn)的瀏覽器
          2.通過一個(gè)郵件接收者啟動(dòng)默認(rèn)的郵件客戶端
          3.啟動(dòng)相關(guān)聯(lián)的應(yīng)用程序來打開,編輯或打印一個(gè)文件

          圖1顯示了用戶界面(UI)

          你可以通過下載源程序和JAR文件來運(yùn)行這個(gè)應(yīng)用程序,把控制臺(tái)轉(zhuǎn)到工程的dist目錄,在Mustang JDK環(huán)境下用以下的命令來運(yùn)行:
             java -jar DesktopDemo.jar

          判定對(duì)Desktop API的支持
          在啟動(dòng)瀏覽器,郵件客戶端或者任何應(yīng)用程序之前,DesktopDemo必須判定你的平臺(tái)是否支持Desktop API。首先,DesktopDemo會(huì)禁用所有的文

          本域和按鈕。它會(huì)在判定你的平臺(tái)支持它們以后再激活它們。
          在展示了用戶界面以后,應(yīng)用程序的構(gòu)造函數(shù)很快地用如下所示的代碼禁用了這個(gè)應(yīng)用程序的組件。
              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操作系統(tǒng)和Linux平臺(tái)上,這個(gè)API依賴于Gnome庫(kù)。如果這些庫(kù)不

          可用,這個(gè)方法會(huì)返回false。在判定了系統(tǒng)支持Desktop API,也就是isDesktopSupported()方法返回true時(shí),應(yīng)用程序就會(huì)使用一個(gè)靜態(tài)

          (static)方法getDesktop()重新獲得一個(gè)Desktop實(shí)例。
              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();
                  ...

          如果你的應(yīng)用程序沒有在調(diào)用getDesktop()方法之前用isDesktopSupported()方法檢查系統(tǒng)對(duì)API的支持,那就必須準(zhǔn)備捕捉

          UnsupportedOperationException異常,該異常會(huì)在你的應(yīng)用程序請(qǐng)求一個(gè)Desktop實(shí)例而平臺(tái)不支持的時(shí)候拋出。另外,如果你的應(yīng)用程序在

          一個(gè)沒有鍵盤,鼠標(biāo)或者監(jiān)聽器的環(huán)境(一個(gè)“無領(lǐng)導(dǎo)者”的環(huán)境)中運(yùn)行,getdesktop()方法會(huì)拋出一個(gè)java.awt.HeadlessException異常。

          一旦重新獲得,Desktop實(shí)例允許你的應(yīng)用程序?yàn)g覽,發(fā)郵件,打開、編輯甚至打印文件或者URI,只要重新獲得的Desktop實(shí)例支持這些動(dòng)作。

          每個(gè)這種動(dòng)作被稱為一個(gè)action,而每一個(gè)Desktop.Action枚舉實(shí)例代表一個(gè)action:
          BROWSE:代表一個(gè)通過主機(jī)瀏覽器執(zhí)行的瀏覽動(dòng)作
          MAIL:代表一個(gè)通過默認(rèn)郵件客戶端執(zhí)行的發(fā)郵件動(dòng)作
          OPEN:代表一個(gè)通過相關(guān)聯(lián)的應(yīng)用程序打開一種特定文件類型的打開動(dòng)作
          EDIT:代表一個(gè)通過相關(guān)聯(lián)的應(yīng)用程序編輯一種特定文件類型的編輯動(dòng)作
          PRINT:代表一個(gè)通過相關(guān)聯(lián)的應(yīng)用程序打印一種特定文件類型的打印動(dòng)作

          在調(diào)用這些動(dòng)作之前,應(yīng)用程序應(yīng)該判定Desktop實(shí)例是否支持它們。這和判定Desktop實(shí)例是否可用是不同的。Desktop.isDesktopSupported

          ()方法告訴我們能否創(chuàng)建一個(gè)實(shí)例。一旦獲得了一個(gè)Desktop對(duì)象,你可以查詢這個(gè)實(shí)例來找出支持哪些特定的動(dòng)作。如果Desktop對(duì)象不支持

          特定的動(dòng)作,或者Desktop API本身不被支持,DesktopDemo會(huì)簡(jiǎn)單地禁用受影響的那些圖形組件。如圖2所展示的,在禁用狀態(tài)下這些組件不能

          被用來調(diào)用Desktop功能。


          使用一個(gè)新的Desktop實(shí)例,下面的代碼檢查了每個(gè)Desktop.Action的支持情況并且激活了適當(dāng)?shù)膱D形組件:
              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);
                  }
              }

          一旦應(yīng)用程序判定了可支持的動(dòng)作,它會(huì)激活適當(dāng)?shù)膱D形組件。如果所有組件都被激活,用戶界面應(yīng)該如圖3所示:


          打開瀏覽器
          調(diào)用下面的實(shí)例方法會(huì)打開主機(jī)的默認(rèn)瀏覽器:
              public void browse(URI uri) throws IOException
          因?yàn)镈esktopDemo的用戶界面組件只有在Desktop.Action被支持的情況下才會(huì)被激活,所以這個(gè)簡(jiǎn)單的示例程序不需要在調(diào)用browse()方法之前

          再次檢查支持情況。然而,在實(shí)際應(yīng)用程序中,在每個(gè)調(diào)用之前檢查支持情況可能會(huì)使程序更加健壯:
              if (desktop.isSupported(Desktop.Action.BROWSE)) {
                  // launch browser
                  ...
              }

          DesktopDemo為每個(gè)按鈕添加了java.awt.event.ActionListener。當(dāng)被激活時(shí),Launch Browser按鈕會(huì)通過它的ActionListener調(diào)用如下方法


              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()方法會(huì)拋出多種異常,包括當(dāng)URI為空時(shí)拋出的NullPointerException,當(dāng)BROWSE動(dòng)作不被支持時(shí)拋出的

          UnsupportedOperationException,當(dāng)默認(rèn)瀏覽器或者應(yīng)用程序無法找到或者啟動(dòng)時(shí)拋出的IOException,以及當(dāng)安全管理器拒絕調(diào)用時(shí)拋出的

          SecurityException。

          如果進(jìn)展順利,監(jiān)聽器會(huì)從圖4中所示的相關(guān)聯(lián)的文本域中重新獲得文本,創(chuàng)建一個(gè)URI,然后調(diào)用browse()方法。上面的代碼啟動(dòng)了你系統(tǒng)上

          默認(rèn)的瀏覽器來加載URI,如圖5所示。


          發(fā)送郵件
          如果動(dòng)作被支持的話,應(yīng)用程序能夠啟動(dòng)主機(jī)的默認(rèn)郵件客戶端,通過調(diào)用Desktop的實(shí)例方法:
              public void mail(URI uri) throws IOException

          DesktopDemo有一個(gè)Launch Mail按鈕的ActionListener。在這種情況下,監(jiān)聽器調(diào)用如下方法:
              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()方法重新獲得和文本域相關(guān)的郵件接收者,如果接收者存在就使用mailto模式參數(shù)創(chuàng)建URI,然后調(diào)用mail()方法。mail()方法

          已經(jīng)被重載,因此你可以通過使用或者不使用代表mailto接收者的URI來調(diào)用它(見圖6)。

          你可以不僅僅使用一個(gè)簡(jiǎn)單郵件接收者來創(chuàng)建URI。mailto模式也支持CC,BCC,SUBJECT和BODY字段。例如,下面的文本可以被用來創(chuàng)建一個(gè)

          mailto URI。
              mailto:duke@sun.com?SUBJECT=Happy New Year!&BODY=Happy New Year, Duke!
          圖7顯示了結(jié)果:


          當(dāng)然,你也可以不使用參數(shù)調(diào)用mail()方法。在這種情況下,你的郵件客戶端將會(huì)啟動(dòng)一個(gè)新的沒有指定接收者、主題或者主體的郵件窗口。

          打開,編輯和打印一個(gè)文件
          Java應(yīng)用程序可以分別使用Desktop對(duì)象的open()、edit()、print()方法通過和文件相關(guān)聯(lián)的應(yīng)用程序打開、編輯和打印文件。(見圖8)而且,

          DesktopDemo只有在Desktop實(shí)例支持的情況下允許這些動(dòng)作,因此在這個(gè)應(yīng)用程序的設(shè)定中,沒有必要再檢查這些支持情況。


          每個(gè)DesktopDemo的單選按鈕也都有它們自己的ActionListener。在這種情況下,每個(gè)監(jiān)聽器設(shè)置一個(gè)實(shí)例變量的值來代表最近選擇的按鈕相關(guān)

          聯(lián)的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;
              }

          當(dāng)你按下Launch Default Application按鈕時(shí),它觸發(fā)它自己的監(jiān)聽器,調(diào)用如下方法:
              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();
                  }
                  ...
              }

          這個(gè)方法判定哪個(gè)Desktop.Action被選擇并且調(diào)用適當(dāng)?shù)腄esktop的實(shí)例方法,open(),edit()或者print()。每個(gè)方法要求一個(gè)File參數(shù)用來

          執(zhí)行被請(qǐng)求的動(dòng)作。

          有趣的是,在相同的文件類型上的不同動(dòng)作可能會(huì)被注冊(cè)為不同的應(yīng)用程序。例如,F(xiàn)irefox瀏覽器可能會(huì)執(zhí)行OPEN操作,Emacs執(zhí)行EDIT操作

          ,另一種不同的應(yīng)用程序執(zhí)行PRINT操作。你的主機(jī)桌面的關(guān)聯(lián)用來決定應(yīng)該調(diào)用哪個(gè)應(yīng)用程序。這種操作桌面文件關(guān)聯(lián)的能力對(duì)目前存在的

          Mustang中的Desktop API來說還不可能,這樣這些關(guān)聯(lián)就只能通過與平臺(tái)相關(guān)的工具來創(chuàng)建或改變了。

          摘要
          桌面整合是一個(gè)重要的Mustang主題。Mustang支持這個(gè)主題的一種方法是通過java.awt.Desktop API。這個(gè)API允許Java應(yīng)用程序啟動(dòng)主機(jī)的默

          認(rèn)的瀏覽器和郵件客戶端。另外,Java應(yīng)用程序能夠啟動(dòng)和文件相關(guān)的應(yīng)用程序來打開、編輯和打印文件。盡管Java應(yīng)用程序不能操作、創(chuàng)建

          或者改變文件關(guān)聯(lián),Desktop API允許Java應(yīng)用程序啟動(dòng)默認(rèn)的相關(guān)聯(lián)的應(yīng)用程序。這篇文章提供了一個(gè)示范這些API的示例程序,你可以從站

          點(diǎn)上下載這個(gè)程序。

          注意:任何Java SE平臺(tái)規(guī)范的增加或改進(jìn)由JSR 270專家組回顧和正式批準(zhǔn)。

          原文地址:http://java.sun.com/developer/technicalArticles/J2SE/Desktop/mustang/desktop_api/

          -----------------------------------------------------------------------------------------

          五、使用Compiler API    top

          現(xiàn)在我們可以用JDK6 的Compiler API(JSR 199)去動(dòng)態(tài)編譯Java源文件,Compiler API結(jié)合反射功能就可以實(shí)現(xiàn)動(dòng)態(tài)的產(chǎn)生Java代碼并編譯執(zhí)行這些代碼,有點(diǎn)動(dòng)態(tài)語言的特征。這個(gè)特性對(duì)于某些需要用到動(dòng)態(tài)編譯的應(yīng)用程序相當(dāng)有用, 比如JSP Web Server,當(dāng)我們手動(dòng)修改JSP后,是不希望需要重啟Web Server才可以看到效果的,這時(shí)候我們就可以用Compiler API來實(shí)現(xiàn)動(dòng)態(tài)編譯JSP文件,當(dāng)然,現(xiàn)在的JSP Web Server也是支持JSP熱部署的,現(xiàn)在的JSP Web Server通過在運(yùn)行期間通過Runtime.exec或ProcessBuilder來調(diào)用javac來編譯代碼,這種方式需要我們產(chǎn)生另一個(gè)進(jìn)程去做編譯工作,不夠優(yōu)雅而且容易使代碼依賴與特定的操作系統(tǒng);Compiler API通過一套易用的標(biāo)準(zhǔn)的API提供了更加豐富的方式去做動(dòng)態(tài)編譯,而且是跨平臺(tái)的。 下面代碼演示了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 {
                      //將產(chǎn)生的類文件拷貝到程序的ClassPath下面,下面這一行代碼是特定于Windows+I(xiàn)ntelliJ IDEA 6.0項(xiàng)目,不具有移植性
                      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();//創(chuàng)建動(dòng)態(tài)編譯得到的DynamicObject類的實(shí)例
                  } 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();
                  }
              }
          }

          程序運(yùn)行后,會(huì)產(chǎn)生DynamicObject.java和DynamicObject.class兩個(gè)文件,并在控制臺(tái)輸出

          In the constructor of DynamicObject

          --------------------------------------------------------------------------------

          六、輕量級(jí)Http Server     top

          JDK6提供了一個(gè)簡(jiǎn)單的Http Server API,據(jù)此我們可以構(gòu)建自己的嵌入式Http Server,它支持Http和Https協(xié)議,提供了HTTP1.1的部分實(shí)現(xiàn),沒有被實(shí)現(xiàn)的那部分可以通過擴(kuò)展已有的Http Server API來實(shí)現(xiàn),程序員必須自己實(shí)現(xiàn)HttpHandler接口,HttpServer會(huì)調(diào)用HttpHandler實(shí)現(xiàn)類的回調(diào)方法來處理客戶端請(qǐng)求,在這里,我們把一個(gè)Http請(qǐng)求和它的響應(yīng)稱為一個(gè)交換,包裝成HttpExchange類,HttpServer負(fù)責(zé)將HttpExchange傳給HttpHandler實(shí)現(xiàn)類的回調(diào)方法.下面代碼演示了怎樣創(chuàng)建自己的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);//設(shè)置HttpServer的端口為8888
                      hs.createContext("/chinajash", new MyHandler());//用MyHandler類內(nèi)處理到/chinajash的請(qǐng)求
                      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();
             }
          }

          運(yùn)行程序后,在瀏覽器內(nèi)輸入http://localhost:8888/chinajash,瀏覽器輸出

          Happy New Year 2007!--Chinajash

          -------------------------------------------------------------------------------------------

          七、用Console開發(fā)控制臺(tái)程序    top

          JDK6中提供了java.io.Console類專用來訪問基于字符的控制臺(tái)設(shè)備. 你的程序如果要與Windows下的cmd或者Linux下的Terminal交互,就可以用Console類代勞. 但我們不總是能得到可用的Console, 一個(gè)JVM是否有可用的Console依賴于底層平臺(tái)和JVM如何被調(diào)用. 如果JVM是在交互式命令行(比如Windows的cmd)中啟動(dòng)的,并且輸入輸出沒有重定向到另外的地方,那么就可以得到一個(gè)可用的Console實(shí)例. 下面代碼演示了Console類的用法:

          /**
           * @author chinajash
           */
          public class ConsoleTest {
             
              public static void main(String[] args) {
                  Console console = System.console();//獲得Console實(shí)例
                  if(console!=null){//判斷console是否可用
                      String user = new String(console.readLine("Enter user:")); //讀取整行字符
                      String pwd = new String(console.readPassword("Enter passowrd:")); //讀取密碼,密碼輸入時(shí)不會(huì)顯示
                      console.printf("User is:"+user+"\n");
                      console.printf("Password is:"+pwd+"\n");
                  }else{
                      System.out.println("Console is unavailable");
                  }
              }
          }

          如果在NetBean5.5里面運(yùn)行上面程序,會(huì)輸出

          Console is unavailable

          表示Console不可獲得,那是因?yàn)镴VM不是在命令行中被調(diào)用的或者輸入輸出被重定向了. 但是如果我們?cè)诿钚兄羞\(yùn)行上面程序(java ConsoleTest),程序能夠獲得Console實(shí)例,并執(zhí)行如下:

          Enter user:chinajash
          Enter passowrd:
          User is:chinajash
          Password is:chinajash

          在這里可以看到輸入密碼時(shí),控制臺(tái)時(shí)不顯示這些密碼字符的,但是程序可以得到輸入的密碼字符串,這與Linux下面輸入密碼的情況是一樣的


           

          posted on 2007-05-31 12:29 hyq 閱讀(965) 評(píng)論(0)  編輯  收藏 所屬分類: java

          只有注冊(cè)用戶登錄后才能發(fā)表評(píng)論。


          網(wǎng)站導(dǎo)航:
           
          主站蜘蛛池模板: 陕西省| 石景山区| 平果县| 平潭县| 庆云县| 阿拉尔市| 临夏县| 剑河县| 礼泉县| 精河县| 稷山县| 承德市| 泰安市| 石狮市| 樟树市| 靖宇县| 舞钢市| 嫩江县| 丰台区| 南木林县| 武定县| 吉安市| 迁西县| 拜城县| 龙州县| 安平县| 德格县| 玉田县| 南澳县| 萝北县| 阳春市| 手游| 乾安县| 达尔| 灵璧县| 那坡县| 吴旗县| 武邑县| 新宾| 浑源县| 南汇区|