一、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="http://blog.csdn.net/chinajash",serviceName="HelloService")
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下面输入密码的情况是一样的