AXIS實現Web服務深入篇

2021-01-11 開源中國

本文主要介紹使用service方式實現Web服務、複雜類型參數或者返回值以及面向消息/文檔的服務類型,同時還會簡單提及Web服務的會話管理以及安 全問題等等。

前段時間我的一篇文章《應用AXIS開始Web服務之旅》介紹了如何通過AXIS這個項目來實現Web服務的功能。該文章主要介紹AXIS的結構、 如何使用jws文件的方式開發一個簡單的Web服務,並用了比較大的篇幅來介紹Web服務的客戶端編程,應該說是使用AXIS開發Web服務的入門篇,本 文假設你已經看過《應用AXIS開始Web服務之旅》並對AXIS有一定的基礎,在這個基礎上我們將要介紹的內容有幾個方面包括使用service方式實 現Web服務、複雜類型參數或者返回值以及面向消息/文檔的服務類型,同時還會簡單提及Web服務的會話管理以及安全問題等等。

在開始我們的文章之前,我們還需要搭建一個環境,我們需要一個支持Web服務的web應用程式並假設名字為axis,如何建立請參照 《應用AXIS開始Web服務之旅》文章中的介紹。

使用定製發布編寫Web服務

 

使用jws文件的方式編寫Web服務具有方便、快捷的優點,它可以很快的將你已有的類發布成Web服務。但是更多的時候這並不 是一個好的主意,因為這種做法引發的問題是我們必須要將已有類的源碼發布出來,因為更多的時候我們並不想這樣做;另外雖然你可以先用工具開發並調試完畢一 個java文件後再改名為jws,但是這多少有些便扭,而且並不是類中的所有方法你都想發布成可通過Web服務來訪問的,這時候你就必須將這些方法的修飾 符改為不是public的,這就跟你原有的類不同步,以後的修改將會更加的麻煩。

在這裡我把定製發布方式稱為service方式,就好像JSP的出現不會使Servlet失寵的道理一樣,有了jws,service 方式還是有它的用武之地,而且是大放異彩。發布一個service方式的Web服務需要兩部分內容:類文件以及Web服務發布描述文件。下面我們使用一個 簡單的例子來講述這個過程。

首先我們需要一個service類,這個類跟普通的類沒有任何區別,下面是我們實現一個城市便民服務的類,我們需要將 CityService類的兩個方法getZip和getTel發布成Web服務,編譯該文件並把class文件拷貝 到<webapp>/WEB-INF/classes對應目錄下。

Package lius.axis.demo;
/**
* 該類實現了城市服務,用於發布成Web服務
* @author Liudong
*/

public class CityService {
/**
* 獲取指定城市的郵編
* @param city
* @return
*/
public String getZip(String city) {
return "510630";
}

/**
* 獲取指定城市的長途區號
* @param city
* @return
*/

public String getTel(String city) {
return "020";
}
}

 

程序已經完成,下面是發布這個Web服務。打開<webapp>/WEB-INF/server-config.wsdd 如果這個文件不存在則創建一個新的文件,內容如下:

<?xml version="1.0" encoding="UTF-8"?>
<deployment xmlns="http://xml.apache.org/axis/wsdd/"
xmlns:java="http://xml.apache.org/axis/wsdd/providers/java">
<globalConfiguration>
<parameter name="adminPassword" value="admin"/>
<parameter name="attachments.implementation"
value="org.apache.axis.attachments.AttachmentsImpl"/>
<parameter name="sendXsiTypes" value="true"/>
<parameter name="sendMultiRefs" value="true"/>
<parameter name="sendXMLDeclaration" value="true"/>
<parameter name="axis.sendMinimizedElements" value="true"/>
<requestFlow>
<handler type="java:org.apache.axis.handlers.JWSHandler">
<parameter name="scope" value="session"/>
</handler>
<handler type="java:org.apache.axis.handlers.JWSHandler">
<parameter name="scope" value="request"/>
<parameter name="extension" value=".jwr"/>
</handler>
</requestFlow>
</globalConfiguration>
<handler name="LocalResponder" type="java:org.apache.axis.transport.local.LocalResponder"/>
< code sample is too wide > <handler name="URLMapper" type="java:org.apache.axis.handlers.http.URLMapper"/>
<handler name="Authenticate" type="java:org.apache.axis.handlers.SimpleAuthenticationHandler"/>
< code sample is too wide > <service name="city" provider="java:RPC">
<!-- 服務類名 -->
<parameter name="className" value="lius.axis.demo.CityService"/>
<!-- 允許訪問所有方法 -->
<parameter name="allowedMethods" value="*"/>
</service>
<transport name="http">
<requestFlow>
<handler type="URLMapper"/>
<handler type="java:org.apache.axis.handlers.http.HTTPAuthHandler"/>
</requestFlow>
</transport>
<transport name="local">
<responseFlow>
<handler type="LocalResponder"/>
</responseFlow>
</transport>
</deployment>

 

其中粗斜體的部分是我們服務的配置信息,啟動Tomcat並打開瀏覽求訪問地址: http://localhost:8080/axis/services/city?wsdl ,下面是瀏覽器顯示我們Web服務的WDSL數據。


當然了,這個過程比起jws方式來說是稍微麻煩一點,你可以把它想像成你發布一個servlet一樣,創建servlet類然後在 web.xml中加入配置信息。

處理複雜類型參數和返回值

 

之前我們做的演示程序都很簡單,方法的參數和返回值都是簡單類型的數據,但是在實際應用過程中往往沒有這麼簡單。在使用面向對 象的程式語言時,我們會希望數據類型可以是某個對象,比如我們提供一個接口用來發送簡訊息,那麼我們希望接口的參數是一個消息對象,這個消息對象封裝了一 條信息的所有內容包括發送者、接收者、發送時間、優先級、信息內容等等,如果我們把每個內容都做成一個參數,那這個接口的參數可能會非常的多。因此封裝成 對象是很有必要的。

在使用Axis來編寫Web服務時對複雜類型數據的處理同樣也是非常簡單。Axis要求複雜類型對象的編寫必須符合JavaBean的 規範,簡單的說就是對象的屬性是通過getter/setter方法來訪問的。來看看下面這個簡單的例子所輸出的WSDL信息有何特殊的地方。為了簡便, 我們還是使用jws來編寫,需要編寫三個文件:sms.jws,Message.java,Response.java。

//文件名:sms.jws
import lius.axis.demo.*;
public class sms{
/**
* 簡訊息發送Web服務接口
*/

public Response send(Message msg) throws Exception{
System.out.println("CONTENT:"+msg.getContent());
Response res = new Response();
res.setMessage(msg);
res.setCode(0);
res.setErrorText("");
return res;
}
}

 

//Message.javapackage lius.axis.demo;
/**
* 欲發送的信息
* @author Liudong
*/

public class Message {
private String from;
private String to;
private String content;
private int priority;

public String getContent() {
return content;
}

public void setContent(String content) {
this.content = content;
}

public String getFrom() {
return from;
}

public void setFrom(String from) {
this.from = from;
}

public int getPriority() {
return priority;
}

public void setPriority(int priority) {
this.priority = priority;
}

public String getTo() {
return to;
}

public void setTo(String to) {
this.to = to;
}
}

 

//Response.javapackage lius.axis.demo;
/**
* 信息發送回應,在這裡我們做了一個對Message 類的引用
* @author Liudong
*/

public class Response {
private int code;

//發送結果代碼
private String errorText;
private Message message;

//發送的原始信息
public int getCode() {
return code;
}

public void setCode(int code) {
this.code = code;
}

public String getErrorText() {
return errorText;
}

public void setErrorText(String errorText) {
this.errorText = errorText;
}

public Message getMessage() {
return message;
}

public void setMessage(Message message) {
this.message = message;
}
}

 

編譯Message.java和Response.java並將編譯後的類文件拷貝到axis/WEB-INF/classes對應包 的目錄下,sms.jws拷貝到axis目錄,訪問http://localhost:8080/axis/sms.jws?wsdl即可看到WSDL信 息,這些信息與之前不同的在於下面列出的內容(注意粗斜體部分內容):

