JWorld@TW the best professional Java site in Taiwan
      註冊 | 登入 | 全文檢索 | 排行榜  

» JWorld@TW » Java & XML、Web Service » Web Services  

按列印兼容模式列印這個話題 列印話題    把這個話題寄給朋友 寄給朋友    訂閱主題
reply to topicthreaded modego to previous topicgo to next topic
本主題所含的標籤
無標籤
作者 Programming in C#(.NET) and Java Web Services [精華]
saijone

Web Services

版主

發文: 470
積分: 24
於 2003-09-22 04:20 user profilesend a private message to userreply to postreply to postsearch all posts byselect and copy to clipboard. 
ie only, sorry for netscape users:-)add this post to my favorite list
WebServices 已成為 .NET 及 J2EE 發展的重點項目之一
本文將就 Programmig model, 也就是以一般 Programmer/Developer 的角度,
來介紹在.NET 及 JAVA 兩種環境下撰寫 WebServices 程式的差異.

在 .NET 的環境底下, 可以用 VB, C#, J# 以及所有
.NET CLR(Common Language Runtime) 所支援的 Programming Langue
來發展 WebServices. 本文 .NET 的範例以 C# 寫成, JAVA方面則以
JSR-101(JAX-RPC) v1.1 及 JSR109(WebServices for J2EE) v1.1的標準 API 為基礎
透過下列主題來比較並介紹在兩種發展環境下WebServices 程式的撰寫:

1. Hello Web Service
2. State and Session Management
3. Operation Style (Document/RPC) and Message format(literal/encoded)
4. Value Type to XML Mapping/Binding
5. SOAP Header
6. Asynchronous Operation

本文改編及翻譯自筆者一年多之前作的一個 presentation, 當時 JAX-PRC
還不到1.1, 如有誤落或不合時宜之處請多加指正.


saijone edited on 2003-09-23 12:33
reply to postreply to post
You don't need a reason to help people
作者 Hello Web Service [Re:saijone]
saijone

Web Services

版主

發文: 470
積分: 24
於 2003-09-22 11:48 user profilesend a private message to userreply to postreply to postsearch all posts byselect and copy to clipboard. 
ie only, sorry for netscape users:-)add this post to my favorite list
Hello Web Service

不論是在 .NET 或 Java, 一個 WebService Class與一般的 Class 基本上沒有太大差
異. 在 .NET 中, 最明顯的就是 Metadata/Attribute 的使用. 就以一最簡單的
Hollo Web Service 為例:
1
2
3
4
5
6
7
8
C#
using System.Web.Services;
public class Hello{
    [ WebMethod ]
    public string SayHey() {
        return “Hello”;
    }
}

Method SayHey() 上頭的 [ WebMethod ] 就是這個 method 的 Attribute (Metadata
Annotation). 意味著這個 method 將可以透過 "Web"來溝通.
也就是說這個 method 會對應到一個 WSDL Operation.

註: WSDL 可以說是一個 WebSerivce 的介面(Interface), 以XML的格式呈現,
一般來說, 由WebService Tool/Platform自動產生.

Annotation的使用可以說是"目前".NET 與 Java 在Programmming上的主要差異.
在 Java(JAX-RPC) 中我們用一個 interface 來定義哪幾個 method 要成為
WSDL Operation.
JAX-RPC 要求這個interface 必須要 extend java.rmi.Remote.
(並且每個method 要throws java.rmi.RemoteException),
在JSR109(J2EE WebServices)中這樣的 interface 叫
Service Endpoint Interface (SEI):
1
2
3
4
5
package hello;
public interface Hello extends java.rmi.Remote {
    public String sayHey() throws
        java.rmi.RemoteException;
}

然後我們根據這個 SEI 發展出 implementaion.
只有在 SEI 上宣告的 method 才會成為 WSDL上的 Operation.
在 J2EE 平台上, JSR109 允許 implementaion class 可以不用 implement SEI,
但必須提供所有 method signature 相同的 methods.
1
2
3
4
5
6
7
package hello;
public class HelloImpl implements Hello {
    public String sayHey() throws
        java.rmi.RemoteException {
        return "Hey!";
    }
}

在不久的未來, Java 也將會支援 Metadata:
JSR-175(Metadata Facility for the JavaTM Programming Language)
將為Java 加入 Metadata Attributes 的支援.

JSR-181 Web Services Metadata (lead by BEA)定義了 WebServices Specific Attributes
然而這些很可能也成為JSR-224 JAX-RPC 2.0(lead by SUN) 的一部分
1
2
3
4
5
6
7
package hello;
@WebService public class Hello {
    @Remote  public String sayHey() throws
        java.rmi.RemoteException {
        return "Hey!";
    }
}


reply to postreply to post
You don't need a reason to help people
作者 State and Session Management [Re:saijone]
saijone

Web Services

版主

發文: 470
積分: 24
於 2003-09-22 11:50 user profilesend a private message to userreply to postreply to postsearch all posts byselect and copy to clipboard. 
ie only, sorry for netscape users:-)add this post to my favorite list
State and Session Management

在.NET 上, 一個 WebService Class 可以 extend System.Web.Services.WebService
來繼承使用一些ASP.NET objects: Application, Session, User, and Context
Application可以用來儲存整個 Application 的 state objects.
Session可以用來儲存每一個 Session 單獨的 state objects.
1. 紀錄ServiceUsage() 總共被用了幾次
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
C#
using System.Web.Services;
public class Usage : WebService {
    [WebMethod(Description="Number of times this service has been accessed.")]
    public int ServiceUsage() {
        if (Application["appMyServiceUsage"] == null){
            Application["appMyServiceUsage"] = 1;
        } else {
            Application["appMyServiceUsage"] =
            ((int) Application["appMyServiceUsage"]) + 1;
    }
    return (int)Application["appMyServiceUsage"];
    }}

2. 紀錄PerSessionServiceUsage() 在一個client session 中總共被用了幾次
1
2
3
4
5
6
7
8
9
10
11
12
13
14
C#
using System.Web.Services;
public class Usage : WebService {
    [WebMethod(Description="Number of times ...", EnableSession=true)]
    public int PerSessionServiceUsage() {
        if (Session["MyServiceUsage"] == null) {
            Session["MyServiceUsage"] = 1;
        } else {
            Session["MyServiceUsage"] =
                ((int) Session["MyServiceUsage"]) + 1;
        }
        return (int) Session["MyServiceUsage"];
    }
}


在Java上, 一個 WebService Endpoint Implementation Class 可以 implement
javax.xml.rpc.server.ServiceLifecycle interface 的方式來得到 ServiceContext
的支援:
1
2
3
4
public interface ServiceLifecycle {
    void init(Object context)  throws ServiceException;
    void destroy();
}

如果這一個 Java WebService Endpoint 是部署在的 Servlet container based
的JAXRPC runtime system上的話, init 帶的參數 context 便會是一個
javax.xml.rpc.server.ServletEndpointContext 的 instance,
透過 ServletEndpointContext, 你便可以取得
javax.servlet.http.HttpSession 及 javax.servlet.ServletContext:
1
2
3
4
5
6
7
8
9
10
11
12
13
public class Hello implements ServiceLifecycle {
    private ServletEndpointContext servletEndpointContext;
    public void init(Object context) throws ServiceException {
        servletEndpointContext = (ServletEndpointContext)context;
    }
    public String sayHey(String str) throws
        javax.servlet.http.HttpSession session =
            context.getHttpSession();
        javax.servlet.ServletContext servletContext =    
            context.getServletContext();
        ...
    }
}

然而, Session or Conversational State, 這個在WebService被認為所應具備的基本功
能上, 最主要的問題在於如何傳達 Session 的 id 以及所存在的位置, 你或許會很直觀
的認為, 既然是"Web"那當然就是 cookie, HTTP header. 目前.NET 以及一些 Java
WebServices Platform 是以 Cookie 的方式. 但是 cookie, HTTP header都是
HTTP specific, 只有 HTTP 才有的東西, 限制了WebService只能以SOAP on HTTP
的方式溝通. 但是不是也可以SOAP on SMTP 甚至 SOAP on JMS 呢?
那麼在這些以外的transport mechanism上, 是不是又要重新 implement 一套
Session 的方式呢?

比較根本的解決之道, 便是將 Session or Conversational State 這些
Service Context Information 以 XML 的格式直接寫在 SOAP message 中
(SOAP Header).

Axis 便是以 HTTP cookies 及 transport-independent SOAP headers 兩種方式
來支持 session-oriented services 但是這樣的 SOAP header 目前尚無標準化, 會有
interoperability的問題, 目前可能很難做到讓一個 Session 從 .NET 延伸到 J2EE 的
WebServices上.


saijone edited on 2003-12-15 11:04
reply to postreply to post
You don't need a reason to help people
作者 Operation Style (Document/RPC) and Message format(literal/encoded) [Re:saijone]
saijone

Web Services

版主

發文: 470
積分: 24
於 2003-09-22 11:51 user profilesend a private message to userreply to postreply to postsearch all posts byselect and copy to clipboard. 
ie only, sorry for netscape users:-)add this post to my favorite list
Operation Style (Document/RPC) and Message format(literal/encoded)

在WSDL 1.1中, 允許兩種定義 message part 格式的方式:

1. encoded: 利用'encodingStyle'(通常是Namespace URI來表示)來作為
xml message part與後端相對應物件之間 mapping 的 typing system.
目前泛用的標準是 SOAP1.1 的http://schemas.xmlsoap.org/soap/encoding/

2. literal: 利用 XML Schema 來定義 message part 的結構及 typing.

WSDL 1.1 中定義了兩種 WebSerivce Operation 的型式: RPC 及 Document.

1. RPC (Remote Proceduce Call): 功能與 Java 中的RMI 相似, 在 SOAP Request
Message 的SOAP Body 中, 第一個 sub-element 必須與 operation 同名 (Response
的SOAP Body 中, 第一個 sub-element 則命名為 operation-name + "Response" ),
這個Operation element內包 parameter/return-value 對應的 xml element:
1
2
3
4
5
6
 <SOAP:Body>
  <rpc-operation>
   <message-part-1><!-- mapped to a parameter-- >
   <message-part-2><!-- mapped to a parameter-- >
  </rpc-operation>
 </SOAP:Body>


2. Document: 最主要的目的個人認為是在 messaging oriented document exchange.
由於是 document-oriented Service 或 messaging-oriented Service, "operation" 的感
覺較弱所以WSDL1.1 spec 允許這種 operation 的 SOAP Body 可以直接帶 message
part, 不用跟一個 operation element:
1
2
3
4
 <SOAP:Body>
  <message-part-1> ...
  <message-part-2> ...
 </SOAP:Body>

然而, 以目前來說, 不管是.NET 或 JAVA, 並沒有將這兩種 operation 的實作方式明顯
的區分, 一搬來說, 不管是 RPC Operation 亦或是 Document Operation, 後端都是以
一個 Method 來實作, 本質上都是 RPC.

Oracle 及 BEA 的 WebServices 產品也提供將一個 document style
one-way operation 對應到一個 JMS destination.

由於WSI-Basi Profile 1.0 (BP) 要求 document style 的SOAP message只能有一個
message part binding(所以像上面的例子是不被BP允許的), .NET 及 JAX-RPC1.1
將所有的 parameter part 包到一個 operation wrapper element 如同 RPC 的格式一樣:
1
2
3
4
5
6
 <SOAP:Body>
  <document-operation-wrapper-message-part>
   <sub-element-1><!-- mapped to a parameter-- >
   <sub-element-1><!-- mapped to a parameter-- >
  </document-operation-wrapper-message-part>
 </SOAP:Body>


一般的 WebServices Platfrom 都會支援 rpc-encoded, rpc-literal, 以及
document-literal 三種組合. 然而在 WSI-Basic Profile 1.0中, 明定要達到
Interoperability 必須是 literal. 在 .NET 上, 以兩個 Attribute (metadata) 來決定
Operation Style 及 message format:
1
2
3
4
5
6
7
8
9
10
11
12
C#
[SoapRpcMethodAttribute( "http://foo.com/Rpc",
    RequestNamespace="http://foo.com",
    ResponseNamespace="http://foo.com")]
public Address Rpc(Address address, bool useZipPlus4) { …
 
[SoapDocumentMethod("http://foo.com/DocumentWrappedLiteral",
    RequestNamespace="http://foo.com",
    ResponseNamespace="http://foo.com",
    Use=SoapBindingUse.Literal,
    ParameterStyle=SoapParameterStyle.Wrapped)]
public string DocumentWrappedLiteral(Address1 address, bool useZipPlus4) {


在 JAX-RPC1.0 中, default 的是 encoded. JAX-RPC 1.1 之後加入 BP 的要求.
支援以'wrapped' 的方式來實作 Document style operation. 在JAVA上, 目前
一搬來說是用 WebService Tool (WSDL generation Tool) 來決定一個 method
要以 rpc-encoded, rpc-literal, 還是 document-literal 的格式在 WSDL 上呈現.
如果是使用 document-literal wrapped 的方式的話, 在
jaxrpc mapping deployment descriptor (defined in JSR109 J2EE WebServices)
上相對應的 method mapping 必須要有一個 <wrapped-element/> sub-element.

在未來的 JSR181 或 JSR224 中相信也會提供以 Attribute 的方式來指定
Operation Style 及 message format.


reply to postreply to post
You don't need a reason to help people
作者 Value Type to XML Mapping/Binding [Re:saijone]
saijone

Web Services

版主

發文: 470
積分: 24
於 2003-09-22 11:52 user profilesend a private message to userreply to postreply to postsearch all posts byselect and copy to clipboard. 
ie only, sorry for netscape users:-)add this post to my favorite list
Value Type to XML Mapping/Binding

不論是 .NET 或是 JAVA, 在實作一個 WebService Class 時,
都會希望用較複雜的Class (or non-primitive Type) 作為 method parameter
而不是簡單的Integer, String 之類.

在JAX-RPC (section 5.4) 中 將這類的 Class 叫做 Value Type,
必須要有 Java Bean 的樣子 (setter, getter, or public field) 並符合一些簡單的要求,
WebService Platform/Tool 便可以自動幫你在 WSDL 上產生XML Schema.
然而對 developer 來說, 可能會希望對 Schema Mapping 方式有所控制,
例如我們有這樣一個 Class (C# or JAVA):
1
2
3
4
5
public class Value {
    public String id;
    public String name;
    public byte[] data;
}

這樣一個就可以有很多不同的 Schema 表示方式
比如說 id 作為 sub-element:
1
2
3
4
5
6
7
<complexType name="Value">
    <sequence>
      <element name="id"   type="string"/>
      <element name="name" type="string"/>
      <element name="data" type="base64Binary"/>
    </sequence>
</complexType>

id 作為 attribute:
1
2
3
4
5
6
7
<complexType name="Value">
    <sequence>
      <element name="name" type="string"/>
      <element name="data" type="base64Binary"/>
    </sequence>
    <attribute name="id" type="string"/>
</complexType>

以 hexBinary的格式 encode Byte array:
1
2
3
4
5
6
7
<complexType name="Value">
    <sequence>
      <element name="name" type="string"/>
      <element name="data" type="hexBinary"/>
    </sequence>
    <attribute name="id" type="string"/>
</complexType>


.NET 允許你用 Attribute 來決定 XML binding/mapping:
1
2
3
4
5
6
7
8
9
10
public class Value {
    [SoapAttribute(DataType = "string", AttributeName = "id")]
    public String id;
 
    [SoapElement(DataType = "string", ElementName  = "name")]
    public String name;
 
    [SoapElement(DataType = "base64Binary", ElementName  = "data")]
    public byte[] data;
}

在 JAVA 中目前可以找的到的"標準方式"是在 JSR-109 J2EE WebServices 中定義的
jaxrpc mapping deployment descriptor (mapping file).
這是一個 XML 格式的 deployment descriptor, 你可以在這個 mapping file中, 描述
Value type 與 xml schema 之間的 mapping/binding:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<java-xml-type-mapping>
    <class-type>com.hello.Value</class-type>
    <root-type-qname xmlns:myPrefix="http://hello/xsd">myPrefix:value
    </root-type-qname>
    <qname-scope>complexType</qname-scope>
    <variable-mapping>
      <java-variable-name>myID</java-variable-name>
      <xml-element-name>id</xml-element-name>
    </variable-mapping>
    <variable-mapping>
      <java-variable-name>myName</java-variable-name>
      <xml-element-name>name</xml-element-name>
    </variable-mapping>
    <variable-mapping>
      <java-variable-name>myData</java-variable-name>
      <xml-element-name>data</xml-element-name>
    </variable-mapping>
</java-xml-type-mapping>

在未來的 JSR181, JSR224, 或 JAXB中, 相信也會提供以 Attribute 的
方式來指定value type class 與 xml schema 之間的 binding.


reply to postreply to post
You don't need a reason to help people
作者 SOAP Header [Re:saijone]
saijone

Web Services

版主

發文: 470
積分: 24
於 2003-09-23 12:22 user profilesend a private message to userreply to postreply to postsearch all posts byselect and copy to clipboard. 
ie only, sorry for netscape users:-)add this post to my favorite list
SOAP Header

在一個 SOAP Message 中, 有兩個最主要的部分: SOAP Header 跟 SOAP Body

(圖取自: http://java.sun.com/webservices/docs/1.3/tutorial/doc/tutorial)
一搬來說, .NET 及 JAVA 都將 Body 的內容對應(serialize and deserialize) 到
method parameter傳給 WebService Endpint implementation 來處理.

一般對 SOAP Header 的期待, 是希望利用 Header 來傳遞關於像 Security,
Reliability, Session, 以及 Transaction 這一類的 Service Context. 不論是.NET, 還是各
家 J2EE 的 WebServices, 多少都由提供這一類 "企業級"的功能, 但多屬 proprietary,
會有 Interoperability 的問題. 例如目前就很難期待 .NET 的 Security SOAP Header
可以跟 Axis 溝通. WebServices 在這上面的規格已經有顯著的發展, 相信在不久的未
來將會有些成果出來.

除了這些應該要被標準化的 Header 之外, .NET 及 JAVA 也有提供 API 讓
developer 在 Application Logic 中發展自己的 Header Processing.

在.NET中, Header 的處理與 Body 不同, Header part 是對應到 public field (Body
part 是對應到的 method parameter), 在相對應的 method 被 invoke 之前 .NET
runtime 會自動把 Header field 的值設好.
1. 首先 subclass SoapHeader 來定義你的 Header Class:
1
2
3
4
5
C#
public class MyHeader : SoapHeader  {
    public string Username;
    public string Password;
}

2. 在 server-side 的 WebService implementation class上, 以之前定義的 Header
Class宣告一個 public field, 必在需要使用這個 Header 的 method上, 加上
[SoapHeader("<field-name>")]的 metadata. .NET runtime 在這個 method
被 invoke 之前, 會自動把 Header field 的值設好:
1
2
3
4
5
6
7
8
9
10
11
12
C#
public class MyWebService {
    public MyHeader myHeaderMemberVariable;
 
    [WebMethod] [SoapHeader("myHeaderMemberVariable")]
    public String MyWebMethod() {
        if ( myHeaderMemberVariable.Username  == "admin") {
            // Do something interesting.
        }
        return "Hello";
    }
}

在 .NET Client-side, 先使用在 .NET SDK 中的 wsdl.exe 來產生 Proxy/Stub:
1
>wsdl http://localhost/MyWebService.asmx?WSDL

(J2EE WebServices 也都會提供相同的 Tool )
然後你就可以透過Proxy來使用遠端的 WebService, Proxy會自動把 invocation 轉成
SOAP Request 必送到 Server上的 WebService, 並把 SOAP Response 轉回傳回值.
在.NET WebService Client Proxy上使用 Header 基本上與 Server-side 一樣, 就是一
個public field, 必須要在 invoke 之前將值設好:
1
2
3
4
5
6
7
C#
MyHeader mySoapHeader = new MyHeader();
mySoapHeader.Username = "username";
mySoapHeader.Password = "password";
proxy = new MyWebService();
proxy.MyHeaderValue = mySoapHeader;
String result = proxy.MyWebMethod();


然而在 JAVA 上, SOAP Header part 可以跟 Body part 一樣對應到 method
parameter上, 在 JAX-RPC Spec. 中 這樣的做法叫 "Explicit Context",
如果Header是屬於 ouput Header 的話, 則會把它以一個相對應 type 的 Holder 表示:
1
2
3
4
5
6
7
package hello;
public interface Hello extends java.rmi.Remote {
    //inHeader is bound to a inout SOAPHeader
    //outHeader is bound to a output SOAPHeader
    public String sayHey(String str, MyHeader inHeader, MyHeaderHolder outHeader) 
    throws java.rmi.RemoteException;
}

這代表 Header 的 MyHeader class 必須與之前提到的 Value Type 一樣,
有 Java Bean的樣子來讓 Tool 產生 Schema.

另外在J2EE/JAX-RPC上還可以使用 MessageHandler 來截取整個 SOAP Message
進而以取得其中的 SOAP Header. 與 .NET 中的 Sink 類似.


saijone edited on 2004-06-10 22:52
reply to postreply to post
You don't need a reason to help people
作者 Asynchronous Programming Model [Re:saijone]
saijone

Web Services

版主

發文: 470
積分: 24
於 2003-09-23 12:31 user profilesend a private message to userreply to postreply to postsearch all posts byselect and copy to clipboard. 
ie only, sorry for netscape users:-)add this post to my favorite list
Asynchronous Programming Model

Asynchronous 的意義在於 invoke 一個 method 之後, 不用去等待傳回值運算完成便
可以繼續其他的工作, 主要的目的在於平行處理. 一般來說, 多以兩種方式來
'asynchronously' 取得傳回值:

1. Polling: Acync. method 的 Caller 自己檢查傳回值是否運算完成 (一般來說, 用
Caller 自己的Thread), 檢查是否運算完成的 API 不會因為傳回值未運算完成就被
block, 所以 Caller 可以反覆檢查直到運算 完成或放棄(Timeout)為止, 至於多久檢查n一次或什麼情況下檢查由 Caller 的 Logic 決定( 屬於平行處理的設計).

2. CallBack/Listener: Caller 在使用acync. method時, 給予一個CallBack作為參數, 或
register 一個 Listener, 在傳回值運算完成時, Runtime 會有一個 Thread (一般來說,
不是Caller 的Thread) 呼叫 CallBack 上的 API 或通知 Listener 運算完成.

這樣 Asynchronous 的觀念已經在 .NET 上簡單得實現 ...
One of tenets of the .NET Framework:
Not necessary for a called object to do additional programming
to support asynchronous behavior by its clients.


因此.NET 的觀點, 是由Client 決定是否使用Asynchronous API.
至於 Server-side (Called object) , 則沒有必要對 Asynchronous 及 Synchronous 的
Programming model 作區別. 當然Server-side (Called object) 更可以不用是 .NET.
至於Server-side 何時(asynchronously or synchronously)送回 Response, 取決於
Application Logic.

.NET在從WSDL 產生的 Proxy/Stub 上, 對每一個 Web Service Operation 都會有三個
對應的 method:
1. <OperationName>: 與operation 同名
2. Begin<OperationName>: operation-name 前置"Begin"
3. End<OperationName>: operation-name 前置"End"

Begin<OperationName>作為啟動一個 Acync. Operation 之用, 除了原來的參數外,
可多帶一個 CallBack參數, 這樣的 method 直接傳回一個 IAsyncResult instance,
透過 IAsyncResult API可以檢查(polling)傳回值是否運算完成.
End<OperationName>結束一個 Acync. Operation 以 IAsyncResult 為參數取回傳回
值.

Synchronous Invocation:
1
2
 C#
string synReturn =  StockService.GetStockQuote("JSPTW");


Asynchronous Invocation:
1
2
3
4
5
6
7
C#
IAsyncResult AsyncResult =  StockService.
BeginGetStockQuote( "JSPTW", null, null);
while(AsyncResult.IsCompleted  == false) {
     //you can do something else
}
string ReturnValue =  StockService.EndGetStockQuote(AsyncResult);

然而這樣的Asynchronous Programming Model 目前必沒有出現在JAVA WebServices
相關的 Spec. 中. 相信 JAVA 並沒有忘掉這一個重要的功能. Asynchronous
Programming 應該會在未來的 Spec. 中出現.
BEA 在 WebLogic 8.1 上有提供類似 .NET Asynchronous Client-side的支援:
http://edocs.bea.com/wls/docs81/webserv/client.html#1069294


reply to postreply to post
You don't need a reason to help people
作者 Re:Programming in C#(.NET) and Java Web Services [Re:saijone]
canbes





發文: 2
積分: 0
於 2007-10-01 10:38 user profilesend a private message to userreply to postreply to postsearch all posts byselect and copy to clipboard. 
ie only, sorry for netscape users:-)add this post to my favorite list
版主老師

感謝您,獲益良多!

cc


reply to postreply to post
» JWorld@TW »  Java & XML、Web Service » Web Services

reply to topicthreaded modego to previous topicgo to next topic
  已讀文章
  新的文章
  被刪除的文章
Jump to the top of page

JWorld@TW 本站商標資訊

Powered by Powerful JuteForum® Version Jute 1.5.8