Spring Boot WebService 实战解析

阿飞技术 2024-08-15 13:33:01 阅读 76

Spring Boot WebServices 实战解析:@Endpoint vs @WebService

前言

Web Services 是特殊的网络服务,它允许位于不同地点的计算机程序通过互联网交流和共享数据。这些服务可以通过多种方式实现,其中包括使用SOAP协议和遵循REST原则。

在SOAP的实现中,<code>Spring Web Services(Spring WS)和Java API for XML Web Services(JAX-WS)是两种主要的技术选择。Spring WS 是专为简化SOAP Web Services的开发而设计的,提供了一种创建文档驱动、基于SOAP的服务的方式,特别适合需要深度集成和复杂配置的企业级应用。相比之下,JAX-WS 是遵循WS-*标准的更为基础和轻量级的Java API,适用于需要标准Java支持且配置较少的场景。

本文主要展示这两种技术在Spring Boot环境中实现方式。

本文两种实现方式

@Endpoint 注解实现 SOAP Web Services

@WebService 注解实现 SOAP Web Services

版本

Java:8

Spring Boot:2.3.12.RELEASE

@Endpoint

@Endpoint注解来自Spring Web Services(Spring WS)项目,它专门用于处理SOAP Web服务的开发。Spring WS 不依赖于企业Java的标准,而是建立在Spring框架的基础之上,提供更灵活的配置和更好的集成。

@Endpoint示例参考此篇文件:https://www.baeldung.com/spring-boot-soap-web-service。但有几个点需要改动。

1. Maven依赖。

<dependency>

    <groupId>org.springframework.boot</groupId>

    <artifactId>spring-boot-starter-web-services</artifactId>

</dependency>

<dependency>

    <groupId>wsdl4j</groupId>

    <artifactId>wsdl4j</artifactId>

</dependency>

2. 在src/main/resources目录下创建一个名为 countries.xsd 的XSD文件(XML Schema Definition),用于定义SOAP消息的结构。这个Schema将作为生成Java类的基础,用于请求和响应的数据结构。

<?xml version="1.0" encoding="UTF-8"?>code>

<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:tns="http://www.baeldung.com/springsoap/gen"code>

           targetNamespace="http://www.baeldung.com/springsoap/gen" elementFormDefault="qualified">code>

    <xs:element name="getCountryRequest">code>

        <xs:complexType>

            <xs:sequence>

                <xs:element name="name" type="xs:string"/>code>

            </xs:sequence>

        </xs:complexType>

    </xs:element>

    <xs:element name="getCountryResponse">code>

        <xs:complexType>

            <xs:sequence>

                <xs:element name="country" type="tns:country"/>code>

            </xs:sequence>

        </xs:complexType>

    </xs:element>

    <xs:complexType name="country">code>

        <xs:sequence>

            <xs:element name="name" type="xs:string"/>code>

            <xs:element name="population" type="xs:int"/>code>

            <xs:element name="capital" type="xs:string"/>code>

            <xs:element name="currency" type="tns:currency"/>code>

        </xs:sequence>

    </xs:complexType>

    <xs:simpleType name="currency">code>

        <xs:restriction base="xs:string">code>

            <xs:enumeration value="GBP"/>code>

            <xs:enumeration value="EUR"/>code>

            <xs:enumeration value="PLN"/>code>

        </xs:restriction>

    </xs:simpleType>

</xs:schema>

3. 配置jaxb maven插件,将定义的 XSD 文件生成对应的 Java 类。

<plugin>

    <groupId>org.codehaus.mojo</groupId>

    <artifactId>jaxb2-maven-plugin</artifactId>

    <version>3.1.0</version>

    <executions>

        <execution>

            <id>xjc</id>

            <goals>

                <goal>xjc</goal>

            </goals>

        </execution>

    </executions>

    <configuration>

        <sources>

            <source>src/main/resources/countries.xsd</source>

        </sources>

        <outputDirectory>src/main/java/endpoint</outputDirectory>

        <clearOutputDir>false</clearOutputDir>

    </configuration>

</plugin>

source路径自己定义,相对路径绝对路径都可以。

控制台输入命令:

mvn package

则会生成对应的java类,拷贝到对应的目录下即可。

alt

4. 添加 SOAP Web 服务端点。

<code>@Component

@Endpoint

public class CountryEndpoint {

    private static final String NAMESPACE_URI = "http://www.baeldung.com/springsoap/gen";

    @PayloadRoot(namespace = NAMESPACE_URI, localPart = "getCountryRequest")

    @ResponsePayload

    public JAXBElement<GetCountryResponse> getCountry(@RequestPayload JAXBElement<GetCountryRequest> request) {

        GetCountryResponse response = new GetCountryResponse();

        Country country = new Country();

        country.setCapital("12");

        country.setName(request.getValue().getName());

        response.setCountry(country);

        return new JAXBElement<>(new QName(NAMESPACE_URI, GetCountryResponse.class.getSimpleName()), GetCountryResponse.class, response);

    }

}

注解含义:

@Endpoint:将类作为 Web 服务端点注册到 Spring WS。(端点可理解为处理特定类型的请求处理器)

@PayloadRoot:标记具体处理SOAP请求的方法。根据命名空间和 localPart 属性定义处理程序方法。

namespace:命名空间URI,用于标识特定的XML文档或元素集。

localPart:本地名称,指定在给定命名空间中的特定元素。

@ResponsePayload:处理将Java对象转换回SOAP消息的注解。

@RequestPayload:该注解将SOAP请求参数反序列化为java对象。

JAXBElement:相当于一个包装器,用来包含单个XML元素的信息。上述例子中创建JAXBElement是确保响应有正确的命令空间和本地名称。

namespace和localPart对应关系如下图:

alt

5. SOAP Web 服务配置 Bean。

WebServiceConfig类主要目的是配置和发布一个基于 SOAP 协议的 Web 服务。

<code>@EnableWs //启用Spring Web Services的配置支持

@Configuration

public class WebServiceConfig extends WsConfigurerAdapter {

    @Bean

    public ServletRegistrationBean<MessageDispatcherServlet> messageDispatcherServlet(ApplicationContext applicationContext) {  

        //定义一个servlet,用于处理soap消息

        MessageDispatcherServlet servlet = new MessageDispatcherServlet();

        servlet.setApplicationContext(applicationContext);

        servlet.setTransformWsdlLocations(true);

        return new ServletRegistrationBean<>(servlet, "/ws/*");

    }

    @Bean(name = "countries")

    public DefaultWsdl11Definition defaultWsdl11Definition(XsdSchema countriesSchema) {

        //公开一个标准的WSDL 1.1文档

        DefaultWsdl11Definition wsdl11Definition = new DefaultWsdl11Definition();

        wsdl11Definition.setPortTypeName("CountriesPort");

        //定义服务的访问地址,即客户端访问Web服务的端点

        wsdl11Definition.setLocationUri("/ws");

        wsdl11Definition.setTargetNamespace("http://www.baeldung.com/springsoap/gen");

        //关联xsd文件

        wsdl11Definition.setSchema(countriesSchema);

        return wsdl11Definition;

    }

    @Bean

    public XsdSchema countriesSchema() {

        return new SimpleXsdSchema(new ClassPathResource("countries.xsd"));

    }

}

应用启动成功后,打开url来验证wsdl文件是否成功发布: http://localhost:18889/ws/countries.wsdl。(我本地应用端口非8080)

WSDL 文件如下:

<?xml version="1.0" encoding="UTF-8" standalone="no"?><wsdl:definitions xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" xmlns:sch="http://www.baeldung.com/springsoap/gen" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:tns="http://www.baeldung.com/springsoap/gen" targetNamespace="http://www.baeldung.com/springsoap/gen">code>

  <wsdl:types>

    <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified" targetNamespace="http://www.baeldung.com/springsoap/gen">code>

    <xs:element name="getCountryRequest">code>

        <xs:complexType>

            <xs:sequence>

                <xs:element name="name" type="xs:string"/>code>

            </xs:sequence>

        </xs:complexType>

    </xs:element>

    <xs:element name="getCountryResponse">code>

        <xs:complexType>

            <xs:sequence>

                <xs:element name="country" type="tns:country"/>code>

            </xs:sequence>

        </xs:complexType>

    </xs:element>

    <xs:complexType name="country">code>

        <xs:sequence>

            <xs:element name="name" type="xs:string"/>code>

            <xs:element name="population" type="xs:int"/>code>

            <xs:element name="capital" type="xs:string"/>code>

            <xs:element name="currency" type="tns:currency"/>code>

        </xs:sequence>

    </xs:complexType>

    <xs:simpleType name="currency">code>

        <xs:restriction base="xs:string">code>

            <xs:enumeration value="GBP"/>code>

            <xs:enumeration value="EUR"/>code>

            <xs:enumeration value="PLN"/>code>

        </xs:restriction>

    </xs:simpleType>