<wsdl:types>
<schema targetNamespace="http://demo.axis.lius" xmlns="http://www.w3.org/2001/XMLSchema">
<import namespace="http://schemas.xmlsoap.org/soap/encoding/" />
<complexType name="Message">
<sequence>
<element name="content" nillable="true" type="xsd:string" />
<element name="from" nillable="true" type="xsd:string" />
<element name="priority" type="xsd:int" />
<element name="to" nillable="true" type="xsd:string" />
</sequence>
</complexType>
<complexType name="Response">
<sequence>
<element name="code" type="xsd:int" />
<element name="errorText" nillable="true" type="xsd:string" />
<element name="message" nillable="true" type="tns1:Message" />
</sequence>
</complexType>
</schema>
</wsdl:types>

 

這裡定義了兩個類型Message和Response,就是我們接口的參數類型以及返回值的類型。現在再使用WSDL2Java工具來 生成客戶端Helper類看看Axis幫我們做了什麼?它會自動幫我們生成兩個類Message和Response,包名與類名都跟我們剛才定義的一致, 你可以打開看看跟我們剛才編寫的類差別多大?這兩個類添加了很多方法例如getTypeDesc、getSerializer、 getDeserializer等等。現在你就可以隨便寫個小程序測試一下了,我們就不在累贅了。Service方式Web服務的處理跟jws是類似的, 不同在於service方式需要在server-config.wsdd添加類型的映射配置,下面給出一個配置的示例,讀者可以根據實際情況進行修改。

<service name="SmsService" provider="java:RPC">
<parameter name="className" value="lius.axis.demo.SmsService"/>
<parameter name="allowedMethods" value="send"/>
<operation name="send" returnType="ns:Response">
<parameter name="msg" type="ns:Message"/>
</operation>

<!-- 這裡定義了方法的參數以及返回值 -->
<typeMapping deserializer="org.apache.axis.encoding.ser.BeanDeserializerFactory"
encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
qname="ns:Message"
serializer="org.apache.axis.encoding.ser.BeanSerializerFactory"
type="java:lius.axis.demo.Message" xmlns:ns="SmsService"/>

<typeMapping
deserializer="org.apache.axis.encoding.ser.BeanDeserializerFactory"
encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
qname="ns:Response"
serializer="org.apache.axis.encoding.ser.BeanSerializerFactory"
type="java:lius.axis.demo.Response" xmlns:ns="SmsService"/>
</service>

 

其他程式語言也都可以藉助語言本身所附帶的工具來生成這些複雜類型,如果你嫌麻煩的話可以使用XML來描述這些複雜類型,這樣就簡單很 多。

面向消息/文檔的Web服務類型

 

我們前面介紹的服務方式是基於RPC(遠程過程調用)方式,這也是Web服務最常用的方式。面向消息/文檔的的類型跟RPC不 同的是它提供了一個更底層的抽象,要求更多的編程工作。客戶端可以傳入任何的XML文檔,得到的響應不一定是SOAPEnvelope,可以返回任何它所 需要的東西,甚至不返回。雖然這對開發者來說非常的靈活,但是這種通訊類型在實際的應用中並不常見。面向消息/文檔的Web服務主要適合於下面幾種情況, 比如批量處理,基於表單的數據導入,有需要返回非XML數據時,Web伺服器實現中要求直接訪問傳輸層等等。

對於RPC類型的服務需要在全局配置文件server-config.wsdd中設置一行<service ... provider="java:RPC">,其中RPC就是服務的方式,而對於面向消息/文檔的服務類型那java:RPC就要替換成為 Message,並且面向消息/文檔的服務類型必須通過WSDD配置來發表。對於完成面向消息服務的類,其方法必須具有以下的格式:

public Element[] methodName(Element [] elems)

 

其中methodName為你自定義的方法名。在Axis的目錄下可以找到MessageService.java,這就是一個完成了 該類型的服務類,該服務的在WSDD中的配置如下:

<deployment name="test" xmlns="http://xml.apache.org/axis/wsdd/"
xmlns:java="http://xml.apache.org/axis/wsdd/providers/java"
xmlns:xsi="http://www.w3.org/2000/10/XMLSchema-instance">
<service name="MessageService" style="message">
<parameter name="className" value="samples.message.MessageService"/>
<parameter name="allowedMethods" value="methodName"/>
</service>
</deployment>

 

不管是什麼內容的Web服務,對客戶端來說都是一樣的,使用WSDL2Java來生成的客戶端Helper類的 MessageService接口如下:

