WebService 四种发布方式总结
1. CXF方式
CXF与spring搭建webservice是目前最流行的方式,但是传闻cxf与jdk1.5有些不兼容,我没有遇到过,我遇到的问题是cxf与was6.1.1不兼容,表现在cxf必须的jar包“wsdl4j-1.6.2.jar”报错,报的错为: java.lang.IncompatibleClassChangeError,明显的jar包不兼容问题,很是头痛,后来查找资料找到解决办法是,将上述jar包新建一个was共享库,可以解决,但是客户周经理不想用此种方式,因为需要修改was,于是改用了axis2方式,下文会介绍。该问题在此处做个记录,以后使用cxf与was的时候需要注意!!!
使用cxf+spring搭建WebService:
第一步,添加jar包。此处需要注意,不同环境(tomcat、was)jar也不一定相同,例如我本地cxf+spring只需要如下jar包:
而泰康的was环境则需要如下jar包:
明显的多了很多,原因应该是服务器jar包池的不同。根据错误提示缺什么补什么就可以了,注意jar包勿重复。
第二步,配置web.xml文件,如下(重要的地方已标记):
<context-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:/applicationContext.xml</param-value> </context-param> <listener> <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> </listener> <!-- Character Encoding filter --> <filter> <filter-name>encodingFilter</filter-name> <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class> <init-param> <param-name>encoding</param-name> <param-value>UTF-8</param-value> </init-param> </filter> <filter-mapping> <filter-name>encodingFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> <servlet> <servlet-name>CXFServlet</servlet-name> <servlet-class>org.apache.cxf.transport.servlet.CXFServlet</servlet-class> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>CXFServlet</servlet-name> <url-pattern>/webservice/*</url-pattern> </servlet-mapping> |
上述标记的地方,第一处是spring配置文件路径;第二出是wsdl地址内容;
第三步,编写接口类与实现类,注意注解
接口类 @WebService public interface SendService { public boolean sendOA(@WebParam(name="param")String param); public boolean sendOrg(OrgEntity org); } 实现类 @WebService(endpointInterface="com.service.SendService",serviceName="sendService") public class SendServiceImpl implements SendService{ public boolean sendOA(String param) { System.out.println("-------sendOA---------param:"+param); if(param.equals("zhoujian")){ return true; } return false; } public boolean sendOrg(OrgEntity org) { System.out.println("-------sendOrg--begin-------"); return true; } } |
第四步,Spring配置文件
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p" xmlns:jaxws="http://cxf.apache.org/jaxws" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://cxf.apache.org/jaxws http://cxf.apache.org/schemas/jaxws.xsd"> <import resource="classpath:META-INF/cxf/cxf.xml"/> <import resource="classpath:META-INF/cxf/cxf-extension-soap.xml"/> <import resource="classpath:META-INF/cxf/cxf-servlet.xml"/>
<jaxws:endpoint id="sendServie" implementor="com.service.impl.SendServiceImpl" address="/sendServie" />
<!-- <jaxws:client id="sendServiceClient" serviceClass="com.service.SendService" address="http://10.137.138.11:9080/Wb/webservice/sendServie?wsdl" />-->
</beans> |
“jaxws:client”该标签可以不必写,访问时可以手动拼接该url
第五步,发布,直接部署到服务器,访问:
http://10.137.138.11:9080/Wb/webservice/sendServie?wsdl |
2. Xfire方式
据说xfire方式已经很老了,但个人感觉,xfire方式很简单且容易配置,不知为啥过时了,也没感觉cxf、axis2哪里先进,我当时卡在cxf与was搞不定时想尝试xfire方式被周经理给拒绝了。
Xfire方式发布webservice:
第一步,添加jar包,如下:
第二步,修改web.xml文件
<servlet> <servlet-name>XFireServlet</servlet-name> <servlet-class>org.codehaus.xfire.transport.http.XFireConfigurableServlet</servlet-class> <load-on-startup>0</load-on-startup> </servlet> <servlet-mapping> <servlet-name>XFireServlet</servlet-name> <url-pattern>/services/*</url-pattern> </servlet-mapping> |
第三步,编写接口类
接口类: public abstract interface IBankingService { public abstract String transferFunds(String paramString1); } 实现类: public class BankingService implements IBankingService{ public String transferFunds(String fromAccount) { return fromAccount+":ok"; } } |
第四步,编写services.xml配置文件
在WEB-INF目录下新建目录META-INF,在该目录下新建文件夹xfire,该目录下新建文件services.xml
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://xfire.codehaus.org/config/1.0"> <service> <name>Banking</name> <namespace>mybank</namespace> <serviceClass> com.mybank.xfire.example.IBankingService </serviceClass> <implementationClass> com.mybank.xfire.impl.BankingService </implementationClass> </service> </beans> |
第五步,发布,部署到服务器,访问url:
http://localhost:9080/Xfire/services/Banking?wsdl |
3. AXIS2方式
Axis2发布WebService有两种方式,其一是利用axis2插件打成aar包放到axis_war里面部署到服务器发布;其二是不打包发布(本例);我不清楚打包发布有什么好处,感觉很麻烦项目外还得部署一个war,现在介绍第二种不打包的方式,类似xfire,同时由于cxf与was不兼容导致wsdl.jar报错,但是xfire与axis2也用到wsdl.jar却不报错,我个人也是很费解,泰康项目目前使用的就是axis2方式。
Axis2发布WebService:
第一步,添加jar包,如下:
很多是吧,不过都是从axis.war里面WEB-INF下的lib目录复制来的。
第二步,修改web.xml文件
<servlet> <servlet-name>AxisServlet</servlet-name> <servlet-class>org.apache.axis2.transport.http.AxisServlet</servlet-class> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>AxisServlet</servlet-name> <url-pattern>/services/*</url-pattern> </servlet-mapping>
|
第三步,编写实现类
public class ServiceImpl { public String sayHello(String name){ System.out.println("================"); return "hello:"+name; } } |
第四步,增加WEN-INF内容
将axis.war解压下的WEN-INF文件夹内的conf、modules复制到项目WEB-INF下
第五步,在WEB-INF下创建文件夹services(名字不可改),在该目录下创建文件夹(名称随意),在该目录下创建文件夹META-INF(名称不可改),在该目录下创建文件services.xml(名称不可改),该文件内容为:
<?xml version="1.0" encoding="UTF-8"?> <service name="axisDemo"> <description> Web Service例子 </description> <parameter name="ServiceClass"> com.ServiceImpl </parameter> <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> |
第六步,部署到服务器,发布URL为:
http://localhost:9080/Axis2Test/services/axisDemo?wsdl |
4. AXIS1方式
同上,不知道AXIS1哪里不好,配置也很简单,如下:
第一步,添加jar包
第二步,修改web.xml
<servlet> <servlet-name>AxisServlet</servlet-name> <servlet-class> org.apache.axis.transport.http.AxisServlet </servlet-class> </servlet> <servlet-mapping> <servlet-name>AxisServlet</servlet-name> <url-pattern>/services/*</url-pattern> </servlet-mapping> |
第三步,实现类与实体类
实现类: package com; public class Axis { public String sayHello(String name){ System.out.println("============:"+name); return "hi:"+name; } public String sayHelloToUser(User u){ System.out.println("============:"+u.getId()); System.out.println("============:"+u.getPath()); System.out.println("============:"+u.getAdd()); return "hi:"+u.getName(); } }
实体类: package com; public class User { private String id; private String name; private String add; private String path;
getter setter ……方法
|
第四步,创建配置文件:在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 标签内容为系统默认 无需更改à <globalConfiguration> <parameter name="adminPassword" value="admin"/> <parameter name="attachments.Directory" value="./attachments"/> <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"/> <handler name="URLMapper" type="java:org.apache.axis.handlers.http.URLMapper"/> <handler name="Authenticate" type="java:org.apache.axis.handlers.SimpleAuthenticationHandler"/> <!—service 标签是需要配置的 -à <!—name 是url中需要的参数 -à <service name="axisTest" provider="java:RPC"> <!—allowedMethods 的value值是方法名 可以写*-à <parameter name="allowedMethods" value="*"/> <!—className的value值是类路径-à <parameter name="className" value="com.Axis"/> <!—wsdlTargetNamespace的wsdl文件中TargetNamespace的值-à <parameter name="wsdlTargetNamespace" value="http://service.impl.tdi.taikang.tivoli.ibm.com/"/> <!—此处很重要,若方法需要传实体类,则配置此处-à <beanMapping qname="myNS:User" xmlns:myNS="urn:BeanService" languageSpecificType="java:com.User"/> </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> |
第五步,部署,同上。
5. AXIS1客户端调用
此处调用方式为axis1的调用,需要传递的参数可以是字符串或实体类,字符串方式:
Service service = new Service(); Call call = (Call) service.createCall(); //wsdl地址 call.setTargetEndpointAddress(new URL(wsdlUrl)); //设定调用3分钟不返回则超时 call.setTimeout(new Integer(180000)); //命名空间(wsdl文件中的targetNameSpace属性值) 以及方法名 call.setOperationName(new QName("http://com", "sayHello")); //参数类型 call.addParameter("name", XMLType.XSD_STRING, ParameterMode.IN); //返回值类型 call.setReturnType(XMLType.XSD_STRING); //参数值 String retXML2 = (String) call.invoke( new Object[] { "yczhang" }); System.out.println( retXML2); |
实体类方式(调用axis2的接口有点问题):
UserEntity userEntry = new UserEntity(); userEntry.setId("yczhang"); userEntry.setName("yczhang"); Service service = new Service(); Call call = (Call) service.createCall(); //wsdl地址 call.setTargetEndpointAddress(new URL(wsdlUrl)); //设定调用3分钟不返回则超时 call.setTimeout(new Integer(180000)); //命名空间(wsdl文件中的targetNameSpace属性值) 以及方法名 call.setOperationName(new QName("http://com", "sayHelloToUser")); //注册SimpleObject的序列化类型 QName qn = new QName("urn:BeanService", "UserEntity"); call.registerTypeMapping(UserEntity.class, qn, new BeanSerializerFactory(UserEntity.class, qn), new BeanDeserializerFactory(UserEntity.class, qn)); //参数类型(可省略) call.addParameter("requestParam", org.apache.axis.encoding.XMLType.XSD_ANYTYPE, ParameterMode.IN); //返回值类型 call.setReturnType(XMLType.XSD_BOOLEAN); Boolean retXML1 = (Boolean) call.invoke( new Object[] { userEntry }); System.out.println( retXML1); |
注意,实体类方式,当调用的是由axis2方式所发布的接口时,容易出现问题,表现在所传递的实体类的属性内容为null,但在该实体类内新建一属性传如该值时,却有值。应该是axis1对axis2的不兼容问题。并且调用axis2的接口时,需要在客户端写出namespace,即:
//call.setOperationName(new QName("http://localhost:9080/WS_Axis/services/axisTest", "sayHelloToUser"));
|
该种调用方式对于axis1的接口没问题。泰康项目最终使用的是axis1发布的接口,并使用该种方式调用的。
public static void main(String[] args) throws ServiceException, MalformedURLException, RemoteException { String wsdlUrl = "http://localhost:9080/WS_Axis/services/axisTest?wsdl"; //实体类 User user = new User(); user.setId("1"); user.setAdd("test"); user.setName("test"); user.setPath("test"); Service service = new Service(); Call call = (Call) service.createCall(); call.setTargetEndpointAddress(new URL(wsdlUrl)); //设定调用3分钟不返回则超时 call.setTimeout(new Integer(180000)); //call.setOperationName(new QName("http://localhost:9080/WS_Axis/services/axisTest", "sayHelloToUser")); //注册SimpleObject的序列化类型(urn:BeanService在wsdd文件内有配置) QName qn = new QName("urn:BeanService", "User"); call.registerTypeMapping(User.class, qn, new BeanSerializerFactory(User.class, qn), new BeanDeserializerFactory(User.class, qn)); //方法名 call.setOperationName("sayHelloToUser"); //“user”是接口服务端方法体中的实体类所声明的变量名(”say(User user)”) call.addParameter("user", org.apache.axis.encoding.XMLType.XSD_ANYTYPE, ParameterMode.IN); //返回值类型 call.setReturnType(XMLType.XSD_STRING); System.out.println( call.invoke( new Object[] { user })); } |
6. AXIS2客户端调用
所需jar包:
具体代码:
public class RPClient { public static void main(String[] args) throws AxisFault { try { //实体类 UserEntity ue = new UserEntity(); ue.setId("123"); ue.setAddress("test"); ue.setMail("123"); ue.setName("yczhang"); RPCServiceClient client = new RPCServiceClient(); Options options = client.getOptions(); String url = "http://localhost:9080/WS_Axis2/services/axisDemo?wsdl"; EndpointReference end = new EndpointReference(url); options.setTo(end);
Object[] obj = new Object[] { ue }; Class<?>[] classes = new Class[] { Boolean.class }; //命名空间 方法名 QName qname = new QName("http://com", "sayHelloToUser"); System.out.println(client.invokeBlocking(qname, obj, classes)[0]); } catch (AxisFault e) { e.printStackTrace(); } } |
注意 该种方式缺点是客户端实体类路径即包名必须与服务端实体类路径相同!!!但该方式可以调任何方式编写的接口!!!!
7. CXF客户端调用
使用axis、axis2客户端调用cxf接口会有问题,建议使用cxf自身客户端调用或者使用webservice Client 自动生成客户端方式
所需的jar包:
功能代码:
public class TT { public static void main(String[] args) { JaxWsDynamicClientFactory dcf = JaxWsDynamicClientFactory.newInstance(); Client client = dcf.createClient("http://10.137.138.11:9080/WS_CXF/webservice/sendServie?wsdl"); try { //此处http://service.com/需要指向接口路径而非实现类 System.out.println(client.invoke(new QName("http://service.com/", "sendOA"),"test")[0]); } catch (Exception e) { e.printStackTrace(); } } } |
注意:若运行程序时报错“JAXB 2.0 API ….. endorsed”则需要将以下jar包放入jdk lib和jre lib
重启exlipse即可。
8. Web Service Client客户端调用
右键项目:
调用代码如下:
public class CXFClient { public static void main(String[] args) throws Exception, IllegalAccessException, InvocationTargetException { JaxWsDynamicClientFactory dcf = JaxWsDynamicClientFactory.newInstance(); Client client = dcf.createClient("http://localhost:9080/WS_CXF/webservice/sendServie?wsdl"); client.invoke("sendOA", "aa"); } } |