posts - 22, comments - 32, trackbacks - 0, articles - 73
  BlogJava :: 首页 :: 新随笔 :: 联系 :: 聚合  :: 管理

前一段时间在公司比较闲看了看CXF2.3 与SPRING 3.0.5集成,以前用XFire开发东西,去XFire社区转时候都说建议换用CXF。哈哈不说废话了开始吧:

准备:CXF2.3.0 所有jar 包,去官网下就可以了,如果为了测试建议把lib下所有jar包导入工程中(它里边包含了spring所必需的jar包版本是spring3.0.5的,如果你不想使用CXF2.3.0中的spirng jar包可以不导入,导入自己的)。

oracle 数据驱动包:ojdbc14.jar
spirng -jdbc 包: org.springframework.jdbc-3.0.5.RELEASE.jar(因为本用例需要用spring JDBC 做持久层测试)

第一步:建立一个webproject ,把CXF包导入工程lib目录下;

接口代码如下:
import javax.jws.WebService;
/*
 * @author zzz
 * @version 1.0
 * @ userservice接口;
 */

@WebService 
public interface UserService {
 public String getSomething(String data);
}


实现类:
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("获得数据库连接:"+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配置数据源方式

 <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>
--> 
<!-- 数据据源配置方式 -->
<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 发布配置 -->
<bean id="client" class="com.test.Client" factory-bean="clientFactory" factory-method="create" />

<bean id="clientFactory" class="org.apache.cxf.jaxws.JaxWsProxyFactoryBean" >
 <!-- 服务发布供外部调用接口 -->
 <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发布地址 , #userServiceImpl引用bean方式,也可以写成类的全路径 -->
   <!--userServiceImpl 加入数据连接, 在此引用  -->
    <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 文件内容:

<?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>
 <!-- 加载数据源
 <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>

测试类内容:
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得到服务实例构造方法;
    private Client(){
     ApplicationContext context=new ClassPathXmlApplicationContext("applicationContext-client-beans.xml");
     userService=(UserService) context.getBean("client");
    }
    //这是普通客户端得到服务实例;
    private Client(UserService userService){
     this.userService=userService;
    }
    public String getText(String text) throws Exception {  
        String data = userService.getSomething(text);  
        return data;  
    }
   /*
    *单独测试spring 加载数据连接;
    */
    public static void  getConnectTest(){
     ApplicationContext context=new ClassPathXmlApplicationContext("applicationContext-client-beans.xml");
     UserServiceImpl userServiceImpl=(UserServiceImpl) context.getBean("userServiceImpl");
     System.out.println("数据库连接测试:"+userServiceImpl.getSomething("adfasdf"));
    }
    /*
     * CXF 普通客户端测试;
     */
    public static void testCxfClient()throws Exception{
     //这里不用Spring 得到bean实例;
  JaxWsProxyFactoryBean factory=new JaxWsProxyFactoryBean();
  //设置服务类的名字;
  factory.setServiceClass(UserService.class);
  //设置服务的地址;
  factory.setAddress("http://127.0.0.1:8080/WebServiceCXF/UserService");
  
  //得到服务类的实例;
  UserService userService=(UserService) factory.create();
  
  Client client=new Client(userService);
  
  System.out.println(client.getText("这是webserviceCXF测试数据"));
    }
    /*
     * spring 与CXF 集成发布测试;
     */
    public static void testSpringCxfClient()throws Exception{
     //这是用spring 得到服务实例;
  System.out.println(client.getText("这是webserviceCXF与 spring集成发布的测试数据!"));
    }
 public static void main(String[] args)throws Exception {
  //测试数据连接是否成功!
  //Client.getConnectTest();
  //普通测试;
  //Client.testCxfClient();
  //集成测试;
  Client.testSpringCxfClient();
 }

}

测试:把工程发布到tomcat上运行测试类出现下面结果:

Client.testSpringCxfClient()方法测试:

 客户端输出:
    这是webserviceCXF与 spring集成发布的测试数据!

服务器端的输出:
this is server message :这是webserviceCXF与 spring集成发布的测试数据!
获得数据库连接:oracle.jdbc.driver.OracleConnection@7fb878



Client.testCxfClient()测试:

客户端输出:
这是webserviceCXF测试数据

服务器端的输出:

this is server message :这是webserviceCXF测试数据
获得数据库连接:oracle.jdbc.driver.OracleConnection@6276e5

Client.getConnectTest()数据库连接测试:
this is server message :adfasdf
获得数据库连接:oracle.jdbc.driver.OracleConnection@c38157
数据库连接测试:adfasdf


好了到此CXF+spring 集成完毕(不足这处没有加入声明式事物的管理,只加入了spring 连接数据库和持久层JDBC,有时间在完善下),如果有什么问题请联系我:zzzlyr@163.com

有时间更新这篇文章了,加入声明式事物,这个很简单。在把项目里用的CXF细节和遇到问题说明下:

把appcliatContext.xml 这个文件加入Spring包 自动扫描,在你的业务层上加下面基于注解事物:
开起注解事物 在需要的方法上加入即可
  默认Spring为每个方法开启一个事务,如果方法发生运行期错误unchecked(RuntimeException),事务会进行回滚
  如果发生checked Exception,事务不进行回滚.
  @Transactional(propagation=Propagation.REQUIRED)
  @Transactional(propagation=Propagation.NOT_SUPPORTED,readOnly=true)

重点说下在项目中用CXF2.3 遇到问题:
   第一个:就是CXF命名空间问题,在网上好多例子,就简单是一个例子。在项目中CXF发布webService ,一般做法是实现类和接口没有在一个包中;这是项目中要用到的:

这是接口:
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 {
 /*
  * 反回值标注,可以改变返回参数WSDL发布名字,还有参数名字;
  */
 public @WebResult(name="sealHandOverService") String getDocumentByBantchNo(String nantchNo)throws Exception;
 
}



