解决springboot整合webservice,使用SOAP Web服务遇到的坑

记录一下springboot整合webservice遇到的问题:

首先,项目需求是,客户那边希望通过webservice来发送数据到本地的服务器,而在本地是希望使用springboot框架,打成的war包在tomcat中启动服务。所以在这里就准备使用springboot整合webservice来完成这一需求。

在网上找了大部分的资料,大多都是关于用webservice的CXF框架,打成war包之后,在运行过程中项目直接启动失败,报了这样一个问题:

java.lang.ClassNotFoundException:com.sun.xml.ws.transport.http.servlet.WSServletContextListener

查了很多原因,发现都是与依赖相关,将相关jar包导入之后仍然报各种问题,所以此方法舍弃。

查看到springboot官网中https://spring.io/guides/gs/consuming-web-service/ 与spring-ws的列子,尝试使用此方法,由于没有跑demo,直接照着上面用了,主要的两个类如下:

首先,schema文件(xsd) service.xsd

<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:tns="http://webservice.server.test.com"
           targetNamespace="http://webservice.server.test.com" elementFormDefault="qualified">

    <xs:element name="getUserInfoRequest">
        <xs:complexType>
            <xs:sequence>
                <xs:element name="type" type="xs:string"/>
                <xs:element name="value" type="xs:string"/>
            </xs:sequence>
        </xs:complexType>
    </xs:element>    
    <xs:element name="getUserInfoResponse" type="xs:string"/>
</xs:schema>

WebServiceConfig.java

package com.test.server.webservice;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.web.servlet.ServletRegistrationBean;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.ClassPathResource;
import org.springframework.ws.config.annotation.EnableWs;
import org.springframework.ws.config.annotation.WsConfigurerAdapter;
import org.springframework.ws.transport.http.MessageDispatcherServlet;
import org.springframework.ws.wsdl.wsdl11.DefaultWsdl11Definition;
import org.springframework.xml.xsd.SimpleXsdSchema;
import org.springframework.xml.xsd.XsdSchema;

/**
 *
 * @author wyj
 */
@EnableWs
@Configuration
public class WebServiceConfig extends WsConfigurerAdapter {

    private final static Logger LOGGER = LoggerFactory.getLogger(WebServiceConfig.class);

    @Bean
    public ServletRegistrationBean messageDispatcherServlet(ApplicationContext applicationContext) {
        MessageDispatcherServlet servlet = new MessageDispatcherServlet();
        servlet.setApplicationContext(applicationContext);
        servlet.setTransformWsdlLocations(true);
        return new ServletRegistrationBean(servlet, "/ws/*");
    }

    @Bean(name = "test")
    public DefaultWsdl11Definition defaultWsdl11Definition() {
        DefaultWsdl11Definition wsdl11Definition = new DefaultWsdl11Definition();
        wsdl11Definition.setPortTypeName("ServicePort");
        wsdl11Definition.setLocationUri("/ws/test.wsdl");
        wsdl11Definition.setSchema(serviceSchema());
        return wsdl11Definition;
    }

    @Bean
    public XsdSchema serviceSchema() {
        return new SimpleXsdSchema(new ClassPathResource("service.xsd"));
    }

}

ServiceEndpoint.java

package com.test.server.webservice;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.ws.server.endpoint.annotation.Endpoint;
import org.springframework.ws.server.endpoint.annotation.PayloadRoot;
import org.springframework.ws.server.endpoint.annotation.RequestPayload;
import org.springframework.ws.server.endpoint.annotation.ResponsePayload;

/**
 *
 * @author wyj
 */
@Endpoint
public class ServiceEndpoint {

    private final static Logger LOGGER = LoggerFactory.getLogger(ServiceEndpoint.class);

    private static final String NAMESPACE_URI = "http://webservice.server.test.com";

    @PayloadRoot(namespace = NAMESPACE_URI, localPart = "getUserInfo")
    @ResponsePayload
    public String getUserInfo(@RequestPayload GetUserInfoRequest request) {
        LOGGER.info("getUserInfo type:[{}],value [{}]", request.getType(), request.getValue());
        String dataValue = Integration.getInstance().getWebServiceResult(request.getType(), request.getValue());
        LOGGER.info("getUserInfo result:[{}]", dataValue);
        return dataValue ;
    }
}

项目可以正常运行,浏览器打开能够正常访问http://localhost:8080/test/ws/test.wsdl

于是跑了个客户端的java项目,代码如下:

/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
package com.test;

import com.ankon.his.integration.server.webservice.GetUserInfoRequest;
import com.ankon.his.integration.server.webservice.GetUserInfoResponse;
import com.ankon.his.integration.server.webservice.ServicePort;
import com.ankon.his.integration.server.webservice.ServicePortService;
import java.net.MalformedURLException;
import java.net.URL;

/**
 *
 * @author wyj
 */
public class NewClass {

    public static void main(String args[]) throws MalformedURLException {
        ServicePortService service = new ServicePortService(new URL("http://localhost:81/test/ws/test.wsdl"));
        GetUserInfoRequest request = new GetUserInfoRequest ();
        request.setType("aaa");
        request.setValue("aaa");
        ServicePort servicePort = service.getServicePortSoap11();
        System.err.println(servicePort );
        String response = ankonService.getUserInfo(request);
        System.err.println(response );
    }
}

报如下问题:

JAX-WS RI 2.2.9-b130926.1035 svn-revision#5f6196f2b90e9460065a4c2f4e30e065b245e51e: Stub for http://localhost:81/test/ws/test.wsdl
Exception in thread "main" com.sun.xml.internal.ws.client.ClientTransportException: 服务器发送了 HTTP 状态代码 404: null
	at com.sun.xml.internal.ws.transport.http.client.HttpTransportPipe.checkStatusCode(HttpTransportPipe.java:310)
	at com.sun.xml.internal.ws.transport.http.client.HttpTransportPipe.createResponsePacket(HttpTransportPipe.java:259)
	at com.sun.xml.internal.ws.transport.http.client.HttpTransportPipe.process(HttpTransportPipe.java:217)
	at com.sun.xml.internal.ws.transport.http.client.HttpTransportPipe.processRequest(HttpTransportPipe.java:130)
	at com.sun.xml.internal.ws.transport.DeferredTransportPipe.processRequest(DeferredTransportPipe.java:95)
	at com.sun.xml.internal.ws.api.pipe.Fiber.__doRun(Fiber.java:1121)

网上找了很多地方,没有找到解决方案,于是与官网上的demo仔细比对,发现ServiceEndpoint.java中localPart 设置为getUserInfo没有与xsd文件中的定义的request对应,导致了这一问题,修改为getUserInfoRequest问题解决。

继续调试,遇到了新的问题:

JAX-WS RI 2.2.9-b130926.1035 svn-revision#5f6196f2b90e9460065a4c2f4e30e065b245e51e: Stub for http://localhost:81/test/ws/test.wsdl
Exception in thread "main" com.sun.xml.internal.ws.fault.ServerSOAPFaultException: Client received SOAP Fault from server: No adapter for endpoint [public java.lang.String com.ankon.test.server.webservice.ServiceEndpoint.getUserInfo(com.ankon.test.server.webservice.GetUserInfoRequest)]: Is your endpoint annotated with @Endpoint, or does it implement a supported interface like MessageHandler or PayloadEndpoint? Please see the server log to find more detail regarding exact cause of the failure.
	at com.sun.xml.internal.ws.fault.SOAP11Fault.getProtocolException(SOAP11Fault.java:178)
	at com.sun.xml.internal.ws.fault.SOAPFaultBuilder.createException(SOAPFaultBuilder.java:116)
	at com.sun.xml.internal.ws.client.sei.StubHandler.readResponse(StubHandler.java:238)
	at com.sun.xml.internal.ws.db.DatabindingImpl.deserializeResponse(DatabindingImpl.java:189)
	at com.sun.xml.internal.ws.db.DatabindingImpl.deserializeResponse(DatabindingImpl.java:276)
	at com.sun.xml.internal.ws.client.sei.SyncMethodHandler.invoke(SyncMethodHandler.java:104)
	at com.sun.xml.internal.ws.client.sei.SyncMethodHandler.invoke(SyncMethodHandler.java:77)
	at com.sun.xml.internal.ws.client.sei.SEIStub.invoke(SEIStub.java:147)
	at com.sun.proxy.$Proxy30.getUserInfo(Unknown Source)

再回过头来运行官网的demo并无此问题,多次尝试后,发现与返回值有关:

定义的方法getUserInfo返回值为String,而官网上不管是request还是response都是定义了一个简单对象,所有再次尝试,将String的返回值重新包装成一个对象,修改了xsd文件及ServiceEndpoint,问题解决。

<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:tns="http://webservice.server.test.com"
           targetNamespace="http://webservice.server.test.com" elementFormDefault="qualified">

    <xs:element name="getUserInfoRequest">
        <xs:complexType>
            <xs:sequence>
                <xs:element name="type" type="xs:string"/>
                <xs:element name="value" type="xs:string"/>
            </xs:sequence>
        </xs:complexType>
    </xs:element>    
    <xs:element name="getUserInfoResponse">
        <xs:complexType>
            <xs:sequence>
                <xs:element name="data" type="xs:string"/>
            </xs:sequence>
        </xs:complexType>
    </xs:element>    
</xs:schema>
@PayloadRoot(namespace = NAMESPACE_URI, localPart = "getUserInfoRequest")
    @ResponsePayload
    public GetUserInfoResponse getUserInfo(@RequestPayload GetUserInfoRequest request) {
        LOGGER.info("getUserInfo type:[{}],value [{}]", request.getType(), request.getValue());
        GetUserInfoResponse data = new GetUserInfoResponse ();
        String dataValue = Integration.getInstance().getWebServiceResult(request.getType(), request.getValue());
        LOGGER.info("getUserInfo result:[{}]", dataValue);
        data.setData(dataValue);
        return data;
    }

 

  • 3
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
好的,我可以为您提供相关的帮助。在SpringBoot中,我们可以使用CXF来实现SOAP WebService。下面是一些基本的步骤: 1. 首先,需要在pom.xml文件中添加CXF依赖: ```xml <dependency> <groupId>org.apache.cxf</groupId> <artifactId>cxf-spring-boot-starter-jaxws</artifactId> <version>3.3.7</version> </dependency> ``` 2. 接下来,我们需要创建一个服务接口。例如: ```java @WebService public interface HelloWorldService { @WebMethod String sayHello(@WebParam(name = "name") String name); } ``` 3. 然后,我们需要创建服务实现类,实现服务接口中的方法。例如: ```java @WebService(endpointInterface = "com.example.demo.HelloWorldService") @Service public class HelloWorldServiceImpl implements HelloWorldService { @Override public String sayHello(String name) { return "Hello " + name + "!"; } } ``` 4. 然后,我们需要在application.properties文件中配置CXF服务。例如: ```properties # CXF properties cxf.path=/soap-api ``` 5. 最后,我们需要在启动类中添加注解@EnableWs和@Bean来配置CXF服务。例如: ```java @SpringBootApplication @EnableWs public class DemoApplication { public static void main(String[] args) { SpringApplication.run(DemoApplication.class, args); } @Bean public ServletRegistrationBean<CXFServlet> cxfServlet() { return new ServletRegistrationBean<>(new CXFServlet(), "/soap-api/*"); } @Bean(name = Bus.DEFAULT_BUS_ID) public SpringBus springBus() { return new SpringBus(); } @Bean public Endpoint endpoint() { EndpointImpl endpoint = new EndpointImpl(springBus(), new HelloWorldServiceImpl()); endpoint.publish("/hello"); return endpoint; } } ``` 这样,我们就可以在SpringBoot整合CXF并实现SOAP WebService了。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值