CXF动态客户端总是提示No operation was found with the name {...},命名空间问题: http://pangsir.iteye.com/blog/1492508 当我们使用CXF动态客户端调用WebService接口容易出现如下问题: Exception in thread "m
http://pangsir.iteye.com/blog/1492508
当我们使用CXF动态客户端调用WebService接口容易出现如下问题:
Exception in thread "main" org.apache.cxf.common.i18n.UncheckedException: No operation was found with the name {http://impl.service.jws/}sum. at org.apache.cxf.endpoint.ClientImpl.invoke(ClientImpl.java:289) at org.apache.cxf.endpoint.ClientImpl.invoke(ClientImpl.java:283) at cxf.bootstrap.CxfDynamicClientOnJwsRtWeb.main(CxfDynamicClientOnJwsRtWeb.java:36)
这个问题是由这个问题因为SIB和SEI类的targetNamespace统一导致的,解决方法
SIB的targetNamespace的命名空间为SEI对应的命名空间targetNamespace相同即可。
1.第一种方式为配置SIB和SEI的targetNamespace相同:
SIB:
package jws.service.impl; import javax.jws.WebService; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import entity.User; import jws.service.JwsIService; /** * Service implementation Bean(SIB) * RPC接口实现 * 注意这里的targetNamespace的命名空间为SEI对应的命名空间,注意最后要加/ * 否则利用CXF动态客户端调用时,会找不到 * Exception in thread "main" org.apache.cxf.common.i18n.UncheckedException: * No operation was found with the name {http://impl.service.jws/}sum. * @author donald * 2017年7月7日 * 下午5:11:49 */ @WebService(endpointInterface="jws.service.JwsIService", serviceName = "jwsService", portName = "jwsPort", targetNamespace = "http://service.jws/" // targetNamespace = "http://www.donald.service/jws_service/" ) public class JwsServiceImpl implements JwsIService { private static final Logger log = LoggerFactory.getLogger(JwsServiceImpl.class); @Override public int sum(int firstNum, int secondNum) { int result = firstNum+secondNum; log.info("======"+firstNum+"+"+secondNum+"="+result); return result; } }
SEI:
package jws.service; import javax.jws.WebMethod; import javax.jws.WebParam; import javax.jws.WebResult; import javax.jws.WebService; import entity.User; /** * service endpoint interface(SEI) * RPC接口 * 如果返回结果时实例类,则targetNamespace必须用http://service.jws/,即http://+SEI倒序报名+/ * 没有的话可以,targetNamespace可任意指定http://www.donald.service/jws_service/ * @author donald * 2017年7月7日 * 下午5:11:53 */ @WebService( targetNamespace = "http://service.jws/" // targetNamespace = "http://www.donald.service/jws_service/" ) public interface JwsIService { //@WebMethod注解可写可不写 // @WebMethod @WebResult(name="sumResult") public int sum(@WebParam(name="firstNum")int firstNum, @WebParam(name="secondNum")int secondNum); }
SIB和SEI的@WebService注解中的targetNamespace要相同,
SIB的@WebService的targetNamespace对应为SEI的targetNamespace。
动态客户端:
package cxf.bootstrap; import org.apache.cxf.endpoint.Client; import org.apache.cxf.jaxws.endpoint.dynamic.JaxWsDynamicClientFactory; import org.apache.cxf.transport.http.HTTPConduit; import org.apache.cxf.transports.http.configuration.HTTPClientPolicy; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import jws.service.User; import util.JsonUtil; /** * CXF 动态代理模式,不用生成本地WS代理类, * 通过反射调用 WS 的对应的方法,传入相应的参数 * 访问cxf-server-web项目下的webservice; * 测试jaxws-rt发布WebService web方式。 * 此测试实例,用于测试SEI和SIB的targetNamespace指定的webService接口: * http://localhost:8080/cxf_server_web/jws_services?wsdl; * @author donald * 2017年7月8日 * 下午7:24:12 */ public class CxfDynamicClientOnJwsRtWeb { private static final Logger log = LoggerFactory.getLogger(CxfClient.class); private static final String JWS_RT_WSDL_URI = "http://localhost:8080/cxf_server_web/jws_services?wsdl"; public static void main(String[] args) throws Exception { log.info("======CXF-WS Dynamic Client start!======"); JaxWsDynamicClientFactory dcf = JaxWsDynamicClientFactory.newInstance(); Client client = dcf.createClient(JWS_RT_WSDL_URI); HTTPConduit conduit = (HTTPConduit)client.getConduit(); HTTPClientPolicy policy = new HTTPClientPolicy(); policy.setConnectionTimeout(10000); policy.setAllowChunking(false); policy.setReceiveTimeout(10000); conduit.setClient(policy); Object[] invokeResult = client.invoke("sum", 17,8); log.info("=======sumResult:" + invokeResult[0]); } }
2.第二种方式动态客户端直接通过QName调用WebService对应的操作,
这种方式针对SIB和SEI的targetNamespace不相同,同时不再同一个包:
动态客户端:
package cxf.bootstrap; import javax.xml.namespace.QName; import org.apache.cxf.endpoint.Client; import org.apache.cxf.endpoint.Endpoint; import org.apache.cxf.jaxws.endpoint.dynamic.JaxWsDynamicClientFactory; import org.apache.cxf.service.model.BindingInfo; import org.apache.cxf.service.model.BindingOperationInfo; import org.apache.cxf.transport.http.HTTPConduit; import org.apache.cxf.transports.http.configuration.HTTPClientPolicy; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import jws.service.User; import util.JsonUtil; /** * CXF 动态代理模式,不用生成本地WS代理类, * 通过反射调用 WS 的对应的方法,传入相应的参数 * 访问cxf-server-web项目下的webservice; * 测试jaxws-rt发布WebService web方式。 * 此测试实例,用于测试SEI和SIB的targetNamespace未指定的webService接口: * http://localhost:8080/cxf_server_web/jws_services?wsdl * @author donald * 2017年7月8日 * 下午7:24:12 */ public class CxfDynamicClientOnJwsRtWebWithQname { private static final Logger log = LoggerFactory.getLogger(CxfClient.class); private static final String JWS_RT_WSDL_URI = "http://localhost:8080/cxf_server_web/jws_services?wsdl"; public static void main(String[] args) throws Exception { log.info("======CXF-WS Dynamic Client start!======"); JaxWsDynamicClientFactory dcf = JaxWsDynamicClientFactory.newInstance(); Client client = dcf.createClient(JWS_RT_WSDL_URI); HTTPConduit conduit = (HTTPConduit)client.getConduit(); HTTPClientPolicy policy = new HTTPClientPolicy(); policy.setConnectionTimeout(10000); policy.setAllowChunking(false); policy.setReceiveTimeout(10000); conduit.setClient(policy); //获取操作对应的Qname QName operateQName = getOperateQName(client,"sum"); //如果Qname已知,可以通过如下方式,直接创建QName // operateQName = new QName("http://service.jws/","login"); Object[] invokeResult = client.invoke(operateQName, 17,8); log.info("=======sumResult:" + invokeResult[0]); } /** * 针对SEI和SIB不在统一个包内的情况,先查找操作对应的Qname, * client通过Qname调用对应操作 * @param client * @param operation * @return */ private static QName getOperateQName(Client client,String operation){ Endpoint endpoint = client.getEndpoint(); QName opName = new QName(endpoint.getService().getName().getNamespaceURI(), operation); BindingInfo bindingInfo = endpoint.getEndpointInfo().getBinding(); if (bindingInfo.getOperation(opName) == null) { for (BindingOperationInfo operationInfo : bindingInfo.getOperations()) { if (operation.equals(operationInfo.getName().getLocalPart())) { opName = operationInfo.getName(); break; } } } log.info("Operation:"+operation+",namespaceURI:" + opName.getNamespaceURI()); return opName; } }强烈建议使用第一种方式,符合规范。