实现类:
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"一要写上,接口和实现类不在同一个包中,接口和实现类一定要一致。但网上好多例子接口和实现类在一包中targetNamespace这个东西默认是一致的,所以不需要指定,如果接口和实现类不在同一个包中,你查看WSDL的时候也可以看到,也不报错,但就是发布WSDL少信息。
 第二客户端问题:网上好多例子就是一个工程,调自己工程发布的WebService的方法,以下是第二个JAVA工程调用第一个发布成功的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();
  //设置服务类的名字;
  factory.setServiceClass(SealHandOverService.class);
  //设置服务的地址;
  factory.setAddress("http://127.0.0.1:8080/seal/ws/SealHandOverService");
  
  //得到服务类的实例;
  SealHandOverService sealHandOverService=(SealHandOverService) factory.create();
  
  
  System.out.println("======="+sealHandOverService.getDocumentByBantchNo("67801100060039"));
    }
    /**
  * @Title: callService
  * @Description: 调用远程的webservice并返回数据
  * @param wsUrl
  *            webservice地址
  * @param method
  *            调用的webservice方法名
  * @param arg
  *            参数
  * @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 是接口中发部的
  String s=WebServiceClientTest.callService("http://110.168.1.121:8080/seal/ws/SealHandOverService?wsdl", "getDocumentByBantchNo", new Object[]{"67801100060039"});
 System.out.println(s);
  WebServiceClientTest.testCxfClient();
 }

}

这个测试类里有两个方法,应该差不多从注释可以看明白什么意思。

以上方法都在项目中正确调用通过。
 

以下是网上的一此方法:

由于我们通常不知道提供Web Service的服务器接口及其相关类的代码,我们也不可能从他人那里获得。

对此,CXF提供了一些命令行工具,在CXF_HOME/bin下(这里是你下载的CXF包下有目录)。

使用wsdl2java,可以根据从服务器返回的wsdl文件生成我们所需要的java接口和相关类。

在上面的工程中,我们可以用以下命令生成JAVA代码,而不是从第一个工程中复制过来。

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    目标文件夹   wsdl 的url地址)

 -p  是指生成客户端代码存放位置;


需要注意的是,对于接口类和相关类的包路径,一定要和服务器的一样, 即:如果服务接口包路径和实现类路径,要和客户端一致。

否则,会出现org.apache.cxf.interceptor.Fault: Unexpected wrapper element {****}addResponse found.……错误。




 


评论

# re: CXF2.3.0 +myEclipse 8.5 +tomcat 6.0 +sping 3.0.5 集成方案  回复  更多评论   

2011-05-26 15:50 by wls
运行client文件的时候报
log4j:WARN No appenders could be found for logger (org.springframework.context.support.ClassPathXmlApplicationContext).
log4j:WARN Please initialize the log4j system properly.
2011-5-26 15:46:49 org.apache.cxf.service.factory.ReflectionServiceFactoryBean buildServiceFromClass
信息: Creating Service {http://dao/}IUserServiceService from class dao.IUserService
2011-5-26 15:46:50 org.apache.cxf.service.factory.ReflectionServiceFactoryBean buildServiceFromClass
信息: Creating Service {http://dao/}IUserServiceService from class dao.IUserService
this is the message:adfasdf
获得数据库连接oracle.jdbc.driver.T4CConnection@1719f30
数据库连接测试:adfasdf
2011-5-26 15:46:51 org.apache.cxf.service.factory.ReflectionServiceFactoryBean buildServiceFromClass
信息: Creating Service {http://dao/}IUserServiceService from class dao.IUserService
javax.xml.ws.soap.SOAPFaultException: Fault occurred while processing.
at org.apache.cxf.jaxws.JaxWsClientProxy.invoke(JaxWsClientProxy.java:146)
at $Proxy31.getSomething(Unknown Source)
at test.Client.getText(Client.java:24)
at test.Client.testCxfClient(Client.java:52)
at test.Client.main(Client.java:70)
Caused by: org.apache.cxf.binding.soap.SoapFault: Fault occurred while processing.
at org.apache.cxf.binding.soap.interceptor.Soap11FaultInInterceptor.unmarshalFault(Soap11FaultInInterceptor.java:75)
at org.apache.cxf.binding.soap.interceptor.Soap11FaultInInterceptor.handleMessage(Soap11FaultInInterceptor.java:46)
at org.apache.cxf.binding.soap.interceptor.Soap11FaultInInterceptor.handleMessage(Soap11FaultInInterceptor.java:35)
at org.apache.cxf.phase.PhaseInterceptorChain.doIntercept(PhaseInterceptorChain.java:255)
at org.apache.cxf.interceptor.AbstractFaultChainInitiatorObserver.onMessage(AbstractFaultChainInitiatorObserver.java:99)
at org.apache.cxf.binding.soap.interceptor.CheckFaultInterceptor.handleMessage(CheckFaultInterceptor.java:69)
at org.apache.cxf.binding.soap.interceptor.CheckFaultInterceptor.handleMessage(CheckFaultInterceptor.java:34)
at org.apache.cxf.phase.PhaseInterceptorChain.doIntercept(PhaseInterceptorChain.java:255)
at org.apache.cxf.endpoint.ClientImpl.onMessage(ClientImpl.java:759)
at org.apache.cxf.transport.http.HTTPConduit$WrappedOutputStream.handleResponseInternal(HTTPConduit.java:2337)
at org.apache.cxf.transport.http.HTTPConduit$WrappedOutputStream.handleResponse(HTTPConduit.java:2195)
at org.apache.cxf.transport.http.HTTPConduit$WrappedOutputStream.close(HTTPConduit.java:2039)
at org.apache.cxf.transport.AbstractConduit.close(AbstractConduit.java:56)
at org.apache.cxf.transport.http.HTTPConduit.close(HTTPConduit.java:697)
at org.apache.cxf.interceptor.MessageSenderInterceptor$MessageSenderEndingInterceptor.handleMessage(MessageSenderInterceptor.java:62)
at org.apache.cxf.phase.PhaseInterceptorChain.doIntercept(PhaseInterceptorChain.java:255)
at org.apache.cxf.endpoint.ClientImpl.invoke(ClientImpl.java:520)
at org.apache.cxf.endpoint.ClientImpl.invoke(ClientImpl.java:317)
at org.apache.cxf.endpoint.ClientImpl.invoke(ClientImpl.java:269)
at org.apache.cxf.frontend.ClientProxy.invokeSync(ClientProxy.java:73)
at org.apache.cxf.jaxws.JaxWsClientProxy.invoke(JaxWsClientProxy.java:124)
... 4 more
找了很久没有找到原因,您能给回复一下么

# re: CXF2.3.0 +myEclipse 8.5 +tomcat 6.0 +sping 3.0.5 集成方案  回复  更多评论   

2011-05-26 16:26 by wls
使用的cxf2.3.4

# re: CXF2.3.0 +myEclipse 8.5 +tomcat 6.0 +sping 3.0.5 集成方案  回复  更多评论   

2011-08-05 09:50 by 淘宝女装
写的太长了,

# re: CXF2.3.0 +myEclipse 8.5 +tomcat 6.0 +sping 3.0.5 集成方案  回复  更多评论   

2011-08-05 14:51 by 淘宝女装
郁闷,,,spring配置出错了

# re: CXF2.3.0 +myEclipse 8.5 +tomcat 6.0 +sping 3.0.5 集成方案  回复  更多评论   

2011-08-08 16:55 by vinsonnubo
我也是用spring自动扫描实现service注入,但是当我调用ws方法时无法注入成功,请问是什么原因呢?

# re: CXF2.3.0 +myEclipse 8.5 +tomcat 6.0 +sping 3.0.5 集成方案  回复  更多评论   

2011-08-16 17:41 by 张钊钊
@vinsonnubo
什么异常?service 层,是不是写上了@Service这个标志了

只有注册用户登录后才能发表评论。


网站导航: