【Java學習筆記】如何寫一個簡單的Web Service

本Guide利用Eclipse以及Ant創建一個簡單的Web Service,以演示Web Service的基本開發過程:html

 

1.系統條件:java

  • Eclipse Java EE IDE for Web Developers
  • Java SE 6
  • Windows XP

2.基本環境搭建:web

1)Java SE6 JDK的安裝:下載Java SE6 JDK,雙擊,安裝默認選項進行安裝便可。服務器

2)Eclipse的安裝與配置:app

    安裝時直接解壓。 
    配置處有兩點,Window>Preferences>Java>Installed JREs確保以下設置:
框架

image

  安裝路徑可能略有不一樣。ide

   Window>Preferences>Java>Compiler 確保以下設置:工具

   image 

3.創建Server端工程和相關包與類:ui

建立一個Java Project,命名爲wsServerHelloWorld:this

image  

在這個項目下創建包:org.gnuhpc.wsServer

image

在這個包下邊創建類:SayHello

image

在SayHello.java文件中輸入如下代碼:

package org.gnuhpc.wsServer;

import javax.jws.WebService;

@WebService 
public class SayHello { 
    private static final String SALUTATION = "Hello";

    public String getGreeting(String name) { 
        return SALUTATION + " " + name; 
    } 
}

其中注意到@WebService ,這個稱做annotation或者metadata,Java SE 5中的Web Services Metadata Specification引入的。Java SE 6中對於Web Services規範的升級以及JAX-WS(Java API for XML Web Services)2.0規範,這些升級使得咱們Web Services的建立和調用變得更加容易。使用這些新功能,咱們能夠僅僅使用簡單的Annotations註釋從一個Java類建立Web Services。開發者將其類和方法以前用該annotations指定,類告訴runtime engine以Web Service的方式和操做來使能該類和方法。這個annotations能夠產生一個可佈署的Web Service,是一個WSDL映射annotations,將Java源代碼與表明Web Service的WSDL元素鏈接在了一塊兒。

 

4.使用Ant產生Server端代碼:

首先在項目中新建一個文件:build.xml,而後使用OpenWith>AntEditor打開,輸入如下腳本代碼:

 

  1. <project default="wsgen">      
  2.     <target name="wsgen">  
  3.         <exec executable="wsgen">              
  4.             <arg line="-cp ./bin -keep -s ./src -d ./bin 
  5.                     org.gnuhpc.wsServer.SayHello"/> 
  6.         </exec> 
  7.     </target> 
  8. </project>  

 

 

default指定了默認執行的Target爲wsgen,wsgen能夠建立一個可以使用WebService的類,它生成全部用於WebService發佈的源代碼文件和通過編譯過的二進制類文件。它還生成WSDL和符合規範的該類的WebService。

Target名稱爲wsgen,具體執行的命令的參數:

-cp 爲類路徑

-keep後產生的java文件

-s 產生的源文件放在哪

-d 產生的輸出問價放在哪

 

而後使用Ant Build選項運行:

image

在成功執行的提示後,咱們刷新一下Project

image

咱們在Project區域能夠看到,結果以下:

image

 

5.分佈Web Service

org.gnuhpc.wsServer下創建一個類RunService:

package org.gnuhpc.wsServer;

import javax.xml.ws.Endpoint;

public class RunService { 
    /** 
     *@paramargs 
     */ 
    public static void main(String[] args) { 
        System.out.println("SayHello Web Service started."); 
        Endpoint.publish("
http://localhost:8080/wsServerExample" , 
                new SayHello()); 
    } 
}

運行Run As>Java Application。咱們獲得結果,說明這個web service的Server端已經啓動。

image

6.查看WSDL:

Window>Show View>Other>General>Internal Web Browser,在其中輸入:http://localhost:8080/wsServerExample?wsdl

image

你能夠看看到底WSDL都記錄了哪些信息。看完後能夠中止該Server。

7.監測Server

咱們建立完Server能夠用過Eclipse Web Services Explorer監測Server,

Window>Open Perspective>Other >JavaEE

image

打開Eclipse Web Services Explorer

 image

點擊右上角的WSDL Page按鈕: 
image

單擊WSDL Main,在URL中輸入:http://localhost:8080/wsServerExample?wsdl 按Go按鈕後出現一下視圖:

image

咱們能夠觸發一個Web Service操做:點擊getGreetings,添加一個參數,好比gnuhpc,而後點擊Go按鈕:

image

 

8.建立Client端 工程和相關包與類:

建立一個Java Project,命名爲wsClientHelloWorld,在這個項目下創建包:org.gnuhpc.wsClient

 

 

9.使用Ant產生Client代碼框架:

編寫Web service時,可使用工具來利用WSDL生成進行調用的客戶端樁;或者也可使用底層API來手動編寫Web service。前者方便,後者靈活,如今咱們經過前者作說明:

新建文件build.xml

New>File>build.xml

 

  1. <project default="wsimport"> 
  2.     <target name="wsimport"> 
  3.         <exec executable="wsimport"> 
  4.             <arg line="-keep -s ./src -p org.gnuhpc.wsClient 
  5.                         -d ./bin http://localhost:8080/wsServerExample?wsdl"/> 
  6.         </exec> 
  7.     </target> 
  8. </project> 

 

注意:wsgen 支持從 Java class 建立 Web services,wsimport 支持從 WSDL 建立 Web services,分別對應於 JAX-RPC 方式下的 Java2WSDL 和 WSDL2Java。要根據發佈的WSDL進行建立,這也就是爲何要先運行RunServer的緣由了。

運行Server的RunService : Run As>Java Application>

運行該Ant腳本,產生Client代碼:Run As>Ant Build

運行成功的提示以下:

image

生成的代碼以下:

image  

這一步讀取WSDL並生成客戶端樁。這些樁是將爲咱們的代碼所用的Java類和接口。這些樁給服務器端功能提供了一個客戶端接口。例如,若是咱們的服務器提供一個Maths服務,該服務帶有一個叫作add的方法。咱們的客戶端代碼將調用樁上的一個方法,而樁實現將對該方法使用參數封裝,把Java方法調用變爲Web service請求。這個請求將基於HTTP發送給服務器,並且將使用SOAP做爲RPC協議。監聽服務器接收該SOAP消息,而後(十有八九)將其轉換爲服務器處的一次方法調用。

200782516132

 

10.編寫Client代碼

建立一個類:SayHelloClient

image

package org.gnuhpc.wsClient;

import java.io.BufferedReader; 
import java.io.IOException; 
import java.io.InputStreamReader;

import javax.xml.ws.BindingProvider;

public class SayHelloClient {

    /** 
     * @param args 
     */ 
    public static void main(String[] args) { 
        SayHelloService shs = new SayHelloService(); 
        SayHello sh = (SayHello) shs.getSayHelloPort(); 
        ((BindingProvider) sh).getRequestContext().put( 
                BindingProvider.ENDPOINT_ADDRESS_PROPERTY, 
                "
http://localhost:8080/wsServerExample"); 
        System.out.println(((BindingProvider) sh).toString());

        String userName = null; 
        boolean exit = false; 
        while (!exit) { 
            System.out.print("/n Please enter yourname (type 'quit' to exit): "); 
            BufferedReader br = new BufferedReader(new InputStreamReader( 
                    System.in)); 
            try { 
                userName = br.readLine(); 
            } catch (IOException e) { 
                System.out.println("Errorreadingname."); 
                System.exit(1); 
            } 
            if (!(exit = userName.trim().equalsIgnoreCase("quit") 
                    || userName.trim().equalsIgnoreCase("exit"))) { 
                System.out.println(sh.getGreeting(userName)); 
            } 
        } 
        System.out.println("/nThank you for running the client."); 
    } 
}

當你運行SayHelloClient時,它建立了一個新的Service--SayHelloService,這是經過Ant腳本調用wsimport產生的一個proxy,用來調用目標服務端點的操做。而後Client獲得請求上下文,添加端點地址http://localhost:8080/wsServerExample ,在這裏處理請求消息。

11.運行Client

右鍵SayHelloClient.java,選擇Run As> Java Application,獲得:

image

可使用腳本完成對Server和Client的調用:

在Client中創建文件buildall.xml:

 

             

  1. <project default="runClient">  
  2.             <!-- =================================  
  3.                       target: wsimport  
  4.                   ================================= -->  
  5.             <target name="wsimport" description="-->  
  6.                       Read the WSDL and generate the required artifacts">  
  7.                  <exec executable="wsimport">  
  8.                       <arg line="-keep -s ./src -p org.gnuhpc.wsClient -d ./bin  
  9. http://localhost:8080/wsServerExample?wsdl"/>  
  10.                  </exec>  
  11.             </target>  
  12.             <!-- =================================  
  13.                       target: runServer  
  14.                   ================================= -->  
  15.             <target name="runServer" description="-->  
  16.                       Runs the Web service server from a terminal">  
  17.                  <echo>  
  18.        Running the following command from the terminal to run the server:  
  19.        ${java.home}/bin/java -cp "C:/Documents and Settings/Administrator/workspace/wsServerHelloWorld/bin"  
  20.             org.gnuhpc.wsServer.RunService  
  21.                 </echo>  
  22.                  <exec dir="c:/Progra~1/Java/jdk1.6.0_13/bin" executable="cmd" spawn="true"  
  23.                                     os="Windows XP" description="runs on XP">  
  24.                       <arg line="start cmd /K start cmd /K" />  
  25.                       <arg line='"c:/Progra~1/Java/jdk1.6.0_13/bin/java" -cp  
  26.                           "C:/Documents and Settings/Administrator/workspace/wsServerHelloWorld/bin"  
  27.                                org.gnuhpc.wsServer.RunService' />  
  28.                  </exec>  
  29.             </target>  
  30.             <!-- =================================  
  31.                       target: pause  
  32.                   ================================= -->  
  33.      <target name="pause" depends="runServer" description="-->  
  34.                           Pauses briefly while the server starts">  
  35.                      <sleep seconds="5"/>  
  36.                 </target>  
  37.                 <!-- =================================  
  38.                           target: runClient  
  39.                       ================================= -->  
  40.                 <target name="runClient" depends="pause" description="-->  
  41.                           Runs a Web service client from a terminal">  
  42.                      <echo>  
  43.            Running the following command from the terminal to run the client:  
  44.            ${java.home}/bin/java -cp "c:/DOCUME~1/Administrator/workspace/wsClientHelloWorld/bin"  
  45.            org.gnuhpc.wsClient.SayHelloClient  
  46.                    </echo>  
  47.                      <exec dir="c:/Progra~1/Java/jdk1.6.0_13/bin/" executable="cmd" spawn="true"  
  48.                               os="Windows XP" description="Runs on XP">  
  49.                           <arg line="start cmd /K start cmd /K" />  
  50.                           <arg line='"c:/Progra~1/Java/jdk1.6.0_13/bin/java -cp" "c:/DOCUME~1/Administrator/workspace/wsClientHelloWorld/bin"  
  51.                               org.gnuhpc.wsClient.SayHelloClient' />  
  52.                      </exec>  
  53.                 </target>  
  54. </project>  

 

注意其中的路徑名稱,選擇與你本身系統的路徑名便可。

在這個腳本中,默認target爲runClient,可是在運行runClient以前還有一個依賴:pause,意味着runClient以前必定要運行pause,而pause的依賴是runServer,那麼運行順序就是

runServer先運行,pause再運行,最後runClient運行。

另外一個須要注意的是os值:只有當前系統與指定的OS匹配時纔會被執行。

爲顯示命令。

用Ant Build運行獲得一個Server,5秒鐘後出現一個Client。

 

12.使用SOAP監視器監視C-S的通訊:

到這一步,咱們已經創建了一個Server 一個Client端,咱們如今想使用Eclipse的TCP/IP Monitor監視SOAP通訊。

image

打開:Window>Show View>Other>Debug>TCP/IP Monitor

配置:Windows>Preferences >Run/Debug > TCP/IPMonitor

添加一個TCP/IP Monitor:

image

Port爲遠端服務器端口,Local Monitoring Port爲本地監聽端口

如今咱們須要更新一下Client代碼(將端口8080,設置爲8081),將Web Service經過Monitor重定向。而後運行腳本: 
image

左右分別的文本全文爲:

POST /wsServerExample HTTP/1.1 
SOAPAction: "" 
Accept: text/xml, multipart/related, text/html, image/gif, image/jpeg, *; q=.2, */*; q=.2 
Content-Type: text/xml; charset=utf-8 
User-Agent: Java/1.6.0_13 
Host: localhost:8081 
Connection: keep-alive 
Content-Length: 210

http://schemas.xmlsoap.org/soap/envelope/">http://wsServer.gnuhpc.org/">gnuhpc

HTTP/1.1 200 OK 
Transfer-encoding: chunked 
Content-type: text/xml; charset=utf-8

5d 
http://schemas.xmlsoap.org/soap/envelope/"> 
8f 
>http://wsServer.gnuhpc.org/">Hello gnuhpc 
0

其中的含義不言自明。

 

全部代碼下載:

http://cid-a0a0b50959052db4.skydrive.live.com/self.aspx/.Public/WebService.rar

 

2010.1.5 補充:

1.網友Alexander Ananiev在其Blog 上表示在他看來仍是手工寫WSDL和schemas比較靠譜,更加有重用性和擴展性,並不推薦使用annotations自動生成WSDL。

 

2.JAX-WS 包括了 Java Architecture for XML Binding (JAXB) 和 SOAP with Attachments API for Java (SAAJ).

前者爲從XML Schema到Java代碼表示提供了一個方便的映射方法,屏蔽了從SOAP消息中的XML Schema到Java代碼之間轉換的具體細節。而SAAJ則爲處理在SOAP消息中附帶的XML提供了一個標準的方法。另外,JAX-WS還定義了從WSDL上定義的服務到實現這些服務的Java類之間的映射,任何定義在WSDL中的複雜類型都將根據JAXB定義的標準轉換到Java類中。

 

3.開發JAX-WS有兩種思路:

  • Contract first:先寫好WSDL,而後從中生成Java 代碼來實現。
  • Code first:先寫好一些plain old Java object (POJO) classes,而後使用annotations產生WSDL和Java類。

前者須要很好的WSDL和XSD知識,初學者通常建議後者,另外要是將一個已經實現的類以Web Service的方式呈現也建議用後者。前者的一個例子是:http://myarch.com/create-jax-ws-service-in-5-minutes

 

4.常見Annotations含義:

The @WebService annotation的含義:

The @WebService annotation is defined by the javax.jws.WebService interface and it is placed on an interface or a class that is intended to be used as a service. @WebService has the following properties:

 

 @WebService Properties

Property Description
name Specifies the name of the service interface. This property is mapped to the name attribute of the wsdl:portType element that defines the service's interface in aWSDL contract. The default is to append PortType to the name of the implementation class. [a ]
targetNamespace Specifies the target namespace under which the service is defined. If this property is not specified, the target namespace is derived from the package name.
serviceName Specifies the name of the published service. This property is mapped to the name attribute of the wsdl:service element that defines the published service. The default is to use the name of the service's implementation class. [a ]
wsdlLocation Specifies the URI at which the service's WSDL contract is stored. The default is the URI at which the service is deployed.
endpointInterface Specifies the full name of the SEI that the implementation class implements. This property is only used when the attribute is used on a service implementation class.
portName Specifies the name of the endpoint at which the service is published. This property is mapped to the name attribute of the wsdl:port element that specifies the endpoint details for a published service. The default is the append Port to the name of the service's implementation class. [a ]

[a ] When you generate WSDL from an SEI the interface's name is used in place of the implementation class' name

 

 

@XmlSeeAlso:

Suppose you want to build a web service that manages the inventory for a store that sells wakeboards and related equipment. Wakeboards are short boards made of buoyant material that are used to ride over the surface of a body of water, typically behind a boat or with a cable-skiing apparatus.

For simplicity, let's assume that the store sells only three types items: wakeboards, bindings, and towers for boats. You want the web service to be fairly simple to use and have a minimal amount of exposed operations. So to keep things simple, the web service uses an abstract Item class in its operations instead of using type-specific operations. The following Item class can be used to model any inventory object that you might want to expose through your web service:

   public abstract class Item implements Serializable { 
       private long id; 
       private String brand; 
       private String name; 
       private double price; 
       ...       
   }

Extending the Item class, you can define the following Wakeboard , WakeboardBinding and Tower classes:

   public class Wakeboard extends Item { 
       private String size;       
   } 
   
   public class WakeboardBinding extends Item { 
       private String size;       
   } 

   public class Tower extends Item { 
       private Fit fit;    
       private String tubing; 
    
       public static enum Fit { Custom, Exact, Universal };       
   }

Because this example is about type substitution, let's make the inheritance hierarchy a little more interesting by introducing a Wearable abstract class.Wearable holds the size attribute for both the Wakeboard and WakeboardBinding classes. The Wearable class is defined as follows:

   public abstract class Wearable extends Item { 
       protected String size;       
   }

And the resulting Wakeboard and WakeboardBinding classes are:

   public class Wakeboard extends Wearable {   
   } 

   public class WakeboardBinding extends Wearable {   
   }

Also, because the web service manages inventory, you'll want the inventory items to be persisted to a database using the Java Persistence API (sometimes referred to as JPA). To do this, you need to add an @Entity annotation to each of the classes that will be persisted. The only class that you probably don't want to persist is the Wearable class. You can add the @MappedSuperclass annotation to this class so that the JPA will use the attributes of this class for persisting subclasses. Next, you need to add the @Id and the @GeneratedValue(strategy = GenerationType.AUTO) annotations to the Item.Id field. As a result, the field will be used as the primary key in the database and the Id will be automatically generated if not provided. Finally, because you might add new types of Item s into the system at a later time, you should add the @Inheritance(strategy=InheritanceType.JOINED) annotation to the Item class. This will store each subclass in its own database table.

The final data classes look like the following:

   @Entity 
   @Inheritance(strategy=InheritanceType.JOINED) 
   public abstract class Item implements Serializable { 
       @Id 
       @GeneratedValue(strategy = GenerationType.AUTO) 
       private Long id; 
       private String brand; 
       private String itemName; 
       private double price; 

       // Getters & setters 
       ...       
   } 

   @MappedSuperclass 
   public abstract class Wearable extends Item { 
       protected String size; 
       ... 
   } 

   @Entity 
   public class Wakeboard extends Wearable {} 

   @Entity 
   public class WakeboardBinding extends Wearable {} 

   @Entity 
   public class Tower extends Item { 
       private Fit fit;    
       private String tubing; 
    
       public static enum Fit { Custom, Exact, Universal }; 
       ...       
   }

Now that you defined the data model for the application, you can now define the web service interface. Because the application manages information about wakeboard equipment, let's call the web service WakeRider and let's expose four operations in the web service: addItem , updateItem , removeItem , andgetItems .

Here is what the WakerRider class looks like:

   @WebService() 
   public class WakeRider { 
       ... 
       public List<Item> getItems() {...} 
  
       public boolean addItem(Item item) {...} 
    
       public boolean updateItem(Item item) {...} 

       public boolean removeItem(Item item) {...} 
   }

If you deployed this web service and then looked at the generated WSDL and schema, you would notice that only the Item type is defined -- there is no mention of Wearable , Wakeboard , WakeboardBinding , or Tower . This is because when JAX-WS introspects the WakeRider class there is no mention of the other classes. To remedy that you can use the new @XmlSeeAlso annotation and list the other classes that you want to expose through the WakeRider web service.

Here is what the WakeRider class looks like with the @XmlSeeAlso annotation:

   @WebService() 
   @XmlSeeAlso({Wakeboard.class, 
                WakeboardBinding.class, 
                Tower.class})   
   public class WakeRider { 
       ... 
   }

Now when you deploy the WakeRider service and look at the generated schema, you will see types for Item , Wearable , Wakeboard , WakeboardBinding , andTower as well as some other types used internally by JAX-WS and JAXB.

 

@WebResult含義:specifies that the name of the result of the operation in the generated WSDL 
targetNamespace含義:The XML namespace used for the WSDL and XML elements generated from this Web Service. 
@RequestWrapper 含義:生成的請求包裝器 bean、元素名稱和名稱空間,用於對在運行時使用的請求包裝器 bean 進行序列化和反序列化。

@ResponseWrapper 含義:提供 JAXB 生成的響應包裝器 bean、元素名稱和名稱空間,用於對在運行時使用的響應包裝器 bean 進行序列化和反序列化。

@WebParam 含義:用於定製從單個參數至 Web Service 消息部件和 XML 元素的映射。

@WebMethod annotation :表示做爲一項 Web Service 操做的方法。

@WebService annotation: 定義了一個Web Service端點接口(service endpoint interface (SEI)),聲明瞭一個Client在這個Service上可能invoke 的方法,全部在這個類中定義的public方法都會被映射到WSDL中,除非有一個@WebMethod中設置有排他元素爲true的。 5.在Web Service完成後要將相關文件打包生成WAR文件,而後將該文件部署到支持JAX-WS 2.0標準的Web Server上,Java 6有一個輕量級的Web server,經過簡單的API就能夠將Web Service發佈。

相關文章
相關標籤/搜索