初学webservice,使用axis2第一个例子
项目中需要使用webservice,所以抓紧时间研究了一下。
目前比较流行的webservice框架有axis2(1和2完全不同),xfire,CXF。
先试试axis2吧。从网上下了jar包和war包。
网上关于axis2发布websevice好像都是同一个例子,而且都是在tomcat
下手工单独发布的,所以自己就研究官方的war包吧。
中文资料少的可怜,英语还是很重要的,不然总是需要依赖谷歌翻译。
看看解压后的axis2。
axis2-web里面是jsp页面,所以从这里应该可以看到请求webservice的url怎么写的,
这个等下再看。
org里面是class文件,
接着看WEB-INF,这个很重要
web.xml,把里面的东西拷贝到自己工程的web.xml去。
内容就是配置了sevlet。
对应的services和modules也拷贝到工程的WEB-INF下。
conf,里面有个axis2.xml,这个也拷贝到WEB-INF下。
lib中的jar包当然是要拷贝的。
这样准备工作就算完成了。
关于axis2.xml,有个
<parameter name="hotdeployment">true</parameter> 热发布
<parameter name="hotupdate">false</parameter> 热更新
把热更新改成true,这样在不重启服务器的情况下,就可以发布webservice。
这个没试过,以后再研究吧
现在写一个测试的service吧。
package lsy.com;
public class HiGirl {
public String sayHi(String str){
return str+",你好";
}
public void goodfBye(String str){
System.out.println(str+"--bye");
}
}
这个类很简单,2个方法sayHi和goodfBye。
刷新一下工程,到workSpace找编译的class文件。
在services目录中有个例子version-1.6.2.arr,这个例子很好,参照它我们很轻松的可以写一个webservice。
解压后,有2个目录,一个META-INF,一个类的包名(里面是class文件)。
仿照这个结构,我也拷贝一个META-INF,类就是我刚才编译的HiGirl.class
,按照这个类建立它的包(一定要建立对应的包package lsy.com);
然后打开META-INF下的services.xml,其他的文件不重要。
把其中的service改写成我们的。
<!--
~ Licensed to the Apache Software Foundation (ASF) under one
~ or more contributor license agreements. See the NOTICE file
~ distributed with this work for additional information
~ regarding copyright ownership. The ASF licenses this file
~ to you under the Apache License, Version 2.0 (the
~ "License"); you may not use this file except in compliance
~ with the License. You may obtain a copy of the License at
~
~ http://www.apache.org/licenses/LICENSE-2.0
~
~ Unless required by applicable law or agreed to in writing,
~ software distributed under the License is distributed on an
~ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
~ KIND, either express or implied. See the License for the
~ specific language governing permissions and limitations
~ under the License.
-->
<service name="ServiceFirst">
<description>
first
</description>
<parameter name="ServiceClass">com.lsy.HiGirl</parameter>
<operation name="sayHi">
<messageReceiver class="org.apache.axis2.rpc.receivers.RPCMessageReceiver" />
</operation>
</service>
service请求是ServiceFirst,
请求的方法是sayHi;消息接收类型是带参数有返回值的那种(org.apache.axis2.rpc.receivers.RPCMessageReceiver)
这个类型可以参照axis2.xml里面定义的。
改好后就要把这2个文件夹打包成aar。
怎么打包呢?eclipse有相关的插件,从axis官网apache也可以下载,目前我还未测试。
其实自己压缩成zip,然后重命名成aar文件就行。
这个压缩包名字随便起,没什么用,比如a.aar
然后把这个a.aar拷贝到WebContent/WEB-INF/services下,
重启工程,在地址栏输入
http://localhost:8080/AxisTest/services/listServices
这是axis2自带的servlet,可以返回目前可用的webservice列表
第二个ServletFirst就是我刚刚写的。
右键查看地址
http://localhost:8080/AxisTest/services/ServiceFirst?wsdl
返回:
<?xml version="1.0" encoding="UTF-8" ?>
- <wsdl:definitions xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" xmlns:ns1="http://org.apache.axis2/xsd" xmlns:ns="http://lsy.com" xmlns:wsaw="http://www.w3.org/2006/05/addressing/wsdl" xmlns:http="http://schemas.xmlsoap.org/wsdl/http/" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:mime="http://schemas.xmlsoap.org/wsdl/mime/" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:soap12="http://schemas.xmlsoap.org/wsdl/soap12/" targetNamespace="http://lsy.com">
<wsdl:documentation>ServiceFirst</wsdl:documentation>
- <wsdl:types>
- <xs:schema attributeFormDefault="qualified" elementFormDefault="qualified" targetNamespace="http://lsy.com">
- <xs:element name="sayHi">
- <xs:complexType>
- <xs:sequence>
<xs:element minOccurs="0" name="str" nillable="true" type="xs:string" />
</xs:sequence>
</xs:complexType>
</xs:element>
- <xs:element name="sayHiResponse">
- <xs:complexType>
- <xs:sequence>
<xs:element minOccurs="0" name="return" nillable="true" type="xs:string" />
</xs:sequence>
</xs:complexType>
</xs:element>
- <xs:element name="goodfBye">
- <xs:complexType>
- <xs:sequence>
<xs:element minOccurs="0" name="str" nillable="true" type="xs:string" />
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:schema>
</wsdl:types>
- <wsdl:message name="sayHiRequest">
<wsdl:part name="parameters" element="ns:sayHi" />
</wsdl:message>
- <wsdl:message name="sayHiResponse">
<wsdl:part name="parameters" element="ns:sayHiResponse" />
</wsdl:message>
- <wsdl:message name="goodfByeRequest">
<wsdl:part name="parameters" element="ns:goodfBye" />
</wsdl:message>
- <wsdl:portType name="ServiceFirstPortType">
- <wsdl:operation name="sayHi">
<wsdl:input message="ns:sayHiRequest" wsaw:Action="urn:sayHi" />
<wsdl:output message="ns:sayHiResponse" wsaw:Action="urn:sayHiResponse" />
</wsdl:operation>
- <wsdl:operation name="goodfBye">
<wsdl:input message="ns:goodfByeRequest" wsaw:Action="urn:goodfBye" />
</wsdl:operation>
</wsdl:portType>
- <wsdl:binding name="ServiceFirstSoap11Binding" type="ns:ServiceFirstPortType">
<soap:binding transport="http://schemas.xmlsoap.org/soap/http" style="document" />
- <wsdl:operation name="sayHi">
<soap:operation soapAction="urn:sayHi" style="document" />
- <wsdl:input>
<soap:body use="literal" />
</wsdl:input>
- <wsdl:output>
<soap:body use="literal" />
</wsdl:output>
</wsdl:operation>
- <wsdl:operation name="goodfBye">
<soap:operation soapAction="urn:goodfBye" style="document" />
- <wsdl:input>
<soap:body use="literal" />
</wsdl:input>
</wsdl:operation>
</wsdl:binding>
- <wsdl:binding name="ServiceFirstSoap12Binding" type="ns:ServiceFirstPortType">
<soap12:binding transport="http://schemas.xmlsoap.org/soap/http" style="document" />
- <wsdl:operation name="sayHi">
<soap12:operation soapAction="urn:sayHi" style="document" />
- <wsdl:input>
<soap12:body use="literal" />
</wsdl:input>
- <wsdl:output>
<soap12:body use="literal" />
</wsdl:output>
</wsdl:operation>
- <wsdl:operation name="goodfBye">
<soap12:operation soapAction="urn:goodfBye" style="document" />
- <wsdl:input>
<soap12:body use="literal" />
</wsdl:input>
</wsdl:operation>
</wsdl:binding>
- <wsdl:binding name="ServiceFirstHttpBinding" type="ns:ServiceFirstPortType">
<http:binding verb="POST" />
- <wsdl:operation name="sayHi">
<http:operation location="sayHi" />
- <wsdl:input>
<mime:content type="application/xml" part="parameters" />
</wsdl:input>
- <wsdl:output>
<mime:content type="application/xml" part="parameters" />
</wsdl:output>
</wsdl:operation>
- <wsdl:operation name="goodfBye">
<http:operation location="goodfBye" />
- <wsdl:input>
<mime:content type="application/xml" part="parameters" />
</wsdl:input>
</wsdl:operation>
</wsdl:binding>
- <wsdl:service name="ServiceFirst">
- <wsdl:port name="ServiceFirstHttpSoap11Endpoint" binding="ns:ServiceFirstSoap11Binding">
<soap:address location="http://localhost:8080/AxisTest/services/ServiceFirst.ServiceFirstHttpSoap11Endpoint/" />
</wsdl:port>
- <wsdl:port name="ServiceFirstHttpSoap12Endpoint" binding="ns:ServiceFirstSoap12Binding">
<soap12:address location="http://localhost:8080/AxisTest/services/ServiceFirst.ServiceFirstHttpSoap12Endpoint/" />
</wsdl:port>
- <wsdl:port name="ServiceFirstHttpEndpoint" binding="ns:ServiceFirstHttpBinding">
<http:address location="http://localhost:8080/AxisTest/services/ServiceFirst.ServiceFirstHttpEndpoint/" />
</wsdl:port>
</wsdl:service>
</wsdl:definitions>
从这里我们能看到一些信息,有一个targetNamespace="http://lsy.com
我的HiGirl.java的包名就是com.lsy
这就是我们在客户端QName是用到的参数。
查看内容还可以用这个方式:
http://localhost:8080/AxisTest/services/ServiceFirst?xsd
返回:
- <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:ns="http://lsy.com" xmlns:ns1="http://org.apache.axis2/xsd" attributeFormDefault="qualified" elementFormDefault="qualified" targetNamespace="http://lsy.com">
- <xs:element name="sayHi">
- <xs:complexType>
- <xs:sequence>
<xs:element minOccurs="0" name="str" nillable="true" type="xs:string" />
</xs:sequence>
</xs:complexType>
</xs:element>
- <xs:element name="sayHiResponse">
- <xs:complexType>
- <xs:sequence>
<xs:element minOccurs="0" name="return" nillable="true" type="xs:string" />
</xs:sequence>
</xs:complexType>
</xs:element>
- <xs:element name="goodfBye">
- <xs:complexType>
- <xs:sequence>
<xs:element minOccurs="0" name="str" nillable="true" type="xs:string" />
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:schema>
url后面只是?后不一样,我想应该是访问的标准不一样吧。
wsdl是一种标准,xsd也是一种标准(个人这么觉的)。
无论哪种标准或格式,能把请求和返回说清楚,过程我们并不关心,怎么用才是重点。
里面无非说清楚了命名空间,方法,方法的参数及其类型,返回值及其类型。
axis2-web丽还有一个页面index.jsp
访问http://localhost:8080/AxisTest/axis2-web/index.jsp
这就是总的浏览页面,点击Service据进入刚才可用的Service列表页面。
所以说axis2-web这个jsp页面包还是有用的,web.xml里面配置的其他servlet我们最好也别注掉,
这样,我们测试更方便,有哪些可用的service,在页面就可以直接看出来,访问地址也
清楚明了。
我的第一个sayHi是有返回值的,访问以下
http://localhost:8080/AxisTest/services/ServiceFirst?sayHi
或者http://localhost:8080/AxisTest/services/ServiceFirst/sayHi
返回
- <ns:sayHiResponse xmlns:ns="http://lsy.com">
<ns:return>null,你好</ns:return>
</ns:sayHiResponse>
如果想要把参数传给webservice,地址这样写:
http://localhost:8080/AxisTest/services/ServiceFirst/sayHi?str=qq
参数名称就是你写的方法的参数名称,这个一旦写好,就固定了,例如
public String sayHi(String str){
return str+",你好";
}
这个参数叫str,在访问时也要用str。
返回:
- <ns:sayHiResponse xmlns:ns="http://lsy.com">
<ns:return>qq,你好</ns:return>
</ns:sayHiResponse>
这样wbservice就可以访问了,而webservice是为程序服务的,所以要在程序中写客户端访问代码。
ClientFirst.java
package com;
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.client.ServiceClient;
import org.apache.axis2.rpc.client.RPCServiceClient;
public class ClientFirst {
public static void main(String[] args) {
// 外接口返回值
String res = "";
try {
RPCServiceClient service = new RPCServiceClient();
Options o=service.getOptions();
String url="http://localhost:8080/AxisTest/services/ServiceFirst";
EndpointReference er=new EndpointReference(url);
o.setTo(er);
QName qn=new QName("http://lsy.com","sayHi");
Object[] param=new Object[]{"haha"};
Class[] retype=new Class[]{String.class};
Object result[]=service.invokeBlocking(qn, param, retype);
System.out.println("返回值是:"+result[0].toString());
} catch (AxisFault e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
要注意的就是引入的包,包名重复的类很多,写的时候一定要引对。
打印:
log4j:WARN No appenders could be found for logger (org.apache.axis2.context.AbstractContext).
log4j:WARN Please initialize the log4j system properly.
返回值是:haha,你好
这样就有返回值了。
这个工程结构如下: