1. CXF相关的jar包可以去http://cxf.apache.org官方网站进行下载。
2. CXF用到的jar分别为:
3. 跟spring集成cxf
a. 创建一个针对cxf使用的applicationContext.xml文件,比如:appContext_cxf.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"
xmlns:cxf="http://cxf.apache.org/core"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://cxf.apache.org/jaxws
http://cxf.apache.org/schemas/jaxws.xsd
http://cxf.apache.org/core
http://cxf.apache.org/schemas/core.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" />
<!-- 通过Spring创建数据绑定的类
<bean id="aegisBean" class="org.apache.cxf.aegis.databinding.AegisDatabinding" />
<bean id="jaxWsServiceFactoryBean" class="org.apache.cxf.jaxws.support.JaxWsServiceFactoryBean">
<property name="wrapped" value="true" />
<property name="dataBinding" ref="aegisBean" />
</bean>-->
<!-- jax-ws endpoint定义 -->
<jaxws:endpoint address="/bulletinQuery">
<jaxws:implementor ref="bulletinQueryWebService" />
</jaxws:endpoint>
<!-- WebService的实现Bean定义 -->
<bean id="bulletinQueryWebService" class="com.sinosoft.gb.ws.services.IWSBulletinQueryServiceImpl">
<property name="bulletinMapper">
<ref bean="bulletinMapper"/>
</property>
</bean>
</beans>
注:红色字体部分一定要注意必须引入和注明;蓝色部分为WebService访问时的地址;绿色部分为实现类中相关bean的调用。
b. web.xml中的配置:
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/applicationContext.xml</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<!-- Spring 刷新Introspector防止内存泄露 -->
<listener>
<listener-class>org.springframework.web.util.IntrospectorCleanupListener</listener-class>
</listener>
<!-- CXF 配置 -->
<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>/cxfService/*</url-pattern>
</servlet-mapping>
c. spring配置文件
将WebService配置使用的applicationContext.xml文件引入:
<import resource="classpath:com/sinosoft/gb/ws/services/configs/appContext_*.xml"/><!-- 数据接口WebService的spring文件 -->
注:红色部分以实际路径为准。
4. 服务端代码的编写:
package com.sinosoft.gb.ws.services;
import java.io.Serializable;
import javax.jws.WebParam;
import javax.jws.WebService;
/************************************************************
* TODO: 简报信息查询接口
* @author LiuLiang
* @since 2012-04-25
************************************************************/
@WebService( name="bulletinQueryService",targetNamespace="http://www.sinosoft.com.cn/" )
public interface IWSBulletinQueryService extends Serializable
{
public String getBulletinInfo( @WebParam( name="strXMLInfo" ) String strXMLInfo );
}
package com.sinosoft.gb.ws.services;
import javax.jws.WebMethod;
import javax.jws.WebService;
import org.apache.log4j.Logger;
import com.sinosoft.gb.bulletin.mappers.IBulletinMapper;
import com.sinosoft.gb.bulletin.pojo.CBulletinBean;
/************************************************************
* TODO: 简报信息查询接口
* @author LiuLiang
* @since 2012-04-25
************************************************************/
@SuppressWarnings( "serial" )
@WebService( name="bulletinQueryService",
serviceName="bulletinQueryService",
portName="bulletinQueryServicePort",
targetNamespace="http://www.sinosoft.com.cn/",
endpointInterface="com.sinosoft.gb.ws.services.IWSBulletinQueryService")
public class IWSBulletinQueryServiceImpl implements IWSBulletinQueryService
{
private static Logger mobjLogger = Logger.getLogger( IWSBulletinQueryServiceImpl.class.getName() );
private IBulletinMapper bulletinMapper ;
@WebMethod( operationName="getBulletinInfo" )
public String getBulletinInfo(String strXMLInfo)
{
mobjLogger.info( "IWSBulletinQueryServiceImpl_getBulletinInfo(...)_通过WebService查询简报相关信息" );
CBulletinBean objBull = this.getBulletinMapper().getBulletinById( 1719 );
System.out.println( "webservice==="+objBull.getObjName() );
return objBull.getObjName();
}
public IBulletinMapper getBulletinMapper()
{
return bulletinMapper;
}
public void setBulletinMapper(IBulletinMapper bulletinMapper)
{
this.bulletinMapper = bulletinMapper;
}
}
注意:红色字体部分为需要注意的地方,相关配置请参阅官方详细说明。
5. 至此CXF与Spring的集成就结束了,运行项目后访问会看到:
6. 项目中如果有struts2,还需要作如下修改:
a. 将struts2(web.xml)的filter修改成自定义的filter:
<!-- 定义Struts2的FilterDispathcer的Filter -->
<filter>
<filter-name>struts2</filter-name>
<!-- <filter-class>org.apache.struts2.dispatcher.FilterDispatcher</filter-class> -->
<filter-class>com.sinosoft.gb.filters.CStrutsCustomFilter</filter-class>
<init-param>
<param-name>excludeURI</param-name>
<param-value>cxfService</param-value>
</init-param>
</filter>
<!-- FilterDispatcher用来初始化struts2并且处理所有的WEB请求。 -->
<filter-mapping>
<filter-name>struts2</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
b. 类为:
package com.sinosoft.gb.filters;
import java.io.IOException;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import org.apache.log4j.Logger;
import org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter;
/**
* FilterDispatcher 在struts2新的版本中不再支持,建议使用StrutsPrepareAndExecuteFilter
*
*/
/**
* TODO: 自定义Struts2的过滤
* @author LiuLiang
*
*/
@SuppressWarnings("deprecation")
public class CStrutsCustomFilter extends StrutsPrepareAndExecuteFilter
{
private static Logger mobjLogger = Logger.getLogger( CStrutsCustomFilter.class.getName() );
private static String strExcludeURI = "";
public CStrutsCustomFilter()
{
super();
}
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException,
ServletException
{
HttpServletRequest request = (HttpServletRequest) req;
String URI = request.getRequestURI();
int nRet = URI.indexOf( strExcludeURI );
if ( nRet > 0 )
{
chain.doFilter( req, res );
}
else
{
super.doFilter( req, res, chain );
}
}
public void init(FilterConfig config) throws ServletException
{
mobjLogger.info( "CStrutsCustomFilter_获取Filter初始化值..." );
super.init( config );
strExcludeURI = config.getInitParameter( "excludeURI" );
}
}
7. 测试访问CXF-WebService
1. 再server端访问配置如下:
a. 填写client端的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"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">
<bean id="client" class="com.sinosoft.ws.server.service.IHello"
factory-bean="clientFactory" factory-method="create"/>
<bean id="clientFactory" class="org.apache.cxf.jaxws.JaxWsProxyFactoryBean">
<property name="serviceClass" value="com.sinosoft.ws.server.service.IHello"/>
<property name="address" value="http://192.168.90.12:7005/ws/hello"/>
</bean>
</beans>
b. 测试类为:
package com.sinosoft.ws.client.service;
import javax.xml.namespace.QName;
import javax.xml.ws.Service;
import javax.xml.ws.soap.SOAPBinding;
import com.sinosoft.ws.server.service.IHello;
public class HelloClient {
// 两个参数分别是 web service的targetNamespace和name
// 默认就是(http://+包名的倒装)和(类名),可以在@WebService()注解中设置
// 最后有/的话不能忘了,一个字符也不能差
private static final QName SERVICE_NAME = new QName("http://www.sinosoft.com.cn", "helloworld");
// 这个是targetNamespace和name+"Port"
private static final QName PORT_NAME = new QName("http://www.sinosoft.com.cn", "helloworldPort");
private HelloClient() {
}
public static void main(String args[]) throws Exception {
Service service = Service.create(SERVICE_NAME);
// Endpoint Address
// 这个只要前面对,后面多上一堆也可以,很是奇怪
// 这样也行??http://localhost:9080/cxf-security/ws/hellosllooiehfkdjfajs
String endpointAddress = "http://192.168.90.12:7005/ws/hello";
// Add a port to the Service
service.addPort(PORT_NAME, SOAPBinding.SOAP11HTTP_BINDING, endpointAddress);
IHello helloService = service.getPort(IHello.class);
System.out.println(helloService.sayHello("World"));
}
}
2. 单独测试的client
a. 使用cxf包中自带的wsdl2java工具进行生成。将webservice的wsdl文件保存到本地,并命名为:xxx.wsdl或xxx.xml都可以;然后将保存的文件放到cxf包中的bin目录下;打开命令窗口并转到cxf-home/bin目录下,敲如下命令:
wsdl2java -clicent xxx.wsdl/xxx.xml
执行完毕后,会在目录下生成相应的目录及类。
b. 新建一个web项目并将cxf使用的相关jar加入进来,然后将命令生成的相关文件拷贝到项目的src下,一般需要修改的文件为:*****_Service.java 将错误注释掉即可。然后通过******_Client.java进行访问即可。
补充:由于CXF总是在更新完善,如果你的项目使用的spring版本比较低的话,亦可以集成最新的CXF,把相关的lib放到项目中的lib目录中,按照上面所述配置完成后如果出现异常,首先检查是否是配置路径问题,其次是否是包冲突造成的。
包冲突造成的异常:
1.could not instantiate bean class [org.apache.cxf.bus.spring.SpringBus]: Constructor threw exception; nested exception is org.apache.cxf.bus.extension.ExtensionException: Could not load extension class org.apache.cxf.ws.policy.AssertionBuilderRegistryImpl
解决办法:这个错误的发生是因为与neethi.jar不兼容的版本。 CXF2.7.3以上期待neethi3.x.jar的。我在classpath中有neethi2.x.jar,所以去掉以前的就可以。