Web Service學習筆記之----JAX-RPC (轉)

worldblog發表於2008-01-22
Web Service學習筆記之----JAX-RPC (轉)[@more@]

Service學習筆記之----JAX-RPC

導讀
本文是我對學習jwsdp-1.2時所做筆記的整理,其中主要是一些指導性的內容,並沒有多少概念以及原理的介紹,讀者可能覺得略顯簡單,如果想要學習基本概念可以參考網上有關Web Service的資料。本文例子所使用的開發環境是WindowXP+JWSDP-1.2。

一.Web Service簡介
1.定義
 由兩部分組成
 ·P--Web Service之間的基本通訊。
 ·WSDL--Web Service描述語言,它定義了Web Service做什麼,怎麼做和查詢的資訊。
2.簡單的Web Service實現
 包含四個基本步驟
 ·建立Web Service的商業邏輯(通常是一些類)
 ·將這些Java類部署到一個SOAP上
 ·生成客戶訪問程式碼
 ·部署客戶應用
 注意:WSDL等的生成通常是利用廠商提供的工具來完成
3.WSDL解析
WSDL描述語言一般包含三部分
 ·What部分--包括了type、message和portType元素
  Type:定義了Web Service使用的資料結構(使用 Schema定義)
  Message:一個Message是SOAP的基本通訊元素。每個Message可以有一個或多個Part,每個Part代表一個引數。
  PortType:訊息彙總為不同的操作並歸入到一個被稱為portType的實體中。一個portType代表一個介面(Web Service支    持的操作集合),每個Web Service可以有多個介面,它們都使用portType表示。每個操作又包含了input和  output部分。
 ·How部分--包含binding元素
  binding元素將portType繫結到特定的通訊協議上(如HTTP上的SOAP協議)
 ·Where部分--由service元素組成
  它將portType,binding以及Web Service實際的位置(URI)放在一起描述
4.客戶端
  通常Web Service可以有三種型別的客戶
  ·商業夥伴(Business Partner)--包括分發商,零售商以及大型消費者)
  此類客戶透過SOAP、WSDL、ebXML、UDDI等XML技術與Web Service連線
  ·瘦客戶--包括Web、PDA以及裝置
  該類客戶通常經由輕量協議(如HTTP)與Web Service連線
  ·肥客戶--包括Applet、各類應用以及現存
  通常使用重量級協議(如IIOP)連線Web Service

二.使用JAX-RPC開發Web Service
1.JAX-RPC支援的資料型別
JAX-RPC除了支援Java的基本資料型別外還支援一些自定義,但這些物件有一些條件限制
·有預設構造的物件
·沒有實現java..Remote介面
·欄位必須是JAX-RPC支援的型別
·公有欄位不能宣告為final或transient
·非公有欄位必須有對應的setter和getter方法
2.使用JAX-RPC建立Web Service
·基本步驟
A. 編寫服務端介面並實現
一個服務的end-point有一些規定:必須實現java.rmi.Remot介面而且每個方法需要丟擲RemoteException異常。
B. 編譯、生成並且將所有服務需要的類和檔案打包成WAR檔案
C. 部署包含服務的WAR檔案
·如何建立服務
A. 編譯服務所需的類檔案
B. 生成服務所需檔案
可以使用wmpile工具生成model.gz檔案,它包含了描述服務的內部資料結構命令如下
wscompile -define -d build -nd build -classpath build config.xml
-model build/model.gz
define標誌告訴工具讀取服務的 endpoint介面並且建立WSDL檔案。-d和-nd標誌告訴工具將輸出檔案寫入指定的目錄build。工具需要讀以下的config.xml檔案


name=”HelloService”
targetNamespace=”urn:Star”
typeNamespace=”urn:Star”
packageName=”helloservice”>



該檔案告訴wscompile建立model檔案所需的資訊
 ·服務名稱:MyHelloService
 ·WSDL名字空間:urn:Star
 ·HelloService的所有類在包helloservice中
 ·服務的端點(endpoint)介面:helloservice.HelloIF
C. 將服務打包為WAR檔案
WEB-INF/classes/hello/HelloIF.class
WEB-INF/classes/hello/HelloImpl.class
WEB-INF/jaxrpc-ri.xml
WEB-INF/model.gz
WEB-INF/web.xml
jaxrpc-ri.xml檔案如下所述

version=”1.0”
targetNamespaceBase=”urn:Star”
typeNamespaceBase=”urn:Star”
urlPatternBase=”webservice”>
displayName=”HelloWorld Service”
description=”A simple web service”
interface=”helloservice.HelloIF”
model=”/WEB-INF/model.gz”
implementation=”helloservice.HelloImpl”/>


D. 處理WAR檔案
使用命令列
 wsdeploy -o hello-jaxrpc.war hello-jaxrpc-original.war
wsdeploy工具完成以下幾個任務
 ·讀 hello-jaxrpc-original.war作為輸入
 ·從jaxrpc-ri.xml檔案中獲得資訊
 ·為服務生成tclasses
 ·生成名為HelloService.wsdl的WSDL檔案
 ·將tie classes和HelloService.wsdl檔案打包到新的war檔案中
E. 在伺服器上部署服務
如果你使用的是,你可以將WAR檔案複製到webapps目錄下,然後可以在
上看是否成功
·如何使用JAX-RPC建立Web Service客戶端
 通常有三種型別的客戶:Static Stub、Dynamic 和Dynamic Invocation Interface(DII)
Static Stub客戶
·生成Stub
透過使用config-wsdl.xml和wscompile工具,可以生成stub
wscompile -gen:client -d build -classpath build config-wsdl.xml
 config-wsdl.xml檔案如下
 

packageName="staticstub"/>

  wscompile工具讀取伺服器上的WSDL檔案並生成stub
·編寫靜態客戶程式碼
 Stub stub=(Stub)(new HelloService_Impl().getHelloIFPort());
 HelloIF hello=(HelloIF)stub;
 Hello.sayHello(“starchu”);
注意:HelloService_Impl類由wscompile生成
  ·編譯程式碼
·執行客戶端(需要包含saaj 和JAX-RPC API執行)
Dynamic Proxy客戶
·生成介面
透過使用config-wsdl.xml檔案和wscompile工具,可以生成客戶所需的介面
wscompile -import -d build -classpath build config-wsdl.xml
config-wsdl.xml和前面列出的檔案內容相同。
·編寫動態客戶程式碼
 ServiceFactory factory=ServiceFactory.newInstance();
 URL wsdlUrl=new URL(“”);
 Service service=factory.createService(wsdlUrl,
 new QName(“urn:Star”,”HelloService”));
 HelloIF hello=(HelloIF)service.getPort(
 new QName(“urn:Star”,”HelloIFPort”),HelloIF.class);
 Hello.sayHello(“starchu”);
 注意:這裡不再需要靜態客戶程式碼的HelloService_Impl類
  ·編譯程式碼
·執行客戶端(需要包含saaj API和JAX-RPC API執行)
Dynamic Invocation Interface客戶
這個方法為我們提供了更有彈性的客戶方式,客戶程式碼不在需要由wscompile工具生成的執行時類,當然這種程式碼更加複雜。具體步驟如下:
·建立ServiceFactory例項
 ServiceFactory factory=ServiceFactory.newInstance();

·建立Service(利用服務名的Qname)
 Service service=factory.createService(new QName(“HelloService”));

·建立Call物件(使用端點介面的Qname)
 Call call=service.createCall(new QName(“HelloIF”));

·設定端點的地址和一些Call物件屬性
 call.setTargetEndpointAddress(args[0]);
 call.setProperty(Call.SOAPACTION_USE_PROPERTY,new Boolean(true));
 call.setProperty(Call.SOAPACTION_URI_PROPERTY,””);
 call.setProperty(“javax.xml.rpc.encodingstyle.namespace.uri”,
  “;

·設定呼叫的返回型別、操作名和引數
 QName stringType=new Qname(“”,”string”)
 call.setReturnType(stringType);
 call.setOperationName(new Qname(“urn:Star”,”sayHello”));
 call.addParameter(“String_1”,stringType,ParameterMode.IN);

·呼叫call的invoke方法
 String [] param={ “ starchu “ };
 String retValue=call.invoke(param);

·編譯程式碼並對Main方法設定)

3.SOAP Message Handler的例子
通常使用JAX-RPC建立的Web Service並不需要開發人員自己處理SOAP訊息,但是JAX-RPC提供了一種機制可以使員獲得這種處理能力,這就是所謂的訊息。總的來說,像日誌和加功能可以透過SOAP訊息處理器實現,除此之外,你根本不需要處理SOAP訊息。
·基本Handler處理過程
 SOAP請求
 ·客戶端處理器在請求訊息傳送到伺服器前被呼叫
 ·服務端處理器在請求訊息分發到端點前被呼叫
 SOAP應答
 ·服務端處理器在應答訊息傳送回客戶前被呼叫
 ·客戶端處理器在應答訊息轉換成Java方法返回前被呼叫
 SOAP錯誤
 處理過程與SOAP應答的方式一樣
注意:處理器可以在任意端組成處理器鏈
A.Handler基本模型
 服務端
 ·編寫服務端點介面程式碼、實現服務並且實現服務端處理器類
 ·建立jaxrpc-ri.xml檔案,以便wscompile使用,其中包含了Handler的資訊
 ·建立web.xml檔案
 ·編譯所有程式碼
 ·將檔案打包為WAR檔案
 ·用wsdeploy工具將原始war檔案替換為完整可部署的war檔案
 ·在伺服器上部署war檔案
 客戶端
 ·編寫客戶程式以及客戶端處理器程式碼
 ·建立config.xml檔案以便wscompile使用,它包含了客戶端處理器的資訊
 ·編譯程式碼
 ·執行wscompile生成服務端點介面和客戶類
 ·編譯所有程式碼,並執行客戶應用

B.建立客戶端處理器
處理器必須擴充套件javax.xml.rpc.handler.GenericHandler類並且提供至少兩個方法的實現init和getHandlers。此外,你可以利用handleXXX方法處理請求、應答和錯誤SOAP訊息。基本步驟如下
 ·編寫客戶端處理器程式碼
 Public class ClientHandler extends GenericHandler{
 Public void init(HandlerInfo info){
 This.info=info;
 }
 public QName[] getHeaders(){
 return info.getHeaders();
 }
 public boolean handleRequest(MessageContext context){
 SOAPMessageContext smc=(SOAPMessageContext)context;
 SOAPMessage message=smc.getMessage();
  can use SOAP API to implement your own logic
  as logging and encrypt
 ……
  a logger element in the SOAPHeader
 SOAPHeaderElement loggerElement=
header.addHeaderElement(envelope.createName(“loginfo”,
 “ns1”,”urn:Star:headprops”));
 loggerElement.setMustUnderstand(true);
 loggerElement.setValue(“10”);
  a name element in the SOAP Header
 SOAPHeaderElement nameElement=
Header.addHeaderElement(envelope.createName(“client”,
 “ns1”,”urn:Star:headprops”));
 nameElement.addTextNode(“Schu”);
 }
 }
 ·編輯config.xml檔案
 
 
   packageName=”client”>
 
 
 
 
 

 

 

 ·編寫靜態客戶
C.建立服務端處理器
 ·編寫服務端處理器(與客戶端結構類似)
 Public boolean handleRequest(MessageContext context){
 SOAPMessageContext smc=(SOAPMessageContext)context;
 ……
 Iterator it=header.examineAllHeaderElements();
 While(it.hasNext()){
 SOAPElement element=(SOAPElement)it.next();
 If(element name is loginfo and must understand it){
 element.getValue();
 element.detach();
  only when the setMustUnderstand(true)
 }
 }
 }
 detach方法用來移除元素,這個需求僅當一個元素設定了mustUnderstand屬性在必要。
 ·編輯jaxrpc-ri.xml檔案
 
  version=”1.0”
targetNamespaceBase=”urn:Star:wsdl”
 typeNamespaceBase=”urn:Star:types”
 urlPatternBase=”/handler”>
  displayName=”Handler Test”
 description=” … …”
 interface=”service.HandlerTest”
 model=”/WEB-INF/model.gz”
 implementation=”service.HandlerTestImpl”>
 
 
   headers=”ns1:loginfo”
xmlns:ns1=”urn:Star:headerprops”>

 

 
 
 

 

 

 

 urlPattern=”/handler”/>
 

在第一個處理器中,XML使用了屬性 headers描述頭資訊。這是因為客戶程式碼告訴服務端,logger頭必須被理解,否則客戶將收到SOAP錯誤訊息
·生成WAR檔案並部署到伺服器上
4.
·HelloIF.java(endpoint介面)
package helloservice;

import java.rmi.RemoteException;
import java.rmi.Remote;

public interface HelloIF extends Remote{
 public String sayHello(String target) throws RemoteException;
}
·HelloImpl.java
package helloservice;

public class HelloImpl implements HelloIF{
 private String message="Hello";
 public String sayHello(String target){
 return message+target;
 }
}
·StaticClient.java
package staticstub;
import javax.xml.rpc.Stub;
public class StaticClient{
 private static String endpointAddress;
 public static void main(String [] args){
 if(args.length!=1){
  System.err.println("Usage : java HelloClient [endpoint address]");
  System.exit(-1);
 } 
 endpointAddress=args[0];
 System.out.println("Connect to :"+endpointAddress);
 try{
  Stub stub=createStub();
  stub._setProperty(javax.xml.rpc.Stub.ENDPOINT_ADDRESS_PROPERTY,
 endpointAddress);
  HelloIF hello=(HelloIF)stub;
  System.out.println(hello.sayHello(" Starchu!")); 
 }catch(Exception e){System.err.println(e.toString());}
 }
 private static Stub createStub(){
 return (Stub)(new HelloService_Impl().getHelloIFPort());
 }
}
 ·DynamicClient.java
package dynamicproxy;
import java.URL;
import javax.xml.namespace.QName;
import javax.xml.rpc.Service;
import javax.xml.rpc.ServiceFactory;
import javax.xml.rpc.JAXRPCException;
import staticstub.HelloIF;

public class DynamicClient{
 private static String wsdl; 
 private static String namespaceUri="urn:Star:wsdl"; 
 private static String serviceName="HandlerService"; 
 private static String portName="HandlerTestPort"; 

 public static void main(String [] args){
 if(args.length!=1){
  System.err.println("Usage : java DynamicClient [server Url]");
  System.exit(-1);
 }
 System.out.println("Connect to :"+args[0]);
 helloWsdl=args[0]+"?WSDL";
 try{
  URL wsdlUrl=new URL(wsdl);
  ServiceFactory serviceFactory=ServiceFactory.newInstance();
  Service service=
 serviceFactory.createService(wsdlUrl,
 new QName(namespaceUri,serviceName));
  HandlerTest proxy=(HandlerTest)service.getPort(
 new QName(namespaceUri,portName),HandlerTest.class);
  proxy.test();
 }catch(Exception e){
  System.err.println(e.toString());
 }
 }
}
 ·DIIClient.java
package dii;
import javax.xml.rpc.*;
import javax.xml.namespace.*;

public class DIIClient{
 private static String qnameService = "HelloService";
 private static String qnamePort = "HelloIF";
 private static String BODY_NAMESPACE_VALUE ="urn:Star";
private static String ENCODING_STYLE_PROPERTY ="javax.xml.rpc.encodingstyle.namespace.uri";
 private static String NS_XSD ="";
private static String URI_ENCODING ="";

 public static void main(String [] args){
 try{
 
 ServiceFactory factory=ServiceFactory.newInstance();
 Service service=factory.createService(new QName(qnameService));
 QName port=new QName(qnamePort);
 Call call=service.createCall(port);
 call.setTargetEndpointAddress(args[0]);
 call.setProperty(Call.SOAPACTION_USE_PROPERTY,new Boolean(true));
 call.setProperty(Call.SOAPACTION_URI_PROPERTY,"");
 call.setProperty(ENCODING_STYLE_PROPERTY,URI_ENCODING);
 QName qnameTypeString=new QName(NS_XSD,"string");
 call.setReturnType(qnameTypeString);
call.setOperationName(new QName(BODY_NAMESPACE_VALUE,"sayHello"));
 call.addParameter("String_1",qnameTypeString,ParameterMode.IN);
 String [] params = { "Starchu" };
 System.out.println((String)call.invoke(params)); 
 }catch(Exception e){
 System.err.println(e.toString());
 }
 }
}
 ·Ant檔案build.xml

 
 
 
 
 
 

 
 
 

 
 
 
 
 

 
 
 
 
   
 
 
 

 
 
 

 

 

 
 
 
 

 
 
 

 

 
    webxml="${build}web.xml">
 

 

 

 
 

 

 

 
 
 

 
 
 
 

<!--  Generating Static Client  --&gt
 
 

 

 

 
 
 
 

 

 
 
 
 

  
    classpathref="classpath"
  fork="true">
 
 
 

 

 <!--  Generating Dynamic Client  --&gt
 
 
 
 

 

 

 

 

 
 
 
 

 
    classpathref="classpath"
  fork="true">
 
 
 

 

 <!--  Generating Dynamic Invocation Interface  --&gt

 
 
 
 

 

 
    classpathref="classpath"
  fork="true">
 
 
 

 


·屬性檔案(build.xml檔案使用)
server=C:/Java/jwsdp-1.2/webapps
tomcat.home=C:/Java/jwsdp-1.2
endpoint=
server.port.url=

參考資料
1. Developing Web Service Series <.com>?l=Systinet-web-services-part-1">> 
2. JWSDP-1.2 Tutorial  java.sun.com

宣告:如需轉帖,請標明出處


來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/10752043/viewspace-998156/,如需轉載,請註明出處,否則將追究法律責任。

相關文章