/**
* MessageService.java
*
* This file was auto-generated from WSDL
* by the Apache Axis WSDL2Java emitter.
*/

package liudong.axis.services.MessageService;
public interface MessageService extends java.rmi.Remote {
public java.lang.Object echoElements(java.lang.Object part) throws java.rmi.RemoteException;
< code sample is too wide >}

我從哪裡可以獲得…

 

Axis文檔中有一句話很有意思,對於絕大多數類似於"我從哪裡可以獲得…"的問題,答案都在MessageContext類 中。通過MessageContext類你可以獲取下面幾個內容,一個AxisEngine實例的引用;請求以及回應的信息;驗證信息以及對於 Servlet規範中的實例引用等等。例如當我們需要客戶端的IP位址時我們可以通過下面代碼片段獲取:

/**
* 獲取客戶端請求
* @return
*/

private HttpServletRequest getRequest() throws Exception{
MessageContext context = MessageContext.getCurrentContext();
HttpServletRequest req = (HttpServletRequest)context.getProperty(HTTPConstants.MC_HTTP_SERVLETREQUEST);
< code sample is too wide > return req.getRemoteHost();
}

 

在類HTTPConstants中,所有以MC_開頭的常量就是你所可以獲取到的信息,例如上面通過 MC_HTTP_SERVLETREQUEST獲取對應Servlet規範中的HTTP請求。更詳細的信息可以通過查詢API文檔獲取。

Web服務會話管理

 

在Web服務中我們可以藉助HTTP以及HTTP Cookie來處理會話信息。前面我們介紹了大多數對Axis的管理都是通過MessageContext實例來完成的。下面的例子首先驗證用戶的登錄帳 號與口令如果正確則在會話中保存用戶的登錄信息,並提供接口供客戶端獲取密碼。

import org.apache.axis.MessageContext;
import org.apache.axis.session.Session;
public class login{
public boolean login(String user, String pass){
MessageContext mc = MessageContext.getCurrentContext();
Session session = mc.getSession();
session.set("user",user);

//保存用戶名與口令
session.set("pass",pass);
return true;
}

public String getPassword(String user){
MessageContext mc = MessageContext.getCurrentContext();
Session session = mc.getSession();
if(user.equals(session.get("user")))
return (String)session.get("pass");
return null;
}
}

 

對於伺服器端來講只需要通過MessageContext實例獲取Session對象即可進行會話級的數據保存或者讀取,而對於通過 Axis的WSDL2Java工具生成的客戶端來講還需要做一個特殊的設置,請看下面客戶端代碼片段。

public static void main(String[] args) throws Exception {
LoginServiceLocator lsl = new LoginServiceLocator();
lsl.setMaintainSession(true);
Login login = lsl.getlogin();
if(login.login("ld","haha"))
System.out.println("PWD:"+login.getPassword("ld"));
else
System.out.println("Login failed.");
}

 

代碼中的粗體部分就是讓Axis幫助我們自動處理伺服器返回的Cookie信息以保證會話正常工作。

保護Web服務

 

網絡的安全問題永遠是需要最先考慮的問題,可是怎麼能讓我們的Web服務更加安全呢?為此Axis建議可以根據實際的需要採取 以下的幾種方法。

使用HTTPS傳輸方式 該方式需要在Web伺服器上進行配置同時需要客戶端的支持。該措施有效的防止數據在網絡傳輸過程中被窺視。重命名Axis已有的一些名字,例如AdminService、AxisServlet,刪除Axis目錄下一些無用的程序,例 如happyaxis.jsp以及一些無用的jar包等。通過設置axis.enableListQuery的值為false來停止AxisServlet列出所有服務的功能。禁止自動生成WSDL的功能使用過濾器來增加一些驗證功能,例如客戶端的地址等。

最常用的不外乎上面幾個,至於更詳細的資料可以參考Axis解壓目錄下的docs/reference.html文件的詳細介紹。

相關焦點

  • 深入研究嵌入式web伺服器視頻監控的應用
    嵌入式web技術是視頻監控系統設計應用最廣泛的技術之一。本文根據監控系統對敖據吞吐量和安全可靠性等各方面的實際要求,結合相關研究的新進展,深入討論了web伺服器在監控系統設計中的應用技巧,並詳細做了實現上的闡述。對所有基於嵌入式web技術的監控系統的設計具有非常實際的指導作用。
  • 基於Django和翻譯API實現web版的中英文對照翻譯(一)
    一番了解之後,決定選用谷歌翻譯/搜狗翻譯/有道翻譯官方提供的翻譯api自己實現一個web版的翻譯界面。目前搜狗翻譯/有道翻譯都已經開始收費,但收費的標準還可以讓人接受,以搜狗翻譯為例,現價:40.00/百萬字符。還是可以接受的。閒言少敘。直入正題。
  • pandas與numpy中神奇的axis
    不知不覺中,pandas各種函數越用越熟練,但是總要靠結果來推算到底應該指定axis=0還是1,你有沒有這種經歷呢?經過摸索,我找到了一種axis利於記憶也好解釋的理論。下面一起來看看吧!核心內容axis是你要操作的軸。pandas導入包,創建一個3X4的dataframe。
  • 手撕numpy(五):一招幫你徹底搞懂axis=0和axis=1
    =0))display(x.sum(axis=1))display(x.sum(axis=2))結果如下=0表示最高維,axis=1表示次高維,依次下去。因此,對於三維數組來說,axis=0指的就是最高維(三維),axis=1指的就是次高維(二維),那麼axis=2指的就是最低維(一維)。
  • web時代的權力演化
    而web 是world wide web(全球資訊網)的簡稱,不是縮寫,全球資訊網是基於http協議進行交互的應用網絡。也就是說,web是運行於網際網路之上的系統。進一步說,網際網路是針對的計算機(點到點),web是針對的計算機上的應用(端到端)。以前,web可以說就是通過使用瀏覽器訪問的各種資源,這是Web1.0時代。
  • Web1.0與Web2.0和Web3.0的本質區別是什麼
    到用戶直接交互的web2.0,再到用戶自主控制數據的web3.0。經過十多年的發展,web2.0的已經極大豐富。而web3.0才剛剛露出尖尖角,它以區塊鏈和加密貨幣為重要基礎,引導網際網路走向個人控制數據所有權,並實現個人隱私。但向真正走向web3.0,並非坦途,web2.0經過十多年的發展,由全世界如此眾多的聰明人不斷改進才取得今日的成就,而web3.0要成為主流採用的網絡,所需的時間也不可能短。
  • 用Scala實現簡單的Web和API伺服器
    這篇指南將向你介紹如何利用Scala簡單的HTTP伺服器,來提供Web內容和API。本文還會介紹一個完整的例子,告訴你如何構建簡單的實時聊天網站,同時支持HTML網頁和JSON API端點。這篇文及章的目的是介紹怎樣用Scala實現簡單的HTTP伺服器,從而提供網頁服務,以響應API請求。
  • Worktile中百萬級實時消息推送服務的實現
    Worktile中的推送服務是採用的是基於XMPP協議、Erlang語言實現的Ejabberd,並在其源碼基礎上,結合我們的業務,對源碼作了修改以適配我們自身的需求。另外,基於AMQP協議也可以作為實時消息推送的一種選擇,踢踢網就是採用 RabbitMQ+STOMP協議實現的消息推送服務。本文將結合我在Worktile和踢踢網的項目實踐,介紹下消息推送服務的具體實現。
  • 關於Numpy和Pandas axis的理解
    ,那麼如果上升為3維數組呢,沒錯,還會多出來一個axis:2。到這裡你應該明白,axis其實就是對數組層數的操作,ndim是幾,那麼對應的axis就有幾個,下面看一張圖,或許你就會明白。操作通俗理解(二維數組)當axis=0的時候,即對第一層進行操作,此時Numpy只對第一層內的數組進行操作,即axis執行方向從上到下;當axis=1的時候,即對第二層進行操作,此時Numpy只對第二層內的數組進行操作,即axis執行方向從左到右。
  • 基於OSGi和Spring開發Web應用
    Web 層基於 Spring-MVC 實現,包含處理 Web訪問相關的 bundle(本例中只有一個)。服務層包含處理數字計算的 bundle,本例中包含一個聲明服務接口的 compute interface bundle 和兩個實現該服務接口的 bundle :add bundle 和 multiply bundle。基本模塊結構如下圖所示:圖 3. 基本框架
  • Azure 靜態 web 應用集成 Azure 函數 API
    前幾次我們演示了如何通過Azure靜態web應用功能發布vue跟blazor的項目(使用 Azure靜態web應用+Github全自動部署VUE站點、使用Azure靜態Web應用部署Blazor Webassembly應用)。
  • 區塊鏈是連接Web2.0與Web3.0橋梁的重要基石
    這就是web2.0時代下網絡服務的中心化模式。然而,網際網路中心化所帶來的資源集中和寡頭效應也存在著巨大的隱患,數據被盜事件屢禁不止,信息洩露所帶來的詐騙和騷擾所有人都深有體會。因為這些你認為屬於你的數據,掌握在人家手裡,斯諾登事件就是最好的證明。在去中心化網絡中,這種直接點對點網絡的原則被應用於網站和網絡應用。
  • 全棧AI工程師指南,DIY一個識別手寫數字的web應用
    第一篇 介紹開發環境--訓練模型--保存至本地; 第二篇 介紹導入訓練好的模型--識別任意的手寫數字圖片; 第三篇 介紹用Flask整合keras訓練好的模型,並開發後端服務;
  • Web前端和後端有什麼區別(上)
    前端主要負責頁面展示,後端是業務邏輯的實現。 包括Web頁面的結構、Web的外觀視覺表現以及Web層面的交互實現。 2、Web後端: 後臺更多的是通過與資料庫交互來處理相應的業務邏輯。要考慮的問題有:功能的實現,數據的訪問,平臺的穩定性和性能等等。
  • Google通過Web App將Stadia雲遊戲服務引入iOS
    谷歌今天宣布,該體育場,其雲遊戲服務,將來到iPhone和iPad上通過即將到來的web應用程式在不久的將來。自推出以來,由於蘋果公司對雲遊戲服務的限制,谷歌一直無法將Stadia引入iOS設備。蘋果在八月份表示,允許在App Store上使用雲遊戲服務,但每個單獨的遊戲都必須提交以供Apple的「 App Store」團隊進行審查。到目前為止,向「 App Store」提交數百種遊戲並不是任何雲遊戲服務都想要做的事情,而這些服務卻選擇了Web訪問。
  • 如何配置web伺服器
    如何配置web伺服器?在伺服器上配置Web服務,首先需要安裝網絡環境,然後上傳web項目文件,在配置web服務時,有一些安全策略也要注意。1 啟用日誌記錄功能Web伺服器應配置日誌功能,對用戶登錄進行記錄,記錄內容包括用戶登錄使用的帳號、登錄是否成功、登錄時間以及遠程登錄時用戶使用的IP位址。
  • web伺服器性能對比
    可以實現一個進程程響應多個用戶請求。支持持海量並發連接數,消耗更少的資源。二、如何提高Web伺服器的並發連接處理能力有幾個基本條件:1、基於線程,即一個進程生成多個線程,每個線程響應用戶的每個請求。2、基於事件的模型,一個進程處理多個請求,並且通過epoll機制來通知用戶請求完成。
  • 使用eclipse開發Java Web項目
    本篇首先給出Tomcat 8.0的安裝及驗證過程,然後在eclipse中配置已安裝成功的Tomcat伺服器,最後新建一個Java web工程,並綁定已部署的Tomcat伺服器,在工程中新建並運行JSP文件。
  • Web3.0改變中心化網絡 將是網際網路先行者的最初設想
    咱們來仔細看一看 Web3.0是如何實現的,以及加密技術在網際網路發展中所扮演的角色。現代網際網路模式討論 Web3.0之前,我們需要了解一下上一個版本。web1.0是原始的網際網路:一個由超級連結連接起來的巨大的web網絡,在錯綜複雜的網狀參考中彼此相連。
  • WindowServer2003伺服器搭建WEB伺服器
    3、Windows Server 2003 Enterprise Edition是企業版,支持高性能伺服器,並且可以群集伺服器,以便處理更大的負荷,通過這些功能實現了可靠性,有助於確保系統即使在出現問題時仍可用。