</xs:schema>

  </wsdl:types>

  <wsdl:message name="getCountryResponse">code>

    <wsdl:part element="tns:getCountryResponse" name="getCountryResponse">code>

    </wsdl:part>

  </wsdl:message>

  <wsdl:message name="getCountryRequest">code>

    <wsdl:part element="tns:getCountryRequest" name="getCountryRequest">code>

    </wsdl:part>

  </wsdl:message>

  <wsdl:portType name="CountriesPort">code>

    <wsdl:operation name="getCountry">code>

      <wsdl:input message="tns:getCountryRequest" name="getCountryRequest">code>

    </wsdl:input>

      <wsdl:output message="tns:getCountryResponse" name="getCountryResponse">code>

    </wsdl:output>

    </wsdl:operation>

  </wsdl:portType>

  <wsdl:binding name="CountriesPortSoap11" type="tns:CountriesPort">code>

    <soap:binding style="document" transport="http://schemas.xmlsoap.org/soap/http"/>code>

    <wsdl:operation name="getCountry">code>

      <soap:operation soapAction=""/>code>

      <wsdl:input name="getCountryRequest">code>

        <soap:body use="literal"/>code>

      </wsdl:input>

      <wsdl:output name="getCountryResponse">code>

        <soap:body use="literal"/>code>

      </wsdl:output>

    </wsdl:operation>

  </wsdl:binding>

  <wsdl:service name="CountriesPortService">code>

    <wsdl:port binding="tns:CountriesPortSoap11" name="CountriesPortSoap11">code>

      <soap:address location="http://localhost:18889/ws"/>code>

    </wsdl:port>

  </wsdl:service>

</wsdl:definitions>

文件内容:

types(类型):定义web服务之间传递的数据类型。

message(消息):定义web服务中用于通信的消息结构。

portType(端口类型):定义web服务接口,包含一组操作,每个操作定义了输入和输出得消息结构。

binding(绑定):定义web服务的通信协议和消息格式。

service(服务):定义web服务的实际访问地址

6. 用 postman 测试 SOAP 项目。

alt

alt

@WebService

@WebService注解来自JAX-WS(Java API for XML Web Services)标准,它是一个专门用于创建SOAP(Simple Object Access Protocol)Web服务的API。这种方法通常用于实现符合WS-标准的Web服务,并且是Java EE规范的一部分。

1. Maven依赖。

<code><dependency>

    <groupId>org.springframework.boot</groupId>

    <artifactId>spring-boot-starter-web-services</artifactId>

</dependency>

<dependency>

    <groupId>org.apache.cxf</groupId>

    <artifactId>cxf-spring-boot-starter-jaxws</artifactId>

    <version>3.4.4</version>

</dependency>

2. 定义webservices接口。

@WebService(name = "PersonnelInfo",

        targetNamespace = "http://service.manage.com/")

public interface PersonnelInfoService {

    @WebMethod

    String syncPersonnelInfo(@WebParam(name = "xmlData", targetNamespace = "http://service.manage.com/") String jsonData);

}

@WebService:标记一个接口或类作为Web服务的服务端点。

name:指定服务的名称。

targetNamespace:定义了这个Web服务所使用的XML命名空间。

@WebMethod 和 @WebParam 注解用于定义 Web 服务中的方法和参数。

3. 定义webservices实现类。

//endpointInterface:服务接口全路径

@Slf4j

@Component

@WebService(name = "PersonnelInfo",

        targetNamespace = "http://service.manage.com/",

        endpointInterface = "com.manage.service.PersonnelInfoService")

public class PersonnelInfoServiceImpl implements PersonnelInfoService {

    @Override

    public String syncPersonnelInfo(@WebParam(name = "xmlData", targetNamespace = "http://service.manage.com/") String xmlData) {

        String result = "success";

        log.info("三方信息调用入参:{}", xmlData);

    }

}

4. 发布webservices服务。

@Configuration

public class CxfConfig {

    @Autowired

    private Bus bus;

    @Autowired

    private PersonnelInfoService personnelInfoService;

    @Bean(name = "wsBean")

    public ServletRegistrationBean dispatcherServlet() {

        //注册servlet,用于处理web服务请求

        ServletRegistrationBean wbsServlet = new ServletRegistrationBean(new CXFServlet(), "/ws/*");

        return wbsServlet;

    }

    /**

     * JAX-WS

     * 站点服务

     **/

    @Bean

    public Endpoint endpoint() {

        //发布Web服务的类,将请求都交给personnelInfoService类处理

        EndpointImpl endpoint = new EndpointImpl(bus, personnelInfoService);

        //将当前端点发布到URL路径/data上

        endpoint.publish("/data");

        return endpoint;

    }

}

输入下面url检查程序发布是否正常: http://localhost:8080/ws/countries.wsdl

alt

5. 用 postman 测试 SOAP 项目。

alt

总结

<code>@Endpoint@WebService 这两种方式都可以实现接收 XML 请求的需求。其中一个依赖于 JAX-WS 标准,更适合定制化和特殊需求的 Web 服务实现;另一个依赖于 JAX-WS 标准,适用于遵循规范和标准化的项目。具体可根据实际需求和开发栈来选择合适的实现方式。

参考资料

https://www.baeldung.com/spring-boot-soap-web-service

本文由 mdnice 多平台发布



声明

本文内容仅代表作者观点,或转载于其他网站,本站不以此文作为商业用途
如有涉及侵权,请联系本站进行删除
转载本站原创文章,请注明来源及作者。