http://blog.csdn.net/zl834205311/article/details/51612207
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"); |