项目中需要使用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,你好
这样就有返回值了。
这个工程结构如下: