.Net 與 J2EE/Java Web Service 互操作完整實(shí)例
實(shí)現(xiàn)支持文件分塊多點(diǎn)異步上傳的 J2EE/Java Web Services 及其 .Net 非 Web 客戶端應(yīng)用程序異步上傳
本文參考:
實(shí)現(xiàn)支持文件分塊多點(diǎn)異步上傳的 Web Services 及其客戶端(非Web)應(yīng)用程序調(diào)用相關(guān)異步執(zhí)行的 Web Method
http://blog.csdn.net/playyuer/archive/2004/12/11/213069.aspx
升級到 JDK 5.0 Update 1 or 2 定制部署 WebServices - Axis 終于正常了!
http://blog.csdn.net/playyuer/archive/2005/03/01/306360.aspx
為了使程序及環(huán)境簡潔,本文均使用最簡陋的 NotePad 編寫程序或配置環(huán)境,命令行編譯程序!
不使用任何集成開發(fā)環(huán)境(IDE)!
相關(guān)源程序下載:
http://www.cnblogs.com/Files/Microshaoft/jws.net.rar
Sever Side:
采用 Resin/Tomcat + Axis 來部署 java Web Service。
1.首先確認(rèn) Windows 系統(tǒng)中安裝(不一定要安裝,解壓到目錄即可)了如下軟件:
J2SE(TM) Development Kit 5.0 Update 4 (JDK 5.0 Update 4):
http://java.sun.com/j2se/1.5.0/download.jsp
Web Application Server: Resin/Tomcat 二者有其一即可:
Resin v2.1.16:
http://www.caucho.com/download/resin-2.1.16.zip
Tomcat v5.5.9:
http://apache.justdn.org/jakarta/tomcat-5/v5.5.9/bin/jakarta-tomcat-5.5.9.zip
下載后解壓到某目錄,如:
D:\dotNet.J2EE\resin-2.1.16\
或
D:\dotNet.J2EE\jakarta-tomcat-5.5.9\
Web Services - Axis
http://apache.freelamp.com/ws/axis/1_2_1/axis-bin-1_2_1.zip
下載后解壓到某目錄,如:
D:\dotNet.J2EE\axis-1_2_1\
然后將該目錄下的 webapps 下的 axis 子目錄,復(fù)制到:
D:\dotNet.J2EE\resin-2.1.16\webapps\
或
D:\dotNet.J2EE\jakarta-tomcat-5.5.9\webapps\
即生成如下路徑:
D:\dotNet.J2EE\resin-2.1.16\webapps\axis\
或
D:\dotNet.J2EE\jakarta-tomcat-5.5.9\webapps\axis\
至此就具備運(yùn)行 Axis 的基本條件了:
先做一下 Java Web Application Server 端口配置到 1080:
(如果你的端口不沖突,可以跳過此步)
Resin:
D:\Resin\resin-2.1.16\conf\resin.conf
<!-- the http port -->
<http port='1080'/>
Tomcat:
D:\dotNet.J2EE\jakarta-tomcat-5.5.9\conf
<!-- Define a non-SSL HTTP/1.1 Connector on port 8080 -->
<Connector port="1080" maxHttpHeaderSize="8192"
maxThreads="150" minSpareThreads="25" maxSpareThreads="75"
enableLookups="false" redirectPort="8443" acceptCount="100"
connectionTimeout="20000" disableUploadTimeout="true" />
然后,啟動 Java Web Application Server:
Resin:
D:\dotNet.J2EE\resin-2.1.16\bin\httpd.exe
Tomcat:
(啟動 Tomcat 要預(yù)先配置 JAVA_HOME 環(huán)境變量)
D:\dotNet.J2EE\jakarta-tomcat-5.5.9\bin\start.bat
用 IE 訪問:
http://localhost:1080/axis/
應(yīng)該看到:
Apache-AXIS 主頁
點(diǎn)擊超鏈接:
Validation - Validate the local installation's configuration
see below if this does not work.
訪問頁面:
http://localhost:1080/axis/happyaxis.jsp
就可以檢測當(dāng)前環(huán)境是否滿足運(yùn)行 Apache-AXIS。
根據(jù)頁面提示下載到所有 zip 文件:
http://192.18.97.238/ECom/EComTicketServlet/BEGIN8656005BAB2BAA9A4B1688FB7D4AF765/-2147483648/972910143/1/359918/359906/972910143/2ts+/westCoastFSEND/7017-jaf-1.0.2-oth-JPR/7017-jaf-1.0.2-oth-JPR:1/jaf-1_0_2-upd2.zip
http://192.18.97.186/ECom/EComTicketServlet/BEGIN87ACAEFABC9A644DBEC89773E476BF24/-2147483648/972928407/1/540782/540770/972928407/2ts+/westCoastFSEND/javamail-1_3_2-oth-JPR/javamail-1_3_2-oth-JPR:1/javamail-1_3_2-upd.zip
http://xml.apache.org/security/dist/java-library/xml-security-bin-1_2_1.zip
各自解壓后得到所需所有 jar 包文件:
activation.jar
axis-ant.jar
axis.jar
commons-discovery-0.2.jar
commons-logging-1.0.4.jar
commons-logging-api.jar
commons-logging.jar
imap.jar
jaxrpc.jar
log4j-1.2.8.jar
mail.jar
mailapi.jar
pop3.jar
saaj.jar
smtp.jar
tt.txt
wsdl4j-1.5.1.jar
xalan.jar
xercesImpl.jar
xml-apis.jar
xmlsec-1.2.1.jar
xmlsecSamples-1.2.1.jar
xmlsecTests-1.2.1.jar
將這些文件全部復(fù)制到如下目錄:
D:\dotNet.J2EE\resin-2.1.16\webapps\axis\WEB-INF\lib
或
D:\dotNet.J2EE\jakarta-tomcat-5.5.9\webapps\axis\WEB-INF\lib
再次訪問:
http://localhost:1080/axis/happyaxis.jsp
以驗(yàn)證是否完全滿足運(yùn)行 Apache-AXIS 的環(huán)境,
如無錯誤就說明已經(jīng)配置好服務(wù)器了!
2.編寫 Java Web Service 程序:
其實(shí)實(shí)現(xiàn) Web Service 的 Java 類沒啥特殊的,
下面程序就是:
實(shí)現(xiàn)支持文件分塊多點(diǎn)異步上傳的 Java Web Services (Server Side)
//=========================================================================

/**//*
Class1.jws
Class1.java
javac Class1.java
java -cp %axis_lib%;%classpath%;. org.apache.axis.client.AdminClient deploy.wsdd -p1080
*/
import java.io.*;
import java.lang.*;

public class Class1


{
public static void main(String[] args)

{
System.out.println("Hello World!");
}
public String SayHelloTo(String Who)

{
return "你好: " + Who;
}
public String SayHelloToo(String Who)

{
return "你好: " + Who;
}
public String UploadFileBytes(byte[] Bytes,String FileName)
throws Exception

{
return UploadFileChunkBytes(Bytes, 0, FileName);
}
public String UploadFileChunkBytes(byte[] Bytes,int Position,String FileName)
throws Exception

{
//"d:\\Server\\Upload\\" 為服務(wù)器端路徑
String ServerPath = "d:\\Server\\Upload\\";
java.io.RandomAccessFile raf = new java.io.RandomAccessFile(ServerPath + FileName,"rws");
raf.skipBytes(Position);
raf.write(Bytes);
//該 Bytes 的字節(jié)要寫到 服務(wù)器端 相應(yīng)文件的從 Position 開始的字節(jié)
raf.close();

raf = null;
System.gc();
return FileName + " 文件塊: 位置[" + Position + "," + (Position + Bytes.length) + "] 大小(" + Bytes.length + ") 上傳成功!";
}
public String CreateBlankFile(String FileName,int Length) //建議由客戶端同步調(diào)用
throws Exception

{
//"d:\\Server\\Upload\\" 為服務(wù)器端路徑
String ServerPath = "d:\\Server\\Upload\\";
FileOutputStream fos = new FileOutputStream(ServerPath + FileName);
fos.write(new byte[Length], 0, Length);
fos.close();
fos = null;
System.gc() ;
return FileName + " (" + Length + ") 空白文件已經(jīng)創(chuàng)建!";
}

public byte[] DownloadFileBytes(String FileName)
throws Exception

{
File f = new File(FileName);
FileInputStream fis = new FileInputStream(f);
int i = (int) f.length();
byte[] b = new byte[i];
fis.read(b,0,i);
fis.close();
fis = null;
f = null;
System.gc() ;
return b;
}
}
//=========================================================================
如果上面程序存為: Class1.jws 文件,直接復(fù)制到:
D:\dotNet.J2EE\resin-2.1.16\webapps\axis\Class1.jws
或
D:\dotNet.J2EE\jakarta-tomcat-5.5.9\webapps\axis\Class1.jws
即可通過 IE 直接訪問如下 URL 地址:
http://localhost:1080/axis/Class1.jws
這就如同 .Net Web Service .asmx 的前代碼方式
接下來著重介紹一下定制部署 Java Web Service
將上面程序存為: Class1.java 文件,并用如下命令行編譯:
javac.exe Class1.java
生成的 Class1.class 文件復(fù)制到:
D:\dotNet.J2EE\resin-2.1.16\webapps\axis\WEB-INF\classes\Class1.class
或
D:\dotNet.J2EE\jakarta-tomcat-5.5.9\webapps\axis\WEB-INF\classes\Class1.class
編寫部署文件
deploy.wsdd (undeploy.wsdd):
<deployment xmlns="http://xml.apache.org/axis/wsdd/" xmlns:java="http://xml.apache.org/axis/wsdd/providers/java">
<service name="Class1Service" provider="java:RPC">
<parameter name="className" value="Class1"/>
<parameter name="allowedMethods" value="*"/>
</service>
</deployment>
在通過如下命令行部署該 Web Service ,此時 Java Web Application Server 應(yīng)已經(jīng)運(yùn)行:
java -cp %axis_lib%;%classpath%;. org.apache.axis.client.AdminClient deploy.wsdd -p1080
如果部署成功屏幕將會輸出:
Processing file deploy.wsdd
<Admin>Done processing</Admin>
如果在 Resin 上部署失敗,可在:
D:\Resin\resin-2.1.16\conf\resin.conf
中:
<war-dir id='webapps'/>
后添加如下配置:
<!-- for Axis -->
<system-property javax.xml.transform.TransformerFactory = "org.apache.xalan.processor.TransformerFactoryImpl" />
<system-property javax.xml.parsers.DocumentBuilderFactory = "org.apache.xerces.jaxp.DocumentBuilderFactoryImpl" />
<system-property javax.xml.parsers.SAXParserFactory = "org.apache.xerces.jaxp.SAXParserFactoryImpl" />

<system-property org.xml.sax.driver = "org.apache.xerces.parsers.SAXParser" />

Tomcat 上暫沒發(fā)現(xiàn)上面部署失敗問題!
部署成功后,在下面文件:
D:\dotNet.J2EE\resin-2.1.16\webapps\axis\WEB-INF\server-config.wsdd
或
D:\dotNet.J2EE\jakarta-tomcat-5.5.9\webapps\axis\WEB-INF\server-config.wsdd
中,已經(jīng)被自動添加如下配置:
<service name="Class1Service" provider="java:RPC">
<parameter name="allowedMethods" value="*"/>
<parameter name="className" value="Class1"/>
</service>
當(dāng)然也可以手工直接填寫配置 server-config.wsdd 而不使用命令行工具!
至此如不出意外 java Web Service 已經(jīng)部署完畢!
Client Side:
http://localhost:1080/axis/services/Class1Service?wsdl
已經(jīng)可以正常訪問!
java Client:
還可以用解壓 axis-bin-1_2_1.zip 后:
D:\dotNet.J2EE\axis-bin-1_2_1\axis-1_2_1\samples\client\DynamicInvoker.java
用如下命令行編譯后:
javac -cp %classpath%;%axis_lib%;. -Xlint:unchecked DynamicInvoker.java
生成 DynamicInvoker.class,
再如下命令行運(yùn)行:
java -cp %axis_lib%;%classpath%;. DynamicInvoker http://localhost:1080/axis/services/Class1Service?wsdl SayHelloTo 小平
其中 %axis_lib% 為環(huán)境變量! 其中 %classpath% 為環(huán)境變量!
測試如果正常則輸出:
Reading WSDL document from 'http://localhost:1080/axis/services/Class1Service?wsdl'
Preparing Axis dynamic invocation
Executing operation SayHelloTo with parameters:
in0=小平
SayHelloToReturn=你好: 小平

Done!
.Net Client:
先用如下命令生成代理類的程序 C# 代碼:
% Visual Studio .Net 2003 安裝目錄下的 %\SDK\v1.1\Bin\wsdl.exe
具體命令行如下:
wsdl.exe /l:CS /out:Class1ServiceProxy.cs http://localhost:1080/axis/services/Class1Service?wsdl
然后用如下命令編譯生成程序集: Class1ServiceProxy.dll
csc /t:library Class1ServiceProxy.cs
using System;
using System.IO;

public class Class1


{
static void Main(string[] args)

{
//Download(ServerSidepath, ClientSidePath)
//Download(@"客戶端本地路徑", @"服務(wù)器端路徑");
Download(@"d:\server\download\editplus.rar", @"e:\download_editplus.rar");
System.Console.WriteLine("down End");

System.Console.WriteLine("同步 up file exec
");
UploadFile(@"d:\Northwind.mdb");
System.Console.WriteLine("同步 up file End\n");

System.Console.WriteLine("異步 up chunks exec
");
UploadFileChunks(@"d:\editplus.rar", 64);
System.Console.ReadLine();
}

public static void UploadFile(string LocalFileName)

{
Class1Service xx = new Class1Service();
FileStream fs = new FileStream(LocalFileName, FileMode.Open); //Client Side Path
byte[] buffer = new byte[fs.Length];
fs.Read(buffer, 0, buffer.Length);
//調(diào)用 "同步執(zhí)行" 的本地 Web Sevices 代理類的 方法,相當(dāng)于同步調(diào)用了 Web Method !
xx.UploadFileBytes(buffer, System.IO.Path.GetFileName(LocalFileName));
}

//指定要上傳的本地文件的路徑,及每次上傳文件塊的大小
public static void UploadFileChunks(string LocalFileName,int ChunkSize)

{
Class1Service xx = new Class1Service();
string filename = System.IO.Path.GetFileName(LocalFileName);

FileStream fs = new FileStream(LocalFileName, FileMode.Open); //Client Side Path
//fs = File.OpenRead(LocalFileName);

int r = (int) fs.Length; //用于記錄剩余還未上傳的字節(jié)數(shù),初值是文件的大小

//調(diào)用 "同步執(zhí)行" 的本地 Web Sevices 代理類的 方法,相當(dāng)于同步調(diào)用了 Web Method !
//預(yù)定服務(wù)器端空間
xx.CreateBlankFile(filename,r);
int size = ChunkSize * 1024;
int k = 0; //用于記錄已經(jīng)上傳的字節(jié)數(shù)
i++; //用于記錄上傳的文件塊數(shù)
while (r >= size)

{
byte[] buffer = new byte[size];
fs.Read(buffer,0,buffer.Length);
//調(diào)用 "異步執(zhí)行" 的本地 Web Sevices 代理類的 方法,相當(dāng)于異步調(diào)用了 Web Method !
//該 buffer 的字節(jié)要寫到 服務(wù)器端 相應(yīng)文件的從 Position = k 開始的字節(jié)
xx.BeginUploadFileChunkBytes(buffer,k,filename,new AsyncCallback(UploadFileChunkCallback),xx);
k += size;
r -= size;
i++;
}
if (r > 0) //剩余的零頭

{
byte[] buffer = new byte[r];
fs.Read(buffer,0,buffer.Length);
//調(diào)用 "異步執(zhí)行" 的本地 Web Sevices 代理類的 方法,相當(dāng)于異步調(diào)用了 Web Method !
//該 buffer 的字節(jié)要寫到 服務(wù)器端 相應(yīng)文件的從 Position = k 開始的字節(jié)
xx.BeginUploadFileChunkBytes(buffer,k,filename,new AsyncCallback(UploadFileChunkCallback),xx);
i++;
}
fs.Close();

}

private static int i = -1; //用于記錄上傳的文件塊數(shù)

private static void UploadFileChunkCallback(IAsyncResult ar)

{
Class1Service x = (Class1Service) ar.AsyncState;
Console.WriteLine(x.EndUploadFileChunkBytes(ar));
if ( --i == 0)

{
Console.WriteLine("異步 up all chunks end");
}
}

public static void Download(string ServerSideFileName,string LocalFileName)

{
Class1Service xx = new Class1Service();
byte[] b = xx.DownloadFileBytes(ServerSideFileName); //Server Side Path

FileStream fs = new FileStream(LocalFileName, FileMode.Create); //Client Side Path
fs.Write(b,0,b.Length);
fs.Close();
}
}
然后用如下命令編譯生成程序集: Class1ServiceClient.exe
csc Class1ServiceClient.cs /r:Class1ServiceService.dll
運(yùn)行 Class1ServiceClient.exe 即可!
運(yùn)行結(jié)束后請檢查 D:\Server\Upload\ 目錄中是否已有文件上床!