JAVA——咖啡館Velocity 的應用示例- -| 回首頁 | 2005年索引 | - -Web Service 的開發層次 |
對于webService 以前也接觸過.但只是皮毛,這次可是來真格的.來就來吧,年輕人這就是機會.一定得把握好,干它一票! 呵,就在網上到處找找啊,在本地機器上左試試,右試試啊, 什么法子都用一遍。就不信搞不定它,小樣!
網上的例子也比較散,比較簡易的,達不我想要的業務水平,只能慢慢搜索與摸索吧。。。。。。就這樣天天想著這事,也沒什么心情來這里寫寫。
近些天,也快回深圳了,定在下周四動身吧。這邊的工作也得告一節了。把我前一些日子,搞一個完整的Samples 放到這里來,與大家共享。希望對有心人有些啟發,也希望高人指點與點評。。。。。。。、
****************************************************
*Axis開發Webservice傳Bean對象返回String串的實例.rtf*
****************************************************
在ECLIPSE 里新建一工程,其次建包,再次建類,
基本包:samples.userguide.example5
基本類: Order.java
內容:
* Order.java *
*《********************************
package samples.userguide.example5;
/**
* This is a JavaBean which represents an order for some products.
* Copyright: Copyright (c) 2007-1
* @author Black skin (blackskin@126.com)
* @version 1.0
*/
public class Order {
/** Who's ordering */
private String customerName;
/** Where do they live */
private String shippingAddress;
/** Which items do we want */
private String itemCodes[];
/** And how many */
private int quantities[];
// Bean accessors
public String getCustomerName() {
return customerName;
}
public void setCustomerName(String name) {
customerName = name;
}
public String getShippingAddress() {
return shippingAddress;
}
public void setShippingAddress(String address) {
shippingAddress = address;
}
public String[] getItemCodes() {
return itemCodes;
}
public void setItemCodes(String[] items) {
itemCodes = items;
}
public int[] getQuantities() {
return quantities;
}
public void setQuantities(int[] quants) {
quantities = quants;
}
}
********************************》*
主服務包: samples.userguide.example5
主服務類: BeanService.java
如下:
* BeanService.java *
**《*******************************
package samples.userguide.example5;
/**
* This is a JavaBean which represents an order for some products.
* Copyright: Copyright (c) 2007-1
* @author Black skin (blackskin@126.com)
* @version 1.0
*/
public class BeanService {
public String processOrder(Order order) {
String sep = System.getProperty("line.separator");
String response = "Hi, " + order.getCustomerName() + "!" + sep;
response += sep + "You seem to have ordered the following:" + sep;
String[] items = order.getItemCodes();
int[] quantities = order.getQuantities();
for (int i = 0; i < items.length; i++) {
response += sep + quantities[i] + " of item : " + items[i];
}
response += sep + sep + "If this had been a real order processing system, "
+ sep + "we'd probably have charged you about now.";
return response;
}
public static void main(String[] args) throws Exception{
/** Who's ordering */
String customerName = "Black Skin";
/** Where do they live */
String shippingAddress = "001 xingan Street, bayuquan, YK";
/** Which items do we want */
String[] items = new String[] { "apple", "160ml-Milk" };
/** And how many */
int[] quantities = new int[] { 2, 4 };
/** request class init() */
Order order = new Order();
order.setCustomerName(customerName);
order.setShippingAddress(shippingAddress);
order.setItemCodes(items);
order.setQuantities(quantities);
/** server class init() */
BeanService beanservice = new BeanService();
String result = beanservice.processOrder(order);
/** OutPut the result */
System.out.println(" " + result);
}
}
********************************》*
BeanService.java里有個本地測試方法(samples.userguide.example5.BeanService.main()),來測試此應用的可運行性;
到此,服務端類寫完了,接著來把此類的方法發布成 WebService 接口
手寫一個deploy.wsdd 文件,可以參考下面的例子:
*deploy.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">
<service name="服務名" provider="java:RPC">
<parameter name="className" value="服務類文件的實際路徑(包括包的信息)"/>
<parameter name="allowedMethods" value="*(即為所有方法都可訪問,如要指定多個可用空格分隔開)"/>
<parameter name="allowedRoles" value="user"/>
<parameter name="scope" value="Session"/>
<requestFlow>
<handler type="java:org.apache.axis.handlers.SimpleAuthenticationHandler"/>
</requestFlow>
</service>
</deployment>
********************************》*
顯然,簡單,造一個deploy.wsdd 信手捏來,如下:
*deploy.wsdd*
*《********************************
<deployment xmlns="http://xml.apache.org/axis/wsdd/" xmlns:java="http://xml.apache.org/axis/wsdd/providers/java">
<service name="OrderProcessor" provider="java:RPC">
<parameter name="className" value="samples.userguide.example5.BeanService"/>
<parameter name="allowedMethods" value="processOrder"/>
<beanMapping qname="myNS:Order" xmlns:myNS="urn:BeanService" languageSpecificType="java:samples.userguide.example5.Order"/>
</service>
</deployment>
********************************》*
有了deploy.wsdd文件了,接著通過它來生成 server-config.wsdd.
OK! 用命令直接生成就行;在deploy.wsdd 的文件夾下新建一個 makeWsdd.bat.
其中的寫法有下面的例子來參考:
* makeWsdd.bat 例子*
*《********************************
set AXISCLASSPATH= “應用發布的路徑”
set AXIS_LIB= “AXIS框架的內部JAR包LIB路徑”
SET CLASSPATH=.;%CLASSPATH%;%AXIS_LIB%\wsdl4j-1.5.1.jar;%AXIS_LIB%\axis.jar;%AXIS_LIB%\jaxrpc.jar;
%AXIS_LIB%\saaj.jar;%AXIS_LIB%\commons-discovery-0.2.jar;%AXIS_LIB%\commons-logging-1.0.4.jar
java -Djava.ext.dirs=%AXISCLASSPATH% org.apache.axis.client.AdminClient
-S服務名\services\AdminService -p端口號(如果你的端口號不是默認的8080需要指定。
例如:8899)deploy.wsdd
********************************》*
如此,我寫了一“makeWsdd.bat”文件。如下:
* makeWsdd.bat*
*《********************************
set AXISCLASSPATH=C:\Axis_webservice\Tomcat_4.1\webapps\axis
set AXIS_LIB=C:\axis-1_4\lib
SET CLASSPATH=.;%CLASSPATH%;%AXIS_LIB%\wsdl4j-1.5.1.jar;%AXIS_LIB%\axis.jar;%AXIS_LIB%\jaxrpc.jar;
%AXIS_LIB%\saaj.jar;%AXIS_LIB%\commons-discovery-0.2.jar;%AXIS_LIB%\commons-logging-1.0.4.jar
java -Djava.ext.dirs=%AXISCLASSPATH% org.apache.axis.client.AdminClient
-SBeanServer\services\AdminService -p 8080 deploy.wsdd
********************************》*
保存好,接下來架設Webservice.
環境架設:
首先,安裝JDK...(略)...本例用JDK版本號V1.4.
其次,安裝Tomcat...(略)...本例用Tomcat版本號V4.1.
再次,AXIS...(略)...本例用AXIS版本號V1.4. 去AXIS官方網站:http://www.apache.org下載AXIS,解壓后得,
|- axis-1_4
|- docs
|- ..(略)...
|- lib
|- axis.jar
|- axis-ant.jar
|- commons-discovery-0.2.jar
|- commons-logging-1.0.4.jar
|- jaxrpc.jar
|- log4j-1.2.8.jar
|- log4j.properties
|- saaj.jar
|- wsdlj-1.5.1.jar
|- samples
|- ..(略)...
|- webapps
|- axis
|- ..(略)...
|- xmls
|- ..(略)...
將解壓后,C:\axis-1_4\webapps 目錄下的 axis 目錄 Copy 到 tomcat/webapps目錄(C:\Axis_webservice\Tomcat_4_1\webapps)下,
架設AXIS:
首先,將deploy.wsdd文件Copy到 %AXISCLASSPATH%/WEB-INF 目錄下;
其次,將之前的類編譯后,連路徑一起Copy到 %AXISCLASSPATH%/WEB-INF/classes目錄下,
最后,將tomcat的 catalina 服務啟動.
(即:C:\Axis_webservice\Tomcat_4.1\bin,
[特別注意的是:]
A。tomcat務必啟動。
B。在寫如上的命令行時,務必注意參數的寫法。“-D” 與 “-S”與其值間不能有空格。切記!
C。各XX的路徑里,最好是不要有空格,因為JAVA里對大小寫與路徑空格有校驗。
,)
測試:
命令行啟動方法;運行"cmd",在命令行里寫:"cd C:\Axis_webservice\Tomcat_4.1\bin",回車,再寫:" catalina run ",回車,OK!
后臺會報錯:
"
- Unable to find config file. Creating new servlet engine config file: /WEB-INF/server-config.wsdd
2007-1-20 10:07:48 org.apache.coyote.http11.Http11Protocol start
信息: Starting Coyote HTTP/1.1 on port 8080
"
說明,在../WEB-INF/下沒有"server-config.wsdd",暫時忽略。
在IE地址欄寫:http://localhost:8080/axis
可見,axis 歡迎首頁,點擊 "list" 便可看到默認情況下發布了兩個服務下各有一個方法。一切準備工作已經OK!
再回到,剛才我們寫的那個批處理文件:" makeWsdd.bat",
直接雙擊,便可執行, 有一個警告,可以忽略的。執行完成后,在相應的
%AXISCLASSPATH%/WEB-INF下便有一“server-config.wsdd”文件,如下:
*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="sendMultiRefs" value="true"/>
<parameter name="disablePrettyXML" value="true"/>
<parameter name="adminPassword" value="admin"/>
<parameter name="attachments.Directory" value="C:\Axis_webservice\Tomcat_4.1\webapps\axis\WEB-INF\attachments"/>
<parameter name="dotNetSoapEncFix" value="true"/>
<parameter name="enableNamespacePrefixOptimization" value="false"/>
<parameter name="sendXMLDeclaration" value="true"/>
<parameter name="sendXsiTypes" value="true"/>
<parameter name="attachments.implementation" value="org.apache.axis.attachments.AttachmentsImpl"/>
<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"/>
<handler name="URLMapper" type="java:org.apache.axis.handlers.http.URLMapper"/>
<handler name="Authenticate" type="java:org.apache.axis.handlers.SimpleAuthenticationHandler"/>
<service name="AdminService" provider="java:MSG">
<parameter name="allowedMethods" value="AdminService"/>
<parameter name="enableRemoteAdmin" value="false"/>
<parameter name="className" value="org.apache.axis.utils.Admin"/>
<namespace>http://xml.apache.org/axis/wsdd/</namespace>
</service>
<service name="Version" provider="java:RPC">
<parameter name="allowedMethods" value="getVersion"/>
<parameter name="className" value="org.apache.axis.Version"/>
</service>
<service name="OrderProcessor" provider="java:RPC">
<parameter name="allowedMethods" value="processOrder"/>
<parameter name="className" value="samples.userguide.example5.BeanService"/>
<beanMapping languageSpecificType="java:samples.userguide.example5.Order" qname="ns1:Order" xmlns:ns1="urn:BeanService"/>
</service>
<transport name="http">
<requestFlow>
<handler type="URLMapper"/>
<handler type="java:org.apache.axis.handlers.http.HTTPAuthHandler"/>
</requestFlow>
<parameter name="qs:list" value="org.apache.axis.transport.http.QSListHandler"/>
<parameter name="qs:wsdl" value="org.apache.axis.transport.http.QSWSDLHandler"/>
<parameter name="qs.list" value="org.apache.axis.transport.http.QSListHandler"/>
<parameter name="qs.method" value="org.apache.axis.transport.http.QSMethodHandler"/>
<parameter name="qs:method" value="org.apache.axis.transport.http.QSMethodHandler"/>
<parameter name="qs.wsdl" value="org.apache.axis.transport.http.QSWSDLHandler"/>
</transport>
<transport name="local">
<responseFlow>
<handler type="LocalResponder"/>
</responseFlow>
</transport>
</deployment>
********************************》*
再去打開:"http://localhost:8080/axis/servlet/AxisServlet",或者,再刷新。
便可以看到,我們新發布的一個webservice接口服務,其名為:"OrderProcessor "
此服務下的個方法:其名為:"processOrder "。
點擊服務對應的"(WSDL)"可見服務WSDL描述內容。在其中也可以得服務的訪問地址:
"http://localhost:8080/axis/services/OrderProcessor?wsdl"
服務器端的開發,搞定了!
-:) -:) -:)
接下來,準備開發,客戶端的開發。
* Client.java *
*《********************************
package samples.userguide.example5;
/**
* This is a JavaBean which represents an order for some products.
* Copyright: Copyright (c) 2007-1
* @author Black skin (blackskin@126.com)
* @version 1.0
*/
import java.net.URL;
import org.apache.axis.AxisFault;
import org.apache.axis.client.Call;
import org.apache.axis.client.Service;
import org.apache.axis.utils.Options;
import javax.xml.namespace.QName;
import javax.xml.rpc.ParameterMode;
public class Client {
public static void main(String[] args) throws Exception {
//Options options = new Options(args);
String urlWsdl = "http://localhost:8080/axis/services/OrderProcessor?wsdl";
Order order = new Order();
order.setCustomerName("Black Skin");
order.setShippingAddress("275 Grove Street, Newton, MA");
String[] items = new String[] { "apple", "160ml-Milk" };
int[] quantities = new int[] { 8, 4 };
order.setItemCodes(items);
order.setQuantities(quantities);
Service service = new Service();
Call call = (Call) service.createCall();
QName qn = new QName("urn:BeanService", "Order");
call.registerTypeMapping(Order.class, qn,
new org.apache.axis.encoding.ser.BeanSerializerFactory(
Order.class, qn),
new org.apache.axis.encoding.ser.BeanDeserializerFactory(
Order.class, qn));
String result;
try {
//call.setTargetEndpointAddress(new java.net.URL(options.getURL()));
call.setTargetEndpointAddress(new java.net.URL(urlWsdl));
call.setOperationName(new QName("OrderProcessor", "processOrder"));
call.addParameter("arg1", qn, ParameterMode.IN);
call.setReturnType(org.apache.axis.encoding.XMLType.XSD_STRING);
result = (String) call.invoke(new Object[] { order });
} catch (AxisFault fault) {
result = "Error : " + fault.toString();
}
System.out.println(result);
}
}
********************************》*
oK! 到此,一個完整的Webservice例子就搞定了。
另外,Axis 還提供了一些工具,如:" wsdl2java "、" java2wsdl "
處理的方式與方法:
java2wsdl:
1. 以上為例,在以上工程的class輸出目錄新建一BAT文件:名為:“java2wsdl.bat”
2. 其內容為:
* java2wsdl.bat *
*《********************************
set AXIS_LIB=C:\axis-1_4\lib
SET CLASSPATH=.;%CLASSPATH%;%AXIS_LIB%\wsdl4j-1.5.1.jar;%AXIS_LIB%\axis.jar;%AXIS_LIB%\jaxrpc.jar;%AXIS_LIB%\saaj.jar;%AXIS_LIB%\commons-discovery-0.2.jar;%AXIS_LIB%\commons-logging-1.0.4.jar
java org.apache.axis.wsdl.Java2WSDL -o Order.wsdl -l"http://localhost:8080/axis/services/OrderProcessor" -n "urn:BeanService" -p"samples.userguide.example5.Order" "urn:Order" samples.userguide.example5.BeanService
********************************》*
把AXIS_LIB設為正確的本地包路徑,再運行“java2wsdl.bat”,
便可以在目錄下看到一個文件:“Order.wsdl”,通過這個WSDL文件,可以生成Webservice接口服務的框架,
既可以是服務器端,也可以是客戶端框架。其細節,可以參考下一節。
處理的方式與方法:
wsdl2java :
1. 以上為例,把Order.wsdl拷貝過來,在其目錄下新建一BAT文件:名為:“wsdl2java.bat”
2. 其內容為:
* wsdl2java.bat *
*《********************************
set AXIS_LIB=C:\axis-1_4\lib
SET CLASSPATH=.;%CLASSPATH%;%AXIS_LIB%\wsdl4j-1.5.1.jar;%AXIS_LIB%\axis.jar;%AXIS_LIB%\jaxrpc.jar;%AXIS_LIB%\saaj.jar;%AXIS_LIB%\commons-discovery-0.2.jar;%AXIS_LIB%\commons-logging-1.0.4.jar
java org.apache.axis.wsdl.WSDL2Java Order.wsdl
********************************》*
或者有另外的作法:把服務端的應用啟動,直接寫成:
“
java org.apache.axis.wsdl.WSDL2Java http://localhost:8080/axis/services/OrderProcessor?wsdl
”
保存好后,運行這個BAT文件,
便會自動生成:
BeanService_pkg\
BeanService.java
BeanServiceService.java
BeanServiceServiceLocator.java
OrderProcessorSoapBindingStub.java
Order.java
ok.
隨著Web服務技術的發展和成熟,其方便性和易用性已逐漸被人們所接受,越來越多的合作伙伴之間開始利用Web服務來實現合作方之間的數據接口。使用Apache Axis和Linux平臺是一種低成本的Web服務解決方案,但Apache Axis文檔的FAQ對開發者來說內容還不夠豐富,本文作者將自己使用Axis時遇到的問題和解決方法整理成文,奉獻給Web服務的開發人員和對此感興趣的讀者朋友,旨在幫助大家節約一些寶貴的時間。有關Web服務的基礎知識,讀者可以閱讀參考文獻中推薦的文檔。作者未在文中介紹Apache和Resin的安裝方法,讀者可以參考相關網站的說明文檔。
作者使用的軟件環境如下。
操作系統:Red Hat Linux 7.2
Web服務器: Apache 1.3.27
應用服務器:Resin 2.1.8 ( http://www.caucho.com/ )
SOAP服務器:Apache Axis 1.1
XML解析器:Xerces 2.5.0,Xalan 2.5.1
JDK版本:JDK 1.4.1
2.1 Axis運行需要哪些jar文件
對Axis解包后,將axis-1_1/webapps/axis/WEB-INF/lib/目錄下的jar文件復制到/usr/local/apache/htdocs/WEB-INF/lib目錄下(Web應用程序的目錄)。應包括以下jar文件。
axis-ant.jar axis.jar commons-discovery.jar commons-logging.jar jaxrpc.jar log4j-1.2.8.jar name.txt saaj.jar wsdl4j.jar |
如果需要使用axis提供的測試頁面,還要將axis-1_1/webapps/axis/目錄下的文件復制到/usr/local/apache/htdocs/axis/目錄下。應包括以下募?
EchoHeaders.jws fingerprint.jsp happyaxis.jsp index.html |
XML解析器選用不當,經常會導致使用Apache Axis時出現一些莫名其妙的問題。
由于Apache Axis 并未對Resin內置的xml解析器進行過測試,因此推薦讀者使用已通過測試的Xerces xml解析器。可以從 http://xml.apache.org/xalan-j/index.html 處下載Xalan的Java版XSLT處理器,其中包含了Xerces的Java版XML解析器,不需要再單獨下載xml解析器。
Xalan 2.5.1解包后,將bin/目錄下的xercesImpl.jar、xml-apis.jar和xalan.jar復制到resin安裝目錄的lib/目錄下,例如/usr/local/resin/lib。
編輯/etc/目錄下的profile文件,找到設置CLASSPATH環境變量的位置,在其后加入下面的內容(B shell)。
XMLPARSER=$RESIN_HOME/lib/xalan.jar:$RESIN_HOME/lib/xercesImpl.jar:$RESIN_HOME/lib/xml-apis.jar export CLASSPATH=$XMLPARSER:$CLASSPATH |
2.2.1 注意事項
如果CLASSPATH中包含其它的XML解析器設置,應將其從CLASSPATH環境變量的設置中去掉,以免發生沖突。
通過修改resin.conf將resin的XmlParser置換為Xerces的XmlParser。在resin.conf對應的Web應用程序配置中加入以下設置。
<system-property javax.xml.transform.TransformerFactory="org.apache.xalan.processor.TransformerFactoryImpl"/> <system-property javax.xml.parsers.DocumentBuilderFactory="org.apache.xerces.jaxp.DocumentBuilderFactoryImpl"/> <system-property javax.xml.parsers.SAXParserFactory="org.apache.xerces.jaxp.SAXParserFactoryImpl"/> <system-property org.xml.sax.driver="org.apache.xerces.parsers.SAXParser"/> |
配置完成后重新啟動Resin。
2.4.1 問題描述
使用http://test.com/axis查看已部署的服務時出現Axis內部錯,顯示有關WSDD配置的異常信息。如果把WEB-INF目錄下的server-config.wsdd刪除,再查看就正常了,但只能看到AdminService和Version兩個系統缺省的服務,后來部署的服務都看不到了。
2.4.2 原因分析
Axis會在WEB應用程序的WEB-INF/目錄下自動生成一個名字為server-config.wsdd的xml文件,其中記錄了已部署的WEB服務。每部署一個新的WEB服務時,Axis都會將新服務的描述信息加入到server-config.wsdd中。
故障站點使用的XmlParser是resin內置的XmlParser,Axis并未對其對進行過兼容性測試,查看WEB服務信息時需要從server-config.wsdd(這是一個xml文件)取得已部署的WEB服務描述信息,當server-config.wsdd的內容較復雜時,resin內置的XmlParser因某種原因出現異常,導致Axis內部錯誤。Server-config.wsdd中記錄的Web服務描述信息較少時不會出現異常。
2.4.3 解決方法
修改resin.conf,將resin的XmlParser置換為Xerces的XmlParser。置換方法參見2.3節。
2.4.4 小結
如果Axis報告的錯誤中有關于xml解析器的錯誤,建議讀者參照本小節描述的方法更換應用服務器的xml解析器,將會有助于問題的解決。
Axis是以Servlet的方式運行的,而Resin的作用相當于Servlets容器(Container),因此只要配置得當,就可以使Axis在Resin環境中運行,這一點也適用于Resin以外的其它應用服務器。在Resin中配置Axis的方法如下。
將axis-1_1/webapps/axis/WEB-INF/web.xml中的Servlet配置項復制到resin.conf中對應的Web應用程序配置中。通常應包括以下內容。
<!-- Axis Web-Service Configuration Start --> <servlet> <servlet-name>AxisServlet</servlet-name> <display-name>Apache-Axis Servlet</display-name> <servlet-class> org.apache.axis.transport.http.AxisServlet </servlet-class> </servlet> <servlet> <servlet-name>AdminServlet</servlet-name> <display-name>Axis Admin Servlet</display-name> <servlet-class> org.apache.axis.transport.http.AdminServlet </servlet-class> <load-on-startup>100</load-on-startup> </servlet> <servlet> <servlet-name>SOAPMonitorService</servlet-name> <display-name>SOAPMonitorService</display-name> <servlet-class> org.apache.axis.monitor.SOAPMonitorService </servlet-class> <init-param> <param-name>SOAPMonitorPort</param-name> <param-value>5001</param-value> </init-param> <load-on-startup>100</load-on-startup> </servlet> <servlet-mapping> <servlet-name>AxisServlet</servlet-name> <url-pattern>/axis/servlet/AxisServlet</url-pattern> </servlet-mapping> <servlet-mapping> <servlet-name>AxisServlet</servlet-name> <url-pattern>*.jws</url-pattern> </servlet-mapping> <servlet-mapping> <servlet-name>AxisServlet</servlet-name> <url-pattern>/services/*</url-pattern> </servlet-mapping> <servlet-mapping> <servlet-name>SOAPMonitorService</servlet-name> <url-pattern>/SOAPMonitor</url-pattern> </servlet-mapping> <!-- uncomment this if you want the admin servlet --> <!-- <servlet-mapping> <servlet-name>AdminServlet</servlet-name> <url-pattern>/axis/servlet/AdminServlet</url-pattern> </servlet-mapping> --> <!-- currently the W3C havent settled on a media type for WSDL; http://www.w3.org/TR/2003/WD-wsdl12-20030303/#ietf-draft for now we go with the basic 'it's XML' response --> <mime-mapping> <extension>wsdl</extension> <mime-type>text/xml</mime-type> </mime-mapping> <mime-mapping> <extension>xsd</extension> <mime-type>text/xml</mime-type> </mime-mapping> <!-- Axis Web-Service Configuration End --> |
Apache Axis提供了WSDL2Java和Java2WSDL兩個開發工具。
WSDL2Java利用已知的WSDL文件生成服務端和客戶端代碼。該WSDL文件可以是由合作伙伴提供的,也可以是利用Java2WSDL生成的。Java2WSDL根據已有的Java類文件生成WSDL文件,Java類文件可以是接口類文件,并不需要實現細節。
此外Axis還提供了SoapMonitorApplet和TCPMon工具,可用于監測Web服務。
2.7.1 生成或取得WSDL文件
Java2WSDL是Axis提供的利用Java類文件得到WSDL文件的工具。類文件可以使用接口文件編譯生成,例如下面的接口文件SoftwarePrice.java。
package samples.userguide.example6; /** * Interface describing a web service to set and get software prices. **/ public interface SoftwarePrice { public void setWidgetPrice(String softWareName, String price); public String getWidgetPrice(String softWareName); |
編譯SoftwarePrice.java。
javac SoftwarePrice.java |
將SoftwarePrice.class復制到正確的package路徑下。
執行下面的命令:
java org.apache.axis.wsdl.Java2WSDL -o sp.wsdl -l"http://test.com:80/services/SoftwarePrice" -n "urn:SoftwarePrice" -p"samples.userguide.example6" "urn:Example6" samples.userguide.example6.SoftwarePrice |
各參數的含義如下。
-o:指定輸出的WSDL文件的文件名。 |
最后面的類文件包含了Web服務的接口。
該命令執行后,將生成sp.wsdl文件。
如果按CLASSPATH的設置找不到指定的類文件,Axis將報告異常,如下所示。
java.lang.ClassNotFoundException: samples.userguide.example6.SoftwarePrice at java.net.URLClassLoader$1.run(URLClassLoader.java:198) at java.security.AccessController.doPrivileged(Native Method) …… |
如果出現上面的問題,請檢查是否已將有關類文件復制到正確的位置或CLASSPATH設置是否正確。
生成WSDL文件以后,就可以利用Axis提供的WSDL2Java工具生成Web服務的服務端代碼和客戶端代碼了。
2.7.1.1 注意事項
WSDL文件也可以由合作伙伴提供。這種情況下合作伙伴往往是Web服務的提供者或標準接口的制定者,開發者只要按照既定的WSDL文件生成客戶端或服務端代碼就可以了。
2.7.2 生成客戶端或服務端代碼
WSDL2Java工具用于從WSDL文件生成客戶端存根(stub)代碼,服務端框架(skeleton)代碼以及WSDL中的數據類型文件(生成與之對應的Java代碼)。開發人員只需向框架代碼中補充相關的業務邏輯代碼即可得到完整的Web服務代碼,因此該工具極大地減輕了開發人員的編碼負擔。WSDL2Java的使用舉例如下。
java org.apache.axis.wsdl.WSDL2Java --server-side --skeletonDeploy true MyService.wsdl |
執行上述命令后將生成下列文件。
No. | 文件 | 用途 |
1. | deploy.wsdd | MyService服務的部署描述文件 |
2. | MyService.java | MyService服務的接口文件 |
3. | MyServiceService.java | 獲得MyService服務的接口文件 |
4. | MyServiceServiceLocator.java | 實現MyServiceService接口 |
5. | MyServiceSoapBindingImpl.java | 實現MyService接口,應向其中補充業務邏輯 |
6. | MyServiceSoapBindingSkeleton.java | MyService服務的服務端框架代碼,實現MyService, org.apache.axis.wsdl.Skeleton接口 |
7. | MyServiceSoapBindingStub.java | MyService服務的客戶端存根代碼,實現MyService接口 |
8. | undeploy.wsdd | 注銷MyService服務的部署描述文件 |
2.7.3 編寫Web服務客戶端代碼
Web服務的客戶端程序完成對Web服務的調用,其程序結構如下。
import com.chinavnet.zx.service.v1_0.*;// WSDL2Java生成的package的名字空間; public class TestClient { public static void main (String[] args) throws Exception { com.chinavnet.zx.service.v1_0.SPInterfaceForVNetLocator locator = new SPInterfaceForVNetLocator();//獲得一個locator對象 locator.setMaintainSession(true); com.chinavnet.zx.service.v1_0.SPInterfaceForVNetSoap service = locator.getSPInterfaceForVNetSoap();//獲得服務對象 com.chinavnet.zx.service.v1_0.DetailLedgerFeedbackResult feedbackRes = null; //初始化Web服務中定義的數據類型 try { feedbackRes = service.generalLedgerFeedback();//調用Web服務的方法并取得返回值 System.out.println("FeedbackResult :"); if(feedbackRes != null) { System.out.println("SPID: " +feedbackRes.getSPID()); System.out.println("errorDesc: " +feedbackRes.getErrorDescription()); System.out.println("result: " +feedbackRes.getResult()); }else { System.out.println("feedbackRes is null!"); } } catch (java.rmi.RemoteException re) { // throw new junit.framework.AssertionFailedError("Remote Exception caught: " + re ); re.printStackTrace(); } }//End of main() }//End of TestClient class |
測試客戶端程序是非常簡單的,將客戶端程序編譯后,執行"java TestClient"即可。
向MyServiceSoapBindingImpl.java添加相關的業務邏輯代碼后,將WSDL2Java生成的源程序編譯,打包成jar文件,復制到/usr/local/apache/htdocs/WEB-INF/lib/目錄下。
有了deploy.wsdd文件并準備好類文件后,就可以發布MyService服務了。Axis在安裝后自動發布了AdminService,利用它可以發布新的Web服務。方法如下。
java org.apache.axis.client.AdminClient -lhttp://localhost:80/services/AdminService deploy.wsdd 上面的命令執行后,有如下提示。 Processing file deploy.wsdd <Admin>Done processing</Admin> |
2.10 執行WSDL2Java時報告" 類型被引用但未定義"
2.10.1 問題描述
執行WSDL2Java時報告下面的異常:
java.io.IOException: Type {http://schemas.xmlsoap.org/wsdl/} ArrayOfFailedRecord is referenced but not defined. |
2.10.2 原因分析
出現上述情況可能的原因有:
類型未定義就被引用。
使用了錯誤的名字空間。
WSDL文件中存在輸入錯誤。
2.10.3 解決方法
經過仔細檢查發現wsdl文件中的
<s:element minOccurs="0" maxOccurs="1" name="FailedRecords" type="s0:ArrayOfFailedRecord" /> |
的type=" s0:ArrayOfFailedRecord"中的s0:前面有一個空格,將空格刪除后問題解決了。
2.10.4 小結
WSDL文件中出現的編輯錯誤有可能導致執行WSDL2Java時出現"類型被引用但未定義"錯誤。
server-config.wsdd記錄了axis已發布的Web服務的描述信息。
2.12 發布Web服務時報告"Exception:: (404)Not Found"
2.12.1 問題描述
執行java org.apache.axis.client.AdminClient -lhttp://localhost:80/services/AdminService deploy.wsdd命令發布WEB服務時報告如下內容。 Processing file deploy.wsdd Exception:: (404)Not Found |
Apache的access_log顯示如下。
127.0.0.1 - - [17/Sep/2003:15:56:33 +0800] "POST /services/AdminService HTTP/1.0" 404 293 |
2.12.2 原因分析
出現這個問題的比較簡單的原因可能是端口不對,或URL路徑不對(例如路徑中多寫了目錄),Axis的SoapMonitor服務按指定的端口或URL找不到AdminService,需要檢查正確的端口號和URL路徑。
比較深層次的原因就復雜得多了。
本文作者遇到的是下面的情況。
AdminService是一個已發布的WEB服務。
AdminClient使用soap協議同AdminService通信,需要按指定的端口和URL定位AdminService,而原來使用的resin.conf中,有兩個web-app配置項,配置A的摘要如下所示。
<host id=' '> <app-dir>/usr/local/apache/htdocs/</app-dir> |
配置B的摘要如下所示。
<host id='test.com'> <app-dir>/usr/local/apache/htdocs/esales/</app-dir> |
Axis的有關配置在配置B中。
Httpd.conf中的DocumentRoot是/usr/local/apache/htdocs/。
使用java org.apache.axis.client.AdminClient -lhttp://localhost:80/services/AdminService deploy.wsdd發布WEB服務時,需要按http協議解析url: //localhost:80/services/AdminService。由于htdocs/目錄下并沒有services/目錄(services是Axis在resin.conf中的servlet-mapping),因此應用服務器按resin.conf中的配置去定位AdminService ,因為url的主機名為localhost,因此resin不會到<host id='test.com'>(配置B)中去定位url,而是到配置A中去定位,在配置A中并沒有Axis的配置,找不到與AdminService相關的url,因此報告了前面描述的異常情況。
2.12.3 解決方法
知道了原因后,按如下方法就可以解決了。
將配置B中全部關于Axis的配置移到配置A中,注意相應地要改變/etc/profile中的CLASSPATH變量的值。
保存resin.conf后,重新登錄服務器(使新的CLASSPATH生效),重新啟動resin。再次發布WEB服務。
java org.apache.axis.client.AdminClient -lhttp://localhost:80/services/AdminService deploy.wsdd |
屏幕顯示如下。
Processing file deploy.wsdd <Admin>Done processing</Admin> |
WEB服務終于發布成功了。
在發布成功的情況下apache的access_log中會看到如下的log:
tail -f access_log|grep vice 127.0.0.1 - - [17/Sep/2003:16:05:00 +0800] "POST /services/AdminService HTTP/1.0" 200 296 "-" "Axis/1.1" |
2.12.4 小結
本小節描述的問題可能是讀者遇到的出現最多的異常,但原因并不是唯一的。遇到該問題時,建議讀者冷靜分析出現問題的可能原因,多實驗幾種解決方法,最終一定可以成功!
2.13.1 引言
發布了Web服務以后,如何觀察請求和響應數據呢?記錄運行日志是一種傳統且有效的方法,但對于調試程序來講還不夠方便和直觀。值得欣慰的是,Axis為我們提供了在客戶端觀察SOAP請求和響應流數據的工具SoapMonitor,經過適當配置后,可以實時地觀察到Web服務的SOAP請求和響應數據。SoapMonitor是一個Java Applet程序,通過瀏覽器下載到客戶端運行。下面就介紹SoapMonitor的配置和使用方法。
2.13.2 準備SOAPMonitor 小應用程序
在Axis 1.1中,沒有為我們編譯SOAPMonitor.java程序,但我們可以在axis-1_1/webapps/axis/目錄下找到名字為SOAPMonitorApplet.java的源程序文件,自己進行編譯。該程序編譯后,會生成如下的類文件:
SOAPMonitorApplet.class SOAPMonitorApplet$ServiceFilterPanel.class SOAPMonitorApplet$SOAPMonitorData.class SOAPMonitorApplet$SOAPMonitorFilter.class SOAPMonitorApplet$SOAPMonitorPage.class SOAPMonitorApplet$SOAPMonitorTableModel.class SOAPMonitorApplet$SOAPMonitorTextArea.class |
讀者需要把上述類文件復制到自己的Web應用程序目錄下,本例中是/usr/local/apache/htdocs/目錄。
在瀏覽器地址樣中輸入SOAPMonitor的地址,例如 http://test.com/SOAPMonitor ,瀏覽器會提示用戶正在下載Applet程序,下載完畢后,讀者可以在瀏覽器窗口中看到如圖4-1所示的用戶界面。如果上述類文件的位置不正確,瀏覽器會報告"找不到類"的錯誤。此時應檢查是否已將上述類文件復制到正確的目錄下。
圖 2-1 SOAPMonitor的界面
2.13.3 發布SOAPMonitor服務
圖2-1所示的SOAPMonitor界面出現后,并不意味著就可以觀察到Web服務的SOAP請求流與響應流了,首先需要發布SOAPMonitorService。該Web服務是由Axis提供的,但需要由用戶自己進行發布,方法如下。
獲得SOAPMonitor服務的WSDD文件deploy.wsdd,內容如下(也可到 http://www.sosnoski.com/presents/java-xml/axis/axis-monitor.html 復制該文件):
<deployment xmlns="http://xml.apache.org/axis/wsdd/" xmlns:java="http://xml.apache.org/axis/wsdd/providers/java"> <handler name="soapmonitor" type="java:org.apache.axis.handlers.SOAPMonitorHandler"> <parameter name="wsdlURL" value="/axis/SOAPMonitorService-impl.wsdl"/> <parameter name="namespace" value="http://tempuri.org/wsdl/2001/12/SOAPMonitorService-impl.wsdl"/> <parameter name="serviceName" value="SOAPMonitorService"/> <parameter name="portName" value="Demo"/> </handler> <service name="SOAPMonitorService" provider="java:RPC"> <parameter name="allowedMethods" value="publishMessage"/> <parameter name="className" value="org.apache.axis.monitor.SOAPMonitorService"/> <parameter name="scope" value="Application"/> </service> </deployment> |
發布SOAPMonitor服務:
java org.apache.axis.client.AdminClient -lhttp://localhost:80/services/AdminService deploy.wsdd |
2.13.4 修改deploy.wsdd
發布SOAPMonitor服務后,還要對被監測的Web服務進行配置。方法是先注銷該Web服務,然后修改該服務對應的WSDD文件,在其中增加請求流和響應流的配置,否則是觀測不到SOAP請求和響應流的。
注銷Web服務的方法如下。
進入該Web服務的undeploy.wsdd文件所在的目錄,執行
Java org.apache.axis.client.AdminClient -lhttp://localhost:80/services/AdminService undeploy.wsdd |
修改WSDD文件的方法如下。
以Axis提供的MyService為例,對MyService的WSDD文件做如下修改。
修改前:
... <service name="MyService" provider="java:RPC"> <parameter name="className" value="samples.userguide.example3.MyService"/> <parameter name="allowedMethods" value="*"/> ... |
修改后: (有下劃線的行是新加入的內容)
... <service name="MyService" provider="java:RPC"> <requestFlow> <handler type="soapmonitor"/> </requestFlow> <responseFlow> <handler type="soapmonitor"/> </responseFlow> <parameter name="className" value="samples.userguide.example3.MyService"/> <parameter name="allowedMethods" value="*"/> ... |
修改WSDD文件后,重新發布MyService服務:
java org.apache.axis.client.AdminClient -lhttp://localhost:80/services/AdminService deploy.wsdd |
2.13.5 啟動SOAPMonitor小應用程序
按2.13.2節介紹的方法啟動SOAPMonitor小應用程序。
使用客戶端程序測試MyService服務:
# java samples.userguide.example3.Client -lhttp://vnet.sohu.com/services/MyService "test" 結果為:You typed : test |
注意,一定要先啟動SOAPMonitor小應用程序,后調用Web服務才能觀察到SOAP請求和響應流。
2.13.6 觀察SOAP請求和響應流
這時在SoapMonitorApplet的窗口中可以觀察到SOAP和請求和響應消息,如圖2-2所示。
圖2-2 MyService的Soap請求和響應流
2.14 使用客戶端程序測試Web服務時報告"Exception:: (404)Not Found"
2.14.1 問題描述
WEB服務接口編寫完成并發布后,客戶端測試程序收不到WEB服務的返回結果,Apache或Resin的log中也看不到訪問記錄。但測試程序返回結果為0(成功),在沒有部署該WEB服務的情況下,也是這個結果,因此懷疑調用的是WSDL文件的提供者自己測試用的WEB服務接口,可能與另一方提供的WSDL文件有關。
2.14.2 原因分析
合作伙伴調用WEB服務就能夠成功,從WEB服務主機自己的客戶端調用就接收不到數據,估計與合作伙伴提供的WSDL文件有關,該WSDL文件影響了WSDL2Java生成的客戶端stub代碼。檢查stub代碼,發現其soapAction都指向了合作伙伴的測試地址。
2.14.3 解決方法
修改stub代碼中的soapAction,改為sp(Service Provider)自己的WEB服務URL。重新編譯程序并發布Web服務,問題解決。
_call.setSOAPActionURI("sp自己的Web服務地址");
2.14.4 小結
本小節描述的問題出現于Web服務提供方按合作伙伴統一提供的WSDL文件生成客戶端代碼的情況。遇到這類問題,讀者可直接檢查WSDL2Java自動生成的代碼的有關部分。
在WSDL文件中可以看到與下列內容相似的設置。
<wsdl:service name="SPInterfaceForVNet"> <wsdl:port binding="impl:SPInterfaceSoapSoapBinding" name="SPInterfaceForVNetSoap"> <wsdlsoap:address location="http://test.com/services/SPInterfaceSoap" /> </wsdl:port> </wsdl:service> |
其中 http://test.com/services/SPInterfaceSoap即為已發布的WEB服務的URL,供客戶端調用。
使用下面的命令:
java org.apache.axis.client.AdminClient -lhttp://localhost:80/services/ list |
實際上該命令的輸出就是server-config.wsdd文件的內容。
2.16.1 問題描述
在部署WEB服務時報告:java.lang.reflect.InvocationTargetException異常。
2.16.2 原因分析
在WSDL文件中自定義的名字空間與Axis的services名字空間沖突。
2.16.3 解決方法
修改WSDL文件,將services改為別的名字。
2.17 WSDL文件中的targetNamespace的作用是什么
TargetNamespace指明目標名字空間,用于驗證xml文檔。
在WSDL文件中,<definitions>中的targetNamespace與<types>中的targetNamespace應保持一致。
2.19 客戶端程序找不到可用的Web服務
2.19.1 問題描述
執行 java org.apache.axis.client.AdminClient -lhttp://localhost:80/services/AdminService deploy.wsdd |
時顯示<Admin>Done processing</Admin>,卻檢查不到新的服務,在WEB-INF/目錄下的server-config.wsdd文件中也看不到相應的配置項。
2.19.2 原因分析
新的WEB服務的類文件沒有重新編譯并復制到正確的位置。
2.19.3 解決方法
WEB服務的類文件可以打包為jar文件。在CLASSPATH環境變量中正確設置jar文件的路徑。例如:
jar cvf SPInterfaceSoap.jar com/zx/service/v1_0/*.class |
將SPInterfaceSoap.jar復制到WEB-INF/lib/目錄下,重新發布WEB服務。
有時,在對WEB服務執行客戶端測試時會出現慕名其妙的錯誤。為保證環境是正確的,可以按下面的步驟排除原因不明的錯誤。
1. Undeploy被測試的服務
java org.apache.axis.client.AdminClient -lhttp://localhost:80/services/AdminService undeploy.wsdd |
2. 重新啟動resin: /usr/local/resin/bin/httpd.sh restart(如果是其它的應用服務器,請按相應的方法重新啟動)
3. 重新發布WEB服務
4. 進行測試
目前有很多可以使用的應用服務器和Web服務平臺軟件,本文僅以Apache Axis和Resin為例介紹了在部署Web服務的過程中可能遇到的問題及其解決方法,其中并未討論Web服務的安全性問題。對于如何高效地開發和部署Web服務以及如何確保Web服務的安全性,還希望對此感興趣的讀者共同參與討論,對于文中存在的錯誤和不足之處也希望讀者朋友們能夠不吝批評指正。
這次的另外一個項目也要用Web Service了,不過人手也少了,沒有人幫做Web Service了,只好自己動手。
好在開發前,有個同事先給我們不熟悉Web Service的程序員進行了一些培訓,我才知道原來以前的Web Service都是可以自動生成代碼的,而且也不難,試了一個下午客戶端和服務器端的Web Service代碼就都調試通過了,真不錯。
為了更多喜愛開發的程序員也能迅速了解Web Service的開發,我這里整理了一些通過Axis開發Web Service的一些要點,希望能讓不熟悉Web Service的開發人員能夠迅速掌握Web Service。
一、Axis環境的安裝
1、安裝環境 J2SE SDK 1.4,Tomcat 5.0,eclipse 3.2。
2、到 http://xml.apache.org 網站下載Axis安裝包。
3、將Axis相關包文件放在WEB-INF\lib目錄下。
4、Axis可選的包:activation.jar; mail.jar; xmlsec-1.4.Beta1.jar拷貝到WEB-INF目錄下,生成客戶端時候需要使用。
Axis支持三種web service的部署和開發,分別為:
1、Dynamic Invocation Interface (DII)
2、Dynamic Proxy方式
3、Stubs方式
前兩種方式我就不介紹了,同事告訴我他們自己都不使用前兩種方式,他們建議我們使用Stubs方式,因此我就主要就介紹一下第三種方式。注意,我自己的Java源代碼是放在D:\workspace\test\目錄下,Axis相關包文件放在D:\workspace\test\WEB-INF目錄下。
二、編寫wsdd發布web服務,編寫stub client訪問web服務
1、編寫服務端程序server,SayHello.java,編譯server.SayHello.java
package server;
public class SayHello
{
public String getName(String name)
{
return "hello "+name;
}
}
2、編寫wsdd文件
deploy.wsdd文件內容如下:
<deployment xmlns="http://xml.apache.org/axis/wsdd/" xmlns:java="http://xml.apache.org/axis/wsdd/providers/java">
<service name="SayHello" provider="java:RPC">
<parameter name="className" value="server.SayHello.getName"/>
<parameter name="allowedMethods" value="*"/>
</service>
</deployment>
3、發布服務:
編輯一個deploy.bat,Axis_Lib為axis.jar路徑。內容如下:
set Axis_Lib=D:\workspace\test\WEB-INF\lib
set Java_Cmd=java -Djava.ext.dirs=%Axis_Lib%
set Axis_Servlet=http://localhost:8080/test/servlet/AxisServlet
%Java_Cmd% org.apache.axis.client.AdminClient -l%Axis_Servlet% deploy.wsdd
執行這個批處理文件,這時候,如果提示成功的話,訪問http://localhost:8080/test/services 就會顯示服務列表。
4、生成客戶端client stub文件
在瀏覽器上訪問服務器端的服務,可以下載到WSDL文件,通過Axis的相關工具,可以自動從WSDL文件中生成Web Service的客戶端代碼。
編寫一個WSDL2Java.bat文件,其內容如下:
set Axis_Lib=D:\workspace\test\WEB-INF\lib
set Java_Cmd=java -Djava.ext.dirs=%Axis_Lib%
set Output_Path=D:\workspace\test\src
set Package=server.SayHello
%Java_Cmd% org.apache.axis.wsdl.WSDL2Java -o%Output_Path% -p%Package% SayHello.wsdl
執行這個批處理文件就可以生成client stub.
生成的stub client文件列表為:SayHello.java,SayHelloService.java,SayHelloServiceLocator.java,SayHelloSoapBindingStub.java .
5、編寫客戶端程序,編譯并執行
下面是一段junit測試客戶端代碼。
import java.net.URL;
import junit.framework.Test;
import junit.framework.TestCase;
import junit.framework.TestSuite;
public class TestWSClient extends TestCase {
public TestWSClient(String string) {
super(string);
}
public void SayHelloClient() throws Exception {
SayHelloService service = new SayHelloServiceLocator();
SayHello_PortType client = service.getSayHello() ;
String retValue = client.getName("clientname");
System.out.println(retValue);
}
public static Test suite() {
TestSuite suite = new TestSuite();
suite.addTest(new TestWSClient("SayHelloClient"));
return suite;
}
}
至此,整個服務器端和客戶端的Web Service框架代碼就完成了,剩下的就是在里面加入你的業務代碼了,怎么樣,Web Service并不難開發吧。
1、axis-1_2 (從apache網站下載最新axis-bin-1_2.zip解壓即可)
2、Tomcat5.0
3、JDK5.0
二、相關配置
1、在你的%TOMCAT_HOME%\common\lib下需要加入三個包 activation.jar、mail.jar、tools.jar
2、環境變量設置
AXIS_HOME 即axis-bin-1_2.zip解壓的目錄(我的是在F:\soap\axis-1_2)
AXIS_LIB 即 %AXIS_HOME%\lib
AXISCLASSPATH 即 %AXIS_LIB%\axis.jar;%AXIS_LIB%\commons-discovery-0.2.jar;%AXIS_LIB%\commons-logging-1.0.4.jar;%AXIS_LIB%\jaxrpc.jar;%AXIS_LIB%\saaj.jar;%AXIS_LIB%\log4j-1.2.8.jar;也就是把%AXIS_LIB%下所用JAR文件都導入
三、實驗一下
在%AXIS_HOME%\webapps下找到axis文件夾,將其整個拷貝到%TOMCAT_HOME%\webapps下,啟動
Tomcat,打開瀏覽器訪問http://localhost:8080/axis/,出現以下頁面說明你配置成功了。很簡單吧:)
四、發布我們的第一個程序
第一個程序簡單的返回HELLO WORLD!
HelloWorld.java
public class HelloWorld {
public String sayHello()
{
return "HELLO WORLD!";
}
}
我們的第一種發布方式:
將HelloWorld.java拷貝到%TOMCAT_HOME%\webapps\axis下,然后將其改名為HelloWorld.jws,這樣AXIS就自然將其發布了。現在寫個客戶端程序訪問一下:
TestClient.java
import org.apache.axis.client.Call;
import org.apache.axis.client.Service;
import javax.xml.rpc.ParameterMode;
public class TestClient
{
public static void main(String [] args) throws Exception {
String endpoint = "http://localhost/:" +"8080"+ "/axis/HelloWorld.jws";//指明服務所在位置
Service service = new Service(); //創建一個Service實例,注意是必須的!
Call call = (Call) service.createCall();//創建Call實例,也是必須的!
call.setTargetEndpointAddress( new java.net.URL(endpoint) );//為Call設置服務的位置
call.setOperationName( "sayHello" );//注意方法名與HelloWorld.java中一樣!!
String res = (String) call.invoke( new Object[] {} );//返回String,沒有傳入參數
System.out.println( res );
}
}
我的測試是在jbuilder2005中,注意項目中要導入其自帶的AXIS包(當然應該把其中JAR文件替換一下),可以看到程序返回了 "HELLO WORLD!"
可以看到在AXIS里發布服務其實是一件很容易的事,這是因為這個服務很簡單的原因:)下面我們介紹第二種發布方式,這是常用的。
我們的第二種發布方式:
1、將HelloWorld.java編譯成HelloWorld.class,放到%TOMCAT_HOME%\webapps\axis\WEB-INF\classes
下
2、在%TOMCAT_HOME%\webapps\axis\WEB-INF下新建deploy.wsdd文件,即SOAP服務發布描述文件
deploy.wsdd
<deployment xmlns="http://xml.apache.org/axis/wsdd/" xmlns:java="http://xml.apache.org/axis/wsdd/providers/java">
<service name="HelloWorld" provider="java:RPC">
<parameter name="className" value="HelloWorld"/>
<parameter name="allowedMethods" value="sayHello"/>
</service>
</deployment>
在DOS下轉換目錄到%TOMCAT_HOME%\webapps\axis\WEB-INF,命令:
java -cp %AXISCLASSPATH% org.apache.axis.client.AdminClient deploy.wsdd
你會發現目錄下多了一個server-config.wsdd文件,這就是AXIS的配置文件,以后所有的服務發布描述都會在里面找到。(當然,你可以直接修改它,不用再寫deploy.wsdd)然后打開瀏覽器http://localhost:8080/axis/servlet/AxisServlet,你就會看到你的服務已發布
同樣用客戶端程序訪問一下:(注意和上邊的差別!!)
HelloClient.java
import org.apache.axis.client.Call;
import org.apache.axis.client.Service;
public class HelloClient
{
public static void main(String [] args) throws Exception {
String endpoint = "http://localhost/:" +"8080"+ "/axis/services/HelloWorld";//注意!差別僅僅在這里!!
Service service = new Service();
Call call = (Call) service.createCall();
call.setTargetEndpointAddress( new java.net.URL(endpoint) );
call.setOperationName("sayHello" );
String res = (String) call.invoke( new Object[] {} );
System.out.println( res );
}
}
將自動部署到axis web應用的server-config.wsdd
要想部署到自己的web 應用下,比如boyoi,要使用以下的方式
java -cp %AXISCLASSPATH% org.apache.axis.client.AdminClient
-lhttp://localhost:8080/boyoi/services/AdminService deploy.wsdd
1. 什么是SOAP
SOAP是一個基于XML的用于應用程序之間通信數據編碼的傳輸協議。最初由微軟和Userland Software提出,隨著不斷地完善和改進,SOAP很快被業界廣泛應用,目前完全發布版本是1.1。在其發展過程中,W3C XML標準工作小組積極促成SOAP成為一個真正的開放標準。在寫作此文檔之時,SOAP1.2草案已經發布,1.2對1.1中相對混亂的部分做了改進。
SOAP被廣泛作為新一代跨平臺、跨語言分布計算Web Services的重要部分。
2. 什么是Axis
Axis是Apache組織推出的SOAP引擎,Axis項目是Apache組織著名的SOAP項目的后繼項目,目前最新版本是采用Java開發的1.1版本,C++的版本正在開發之中。Axis v1.1軟件包可以從http://ws.apache.org/axis/dist/1_1/下載得到。
但是Axis不僅僅是一個SOAP引擎,它還包括:
一個獨立運行的SOAP服務器
一個servlet引擎的插件,這個servlet引擎可以是Tomcat
對WSDL的擴展支持
一個將WSDL的描述生成JAVA類的工具
一些示例代碼
還有一個監控TCP/IP包的工具
二、Axis的安裝
應用Axis開發Web Services,你需要安裝如下軟件:
1.JDK1.4.2
2.一個支持Servlet的服務器引擎,比如廣為人知的Tomcat。
當安裝好Tomcat之后,只需將下載的Axis軟件包解壓縮,將其中的“webapps”目錄下的“axis”目錄整個拷貝到Tomcat安裝目錄下的“webapps”目錄下即可。
三、Axis的配置
Axis基于Java開發,可以部署于多種操作系統,使用前需要配置一系列的系統變量,在此假定你已經在本機上裝好了Tomcat 4.0以上的版本,需要配置的系統變量如下表所示:
CATALINA_HOME
C:\Tomcat_4_1
(此處應為Tomcat的安裝位置,注意路徑名中不要有空格)
AXIS_HOME
%CATALINA_HOME%\webapps\axis
AXIS_LIB
%AXIS_HOME%\lib
AXISCLASSPATH
%AXIS_LIB%\axis.jar;%AXIS_LIB%\commons-discovery.jar; %AXIS_LIB%\commons-logging.jar;%AXIS_LIB%\jaxrpc.jar; %AXIS_LIB%\saaj.jar;%AXIS_LIB%\log4j-1.2.8.jar; %AXIS_LIB%\xml-apis.jar;%AXIS_LIB%\xercesImpl.jar
CLASSPATH 中加入:
%AXIS_LIB%\axis.jar;%AXIS_LIB%\commons-discovery.jar; %AXIS_LIB%\commons-logging.jar;%AXIS_LIB%\jaxrpc.jar; %AXIS_LIB%\saaj.jar;%AXIS_LIB%\log4j-1.2.8.jar; %AXIS_LIB%\xml-apis.jar;%AXIS_LIB%\xercesImpl.jar
四、Axis的測試
安裝配置完畢后,應測試一下是否Axis可以正確運行了。
啟動Tomcat服務器,在瀏覽器中訪問http://localhost:8080/axis/happyaxis.jsp,如果頁面顯示有錯誤,則需要回頭檢查一下相關配置是否正確,如果瀏覽頁面能正確顯示出系統組件、屬性等參數配置信息,則表示安裝成功。現在可以開始開發你的Web Services應用了。
五、服務的發布
Axis提供了兩種服務發布方式,一種是即時發布(Instant Deployment),一種是定制發布(Custom Deployment)。
1. 使用即時發布 Java Web Service(JWS)
對即時發布的支持是Axis的特色之一,使用即時發布使用戶只需有提供服務的Java類的源代碼,即可將其迅速發布成Web服務。每當用戶調用這類服務的時候,Axis會自動進行編譯,即使服務器重啟了也不必對其做任何處理,使用非常簡單快捷。
使用即時發布首先需要一個實現服務功能的Java源文件,將其擴展名改為.jws(Java Web Service的縮寫),然后將該文件放到“……\webapps\axis”目錄下即可。
在此給出一個從英里到公里的長度單位轉換的服務,其源碼如下:
文件Distance.jws
public class Distance
{
public double convertMile2Kilometre( double mile )
{
return mile * 1.609; //實現英里到公里的距離轉換
}
}
將其放到“……\webapps\axis”目錄,通過訪問http://localhost:8080/axis/Distance.jws?wsdl可以看到這個服務的WSDL描述文件,這說明Distance服務被成功發布了。描述的WDSL代碼如下:
<?xml version="1.0" encoding="UTF-8" ?>
- <wsdl:definitions targetNamespace="- <wsdl:message name="convertMile2KilometreRequest">
<wsdl:part name="mile" type="xsd:double" />
</wsdl:message>
- <wsdl:message name="convertMile2KilometreResponse">
<wsdl:part name="convertMile2KilometreReturn" type="xsd:double" />
</wsdl:message>
- <wsdl:portType name="Distance">
- <wsdl:operation name="convertMile2Kilometre" parameterOrder="mile">
<wsdl:input message="impl:convertMile2KilometreRequest" name="convertMile2KilometreRequest" />
<wsdl:output message="impl:convertMile2KilometreResponse" name="convertMile2KilometreResponse" />
</wsdl:operation>
</wsdl:portType>
- <wsdl:binding name="DistanceSoapBinding" type="impl:Distance">
<wsdlsoap:binding style="rpc" transport="- <wsdl:operation name="convertMile2Kilometre">
<wsdlsoap:operation soapAction="" />
- <wsdl:input name="convertMile2KilometreRequest">
<wsdlsoap:body encodingStyle="http://defaultnamespace/" use="encoded" />
</wsdl:input>
- <wsdl:output name="convertMile2KilometreResponse">
<wsdlsoap:body encodingStyle=" </wsdl:output>
</wsdl:operation>
</wsdl:binding>
- <wsdl:service name="DistanceService">
- <wsdl:port binding="impl:DistanceSoapBinding" name="Distance">
<wsdlsoap:address location=" </wsdl:port>
</wsdl:service>
</wsdl:definitions>
需要注意的是:JWS的web服務發布是一個很簡單的Web服務發布方式,在頁面中你不能使用包,而且由于代碼是在運行期被編譯的,所以在部署之后,你也很難找到錯誤所在。
2. 使用定制發布 Web Service Deployment Descriptor(WSDD)
即時發布是一項令人激動的技術,它使Web服務的開發變得如此簡單;然而即時發布并不總是最好的選擇,比如有些應用系統是第三方提供的,我們沒有購買源代碼,只有.class文件,但我們又希望將這個應用系統的一些功能對外發布成Web服務,使其能夠在更大范圍內產生作用,這個時候即時發布技術就無能為力了。此外,即時發布技術并不靈活,無法進行更多的服務配置,這使得它并不能滿足一些特定系統的需求。
因此,Axis提供了另一種服務發布方式,這就是定制發布。
在此給出一個從加侖到升的容積單位轉換的服務,其源碼如下:
文件Capacity.java
package samples.capacity;
public class Capacity
{
public double convertGallon2Litre( double gallon )
{
return gallon * 4.546;//實現加侖到升的容積轉換
}//convertGallon2Litre()
}/* Capacity */
將其編譯成.class文件,放置到“……\webapps\axis\samples\capacity”目錄下,即可著手進行發布。
定制發布不需要構建.jws文件,但必須創建服務發布描述文件deploy.wsdd(Web Service Deployment Descriptor的縮寫),這個文件負責描述服務的名稱、入口等信息,其內容如下:
文件deploy.wsdd
<deployment xmlns=" <parameter name="className" value="samples.capacity.Capacity"/>
<parameter name="allowedMethods" value="*"/>
</service>
</deployment>
在這里服務的提供者是“java:RPC”,它被內建在Axis中,而且指明了一個JAVA RPC服務,做這個處理的類是org.apache.axis.providers.java.RPCProvider。
我們是通過一個<parameter>標簽告訴RPC服務應該調用的類,而另外一個<parameter>標簽則告訴引擎,它可以調用這個類中的任何的Public方法。你也可以指定通過使用名字空間或者一些可以調用的方法列表,來指明那些方法可以被調用。
將該文件也放到“……\webapps\axis\samples\capacity”目錄下,然后可以采用Axis提供的一個客戶端管理工具——AdminClient來完成服務的定制發布。
在“……\webapps\axis\samples\capacity”目錄下,運行:
java -cp %AXISCLASSPATH% org.apache.axis.client.AdminClient deploy.wsdd
如果運行時說沒有找到類,那么可能是類路徑沒有配置好,建議將所有的與axis相關的jar都寫到classpath中去。這樣只要運行:
java org.apache.axis.client.AdminClient deploy.wsdd
可以看到以下運行結果:
Processing file deploy.wsdd
<Admin>Doneprocessing</Admin>
這表明Capacity服務定制發布完成。
你也可以調用:
java org.apache.axis.client.AdminClient undeploy.wsdd 來取消部署。
你也可以調用:
java org.apache.axis.client.AdminClient list 來獲得所有的已經部署的服務的列表。在這里你會看到services, handlers, transports等等,注意這個調用只是列出了WEB-INF\server-config.wsdd的文件內容。
一定要注意:編譯后的class文件要拷貝到web-inf/classes的目錄中,如果該文件中有包存在的話,別忘了還要在classes目錄下創建包的目錄
通過訪問http://localhost:8080/axis/services/Capacity?wsdl可以看到這個服務的WSDL描述文件,這說明Capacity服務被成功發布了。
你也可以通過訪問http://localhost:8080/axis/servlet/AxisServlet查看所有定制發布的服務。
WDSL如下:
<?xml version="1.0" encoding="UTF-8" ?>
- <wsdl:definitions targetNamespace="http://localhost:8080/axis/services/Capacity" xmlns=" xmlns:apachesoap="http://localhost:8080/axis/services/Capacity" xmlns:intf="http://localhost:8080/axis/services/Capacity" xmlns:soapenc=" <wsdl:part name="convertGallon2LitreReturn" type="xsd:double" />
</wsdl:message>
- <wsdl:message name="convertGallon2LitreRequest">
<wsdl:part name="in0" type="xsd:double" />
</wsdl:message>
- <wsdl:portType name="Capacity">
- <wsdl:operation name="convertGallon2Litre" parameterOrder="in0">
<wsdl:input message="impl:convertGallon2LitreRequest" name="convertGallon2LitreRequest" />
<wsdl:output message="impl:convertGallon2LitreResponse" name="convertGallon2LitreResponse" />
</wsdl:operation>
</wsdl:portType>
- <wsdl:binding name="CapacitySoapBinding" type="impl:Capacity">
<wsdlsoap:binding style="rpc" transport="- <wsdl:operation name="convertGallon2Litre">
<wsdlsoap:operation soapAction="" />
- <wsdl:input name="convertGallon2LitreRequest">
<wsdlsoap:body encodingStyle=" </wsdl:input>
- <wsdl:output name="convertGallon2LitreResponse">
<wsdlsoap:body encodingStyle="http://localhost:8080/axis/services/Capacity" use="encoded" />
</wsdl:output>
</wsdl:operation>
</wsdl:binding>
- <wsdl:service name="CapacityService">
- <wsdl:port binding="impl:CapacitySoapBinding" name="Capacity">
<wsdlsoap:address location="http://localhost:8080/axis/services/Capacity" />
</wsdl:port>
</wsdl:service>
</wsdl:definitions>
WSDD 的高級功能:
(1) AXIS支持三種對象范圍:
"request"范圍:這是默認的情況,每一次Soap請求的時候都將創建新的對象。
"application"范圍:將會為所有的請求生成一個單獨的共享的對象。
"session"范圍:為每一個session期的客戶端請求創建一個對象。
指定方法如下:
<service name="MyService"...>
<parameter name="scope" value="value"/>
...
</service>
(2) 更多部署內容:Handlers and Chains
讓我們來深入挖掘一下Axis引擎的更強大的特性。如果我們想跟蹤我們的服務被調用了多少次,那么我們只需要包含一個簡單的handler,它存放在samples/log目錄下。要使用這個handler,你就首先應該部署這個handler,然后使用在部署服務時給它指定的名字。下面是一個wsdd文件的例子:
<deployment xmlns=" <parameter name="filename" value="MyService.log"/>
</handler>
<!-- define the service, using the log handler we just defined -->
<service name="LogTestService" provider="java:RPC">
<requestFlow>
<handler type="track"/>
</requestFlow>
<parameter name="className" value="samples.userguide.example4.Service"/>
<parameter name="allowedMethods" value="*"/>
</service>
</deployment>
第一段指明了一個名為track的handler,它是samples.userguide.example4.LogHandler類的實例。另外還指定了一個參數filename,用于指定日志文件名稱。
下面的那段指明了一個RPC服務,和我們在上面的例子中看到的一樣,所不同的是在service標簽中的<requestFlow>標簽,它指定了一些在調用服務前應該被調用的handler集。也就是由于我們在部署中插入了這個"track"的引用,所以我們確定每次調用服務的時候都將被記錄到日志文件中去。
(3)遠程管理:
<service name="AdminService" provider="java:MSG">
<parameter name="className" value="org.apache.axis.util.Admin"/>
<parameter name="allowedMethods" value="*"/>
<parameter name="enableRemoteAdmin" value="true"/>
</service>
WARNING: enabling remote administration may give unauthorized parties access to your machine. If you do this, please make sure to add security to your configuration!
所以遠程管理涉及到安全問題,不建議采用。
首先假定您熟悉 AXIS 處理系統和Ant工具。文中示例所需要的軟件如下:
l Apache Axis 1.1
l Apache Ant 1.5.3
l Jarkat Tomcat 4.1.24
在開始前,假定上述軟件已經安裝和配置好了。
Axis和Ant簡介
Axis 框架是來自 Apache Group 的、基于 java 的、最新的 SOAP 規范(SOAP 1.2)和 SOAP with Attachments 規范(來自 Apache Group )的開放源代碼實現。其本質上是一個SOAP引擎--一個構建諸如客戶端、服務器、網關等SOAP處理器的框架。是Apache SOAP的后繼項目。但是,Axis使用SAX(基于事件)解析器獲得了比Apache SOAP早期版本(使用DOM解析)非常明顯的速度優勢。另外,它還具有很強的靈活性和穩定性,支持Web服務描述語言1.1版。
Apache Ant是Apache軟件基金會jakarta項目中的一個子項目,是一個基于Java的構建工具,類似于make,但它沒有make那么復雜繁瑣。Ant由一些內置任務(task)和可選擇的任務組成,還可以配置第三方提供的任務。它的構建配置文件基于XML的,所以容易書寫和維護,而且結構清晰。Ant還可以集成到一些開發環境中(例如visual age,jbuilder,Elipse)。
Axis對Ant的支持
Axis為支持Ant構建,提供了一個axis-ant.jar文件。該文件包含三個可選任務(task)的定義和實現:axis-wsdl2java,axis-java2wsdl和axis-admin。任務axis-wsdl2java與Axis提供的工具WSDL2Java具有同樣的功能,根據web服務描述文件生成對應的Java源程序,它的屬性設置與WSDL2Java的命令參數設置類似。而任務axis-java2wsdl則相反,它與Java2WSDL工具一樣,是根據已有的類文件來生成Web服務描述文件。最后一個任務axis-admin是用于web服務的部署和取消部署的,對應于Axis的AminClient工具。
為了使Ant能夠正確使用上述三個任務(task),還需要做一些配置。注意:Apache Ant的版本必須是1.5.1或更高版本。
1.設置系統的環境變量CLASSPATH包含Axis提供的axis-ant.jar文件,或者在Ant的配置文件(通常是build.xml)中設置路徑包含它。例如,
<path id="axis.classpath">
<fileset dir="${axis.home}/lib">
<include name="**/*.jar" />
</fileset>
</path>
2.然后使用<taskdef>聲明導入axis-ant.jar文件中的屬性文件所定義的任務(task)列表。
<taskdef resource="axis-tasks.properties"
classpathref="axis.classpath" />
3.設置在構建過程中可能要需要的java包,例如, Axis所有的jar包,wsdl4j.jar,junit.jar等等。
實例開發
下面就用一個實例來講解怎樣把Ant和Axis結合來開發Web服務。為了注重本文的目的,我們開發一個比較簡單的Web服務,它接受客戶端傳入的字符串數組,如果傳入的參數為null,則拋出一個自定義的異常,否則把每個字符串連接起來返回給客戶端。
首先定義一個Web服務接口Hello,如下所示:
package com.bidlink.hello;
public interface Hello{
public String echo(String[] content ) throws
java.rmi.RemoteException,com.bidlink.hello.MyException;
}
自定義異常MyException包含一個時間值,以記錄異常出現的時間,如下:
package com.bidlink.hello;
public class MyException extends org.apache.axis.AxisFault implements java.io.Serializable{
private java.util.Calendar occurTime;
public MyException() {
}
public MyException(
java.util.Calendar occurTime) {
super();
this.occurTime = occurTime;
}
public java.util.Calendar getOccurTime() {
return occurTime;
}
public void setOccurTime(java.util.Calendar occurTime) {
this.occurTime = occurTime;
}
}
1.axis-java2wsdl:從類文件生成服務描述文件
編譯上面定義的兩個文件Hell.java和MyException.java。接著編寫Ant的配置文件build.xml(文件詳細信息請查看示例源代碼),使用axis-java2wsdl任務根據類Hello來生成Web服務描述文件hello.wsdl。任務具體配置如下:
<axis-java2wsdl classname="com.bidlink.hello.Hello"
location="http://localhost:8080/axis/services/Hello"
namespace="http://hello.bidlink.com"
output="hello.wsdl"
style="RPC"
extraclasses="com.bidlink.hello.MyException">
<classpath>
<pathelement path="${dist}"/>
</classpath>
</axis-java2wsdl>
其中,<pathelement path="${dist}"/>指出Hello.class和MyException.class文件的位置。
運行命令ant java2wsdl,構建出Web服務描述文件hello.wsdl。
2.axis-wsdkl2java:從服務描述文件生成服務源程序
下面講解怎樣根據剛剛得到的hello.wsdl文件生成服務所需要的java源程序。在這里需要用到任務axis-wsdl2java。任務屬性設置如下:
<axis-wsdl2java all="true"
url="hello.wsdl"
deployscope="Request"
output="${gensrc}"
serverside="true"
skeletondeploy="false"
testcase="true"
noimports="false"
typemappingversion="1.2">
</axis-wsdl2java>
運行ant wsdl2java,根據axis-wsdl2java任務的屬性配置生成相應的java源程序,本例所生成的文件包括:服務端服務接口文件Hello.java及其實現HelloSoapBindingImpl.java,以及客戶端的HelloService.java,HelloServiceLocator.java,HelloServiceLocator.java和客戶端存根文件HelloSoapBindingStub.java。又因為屬性testcase="true",所以還生成了測試文件HelloServiceTestCase.java。當然,自定義異常MyException也是重新生成的。
3.axis-admin:向Axis部署Hello服務
服務源程序生成后,需要根據服務的功能修改HelloSoapBindingImpl.java文件,以真正實現該Web服務。修改如下:
/**
* HelloSoapBindingImpl.java
*
* This file was auto-generated from WSDL
* by the Apache Axis WSDL2Java emitter.
*/
package com.bidlink.hello;
public class HelloSoapBindingImpl implements com.bidlink.hello.Hello{
public java.lang.String echo(java.lang.String[] in0) throws java.rmi.RemoteException, com.bidlink.hello.MyException {
if(in0 == null)
throw new MyException(java.util.Calendar.getInstance());
String retStr = "";
for(int i=0; i< in0.length; i++)
retStr += in0[i];
return retStr;
}
}
編譯所有的生成的源程序,最后使用axis-admin任務向Axis部署Hello Web服務。
<axis-admin
port="${target.port}"
hostname="${target.server}"
failonerror="true"
servletpath="${target.appname}/services/AdminService"
debug="true"
xmlfile="deploy.wsdd"/>
運行ant deploy,部署Hello服務。
測試
現在可以測試所部署的Web服務hello。可以通過瀏覽器,也可以利用剛才生成的測試文件HelloServiceTestCase.java來進行該項工作。如果利用測試文件HelloServiceTestCase.java,那么還需要對它進行稍作修改。具體來說,就是添加一個main函數,然后修改所生成的測試方法。
Axis簡介
Axis是Apache組織推出的SOAP引擎,Axis項目是Apache組織著名的SOAP項目的后繼項目,目前最新版本是采用Java開發的1.1版本,C 的版本正在開發之中。Axis v1.1軟件包可以從http://ws.apache.org/axis/dist/1_1/下載得到。
Axis的安裝
應用Axis開發Web Services,你需要有一個支持Servlet的服務器引擎,比如廣為人知的Tomcat(Tomcat也是由Apache組織所提供的,目前的最新版本為4.1.24,下載地址為http://jakarta.apache.org/builds/jakarta-tomcat-4.0/release/v4.1.24/)。在此之前當然你機器必須已經裝好了JDK1.3以上的版本,當安裝好Tomcat之后,只需將下載的Axis軟件包解壓縮,將其中的“webapps”目錄下的“axis”目錄整個拷貝到Tomcat安裝目錄下的“webapps”目錄下即可。
Axis的配置
Axis基于Java開發,可以部署于多種操作系統,使用前需要配置一系列的系統變量,在此假定你已經在本機上裝好了Tomcat 4.0以上的版本,需要配置的系統變量如下表所示:
CATALINA_HOME
C:\Tomcat_4_1
(此處應為Tomcat的安裝位置,注意路徑名中不要有空格)
AXIS_HOME
蔜ALINA_HOME%\webapps\axis
AXIS_LIB
%AXIS_HOME%\lib
AXISCLASSPATH
%AXIS_LIB%\axis.jar;%AXIS_LIB%\commons-discovery.jar; %AXIS_LIB%\commons-logging.jar;%AXIS_LIB%\jaxrpc.jar; %AXIS_LIB%\saaj.jar;%AXIS_LIB%\log4j-1.2.8.jar; %AXIS_LIB%\xml-apis.jar;%AXIS_LIB%\xercesImpl.jar
如果你不愿做這么繁瑣的類路徑設置,可以直接將axis軟件包中“lib”目錄下的所有.jar文件加入到系統環境變量CLASSPATH中即可。
Axis的測試
安裝配置完畢后,應測試一下是否Axis可以正確運行了。
啟動Tomcat服務器,在瀏覽器中訪問http://localhost:8080/axis/happyaxis.jsp,如果頁面顯示有錯誤,則需要回頭檢查一下相關配置是否正確,如果瀏覽頁面能正確顯示出系統組件、屬性等參數配置信息,則表示安裝成功,如下圖所示:
現在可以開始開發你的Web Services應用了。
概述
本文介紹了一個比較簡單實用的基于Java的SOAP引擎——Apache組織推出的Axis——的安裝、配置和應用開發方法,希望對有興趣做基于Java的Web Services應用開發的朋友有所幫助。
Axis簡介
Axis是Apache組織推出的SOAP引擎,Axis項目是Apache組織著名的SOAP項目的后繼項目,目前最新版本是采用Java開發的1.1版本,C 的版本正在開發之中。Axis v1.1軟件包可以從http://ws.apache.org/axis/dist/1_1/下載得到。
Axis的安裝
應用Axis開發Web Services,你需要有一個支持Servlet的服務器引擎,比如廣為人知的Tomcat(Tomcat也是由Apache組織所提供的,目前的最新版本為4.1.24,下載地址為http://jakarta.apache.org/builds/jakarta-tomcat-4.0/release/v4.1.24/)。在此之前當然你機器必須已經裝好了JDK1.3以上的版本,當安裝好Tomcat之后,只需將下載的Axis軟件包解壓縮,將其中的“webapps”目錄下的“axis”目錄整個拷貝到Tomcat安裝目錄下的“webapps”目錄下即可。
Axis的配置
Axis基于Java開發,可以部署于多種操作系統,使用前需要配置一系列的系統變量,在此假定你已經在本機上裝好了Tomcat 4.0以上的版本,需要配置的系統變量如下表所示:
CATALINA_HOME
C:\Tomcat_4_1
(此處應為Tomcat的安裝位置,注意路徑名中不要有空格)
AXIS_HOME
蔜ALINA_HOME%\webapps\axis
AXIS_LIB
%AXIS_HOME%\lib
AXISCLASSPATH
%AXIS_LIB%\axis.jar;%AXIS_LIB%\commons-discovery.jar; %AXIS_LIB%\commons-logging.jar;%AXIS_LIB%\jaxrpc.jar; %AXIS_LIB%\saaj.jar;%AXIS_LIB%\log4j-1.2.8.jar; %AXIS_LIB%\xml-apis.jar;%AXIS_LIB%\xercesImpl.jar
如果你不愿做這么繁瑣的類路徑設置,可以直接將axis軟件包中“lib”目錄下的所有.jar文件加入到系統環境變量CLASSPATH中即可。
Axis的測試
安裝配置完畢后,應測試一下是否Axis可以正確運行了。
啟動Tomcat服務器,在瀏覽器中訪問http://localhost:8080/axis/happyaxis.jsp,如果頁面顯示有錯誤,則需要回頭檢查一下相關配置是否正確,如果瀏覽頁面能正確顯示出系統組件、屬性等參數配置信息,則表示安裝成功,如下圖所示:
現在可以開始開發你的Web Services應用了。
服務的發布
使用即時發布
對即時發布的支持是Axis的特色之一,使用即時發布使用戶只需有提供服務的Java類的源代碼,即可將其迅速發布成Web服務。每當用戶調用這類服務的時候,Axis會自動進行編譯,即使服務器重啟了也不必對其做任何處理,使用非常簡單快捷。
使用即時發布首先需要一個實現服務功能的Java源文件,將其擴展名改為.jws(Java Web Service的縮寫),然后將該文件放到“……\webapps\axis”目錄下即可。
在此給出一個從英里到公里的長度單位轉換的服務,其源碼如下:
文件Distance.jws
/**
* @author 飛鷹
*/
public class Distance
{
public double convertMile2Kilometre( double mile )
{
//實現英里到公里的距離轉換
return mile * 1.609;
}//convertMile2Kilometre()
}/* Distance */
將其放到“……\webapps\axis”目錄,通過訪問http://localhost:8080/axis/Distance.jws?wsdl可以看到這個服務的WSDL描述文件,這說明Distance服務被成功發布了。如下圖所示:
使用定制發布
即時發布是一項令人激動的技術,它使Web服務的開發變得如此簡單;然而即時發布并不總是最好的選擇,比如有些應用系統是第三方提供的,我們沒有購買源代碼,只有.class文件,但我們又希望將這個應用系統的一些功能對外發布成Web服務,使其能夠在更大范圍內產生作用,這個時候即時發布技術就無能為力了。此外,即時發布技術并不靈活,無法進行更多的服務配置,這使得它并不能滿足一些特定系統的需求。
因此,Axis提供了另一種服務發布方式,這就是定制發布。
在此給出一個從加侖到升的容積單位轉換的服務,其源碼如下:
文件Capacity.java
package samples.capacity;
/**
* @author 飛鷹
*/
public class Capacity
{
public double convertGallon2Litre( double gallon )
{
//實現加侖到升的容積轉換
return gallon * 4.546;
}//convertGallon2Litre()
}/* Capacity */
將其編譯成.class文件,放置到“……\webapps\axis\samples\capacity”目錄下,即可著手進行發布。
定制發布不需要構建.jws文件,但必須創建服務發布描述文件deploy.wsdd(Web Service Deployment Descriptor的縮寫),這個文件負責描述服務的名稱、入口等信息,其內容如下:
文件deploy.wsdd
<deployment xmlns="http://xml.apache.org/axis/wsdd/"
xmlns:java="http://xml.apache.org/axis/wsdd/providers/java">
<service name="Capacity" provider="java:RPC">
<parameter name="className" value="samples.capacity.Capacity"/>
<parameter name="allowedMethods" value="*"/>
</service>
</deployment>
將該文件也放到“……\webapps\axis\samples\capacity”目錄下,然后可以采用Axis提供的一個客戶端管理工具——AdminClient來完成服務的定制發布。
在“……\webapps\axis\samples\capacity”目錄下,運行:
java -cp %AXISCLASSPATH% org.apache.axis.client.AdminClient deploy.wsdd
可以看到以下運行結果:
Processing file deploy.wsdd
<Admin>Doneprocessing</Admin>
這表明Capacity服務定制發布完成。
通過訪問http://localhost:8080/axis/services/Capacity?wsdl可以看到這個服務的WSDL描述文件,這說明Capacity服務被成功發布了。如下圖所示:
服務的訪問
GET方式的服務訪問
一般的SOAP消息都是采用POST方式實現傳遞,但也可以通過GET方式來訪問。比如以下給出的一個服務——“HelloWorld”,其源碼如下:
文件HelloWorld.jws
/**
* @author 飛鷹
*/
public class HelloWorld
{
public String helloWorld()
{
//在服務器端打印輸出
System.out.println( "Hello World!" );
//返回相應字符串
return "Hello World!";
}//helloWorld()
}/* HelloWorld */
這個服務給出一個名位“helloWorld”的無入口參數的操作,返回一個內容為“Hello World!的字符串”,同時在服務器端打印“Hello World!”,將該文件放到“……\webapps\axis”目錄下,即可通過GET方法直接訪問該服務,訪問的地址為http://localhost:8080/axis/HelloWorld.jws?method=helloWorld,可以看到返回的SOAP信封消息,同時服務器端給出了相應的顯示信息“Hello World!”這表明HelloWorld服務被成功訪問了。如下圖所示:
客戶端服務訪問編程
Axis提供了一套API來實現SOAP,從http://localhost:8080/axis/docs/apiDocs/index.html可以看到Axis的API文檔。
其中,org.apache.axis.client.Call和org.apache.axis.client.Service是兩個比較常用的類,一般的客戶端程序欲訪問一個Web Service時,都要生成一個客戶端的Service對象和Call對象,在訪問服務之前,首先要對Call對象設置相應的參數,包括服務的位置、操作名、入口參數、返回值類型等,最后調用Call對象的invoke方法訪問服務。
以下給出了一個客戶端訪問Web服務的例程——AXISTest.java:
文件AXISTest.java
package axisexercise;
import org.apache.axis.client.Call;
import org.apache.axis.client.Service;
import org.apache.axis.encoding.XMLType;
import javax.xml.rpc.ParameterMode;
/**
* @author 飛鷹
*/
public class AXISTest
{
public static void main( String[] args ) throws Exception
{
Service service = new Service();
Call call = ( Call ) service.createCall();
//////////訪問即時發布的Distance服務
//設置訪問點
call.setTargetEndpointAddress( "http://localhost:8080/axis/Distance.jws" );
//設置操作名
call.setOperationName( "convertMile2Kilometre" );
//設置入口參數
call.addParameter( "op1", XMLType.XSD_DOUBLE, ParameterMode.IN );
call.setReturnType( XMLType.XSD_DOUBLE );
Double d1 = new Double( 190 );
//調用服務
System.out.println( d1 " 英里相當于 "
call.invoke( new Object[] {d1} ) " 公里!" );
//////////訪問定制發布的Capacity服務
call = ( Call ) service.createCall();
//設置訪問點
call.setTargetEndpointAddress( "http://localhost:8080/axis/services/Capacity" );
//設置操作名
call.setOperationName( "convertGallon2Litre" );
//設置入口參數
call.addParameter( "op1", XMLType.XSD_DOUBLE, ParameterMode.IN );
call.setReturnType( XMLType.XSD_DOUBLE );
d1 = new Double( 10.00 );
//調用服務
System.out.println( d1 " 加侖相當于 "
call.invoke( new Object[] {d1} ) " 升!" );
} //main()
}/* AXISTest */
編譯運行后運行可以看到以下的結果:
190.0英里相當于305.71公里!
10.0加侖相當于45.46升!
注意程序在訪問即時發布的Distance服務和定制發布的Capacity服務時的不同,前者的服務訪問點地址為http://localhost:8080/axis/HelloWorld.jws,而后者的則為http://localhost:8080/axis/services/Capacity。
總結
Web Services是未來網絡應用的發展方向,SOAP和WSDL是Web Services的核心協議,Axis給出了一個很好的SOAP實現,它使得開發Web Services應用變得輕松而有趣。
public class ServiceClient{
public static void main(String[] args) throws Exception{
String endpoint=" String name="gaong1";
Service service=new Service();
Call call=(Call) service.createCall();//回調服務
call.setUsername("gaolong1");
call.setPassword("8001");//用戶認證
call.setTargetEndpointAddress(new java.net.URL(endpoint));
// call.setOperationName("sayHelloG");
call.setOperationName(new QName(" call.addParameter("name",XMLType.XSD_STRING,ParameterMode.IN);
call.setReturnType(XMLType.XSD_STRING);//XMLType.XSD_STRING);
String ret=(String)call.invoke(new Object[] {name});
System.out.println(ret);
}
}
運行之后有關的顯示。
6。通過tcpmonitor來監聽的soap消息如下:
請求soap:
<?xml version="1.0" encoding="UTF-8"?><soapenv:Envelope xmlns:soapenv="<soapenv:Body>
<ns1:sayHelloG soapenv:encodingStyle=" </ns1:sayHelloG>
</soapenv:Body></soapenv:Envelope>
回應soap:
<?xml version="1.0" encoding="utf-8"?><soapenv:Envelope xmlns:soapenv="<soapenv:Body>
<ns1:sayHelloGResponse soapenv:encodingStyle="
import java.io.*;
import javax.activation.*;
public class FileService{
public static String Repository="./files/";
public String putFile(DataHandler dh,String name){
if(name==null)
name="test.tmp";
System.out.println("test");
try{
File dir=new File(Repository);
if(!dir.exists()){
dir.mkdir(); System.out.println("makedir"+"test");
}
InputStream input=dh.getInputStream();
FileOutputStream fos=new FileOutputStream(new File(dir,name));
System.out.println("test");
byte[] buffer=new byte[1024*4];
int n=0;
while((n=input.read(buffer))!=-1){
fos.write(buffer,0,n);
System.out.println(buffer);
}
System.out.println("test");
input.close();
fos.close();
}catch(IOException e){
e.printStackTrace();
}
return name+"send OK";
}
public DataHandler getFile(String name){
File dir=new File(Repository);
if(!dir.exists())
dir.mkdir();
File data=new File(dir,name);
if(data.exists())
return new DataHandler(new FileDataSource(data));
else
return null;
}
}
3。寫deploy.wsdd部署描述文件如下:
<deployment xmlns="http://localhost:7001/axis/services/FileService" >
<service name="FileService" provider="java:RPC">
<parameter name="className" value="test.gaolong.FileService"/>
<parameter name="allowedMethods" value="*"/>
<parameter name="allowedRoles" value="user"/>
<operation name="getFile" returnQName="returnqname" returnType="ns1:DataHandler" xmlns:SchemaNS=" <parameter name="name" type="SchemaNS:string"/>
</operation>
<operation name="putFile" returnQName="returnqname" returnType="ns1:DataHandler" xmlns:SchemaNS=" <parameter name="dh" type="ns1:DataHandler"/>
<parameter name="name" type="SchemaNS:string"/>
</operation>
<typeMapping deserializer="org.apache.axis.encoding.ser.JAFDataHandlerDeserializerFactory" type="java:javax.activation.DataHandler" qname="ns1:DataHandler" serializer="org.apache.axis.encoding.ser.JAFDataHandlerSerializerFactory" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/%22/%3E//注意見下面的。
</service>
</deployment>
注:對于soap1.2而言,要使用上面的<typeMaping>,而對于soap1.1而言,則有一點區別如下:
<typeMapping deserializer="org.apache.axis.encoding.ser.JAFDataHandlerDeserializerFactory" lanuageSpecificType="java:javax.activation.DataHandler" qname="ns1:DataHandler" serializer="org.apache.axis.encoding.ser.JAFDataHandlerSerializerFactory" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/%22/>
4。啟動服務器,用java org.apache.axis.client.AdminClient -p 7001 deploy.wsdd部署webservices即可訪問。
5。編寫客戶端應用訪問程序如下:
import javax.xml.rpc.ParameterMode;
import org.apache.axis.client.Call;
import org.apache.axis.client.Service;
import org.apache.axis.encoding.XMLType;
import javax.xml.namespace.QName;
import org.apache.axis.soap.SOAP11Constants;
import java.net.URL;
import javax.activation.DataHandler;
import javax.activation.FileDataSource;
import org.apache.axis.encoding.ser.*;
public class ServiceClient{
public static void main(String[] args) throws Exception{
String filename="HelloWorld.java";
DataHandler dh=new DataHandler(new FileDataSource(filename));
String endpoint=" String name="gaolong1";
Service service=new Service();
Call call=(Call) service.createCall();
call.setTargetEndpointAddress(new java.net.URL(endpoint));
call.setOperationName(new QName(" QName qnameattachment=new QName("FileService","DataHandler");
call.registerTypeMapping(dh.getClass(),qnameattachment,JAFDataHandlerSerializerFactory.class,JAFDataHandlerDeserializerFactory.class);
call.addParameter("s1",qnameattachment,ParameterMode.IN);
call.addParameter("s2",XMLType.XSD_STRING,ParameterMode.IN);
call.setReturnType(XMLType.XSD_STRING);//XMLType.XSD_STRING);//用Class.forName("java.lang.String")來獲取java類型
String ret=(String)call.invoke(new Object[] {dh,"HelloWorld.java"});
System.out.println(ret);
}
}
6。成功執行客戶端應用程序,可以找到上傳文件。
請求的soap消息:
POST /axis/services/FileService HTTP/1.0
Content-Type: multipart/related; type="text/xml"; start="<3165C8664597DC7EF29D5BFAC8972562>"; boundary="----=_Part_0_21866740.1141202759484"
Accept: application/soap+xml, application/dime, multipart/related, text/*
User-Agent: Axis/1.2.1
Host: localhost:7003
Cache-Control: no-cache
Pragma: no-cache
SOAPAction: ""
Content-Length: 1050
------=_Part_0_21866740.1141202759484
Content-Type: text/xml; charset=UTF-8
Content-Transfer-Encoding: binary
Content-Id: <3165C8664597DC7EF29D5BFAC8972562>
<?xml version="1.0" encoding="UTF-8"?><soapenv:Envelope xmlns:soapenv="http://www.w3.org/2001/XMLSchema-instance%22%3E%3Csoapenv:Body%3E%3Cns1:putFile soapenv:encodingStyle="------=_Part_0_21866740.1141202759484
Content-Type: application/octet-stream
Content-Transfer-Encoding: binary
Content-Id: <03D9C1D3A9E0788D274934C3ABD52811>
public class HelloWorld{
public String sayHello(String name){
return "Hello"+name;
}
}
------=_Part_0_21866740.1141202759484--
上傳后的文件的位置:/*在該目錄下創建文件夾:D:\bea\user_projects\domains\mydomain\files,并把相應的文件存入該目錄下*/
7.另一種基于java mail的帶附件的傳輸,是基于xmlDOM+servlet可以來實現,只是比較底層而已。