springboot集成webservice以及遇到的问题

需求

公司最近需要做一个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种方式:

  1. 直接在启动类使用Endpoint,不需要配置类,但这种方式需要jetty依赖,端口号可以不和启动类一致,可以自定义(切勿冲突)
  2. 使用配置类,不用在启动类中加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种方式:

  1. 代理类工厂
  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();
        }
    }
}

期间遇到的问题:

  1. 在网上百度了许多答案后,发现他们中的配置类第一个@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

  2. 如果出现以下异常:

    Caused by: org.apache.cxf.binding.soap.SoapFault: Unmarshalling Error: 意外的元素 (uri:"", local:"id")。所需元素为<{}arg1>,<{}arg0> 
    

    需要检查自己的参数是否正确,如果确认没错的话,就需要检查一下接口那块是否有@WebParam修饰

  3.  如果后台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

 

解决方法:(可能原因)

  1. 将服务端的services接口返回的Map/List类型的值,改成基本类型或者string类型.因为在做webServices复杂类型值传递时,返回值的类型不要用接口类型。对于处理复杂类型webservice有点出入。

  2. 版本冲突,理论上来讲

    1. spring boot 1.4 版本对应cxf-spring-boot-starter-jaxws 3.1.X 版本

    2. spring boot 1.5 版本对应cxf-spring-boot-starter-jaxws 3.2.X 版本

5. 另外,如果以上没有你出现的异常,可以参考此篇:WebServices CXF开发常见异常及解决方法

题外

以下纯属个人理解,如果有误,感谢大家指正

  1. @WebMethod:筛选是否暴露该方法

    @WebMethod(exclude=true) //阻止对外公开
    

    如果没有不想’暴露的方法‘,个人认为去掉也没影响的,类似一个注释信息。因为不管方法里面有没有这个注解,都可以访问到。

  2. @WebParam(name="id"):理解为必须有一个名为‘id’的参数名 返回soap报文时,必须有显示或者请求soap报文的时候,必须制定参数名为‘id’ 如果没理解,请看这篇:@WebParam的作用

  • 3
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 5
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值