springboot集成webservice以及遇到的问题
需求公司最近需要做一个soap请求数据接口,由于没有webservice的服务端,而系统项目使用的是springboot框架,所以索性用springboot集成一个webservice框架用作发布服务,以便方便为后面的soap接口提供数据。如果这篇文章不是您想找的,请看这篇: WebService soap报文请求返回xml格式以及自定义soap模板所需依赖<...
需求
公司最近需要做一个soap请求数据接口,由于没有webservice的服务端,而系统项目使用的是springboot框架,所以索性用springboot集成一个webservice框架用作发布服务,以便方便为后面的soap接口提供数据。
如果这篇文章不是您想找的,请看这篇: WebService soap报文请求返回xml格式以及自定义soap模板
所需依赖
<!-- CXF webservice -->
<dependency>
<groupId>org.apache.cxf</groupId>
<artifactId>cxf-spring-boot-starter-jaxws</artifactId>
<version>3.1.11</version>
</dependency>
<!-- CXF webservice -->
服务端(webserviceServer)
一、接口及实现类:
接口:
@WebService
@Component
public interface TestService {
@WebMethod
String getUserName(@WebParam(name = "id") String id) throws UnsupportedEncodingException;
@WebMethod
public User getUser(String id) throws UnsupportedEncodingException;
}
====================================================================
实现类:
//name暴露服务名称, targetNamespace:命名空间,设置为接口的包名倒写(默认是本类包名倒写). endpointInterface接口地址
@WebService(name = "test" ,targetNamespace ="http://webservice.cxf.com/" ,endpointInterface = "com.cxf.webservice.TestService")
@Component
public class TestServiceImpl implements TestService {
JSONResult jsonResult = JSONResult.getJsonResult();
@Override
public String getUserName(String id) throws UnsupportedEncodingException {
JSONResult result= JSONResult.getJsonResult();
result.setSuccess(true);
result.setMessage("lisi");
return result.toJsonObject();
}
@Override
public User getUser(String id)throws UnsupportedEncodingException {
return new User(2L,"zhangsan");
}
}
二、发布服务:
发布服务有2种方式:
- 直接在启动类使用Endpoint,不需要配置类,但这种方式需要jetty依赖,端口号可以不和启动类一致,可以自定义(切勿冲突)
- 使用配置类,不用在启动类中加Endpoint.publish。这种方式的端口号与启动类一致
下面我们用到的是配置类方式:
@Configuration
public class CxfConfig {
@Autowired
private Bus bus;
@Autowired
private TestService testService;
//默认servlet路径/*,可自定义
@Bean
public ServletRegistrationBean dispatcherServlet() {
return new ServletRegistrationBean(new CXFServlet(), "/services/*");
}
//终端路径
@Bean
public Endpoint endpoint() {
EndpointImpl endpoint = new EndpointImpl(bus, appService);
endpoint.publish("/user");
return endpoint;
}
}
启动服务
@SpringBootApplication
public class WebserviceApplication {
public static void main(String[] args) {
SpringApplication.run(WebserviceApplication.class, args);
}
}
然后就可以访问服务了,
访问地址:localhost:port/services/user?wsdl
如果出新内容,则成功~~
客户端(webserviceClient)
调用服务的时候有2种方式:
- 代理类工厂
- 动态调用
代码如下:
/**
* 使用代理类工厂
*/
public static void test1() {
try {
// 代理工厂
JaxWsProxyFactoryBean jaxWsProxyFactoryBean = new JaxWsProxyFactoryBean();
// 设置代理地址
jaxWsProxyFactoryBean.setAddress(address);
// 设置接口类型
jaxWsProxyFactoryBean.setServiceClass(TestService.class);
// 创建一个代理接口实现
TestService cs = (TestService) jaxWsProxyFactoryBean.create();
// 数据准备
String LineId = "1";
// 调用代理接口的方法调用并返回结果
User result = (User)cs.getUser(LineId);
System.out.println("返回结果:" + result);
//返回值为:返回结果:User{id=1, name='lisi'}
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 动态调用方式
*/
public static void test2() {
// 创建动态客户端
JaxWsDynamicClientFactory dcf = JaxWsDynamicClientFactory.newInstance();
Client client = dcf.createClient(address);
Object[] objects = new Object[0];
try {
// invoke("方法名",参数1,参数2,参数3....);
objects = client.invoke("getUserName", "1");
System.out.println("返回数据:" + objects[0]);
//返回值为:返回数据:{"result":{},"success":true,"message":"zhangsan"}
} catch (Exception e) {
e.printStackTrace();
}
}
}
期间遇到的问题:
-
在网上百度了许多答案后,发现他们中的配置类第一个@bean的方法名都是:
public ServletRegistrationBean dispatcherServlet(){....}
然后就会抛出一个异常:
Action: Consider revisiting the entries above or defining a bean of type 'org.springframework.boot.autoconfigure.web.servlet.DispatcherServletPath' in your configuration.
其实他抛出这样的异常原因是因为他的方法名与springMVC中dispatcherServlet相同,程序会默认为是重写,所以会抛出此异常;处理方法为:
将方法名改一下就ok
-
如果出现以下异常:
Caused by: org.apache.cxf.binding.soap.SoapFault: Unmarshalling Error: 意外的元素 (uri:"", local:"id")。所需元素为<{}arg1>,<{}arg0>
需要检查自己的参数是否正确,如果确认没错的话,就需要检查一下接口那块是否有@WebParam修饰
-
如果后台console出现日志如下图所示:
这种代表发布成功,但是访问wsdl页面的时候404,出现这种情况需要排查以下情况:
1. 仔细检查url路径,尤其是大小写;
2. 仔细检查拦截器的拦截路径,看是否被拦截;
4. 如果出现以下异常:
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'endpoint' defined in class path resource [com/citi/gpf/ah/config/EndpointConfig.class]: Bean instantiation via factory method failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [javax.xml.ws.Endpoint]: Factory method 'endpoint' threw exception; nested exception is javax.xml.ws.WebServiceException: org.apache.cxf.service.factory.ServiceConstructionException
at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:599) ~[spring-beans-4.3.13.RELEASE.jar:4.3.13.RELEASE]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateUsingFactoryMethod(AbstractAutowireCapableBeanFactory.java:1173) ~[spring-beans-4.3.13.RELEASE.jar:4.3.13.RELEASE]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1067) ~[spring-beans-4.3.13.RELEASE.jar:4.3.13.RELEASE]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:513) ~[spring-beans-4.3.13.RELEASE.jar:4.3.13.RELEASE]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:483) ~[spring-beans-4.3.13.RELEASE.jar:4.3.13.RELEASE]
at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:306) ~[spring-beans-4.3.13.RELEASE.jar:4.3.13.RELEASE]
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:230) ~[spring-beans-4.3.13.RELEASE.jar:4.3.13.RELEASE]
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:302) ~[spring-beans-4.3.13.RELEASE.jar:4.3.13.RELEASE]
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:197) ~[spring-beans-4.3.13.RELEASE.jar:4.3.13.RELEASE]
at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:761) ~[spring-beans-4.3.13.RELEASE.jar:4.3.13.RELEASE]
at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:867) ~[spring-context-4.3.13.RELEASE.jar:4.3.13.RELEASE]
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:543) ~[spring-context-4.3.13.RELEASE.jar:4.3.13.RELEASE]
at org.springframework.boot.context.embedded.EmbeddedWebApplicationContext.refresh(EmbeddedWebApplicationContext.java:122) ~[spring-boot-1.5.9.RELEASE.jar:1.5.9.RELEASE]
at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:693) [spring-boot-1.5.9.RELEASE.jar:1.5.9.RELEASE]
at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:360) [spring-boot-1.5.9.RELEASE.jar:1.5.9.RELEASE]
at org.springframework.boot.SpringApplication.run(SpringApplication.java:303) [spring-boot-1.5.9.RELEASE.jar:1.5.9.RELEASE]
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1118) [spring-boot-1.5.9.RELEASE.jar:1.5.9.RELEASE]
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1107) [spring-boot-1.5.9.RELEASE.jar:1.5.9.RELEASE]
at com.citi.gpf.ah.AHServicesApp.main(AHServicesApp.java:17) [classes/:na]
Caused by: org.springframework.beans.BeanInstantiationException: Failed to instantiate [javax.xml.ws.Endpoint]: Factory method 'endpoint' threw exception; nested exception is javax.xml.ws.WebServiceException: org.apache.cxf.service.factory.ServiceConstructionException
at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:189) ~[spring-beans-4.3.13.RELEASE.jar:4.3.13.RELEASE]
at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:588) ~[spring-beans-4.3.13.RELEASE.jar:4.3.13.RELEASE]
... 18 common frames omitted
Caused by: javax.xml.ws.WebServiceException: org.apache.cxf.service.factory.ServiceConstructionException
at org.apache.cxf.jaxws.EndpointImpl.doPublish(EndpointImpl.java:375) ~[cxf-rt-frontend-jaxws-3.2.1.jar:3.2.1]
at org.apache.cxf.jaxws.EndpointImpl.publish(EndpointImpl.java:255) ~[cxf-rt-frontend-jaxws-3.2.1.jar:3.2.1]
at com.citi.gpf.ah.config.EndpointConfig.endpoint(EndpointConfig.java:23) ~[classes/:na]
at com.citi.gpf.ah.config.EndpointConfig$$EnhancerBySpringCGLIB$$dd140a18.CGLIB$endpoint$0(<generated>) ~[classes/:na]
at com.citi.gpf.ah.config.EndpointConfig$$EnhancerBySpringCGLIB$$dd140a18$$FastClassBySpringCGLIB$$dbcd1e21.invoke(<generated>) ~[classes/:na]
at org.springframework.cglib.proxy.MethodProxy.invokeSuper(MethodProxy.java:228) ~[spring-core-4.3.13.RELEASE.jar:4.3.13.RELEASE]
at org.springframework.context.annotation.ConfigurationClassEnhancer$BeanMethodInterceptor.intercept(ConfigurationClassEnhancer.java:358) ~[spring-context-4.3.13.RELEASE.jar:4.3.13.RELEASE]
at com.citi.gpf.ah.config.EndpointConfig$$EnhancerBySpringCGLIB$$dd140a18.endpoint(<generated>) ~[classes/:na]
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.8.0_152]
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:1.8.0_152]
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:1.8.0_152]
at java.lang.reflect.Method.invoke(Method.java:498) ~[na:1.8.0_152]
at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:162) ~[spring-beans-4.3.13.RELEASE.jar:4.3.13.RELEASE]
... 19 common frames omitted
Caused by: org.apache.cxf.service.factory.ServiceConstructionException: null
at org.apache.cxf.jaxb.JAXBDataBinding.initialize(JAXBDataBinding.java:329) ~[cxf-rt-databinding-jaxb-3.2.1.jar:3.2.1]
at org.apache.cxf.service.factory.AbstractServiceFactoryBean.initializeDataBindings(AbstractServiceFactoryBean.java:86) ~[cxf-core-3.2.1.jar:3.2.1]
at org.apache.cxf.wsdl.service.factory.ReflectionServiceFactoryBean.buildServiceFromClass(ReflectionServiceFactoryBean.java:470) ~[cxf-rt-wsdl-3.2.1.jar:3.2.1]
at org.apache.cxf.jaxws.support.JaxWsServiceFactoryBean.buildServiceFromClass(JaxWsServiceFactoryBean.java:695) ~[cxf-rt-frontend-jaxws-3.2.1.jar:3.2.1]
at org.apache.cxf.wsdl.service.factory.ReflectionServiceFactoryBean.initializeServiceModel(ReflectionServiceFactoryBean.java:530) ~[cxf-rt-wsdl-3.2.1.jar:3.2.1]
at org.apache.cxf.wsdl.service.factory.ReflectionServiceFactoryBean.create(ReflectionServiceFactoryBean.java:263) ~[cxf-rt-wsdl-3.2.1.jar:3.2.1]
at org.apache.cxf.jaxws.support.JaxWsServiceFactoryBean.create(JaxWsServiceFactoryBean.java:199) ~[cxf-rt-frontend-jaxws-3.2.1.jar:3.2.1]
at org.apache.cxf.frontend.AbstractWSDLBasedEndpointFactory.createEndpoint(AbstractWSDLBasedEndpointFactory.java:103) ~[cxf-rt-frontend-simple-3.2.1.jar:3.2.1]
at org.apache.cxf.frontend.ServerFactoryBean.create(ServerFactoryBean.java:168) ~[cxf-rt-frontend-simple-3.2.1.jar:3.2.1]
at org.apache.cxf.jaxws.JaxWsServerFactoryBean.create(JaxWsServerFactoryBean.java:211) ~[cxf-rt-frontend-jaxws-3.2.1.jar:3.2.1]
at org.apache.cxf.jaxws.EndpointImpl.getServer(EndpointImpl.java:460) ~[cxf-rt-frontend-jaxws-3.2.1.jar:3.2.1]
at org.apache.cxf.jaxws.EndpointImpl.doPublish(EndpointImpl.java:338) ~[cxf-rt-frontend-jaxws-3.2.1.jar:3.2.1]
... 31 common frames omitted
Caused by: com.sun.xml.internal.bind.v2.runtime.IllegalAnnotationsException: 3 counts of IllegalAnnotationExceptions
at com.sun.xml.internal.bind.v2.runtime.IllegalAnnotationsException$Builder.check(IllegalAnnotationsException.java:91) ~[na:1.8.0_152]
at com.sun.xml.internal.bind.v2.runtime.JAXBContextImpl.getTypeInfoSet(JAXBContextImpl.java:445) ~[na:1.8.0_152]
at com.sun.xml.internal.bind.v2.runtime.JAXBContextImpl.<init>(JAXBContextImpl.java:277) ~[na:1.8.0_152]
at com.sun.xml.internal.bind.v2.runtime.JAXBContextImpl.<init>(JAXBContextImpl.java:124) ~[na:1.8.0_152]
at com.sun.xml.internal.bind.v2.runtime.JAXBContextImpl$JAXBContextBuilder.build(JAXBContextImpl.java:1123) ~[na:1.8.0_152]
at com.sun.xml.internal.bind.v2.ContextFactory.createContext(ContextFactory.java:147) ~[na:1.8.0_152]
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.8.0_152]
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:1.8.0_152]
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:1.8.0_152]
at java.lang.reflect.Method.invoke(Method.java:498) ~[na:1.8.0_152]
at javax.xml.bind.ContextFinder.newInstance(ContextFinder.java:247) ~[na:1.8.0_152]
at javax.xml.bind.ContextFinder.newInstance(ContextFinder.java:234) ~[na:1.8.0_152]
at javax.xml.bind.ContextFinder.find(ContextFinder.java:462) ~[na:1.8.0_152]
at javax.xml.bind.JAXBContext.newInstance(JAXBContext.java:641) ~[na:1.8.0_152]
at org.apache.cxf.common.jaxb.JAXBContextCache.createContext(JAXBContextCache.java:358) ~[cxf-core-3.2.1.jar:3.2.1]
at org.apache.cxf.common.jaxb.JAXBContextCache.getCachedContextAndSchemas(JAXBContextCache.java:246) ~[cxf-core-3.2.1.jar:3.2.1]
at org.apache.cxf.jaxb.JAXBDataBinding.createJAXBContextAndSchemas(JAXBDataBinding.java:472) ~[cxf-rt-databinding-jaxb-3.2.1.jar:3.2.1]
at org.apache.cxf.jaxb.JAXBDataBinding.initialize(JAXBDataBinding.java:327) ~[cxf-rt-databinding-jaxb-3.2.1.jar:3.2.1]
... 42 common frames omitted
形成异常跟踪 :
Caused by: com.sun.xml.bind.v2.runtime.IllegalAnnotationsException: 2 counts of IllegalAnnotationExceptions
解决方法:(可能原因)
-
将服务端的services接口返回的Map/List类型的值,改成基本类型或者string类型.因为在做webServices复杂类型值传递时,返回值的类型不要用接口类型。对于处理复杂类型webservice有点出入。
-
版本冲突,理论上来讲
-
spring boot 1.4 版本对应cxf-spring-boot-starter-jaxws 3.1.X 版本
-
spring boot 1.5 版本对应cxf-spring-boot-starter-jaxws 3.2.X 版本
-
5. 另外,如果以上没有你出现的异常,可以参考此篇:WebServices CXF开发常见异常及解决方法
题外
以下纯属个人理解,如果有误,感谢大家指正
-
@WebMethod:筛选是否暴露该方法
@WebMethod(exclude=true) //阻止对外公开
如果没有不想’暴露的方法‘,个人认为去掉也没影响的,类似一个注释信息。因为不管方法里面有没有这个注解,都可以访问到。
-
@WebParam(name="id"):理解为必须有一个名为‘id’的参数名 返回soap报文时,必须有显示或者请求soap报文的时候,必须制定参数名为‘id’ 如果没理解,请看这篇:@WebParam的作用
开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!
更多推荐
所有评论(0)