主要介紹如何使用 axis2 開發 webservice 接口。
以下以實例講解如何編寫一個 axis2 的服務端和客戶端。
axis2版本:axis2-1.5.4-bin.zip
目錄結構:
關鍵代碼:

package com.alfred.check; import java.util.Iterator; import org.apache.axiom.om.OMElement; import org.apache.axis2.AxisFault; import org.apache.axis2.context.MessageContext; public class AccessCheck { public static void checkUserPwd() throws AxisFault { MessageContext msgContext = MessageContext.getCurrentMessageContext(); // 獲取Head Iterator list = (Iterator) msgContext.getEnvelope().getHeader() .getFirstElement().getChildren(); String username = ""; String password = ""; while (list.hasNext()) { OMElement element = (OMElement) list.next(); if (element.getLocalName().equals("username")) { username = element.getText(); } if (element.getLocalName().equals("password")) { password = element.getText(); } } if (!username.equals("admin") || !password.equals("123456")) { throw new AxisFault( " Authentication Fail! Check username/password "); } } }

package com.alfred.service; import org.apache.axis2.AxisFault; import com.alfred.check.AccessCheck; public class SoapService { public String sayHello(String name) throws AxisFault { // 以下是添加axis2訪問頭部驗證 // AccessCheck.checkUserPwd(); return "Hello," + name; } public String getWorld() { return "Hello,World"; } }

package com.alfred.client; import javax.xml.namespace.QName; import org.apache.axis2.AxisFault; import org.apache.axis2.addressing.EndpointReference; import org.apache.axis2.client.Options; import org.apache.axis2.rpc.client.RPCServiceClient; import org.apache.axiom.om.OMAbstractFactory; import org.apache.axiom.om.OMElement; import org.apache.axiom.om.OMFactory; import org.apache.axiom.om.OMNamespace; public class ServiceClient { public static void main(String args[]) throws AxisFault { sendAxis2(); } /** * 添加Header頭部驗證信息 * * @return */ public static OMElement createHeaderOMElement() { OMFactory factory = OMAbstractFactory.getOMFactory(); OMNamespace SecurityElementNamespace = factory.createOMNamespace( "http://handler.com", "wsse"); OMElement authenticationOM = factory.createOMElement("Authentication", SecurityElementNamespace); OMElement usernameOM = factory.createOMElement("username", SecurityElementNamespace); OMElement passwordOM = factory.createOMElement("password", SecurityElementNamespace); usernameOM.setText("admin"); passwordOM.setText("123456"); authenticationOM.addChild(usernameOM); authenticationOM.addChild(passwordOM); return authenticationOM; } /** * 發送axis2的接口信息 * @throws AxisFault */ private static void sendAxis2() throws AxisFault { // 使用RPC方式調用WebService RPCServiceClient serviceClient = new RPCServiceClient(); // 向Soap Header中添加校驗信息 serviceClient.addHeader(createHeaderOMElement()); Options options = serviceClient.getOptions(); // 指定調用WebService的URL EndpointReference targetEPR = new EndpointReference( "http://127.0.0.1:8080/aw/services/mySoapService"); options.setTo(targetEPR); // 指定sayHello方法的參數值,如果有多個,繼續往后面增加即可 Object[] opAddEntryArgs = new Object[] { "alfred" }; // 指定sayHello方法返回值的數據類型的Class對象 Class[] classes = new Class[] { String.class }; // 在創建QName對象時,QName類的構造方法的第一個參數表示WSDL,文件的命名空間名,也就是<wsdl:definitions>元素的targetNamespace屬性值 // 第二個參數是要調用的方法名 QName opAddEntry = new QName("http://service.alfred.com", "sayHello"); // 返回參數類型,這個和axis1有點區別 // invokeBlocking方法有三個參數: // 第一個參數的類型是QName對象,表示要調用的方法名; // 第二個參數表示要調用的WebService方法的參數值,參數類型為Object[]; // 第三個參數表示WebService方法的返回值類型的Class對象,參數類型為Class[]; // 當方法沒有參數時,invokeBlocking方法的第二個參數值不能是null,而要使用new Object[]{} // 如果被調用的WebService方法沒有返回值,應使用RPCServiceClient類的invokeRobust方法, // 該方法只有兩個參數,它們的含義與invokeBlocking方法的前兩個參數的含義相同 Object ret = serviceClient.invokeBlocking(opAddEntry, opAddEntryArgs, classes)[0]; System.out.println(ret); } }

<?xml version="1.0" encoding="UTF-8"?> <serviceGroup> <!-- 可以指定發布多個service --> <service name="mySoapService"> <description> axis2 example </description> <!-- 指定接口類地址 --> <parameter name="ServiceClass"> com.alfred.service.SoapService </parameter> <!-- Operation級消息接收器:可以為不同的操作指定不同的消息接收器 <operation name="sayHello"> <messageReceiver class="org.apache.axis2.rpc.receivers.RPCMessageReceiver" /> </operation> <operation name="getWorld"> <messageReceiver class="org.apache.axis2.rpc.receivers.RPCMessageReceiver" /> </operation> --> <!-- 服務級消息接收器 --> <messageReceivers> <messageReceiver mep="http://www.w3.org/2004/08/wsdl/in-out" class="org.apache.axis2.rpc.receivers.RPCMessageReceiver" /> <messageReceiver mep="http://www.w3.org/2004/08/wsdl/in-only" class="org.apache.axis2.rpc.receivers.RPCInOnlyMessageReceiver" /> </messageReceivers> </service> </serviceGroup>

<?xml version="1.0" encoding="UTF-8"?> <web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"> <!--Axis2 config start--> <display-name>Apache-Axis2</display-name> <servlet> <servlet-name>AxisServlet</servlet-name> <servlet-class>org.apache.axis2.transport.http.AxisServlet</servlet-class> <!--<init-param>--> <!--<param-name>axis2.xml.path</param-name>--> <!--<param-value>/WEB-INF/conf/axis2.xml</param-value>--> <!--<param-name>axis2.xml.url</param-name>--> <!--<param-value>http://localhost/myrepo/axis2.xml</param-value>--> <!--<param-name>axis2.repository.path</param-name>--> <!--<param-value>/WEB-INF</param-value>--> <!--<param-name>axis2.repository.url</param-name>--> <!--<param-value>http://localhost/myrepo</param-value>--> <!--</init-param>--> <load-on-startup>1</load-on-startup> </servlet> <servlet> <servlet-name>AxisAdminServlet</servlet-name> <servlet-class> org.apache.axis2.webapp.AxisAdminServlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>AxisServlet</servlet-name> <url-pattern>/servlet/AxisServlet</url-pattern> </servlet-mapping> <servlet-mapping> <servlet-name>AxisServlet</servlet-name> <url-pattern>/services/*</url-pattern> </servlet-mapping> <servlet-mapping> <servlet-name>AxisServlet</servlet-name> <url-pattern>*.jws</url-pattern> </servlet-mapping> <!--Axis2 end--> <welcome-file-list> <welcome-file>index.jsp</welcome-file> </welcome-file-list> </web-app>
在瀏覽器地址欄輸入地址:http://127.0.0.1:8080/aw/services/mySoapService?wsdl(使用tomcat服務器,項目名為aw),可以看到顯示出 webservice 的 wsdl 信息,說明部署成功。
在 ServiceClient 中,調用 sayHello,打印信息:
需要注意的一點就是 services.xml 文件的存放位置是固定的:WEB-INF/services/ 任意名字的文件夾 /META-INF/services.xml
Axis2 訪問驗證
axis2 接口可以通過向信息頭部(Header)中添加驗證信息,對接口調用者的身份進行驗證。具體配置步驟是:
1、服務端在想要進行訪問驗證的接口方法中(sayHello),添加驗證模塊(AccessCheck.checkUserPwd());
2、驗證模塊通過獲取 webservice 訪問信息頭部,提取驗證信息,對客戶端傳遞的驗證信息進行進行檢查判斷;
3、客戶端調用接口時,加入訪問驗證信息;
// 向Soap Header中添加校驗信息 serviceClient.addHeader(createHeaderOMElement());
Axis2 的 https 訪問
axis2 如果需要進行 https 訪問,需要加入全局配置文件 axis2.xml (Axis2 下提供了三種配置文件,第一種是整個系統的全局配置 axis2.xml,第二種是服務配置 services.xml,第三種是模塊配置 module.xml),默認該文件是存儲在 /WEB-INF/conf/axis2.xml。axis2.xml 文件可以在 axis2 的開發包下獲取。
在 axis2.xml 中加入一段:
<transportReceiver name="https" class="org.apache.axis2.transport.http.AxisServletListener"> <parameter name="port">443</parameter> </transportReceiver>
配置完成后訪問 https://127.0.0.1/aw/services/mySoapService?wsdl 顯示出 webservice 的 wsdl 信息,說明配置成功。
客戶端如果想要訪問 https 的服務端,需將服務端證書加入系統屬性中
//指定服務端證書 System.setProperty("javax.net.ssl.keyStore",ProjConf.SERVER_KEYSTORE); System.setProperty("javax.net.ssl.keyStorePassword",ProjConf.SERVER_KEYSTORE_PASSWORD); System.setProperty("javax.net.ssl.trustStore",ProjConf.SERVER_TRUSTSTORE); System.setProperty("javax.net.ssl.trustStorePassword",ProjConf.SERVER_TRUSTSTORE_PASSWORD);
如果想要手動指定 axis2.xml 文件路徑(例如改為 config 文件夾下),可以在 web.xml 中配置(見上方 web.xml)
<init-param> <param-name>axis2.xml.path</param-name> <param-value>/WEB-INF/config/axis2.xml</param-value> </init-param>
常見錯誤
1、javax.servlet.ServletException: org.apache.axis2.AxisFault: The system is attempting to engage a module that is not available: addressing
解決方法:到 axis2.xml 中查找
<!-- Comment this to disable Addressing --> <module ref="addressing"/>
將 addressing 的引用注釋掉。
2、https is forbidden
解決方法:核實 axis2.xml 文件位置是否正確,默認是在 WEB-INF/conf/axis2.xml,以及 axis2.xml 中是否配置了 https。
3、unable to find valid certification path to requested target
解決方法:核實客戶端訪問 https 是否將證書加入系統屬性。
最后,項目的結構如下: