Spring整合CXF发布Web Services

Spring的Web项目搭建不再描述,主要介绍Web项目整合CXF发布Web Services

1.导入CXF需要的jar包

cxf-2.7.2.jar

httpasyncclient-4.0-beta3.jar

httpclient-4.2.1.jar

httpcore-4.2.2.jar

httpcore-nio-4.2.2.jar

neethi-3.0.2.jar

wsdl4j-1.6.2.jar

xmlschema-core-2.0.3.jar

2.web.xml文件添加下面内容

<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:beans.xml,classpath:applicationContext.xml</param-value>
</context-param>

<!-- 部署CXFServlet -->
<servlet>
<servlet-name>CXFServlet</servlet-name>
<servlet-class>
org.apache.cxf.transport.servlet.CXFServlet
  </servlet-class>
<load-on-startup>2</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>CXFServlet</servlet-name>
<url-pattern>/webservice/*</url-pattern>
</servlet-mapping>

3.添加applicationContext.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">
<!-- 导入cxf.jar解压出来的文件 -->        
<import resource="classpath:META-INF/cxf/cxf.xml"/>
<import resource="classpath:META-INF/cxf/cxf-servlet.xml"/>
<bean id="testWebServiceImpl" class="com.cName.pName.webservice.impl.TestWebServiceImpl"/>
<jaxws:endpoint id="testWebService" address="/testWebService" implementorClass="com.cName.pName.webservice.impl.TestWebServiceImpl">
    <jaxws:implementor ref="testWebServiceImpl"/>
</jaxws:endpoint>
</beans>

4.提供服务的接口TestWebService.java

package com.cName.pName.webservice;
import javax.jws.WebParam;
import javax.jws.WebService;
@WebService
public interface TestWebService {
/**

* @param xmlStr
* @return String

*/
public String testRequest(@WebParam(name = "xmlStr") String xmlStr);
}

4.服务的接口实现类TestWebServiceImpl.java

package com.cName.pName.webservice.impl;
import javax.jws.WebService;
import com.cName.pName.webservice.TestWebService;
@WebService
public class TestWebServiceImpl implements TestWebService {
public String testRequest(String xmlStr) {
System.out.println(xmlStr);
String resultXml = "resultXml";
return resultXml;
}
}

5.调用接口的客户端TestWebServiceClient.java

import java.rmi.RemoteException;
import javax.xml.namespace.QName;
import javax.xml.rpc.ParameterMode;
import javax.xml.rpc.ServiceException;
import javax.xml.rpc.encoding.XMLType;
import org.apache.axis.client.Call;
import org.apache.axis.client.Service;
public class TestWebServiceClient {
public static void main(String[] args) throws ServiceException,
RemoteException {
String xmlStr = "test";
Service service = new Service();
Call call = (Call) service.createCall();
call.setTargetEndpointAddress("http://localhost:8080/pName/webservice/testWebService?wsdl");
QName qName = new QName("http://webservice.pName.cName.com/",
"testRequest");
call.setOperationName(qName);
call.setUseSOAPAction(true);
// 这下面两行一定要加上,否则接收在服务器端收不到。
call.addParameter("xmlStr", XMLType.XSD_STRING, ParameterMode.IN);
call.setReturnType(XMLType.XSD_STRING);
String result = (String) call.invoke(new Object[] { xmlStr });
System.out.println("aa" + result);
}
}

到目前CXF就整合到Spring项目中了,启动Web,访问http://localhost:8080/pName/webservice/testWebService?wsdl就可以看到wsdl的描述文件了。

注意:

将Spring的容器初始化交给了DispatcherServlet,在applicationContext.xm配置了webService

运行部署后发现提示错误No Service have found。原因是因为cxf的spring容器必须使用ContextLoadListener来启动,而spring MVC采用的DispatcherServlet来启动的,所以无法加载cxf的服务。

以下注意事项来自博文http://kyfxbl.iteye.com/blog/1432920

Spring MVC是通过DispatcherServlet来加载Spring配置文件的,因此不需要在web.xml中配置ContextLoaderListener。但是CXF却需要通过ContextLoaderListener来加载Spring。 

这样就产生了一个矛盾,如果不配置ContextLoaderListener,CXF就无法正常使用。但如果配置ContextLoaderListener,又会造成Spring的重复加载(DispatcherServlet一次,ContextLoaderListener一次) 

在网上查了一下资料,只看到一个国外的程序员提出不配置ContextLoaderListener,通过写一个CXFController,来替代默认的CXFServlet。但是这种HACK的方式总是不太好 

所以我采用一种折中的方式,来解决Spring MVC和cxf并存的问题。但是也不是很优雅,希望有人能给出更好的办法 

首先是web.xml的配置 

Xml代码   收藏代码
  1. <?xml version="1.0" encoding="UTF-8"?>  
  2. <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  
  3.     xmlns="http://java.sun.com/xml/ns/javaee"  
  4.     xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"  
  5.     id="MyFramework" version="3.0">  
  6.       
  7.     <display-name>MyFramework</display-name>  
  8.       
  9.     <context-param>  
  10.         <param-name>contextConfigLocation</param-name>  
  11.         <param-value>   
  12.             WEB-INF/beans.xml,   
  13.             WEB-INF/cxf.xml  
  14.         </param-value>   
  15.     </context-param>  
  16.       
  17.     <listener>    
  18.         <listener-class>    
  19.             org.springframework.web.context.ContextLoaderListener    
  20.         </listener-class>    
  21.     </listener>    
  22.       
  23.     <servlet>  
  24.         <servlet-name>framework</servlet-name>  
  25.         <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>  
  26.         <init-param>    
  27.             <param-name>contextConfigLocation</param-name>    
  28.             <param-value>WEB-INF/spring-mvc.xml</param-value>    
  29.         </init-param>    
  30.         <load-on-startup>1</load-on-startup>  
  31.     </servlet>  
  32.   
  33.     <servlet-mapping>  
  34.         <servlet-name>framework</servlet-name>  
  35.         <url-pattern>/</url-pattern>  
  36.     </servlet-mapping>  
  37.       
  38.     <servlet>    
  39.         <servlet-name>CXFServlet</servlet-name>    
  40.         <servlet-class>org.apache.cxf.transport.servlet.CXFServlet</servlet-class>    
  41.         <load-on-startup>2</load-on-startup>    
  42.     </servlet>    
  43.     
  44.     <servlet-mapping>    
  45.         <servlet-name>CXFServlet</servlet-name>    
  46.         <url-pattern>/webservice/*</url-pattern>    
  47.     </servlet-mapping>    
  48.       
  49. </web-app>  

在ContextLoaderListener里面,加载cxf和spring的公共配置信息。然后在DispatcherServlet中加载spring mvc所需的信息。利用Spring配置文件拆分的方式,既实现spring mvc和cxf的共存,又避免spring配置信息的重复加载 

然后是公共的配置信息,beans.xml 
Xml代码   收藏代码
  1. <?xml version="1.0" encoding="UTF-8"?>  
  2.   
  3. <beans xmlns="http://www.springframework.org/schema/beans"  
  4.     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  
  5.     xmlns:context="http://www.springframework.org/schema/context"  
  6.     xmlns:tx="http://www.springframework.org/schema/tx"  
  7.     xsi:schemaLocation="http://www.springframework.org/schema/beans  
  8.                             http://www.springframework.org/schema/beans/spring-beans-3.1.xsd  
  9.                             http://www.springframework.org/schema/context   
  10.                             http://www.springframework.org/schema/context/spring-context-3.1.xsd  
  11.                             http://www.springframework.org/schema/tx  
  12.                             http://www.springframework.org/schema/tx/spring-tx-3.1.xsd">  
  13.   
  14.     <context:component-scan base-package="com.huawei.framework" />  
  15.   
  16.     <bean id="propertyConfigurer"  
  17.         class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">  
  18.         <property name="locations">  
  19.             <list>  
  20.                 <value>classpath:jdbc.properties</value>  
  21.             </list>  
  22.         </property>  
  23.     </bean>  
  24.   
  25.     <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">  
  26.         <property name="driverClass" value="${jdbc.driver}" />  
  27.         <property name="jdbcUrl" value="${jdbc.url}" />  
  28.         <property name="user" value="${jdbc.username}" />  
  29.         <property name="password" value="${jdbc.password}" />  
  30.         <property name="minPoolSize" value="10" />  
  31.         <property name="maxPoolSize" value="50" />  
  32.     </bean>  
  33.   
  34.     <bean id="sessionFactory"  
  35.         class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">  
  36.         <property name="dataSource" ref="dataSource" />  
  37.         <property name="mappingLocations"  
  38.             value="classpath:/com/huawei/framework/model/**/*.hbm.xml" />  
  39.         <property name="hibernateProperties">  
  40.             <props>  
  41.                 <prop key="hibernate.dialect">org.hibernate.dialect.OracleDialect</prop>  
  42.                 <prop key="hibernate.show_sql">true</prop>  
  43.                 <prop key="hibernate.format_sql">true</prop>  
  44.                 <prop key="hibernate.jdbc.fetch_size">50</prop>  
  45.                 <prop key="hibernate.jdbc.batch_size">25</prop>  
  46.                 <prop key="hibernate.temp.use_jdbc_metadata_defaults">false</prop>  
  47.             </props>  
  48.         </property>  
  49.     </bean>  
  50.   
  51.     <bean id="hibernateTemplate" class="org.springframework.orm.hibernate3.HibernateTemplate">  
  52.         <property name="sessionFactory" ref="sessionFactory" />  
  53.         <property name="fetchSize" value="10" />  
  54.     </bean>  
  55.   
  56.     <bean id="transactionManager"  
  57.         class="org.springframework.orm.hibernate3.HibernateTransactionManager">  
  58.         <property name="sessionFactory" ref="sessionFactory" />  
  59.     </bean>  
  60.   
  61.     <tx:annotation-driven transaction-manager="transactionManager" />  
  62.   
  63. </beans>  

然后是cxf所需的信息,cxf.xml 
Xml代码   收藏代码
  1. <?xml version="1.0" encoding="UTF-8"?>  
  2.   
  3. <beans xmlns="http://www.springframework.org/schema/beans"  
  4.     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:jaxws="http://cxf.apache.org/jaxws"  
  5.     xsi:schemaLocation="http://www.springframework.org/schema/beans  
  6.                             http://www.springframework.org/schema/beans/spring-beans-3.1.xsd  
  7.                             http://cxf.apache.org/jaxws   
  8.                             http://cxf.apache.org/schemas/jaxws.xsd">  
  9.   
  10.     <import resource="classpath:META-INF/cxf/cxf.xml" />  
  11.     <import resource="classpath:META-INF/cxf/cxf-servlet.xml" />  
  12.   
  13.     <jaxws:endpoint id="helloWorld"  
  14.         implementorClass="com.huawei.framework.webservice.HelloWorldImpl"  
  15.         address="/HelloWorld" />  
  16.   
  17. </beans>  

最后是spring mvc所需的信息,spring-mvc.xml 
Xml代码   收藏代码
  1. <?xml version="1.0" encoding="UTF-8"?>  
  2.   
  3. <beans xmlns="http://www.springframework.org/schema/beans"  
  4.     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"   
  5.     xmlns:p="http://www.springframework.org/schema/p"  
  6.     xmlns:context="http://www.springframework.org/schema/context"  
  7.     xmlns:mvc="http://www.springframework.org/schema/mvc"   
  8.     xsi:schemaLocation="http://www.springframework.org/schema/beans  
  9.                             http://www.springframework.org/schema/beans/spring-beans-3.1.xsd  
  10.                             http://www.springframework.org/schema/context   
  11.                             http://www.springframework.org/schema/context/spring-context-3.1.xsd  
  12.                             http://www.springframework.org/schema/mvc  
  13.                             http://www.springframework.org/schema/mvc/spring-mvc-3.1.xsd">  
  14.   
  15.     <context:component-scan base-package="com.huawei.framework" />  
  16.   
  17.     <mvc:annotation-driven />  
  18.   
  19.     <mvc:default-servlet-handler />  
  20.   
  21.     <bean  
  22.         class="org.springframework.web.servlet.view.InternalResourceViewResolver"  
  23.         p:prefix="/WEB-INF/view/" p:suffix=".jsp"  
  24.         p:viewClass="org.springframework.web.servlet.view.JstlView" />  
  25.   
  26. </beans>  

这顺便还带来一个附带的好处,即进行单元测试的时候,可以仅加载必须的类,比如做DAO组件的单元测试,就不需要加载spring-mvc.xml和cxf.xml了 
Java代码   收藏代码
  1. @RunWith(SpringJUnit4ClassRunner.class)  
  2. @ContextConfiguration(locations = { "file:WebContent/WEB-INF/beans.xml" })  
  3. public class UserDaoHibernateTest {  
  4.   
  5.     @Autowired  
  6.     private UserDao dao;  
  7.   
  8.     private static String ID;  
  9.   
  10.     @Test  
  11.     public void testInsert() {  
  12.         User user = new User();  
  13.         user.setName("fme001");  
  14.         user.setAge(23);  
  15.         dao.insert(user);  
  16.     }  
  17.   
  18.     @Test  
  19.     public void testQueryByName() {  
  20.         String name = "fme001";  
  21.         User user = dao.queryByName(name);  
  22.         assertEquals(23, user.getAge());  
  23.         ID = user.getId();  
  24.     }  
  25.   
  26.     @Test  
  27.     public void testQueryByAge() {  
  28.         int age = 23;  
  29.         List<User> result = dao.queryByAge(age);  
  30.         assertEquals(1, result.size());  
  31.     }  
  32.   
  33.     @Test  
  34.     public void testQueryAll() {  
  35.         List<User> result = dao.queryAll();  
  36.         assertEquals(1, result.size());  
  37.     }  
  38.   
  39.     @Test  
  40.     public void testQuery() {  
  41.         User user = dao.query(ID);  
  42.         assertEquals(23, user.getAge());  
  43.         assertEquals("fme001", user.getName());  
  44.     }  
  45.   
  46.     @Test  
  47.     public void testUpdate() {  
  48.         User user = dao.query(ID);  
  49.         user.setAge(24);  
  50.         dao.update(user);  
  51.         user = dao.query(ID);  
  52.         assertEquals(24, user.getAge());  
  53.     }  
  54.   
  55.     @Test  
  56.     public void testDelete() {  
  57.         User user = dao.query(ID);  
  58.         dao.delete(user);  
  59.     }  
  60.   
  61. }  

可以看到,集成cxf和spring mvc确实不算很方便,需要绕一绕。上述方法只是一个折中的方案,希望新版本的cxf可以提供一个CXFController,这样的话就可以统一用DispatcherServlet来加载Spring,不配置ContextLoaderListener。这样的话web.xml可以简洁很多。


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值