前一段時間在公司比較閑看了看CXF2.3 與SPRING 3.0.5集成,以前用XFire開發(fā)東西,去XFire社區(qū)轉(zhuǎn)時候都說建議換用CXF。哈哈不說廢話了開始吧:
準(zhǔn)備:CXF2.3.0 所有jar 包,去官網(wǎng)下就可以了,如果為了測試建議把lib下所有jar包導(dǎo)入工程中(它里邊包含了spring所必需的jar包版本是spring3.0.5的,如果你不想使用CXF2.3.0中的spirng jar包可以不導(dǎo)入,導(dǎo)入自己的)。
oracle 數(shù)據(jù)驅(qū)動包:ojdbc14.jar
spirng -jdbc 包: org.springframework.jdbc-3.0.5.RELEASE.jar(因為本用例需要用spring JDBC 做持久層測試)
第一步:建立一個webproject ,把CXF包導(dǎo)入工程lib目錄下;
接口代碼如下:
import javax.jws.WebService;
/*
* @author zzz
* @version 1.0
* @ userservice接口;
*/
@WebService
public interface UserService {
public String getSomething(String data);
}
實現(xiàn)類:
import java.sql.SQLException;
import javax.jws.WebService;
import org.springframework.jdbc.core.JdbcTemplate;
import com.tchzt.demo.user.service.UserService;
@WebService
public class UserServiceImpl extends JdbcTemplate implements UserService{
public String getSomething(String data) {
System.out.println("this is server message :"+data);
try {
System.out.println("獲得數(shù)據(jù)庫連接:"+getDataSource().getConnection());
//這里是用的spring 的JDBC,可以在這里寫持久化代碼;
} catch (SQLException e) {
e.printStackTrace();
}
return data;
}
}
在src目錄下建立一個applicationContext-client-beans.xml 這個名字可以自己定,但在web.xml 加載名字要一致:
<?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: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/schema/jaxws.xsd">
<!-- 這是JNDI配置數(shù)據(jù)源方式
<bean id="propertyPlaceholderConfigurer" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="location">
<value>classpath:com/chtt/cfg/dbconn/oracle_jndi.properties</value>
</property>
</bean>
<bean id="dataSource" class="org.springframework.jndi.JndiObjectFactoryBean">
<property name="jndiName">
<value>${oraconn.jndi}</value>
</property>
</bean>
-->
<!-- 數(shù)據(jù)據(jù)源配置方式 -->
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="oracle.jdbc.driver.OracleDriver"/>
<property name="url" value="jdbc:oracle:thin:@110.168.1.51:1521:pos"/>
<property name="username" value="pos"/>
<property name="password" value="pos"/>
</bean>
<!-- 配置DAO -->
<bean id="daoTemplate" abstract="true">
<property name="dataSource">
<ref local="dataSource"/>
</property>
</bean>
<!-- dao引用 -->
<bean id="userServiceImpl" class="com.tchzt.demo.user.serviceImpl.UserServiceImpl" parent="daoTemplate"/>
<!-- webservice 發(fā)布配置 -->
<bean id="client" class="com.test.Client" factory-bean="clientFactory" factory-method="create" />
<bean id="clientFactory" class="org.apache.cxf.jaxws.JaxWsProxyFactoryBean" >
<!-- 服務(wù)發(fā)布供外部調(diào)用接口 -->
<property name="serviceClass" value="com.tchzt.demo.user.service.UserService" />
<property name="address" value="http://127.0.0.1:8080/WebServiceCXF/UserService" />
</bean>
</beans>
WEB-INF目錄下建立一個services.xml (名字自己定):
<?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: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" />
<!-- webService發(fā)布地址 , #userServiceImpl引用bean方式,也可以寫成類的全路徑 -->
<!--userServiceImpl 加入數(shù)據(jù)連接, 在此引用 -->
<jaxws:endpoint id="userService" implementor="#userServiceImpl" address="/UserService"/>
<!-- 第二種方式引用其它bean;
<jaxws:endpoint id="userService"
implementorClass="demo.spring.HelloWorld"
address="/UserService">
<jaxws:implementor>
<bean ref="userServiceImpl"/>
</jaxws:implementor>
<jaxws:implementor>
<bean ref="userServiceImpl2"/>
</jaxws:implementor>
</jaxws:endpoint>
-->
</beans>
web.xml 文件內(nèi)容:
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:applicationContext-client-beans.xml,WEB-INF/services.xml</param-value>
</context-param>
<listener>
<listener-class>
org.springframework.web.context.ContextLoaderListener
</listener-class>
</listener>
<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>/*</url-pattern>
</servlet-mapping>
<welcome-file-list>
<welcome-file>index.jsp</welcome-file>
</welcome-file-list>
<!-- 加載數(shù)據(jù)源
<resource-ref>
<res-ref-name>jdbc/cdbank</res-ref-name>
<res-type>javax.sql.DataSource</res-type>
<res-auth>Container</res-auth>
</resource-ref>
-->
</web-app>
測試類內(nèi)容:
package com.test;
import org.apache.cxf.jaxws.JaxWsProxyFactoryBean;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import com.tchzt.demo.user.service.UserService;
import com.tchzt.demo.user.serviceImpl.UserServiceImpl;
public class Client {
public static Client client = new Client();
private UserService userService=null;
//這是spring得到服務(wù)實例構(gòu)造方法;
private Client(){
ApplicationContext context=new ClassPathXmlApplicationContext("applicationContext-client-beans.xml");
userService=(UserService) context.getBean("client");
}
//這是普通客戶端得到服務(wù)實例;
private Client(UserService userService){
this.userService=userService;
}
public String getText(String text) throws Exception {
String data = userService.getSomething(text);
return data;
}
/*
*單獨測試spring 加載數(shù)據(jù)連接;
*/
public static void getConnectTest(){
ApplicationContext context=new ClassPathXmlApplicationContext("applicationContext-client-beans.xml");
UserServiceImpl userServiceImpl=(UserServiceImpl) context.getBean("userServiceImpl");
System.out.println("數(shù)據(jù)庫連接測試:"+userServiceImpl.getSomething("adfasdf"));
}
/*
* CXF 普通客戶端測試;
*/
public static void testCxfClient()throws Exception{
//這里不用Spring 得到bean實例;
JaxWsProxyFactoryBean factory=new JaxWsProxyFactoryBean();
//設(shè)置服務(wù)類的名字;
factory.setServiceClass(UserService.class);
//設(shè)置服務(wù)的地址;
factory.setAddress("http://127.0.0.1:8080/WebServiceCXF/UserService");
//得到服務(wù)類的實例;
UserService userService=(UserService) factory.create();
Client client=new Client(userService);
System.out.println(client.getText("這是webserviceCXF測試數(shù)據(jù)"));
}
/*
* spring 與CXF 集成發(fā)布測試;
*/
public static void testSpringCxfClient()throws Exception{
//這是用spring 得到服務(wù)實例;
System.out.println(client.getText("這是webserviceCXF與 spring集成發(fā)布的測試數(shù)據(jù)!"));
}
public static void main(String[] args)throws Exception {
//測試數(shù)據(jù)連接是否成功!
//Client.getConnectTest();
//普通測試;
//Client.testCxfClient();
//集成測試;
Client.testSpringCxfClient();
}
}
測試:把工程發(fā)布到tomcat上運行測試類出現(xiàn)下面結(jié)果:
Client.testSpringCxfClient()方法測試:
客戶端輸出:
這是webserviceCXF與 spring集成發(fā)布的測試數(shù)據(jù)!
服務(wù)器端的輸出:
this is server message :這是webserviceCXF與 spring集成發(fā)布的測試數(shù)據(jù)!
獲得數(shù)據(jù)庫連接:oracle.jdbc.driver.OracleConnection@7fb878
Client.testCxfClient()測試:
客戶端輸出:
這是webserviceCXF測試數(shù)據(jù)
服務(wù)器端的輸出:
this is server message :這是webserviceCXF測試數(shù)據(jù)
獲得數(shù)據(jù)庫連接:oracle.jdbc.driver.OracleConnection@6276e5
Client.getConnectTest()數(shù)據(jù)庫連接測試:
this is server message :adfasdf
獲得數(shù)據(jù)庫連接:oracle.jdbc.driver.OracleConnection@c38157
數(shù)據(jù)庫連接測試:adfasdf
好了到此CXF+spring 集成完畢(不足這處沒有加入聲明式事物的管理,只加入了spring 連接數(shù)據(jù)庫和持久層JDBC,有時間在完善下),如果有什么問題請聯(lián)系我:zzzlyr@163.com
有時間更新這篇文章了,加入聲明式事物,這個很簡單。在把項目里用的CXF細節(jié)和遇到問題說明下:
把appcliatContext.xml 這個文件加入Spring包 自動掃描,在你的業(yè)務(wù)層上加下面基于注解事物:
開起注解事物 在需要的方法上加入即可
默認Spring為每個方法開啟一個事務(wù),如果方法發(fā)生運行期錯誤unchecked(RuntimeException),事務(wù)會進行回滾
如果發(fā)生checked Exception,事務(wù)不進行回滾.
@Transactional(propagation=Propagation.REQUIRED)
@Transactional(propagation=Propagation.NOT_SUPPORTED,readOnly=true)
重點說下在項目中用CXF2.3 遇到問題:
第一個:就是CXF命名空間問題,在網(wǎng)上好多例子,就簡單是一個例子。在項目中CXF發(fā)布webService ,一般做法是實現(xiàn)類和接口沒有在一個包中;這是項目中要用到的:
這是接口:
package com.tchzt.service;
import javax.jws.WebResult;
import javax.jws.WebService;
/*
* @author zzz
* @version 1.0
* @ userservice接口;
*/
/*
* webService接口綁定;
* com.tchzt.webService
*
*/
@WebService(targetNamespace="com.tchzt.seals.service")
public interface SealHandOverService {
/*
* 反回值標(biāo)注,可以改變返回參數(shù)WSDL發(fā)布名字,還有參數(shù)名字;
*/
public @WebResult(name="sealHandOverService") String getDocumentByBantchNo(String nantchNo)throws Exception;
}
實現(xiàn)類:
package com.tchzt.service.imp;
import java.util.LinkedList;
import java.util.List;
import javax.jws.WebService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;
import com.tchzt.dao.PrintlogDaoIf;
import com.tchzt.dao.SealTypeDaoIf;
import com.tchzt.dao.SealsDaoIf;
import com.tchzt.po.AppSeals;
import com.tchzt.po.AppSealtype;
import com.tchzt.po.Printlog;
import com.tchzt.service.SealHandOverService;
import com.tchzt.util.Document4jUtils;
@Service
@WebService(targetNamespace="com.tchzt.seals.service",endpointInterface="com.tchzt.service.SealHandOverService")
public class SealHandOverServiceImpl implements SealHandOverService {
@Autowired
@Qualifier("printlogDaoIfImpl")
private PrintlogDaoIf printlogDao;
@Autowired
@Qualifier("sealsDaoIfImpl")
private SealsDaoIf sealsDao;
@Autowired
@Qualifier("sealTypeDaoIfImpl")
private SealTypeDaoIf sealTypeDao;
@Override
public String getDocumentByBantchNo(String banchno) throws Exception {
List<Printlog> list=printlogDao.getPrintlogs(banchno);
List<String> sealXML=new LinkedList<String>();
for(Printlog p:list){
AppSeals seal=sealsDao.getByIdx(AppSeals.class, p.getSealid());
AppSealtype sealType=sealTypeDao.getByIdx(AppSealtype.class, seal.getSealtypeId());
sealXML.add("id:"+seal.getId());
sealXML.add("sealName:"+sealType.getSealName());
sealXML.add("sealType:"+sealType.getId());
sealXML.add("image:"+seal.getImage());
}
for(String s:sealXML){
System.out.println(s);
}
return Document4jUtils.getHandOverScanXML(sealXML,banchno);
}
}
上面注意一個就行targetNamespace="com.tchzt.seals.service"一要寫上,接口和實現(xiàn)類不在同一個包中,接口和實現(xiàn)類一定要一致。但網(wǎng)上好多例子接口和實現(xiàn)類在一包中targetNamespace這個東西默認是一致的,所以不需要指定,如果接口和實現(xiàn)類不在同一個包中,你查看WSDL的時候也可以看到,也不報錯,但就是發(fā)布WSDL少信息。
第二客戶端問題:網(wǎng)上好多例子就是一個工程,調(diào)自己工程發(fā)布的WebService的方法,以下是第二個JAVA工程調(diào)用第一個發(fā)布成功的webService 方法如下 :
package com.tchzt.test;
import org.apache.cxf.endpoint.Client;
import org.apache.cxf.jaxws.JaxWsProxyFactoryBean;
import org.apache.cxf.jaxws.endpoint.dynamic.JaxWsDynamicClientFactory;
import com.tchzt.service.SealHandOverService;
public class WebServiceClientTest {
/*
* CXF 變通客戶端測試;
*/
public static void testCxfClient()throws Exception{
//這里不用Spring 得到bean實例;
JaxWsProxyFactoryBean factory=new JaxWsProxyFactoryBean();
//設(shè)置服務(wù)類的名字;
factory.setServiceClass(SealHandOverService.class);
//設(shè)置服務(wù)的地址;
factory.setAddress("http://127.0.0.1:8080/seal/ws/SealHandOverService");
//得到服務(wù)類的實例;
SealHandOverService sealHandOverService=(SealHandOverService) factory.create();
System.out.println("======="+sealHandOverService.getDocumentByBantchNo("67801100060039"));
}
/**
* @Title: callService
* @Description: 調(diào)用遠程的webservice并返回數(shù)據(jù)
* @param wsUrl
* webservice地址
* @param method
* 調(diào)用的webservice方法名
* @param arg
* 參數(shù)
* @return
* @return:String
* @throws
*/
public static String callService(String wsUrl, String method, Object... arg)throws Exception {
JaxWsDynamicClientFactory dcf = JaxWsDynamicClientFactory.newInstance();
Client client = dcf.createClient(wsUrl);
Object[] res = client.invoke(method, arg);
return (String) res[0];
}
public static void main(String[] args)throws Exception {
//URL 組成:http://110.168.1.121:8080/seal ;第二部分:ws/這個是在web.xml配置的一個攔截地址; 第三部分: SealHandOverService?wsdl 是接口中發(fā)部的
String s=WebServiceClientTest.callService("http://110.168.1.121:8080/seal/ws/SealHandOverService?wsdl", "getDocumentByBantchNo", new Object[]{"67801100060039"});
System.out.println(s);
WebServiceClientTest.testCxfClient();
}
}
這個測試類里有兩個方法,應(yīng)該差不多從注釋可以看明白什么意思。
以上方法都在項目中正確調(diào)用通過。
以下是網(wǎng)上的一此方法:
由于我們通常不知道提供Web Service的服務(wù)器接口及其相關(guān)類的代碼,我們也不可能從他人那里獲得。
對此,CXF提供了一些命令行工具,在CXF_HOME/bin下(這里是你下載的CXF包下有目錄)。
使用wsdl2java,可以根據(jù)從服務(wù)器返回的wsdl文件生成我們所需要的java接口和相關(guān)類。
在上面的工程中,我們可以用以下命令生成JAVA代碼,而不是從第一個工程中復(fù)制過來。
wsdl2java -p client http://110.168.1.121:8080/seal/ws/SealHandOverService?wsdl (需要在cmd窗口中將路徑切換至CXF_HOME/bin下)
例如:F:\apache-cxf-2.2.7\bin>wsdl2java -d E:\programFiles -client http://127.0.0.1/services/AlarmInformationServices?wsdl
(解釋:wsdljava –p 包路徑 –d 目標(biāo)文件夾 wsdl 的url地址)
-p 是指生成客戶端代碼存放位置;
需要注意的是,對于接口類和相關(guān)類的包路徑,一定要和服務(wù)器的一樣, 即:如果服務(wù)接口包路徑和實現(xiàn)類路徑,要和客戶端一致。
否則,會出現(xiàn)org.apache.cxf.interceptor.Fault: Unexpected wrapper element {****}addResponse found.……錯誤。