WebService課程由徐培成老師主講,依然發揚傳智播客的特點——深入理論和實踐。今天老徐講的原理的專業術語比較多,但我只做WebService的應用總結。如果你的Java和JavaWeb基礎好些,我想你看到WebService的應用,自然就能想到它的實現原理。
WebService又是一種高級應用,與之前學習的Struts、Spring、Hibernate等框架不同。WebService是面向服務的架構(SOA),看起來像是比SSH框架要大。那么它到底是做什么用的?什么才是面向服務的架構?
讓我們來看一種需求,集團公司可能具有多種WEB應用。比如,前年開發了個進銷存系統、去年開發了一個ERP、今年又開發了一個OA。現在這家集團公司需要將這三個系統整合,難道需要重新編碼將它們整合嗎?而這三個系統又是用不同語言編寫的,這種成本對公司來說無疑是一種浪費。WebService可以很好的解決這種需求。
WebService是可以進行跨語言、跨平臺、分布式系統間整合的方案,WebService像是一條線將這些系統穿起來——企業服務總線(ESB)。WebService使用簡單對象訪問協議(SOAP)使用http協議傳輸xml數據(xml是最常用的,也有其他格式數據。)來完成系帶間的整合。
什么是整合?當然是功能和數據的整合,也就是一個系統可以調用另一個系統的WebService接口來完成數據的交互。這樣我們就需要知道,提供WebService服務功能的應用公開了哪些接口,我們可以通過WebService描述文檔(WSDL)得知。WSDL不需要我們手動編寫,Java的WebService實現可以為我們自動生成。JDK1.6新增支持WebService,但還不夠成熟。所以我們使用Apache第三方開源組織提供的WebService實現——Axis。
Axis的當前版本是Java版本,它的C++版本正在開發中。Axis是一個功能強大的soap引擎,關于它們的詳細信息在此就不做介紹了。下面,讓我們來編寫一個例子程序,以了解WebService的應用流程。
一、編寫支持WebService的WEB應用
1.創建工程
Project Name:TestWebService
Target runtime:Apache Tomcat V6.0
其他的默認
2.添加Axis的Jar包
在axis的jar包目錄lib子目錄中的所有jar文件添加到工程中。
3.配置web.xml
在axis的webapps子目錄中有一個axisWeb應用,我們直接使用它的web.xml文件內容。
4.添加功能類
package com.changcheng.webservice; import com.changcheng.webservice.entity.User; public class TestWebService { /** * 基本數據的遠程 * @param words * @return */ public String hello(String words) { return "WebService say: hello " + words; } /** * * @param user * @return */ public User update(User user){ System.out.println(user); user.setName("new_name_haha"); user.setPassword("new_password_123"); return user; } } |
其中使用到的User實體類在此就不列出了。
5.部署WebService
我們可以將需要公開的類文件復制到WEB應用目錄下,并修改文件后綴名為jws。把類文件更名并放到WEB目錄下?這樣做并不好,它被暴露了。
所以在這里我們使用一個常量的部署方法,在工程中(根目錄)添加一個deploy.wsdd文件:
<!-- 部署描述符 --> <deployment xmlns="http://xml.apache.org/axis/wsdd/" xmlns:java="http://xml.apache.org/axis/wsdd/providers/java"> <!-- 定義處理器 --> <handler name="track" type="java:com.changcheng.webservice.handler.LogHandler"> <parameter name="filename" value="d:/MyService.log" /> </handler> <!-- 定義服務,并且在服務中使用處理器 --> <service name="HandlerService" provider="java:RPC"> <requestFlow> <handler type="track" /> </requestFlow> <parameter name="className" value="com.changcheng.webservice.TestWebService" /> <parameter name="allowedMethods" value="*" /> </service> </deployment> |
首先將工程部署到Tomcat服務器上,并啟動Tomcat服務器。然后在工程上右鍵-->Run As...-->Run Configurations...,新建一個JavaApplication。在main頁面中,project指定為我們的TestWebService,MainClass指定為org.apache.axis.client.AdminClient。在Arguments頁面下設置Program arguments為-l http://localhost:8080/TestWebService/servlet/AxisServlet deploy.wsdd。點擊Run按鈕。
完成上面的操作后,AdminClient會為我們部署在Tomcat的TestWebService的WEB-INF目錄下生成一個server-config.wsdd文件,它是提供給Axis使用的配置文件。
我們需要將向server-config.wsdd文件的HandlerService元素添加一個beanMapping子元素:
<service name="HandlerService" provider="java:RPC"> <requestFlow> <handler type="track"/> </requestFlow> <parameter name="allowedMethods" value="*"/> <parameter name="className" value="com.changcheng.webservice.TestWebService"/> <beanMapping qname="myNS:User" xmlns:myNS="urn:pojo:ws:changcheng:com" languageSpecificType="java:com.changcheng.webservice.entity.User"/> </service> |
其中的添加的處理器是WebService的一項功能,在遠程調用指定的方法時,會先由處理器進行處理。
package com.changcheng.webservice.handler; import java.io.FileOutputStream; import java.io.PrintWriter; import java.text.SimpleDateFormat; import java.util.Date; import org.apache.axis.AxisFault; import org.apache.axis.Handler; import org.apache.axis.MessageContext; import org.apache.axis.handlers.BasicHandler; /** * 日志處理器,類似于web中的filter */ public class LogHandler extends BasicHandler { private static final long serialVersionUID = 3227593680689235885L; public void invoke(MessageContext arg0) throws AxisFault { try { Handler serviceHandler = arg0.getService(); // 提取配置文件(server-config)的配置信息 String filename = (String) getOption("filename"); // FileOutputStream fos = new FileOutputStream(filename); PrintWriter writer = new PrintWriter(fos); // getOption()類似于request.getAttribute("") // 獲得在handler對象中存放的訪問次數 Integer numAccesses = (Integer) serviceHandler .getOption("accesses"); // 如果首次訪問 if (numAccesses == null) numAccesses = new Integer(0); // 次數 ++ numAccesses = new Integer(numAccesses.intValue() + 1); // Date date = new Date(); // 對日期進行格式化 SimpleDateFormat sdf = new SimpleDateFormat(); sdf.applyPattern("yyyy-MM-dd hh:mm:ss"); String result = sdf.format(date) + ": service " + arg0.getTargetService() + " accessed " + numAccesses + " time(s)."; // 將訪問次數寫入到handler對象中(request.setAttribute(..)); serviceHandler.setOption("accesses", numAccesses); writer.println(result); writer.close(); } catch (Exception e) { throw AxisFault.makeFault(e); } } } |
二、編寫運程調用WebServiceWEB應用的Java工程
1.添加上面WEB工程中所用到的Axis的jar包
2.編寫測試類:
package com.changcheng.client; import java.net.URL; import javax.xml.namespace.QName; import org.apache.axis.client.Call; import org.apache.axis.client.Service; import org.apache.axis.encoding.ser.BeanDeserializerFactory; import org.apache.axis.encoding.ser.BeanSerializerFactory; import org.junit.Test; import com.changcheng.webservice.entity.User; public class TestMain { // 測試一般方法 @Test public void hello() throws Exception{ Service s = new Service(); Call call = (Call) s.createCall(); String url = "http://localhost:8080/TestWebService/services/HandlerService"; call.setTargetEndpointAddress(new URL(url)); call.setOperationName("hello"); Object res = call.invoke(new Object[] { "itcast" }); System.out.println(res); } // 測試實體方法 @Test public void update() throws Exception { Service s = new Service(); Call call = (Call) s.createCall(); String url = "http://localhost:8080/TestWebService/services/HandlerService"; call.setTargetEndpointAddress(new URL(url)); call.setOperationName("update"); // 客戶端同樣需要對pojo進行注冊.以確保也能夠進行序列化和反序列化. Class clazz = User.class; // 限定名必須和服務器端注冊限定名保持一致,嚴格區分大小寫 QName qname = new QName("urn:pojo:ws:changcheng:com", "User"); // 注冊類型映射,以便傳遞pojo對象 call.registerTypeMapping(clazz, qname, new BeanSerializerFactory(clazz, qname), new BeanDeserializerFactory(clazz, qname)); // User user = new User(); user.setName("itcast"); user.setPassword("abcd"); Object res = call.invoke(new Object[] { user }); System.out.println(res); } } |
3.運行測試
總結完成!