標籤:
WebService曆來都很受重視,特別是Java陣營,WebService架構和技術層出不窮。知名的XFile(新的如CXF)、Axis1、Axis2等。
而Sun公司也不甘落後,從早期的JAX-RPC到現在成熟的、支援RPC調用與訊息傳遞的JAX-WS都經過了市場的考驗,十分成熟,而且使用JAX-WS開發WebService的收益是很大的,它是輕量級的。
我們使用JAX-WS開發WebService只需要很簡單的幾個步驟:寫介面和實現=>發布=>產生用戶端(測試或使用)。
而在開發階段我們也不需要匯入外部jar包,因為這些api都是現成的。首先是介面的編寫(介面中只需要把類註明為@WebService,把 要暴露給用戶端的方法註明為@WebMethod即可,其餘如@WebResult、@WebParam等都不是必要的,而用戶端和服務端的通訊用RPC 和Message-Oriented兩種,區別和配置以後再說):
package service;import java.util.Date;import javax.jws.WebMethod;import javax.jws.WebParam;import javax.jws.WebResult;import javax.jws.WebService;import javax.jws.soap.SOAPBinding;/** * 作為測試的WebService介面 * * @author Johness * */@WebService@SOAPBinding(style = SOAPBinding.Style.RPC)public interface SayHiService { /** * 執行測試的WebService方法 */ @WebMethod void SayHiDefault(); /** * 執行測試的WebService方法(有參) * * @param name */ @WebMethod void SayHi(@WebParam(name = "name") String name); /** * 執行測試的WebService方法(用於時間校正) * * @param clentTime 用戶端時間 * @return 0表示時間校正失敗 1表示校正成功 */ @WebMethod @WebResult(name = "valid") int CheckTime(@WebParam(name = "clientTime") Date clientTime);}
然後是實作類別(註解@WebService及其endpointInterface屬性是必要的):
package service.imp;import java.text.SimpleDateFormat;import java.util.Date;import javax.jws.WebService;import javax.jws.soap.SOAPBinding;import service.SayHiService;/** * 作為測試的WebService實作類別 * * @author Johness * */@WebService(endpointInterface = "service.SayHiService")@SOAPBinding(style = SOAPBinding.Style.RPC)public class SayHiServiceImp implements SayHiService { @Override public void SayHiDefault() { System.out.println("Hi, Johness!"); } @Override public void SayHi(String name) { System.out.println("Hi, " + name + "!"); } @Override public int CheckTime(Date clientTime) { // 精確到秒 String dateServer = new java.sql.Date(System.currentTimeMillis()) .toString() + " " + new java.sql.Time(System.currentTimeMillis()); String dateClient = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss") .format(clientTime); return dateServer.equals(dateClient) ? 1 : 0; }}
然後是發布(一般有兩種方式):
方式一(此方式只能作為調試,有以下bug:
jdk1.6u17?以下編譯器不支援以Endpoint.publish方式發布document方式的soap,必須在service介面和實作類別添加“@SOAPBinding(style = SOAPBinding.Style.RPC)”註解;
訪問受限,似乎只能本機訪問(應該會綁定到publish的URL上,如下使用localhost的話就只能本機訪問)……):
package mian;import javax.xml.ws.Endpoint;import service.imp.SayHiServiceImp;public class Main { /** * 發布WebService * 簡單 */ public static void main(String[] args) { Endpoint.publish("http://localhost:8080/testjws/service/sayHi", new SayHiServiceImp()); }}
方式二(基於web伺服器Servlet方式):
以Tomcat為例,首先編寫sun-jaxws.xml檔案並放到WEB-INF下:
<?xml version="1.0" encoding="UTF-8"?><endpoints xmlns="http://java.sun.com/xml/ns/jax-ws/ri/runtime" version="2.0"> <endpoint name="SayHiService" implementation="service.imp.SayHiServiceImpl" url-pattern="/service/sayHi" /></endpoints>
然後改動web.xml,添加listener和servlet(url-pattern要相同哦):
<?xml version="1.0" encoding="UTF-8"?><web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" version="2.5"> <listener> <listener-class> com.sun.xml.ws.transport.http.servlet.WSServletContextListener </listener-class> </listener> <servlet> <servlet-name>SayHiService</servlet-name> <servlet-class> com.sun.xml.ws.transport.http.servlet.WSServlet </servlet-class> </servlet> <servlet-mapping> <servlet-name>SayHiService</servlet-name> <url-pattern>/service/sayHi</url-pattern> </servlet-mapping> <welcome-file-list> <welcome-file>index.html</welcome-file> <welcome-file>index.htm</welcome-file> <welcome-file>index.jsp</welcome-file> </welcome-file-list></web-app>
最後部署到Tomcat裡,值得一提的是您可能需要添加以下jar包(因為Tomcat沒有):
啟動Tomcat。
服務端工作就完成了,注意兩個事情。
注意:項目需要使用UTF-8編碼(至少sun-jaxws.xml必須是UTF-8格式的);
對於MyEclipse的內建Tomcat,可能會出現不需要手動添加上述jar包,但獨立部署時應該添加,因為它們使用的class-path不一樣;
多個不同路徑的介面也要使用同一個WSServlet;
最好加上@SOAPBinding(style = SOAPBinding.Style.RPC)註解。
部署好了之後開啟瀏覽器輸入網址:http://localhost:8080/testjws/service/sayHi?wsdl。可以看到東西就證明發布成功了。
附上項目樹狀圖:
最後是用戶端使用,由於WebService是平台和語言無關的基於xml的,所以我們完全可以使用不同語言來編寫或產生用戶端。
一般有三種方式來使用(對於Java語言而言):
一,使用jdk內建工具wsimport產生用戶端:
jdk內建的wsimport工具產生,我是把用戶端檔案產生到了案頭src檔案中(-d),並保留了源檔案(-keep),指定了包名(-p)。
然後我們就可以使用產生的檔案來調用伺服器暴露的方法了:
值得一提的是你產生使用的jdk和你用戶端的jre需要配套!
從上面的目錄結構我們可以發現:服務端的每個webmethod都被單獨解析成為了一個類(如果使用了實體,實體也會被解析到用戶端,並且是源碼,所以建議使用實體時謹慎)。
(上面的圖是舊圖,只是為了表示一下jaxws是為每個webmethod產生類的情況)
而我們的service則被產生了一個代理類來調用服務,接下來我們看看使用方式:
package test;import java.util.Date;import java.util.GregorianCalendar;import javax.xml.datatype.DatatypeConfigurationException;import javax.xml.datatype.DatatypeFactory;import javax.xml.datatype.XMLGregorianCalendar;import testjws.client.SayHiService;import testjws.client.SayHiServiceImpService;public class Main { public static void main(String[] args) throws DatatypeConfigurationException { // 擷取service SayHiService service = new SayHiServiceImpService().getSayHiServiceImpPort(); // sayhi service.sayHiDefault(); service.sayHi("Ahe"); // checktime // 這裡主要說一下時間日期的xml傳遞,方法還略顯複雜 GregorianCalendar calender = new GregorianCalendar(); calender.setTime(new Date(System.currentTimeMillis())); XMLGregorianCalendar xmldate = DatatypeFactory.newInstance().newXMLGregorianCalendar(calender); System.out.println(service.checkTime(xmldate)); }}
看看伺服器的輸出,我們是否調用成功:
成功了!
對於校正時間的方法用戶端也收到反饋了:
二,使用諸如MyEclipse(Eclipse for Jave EE也可以)建立一個Web Service Client的項目
然後填入wsdl地址即可,後續步驟我就不貼出了。
三,自己寫代碼-_-,其實這個方法不得不說是最好的。
真正的輕量級WebService架構——使用JAX-WS(JWS)發布WebService