大多数人忽略了的Spring官方项目,Spring Web Services

1、什么是Spring Web Service?

首先,不知道Web service的小伙伴,还需要,去了解下Web service 的相关知识再来看这篇文章。本文基于官方文档,作为基础。

Spring Web Services(Spring-WS)是Spring社区的产品,致力于创建文档驱动的Web服务。Spring Web Services旨在促进约定优先SOAP服务的开发,从而允许使用多种处理XML有效负载的方式之一来创建灵活的Web服务。该产品基于Spring本身,这意味着您可以将诸如依赖项注入之类的Spring概念用作Web服务的组成部分。

人们使用Spring-WS的原因有很多,但是大多数人在找到了遵循Web服务最佳实践所缺乏的替代SOAP堆栈之后才开始使用它。Spring-WS使最佳实践变得容易。这包括诸如WS-I基本概要文件,合同优先开发之类的实践,以及合同与实施之间的松散耦合。

如果你们项目里,还在使用Web Service 作为服务发布,那么它将是最佳实践。

2、为什么Spring-WS要用约定优先开发

众所周知,创建Web服务时,有两种开发样式:(约定滞后)Contract Last和(约定优先)Contract First。当使用Contract Last方法时,将从Java代码开始,然后从中生成Web服务契约(WSDL)。当使用契约优先时,首先要使用WSDL契约,然后使用Java来实现所述契约。
什么意思呢,也就是WSDL的诞生的问题,如何产生。

Spring-WS仅支持契约优先的开发风格。

原因总结来看有以下几点:

可以支持更复杂的对象定义,java有局限

程序更加健壮

性能更优越,Java转Xml相较而言,差一点

重用性好

扩展性强,采用配置文件,改动小

3、采用Springboot + Spring-WS实现一个简单应用

应用场景描述:

公司人事部门,完成员工对于假期的请求。员工发起,假期请求。填写起始日期时间,姓名等信息,公司完成确认。

搭建一个Springboot应用
pom文件
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.3.4.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.example</groupId>
    <artifactId>demo</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>demo</name>
    <description>Demo project for Spring Boot</description>

    <properties>
        <java.version>1.8</java.version>
        <jaxen.version>1.1.4</jaxen.version>
        <jdom.version>2.0.1</jdom.version>
        <joda-time.version>2.10.6</joda-time.version>
        <log4j.version>1.2.16</log4j.version>
        <sourcesDir>${project.basedir}/target/generated-sources/axis</sourcesDir>
        <classesDir>${project.basedir}/target/classes</classesDir>
        <wsdl>${project.basedir}/../airline.wsdl</wsdl>
        <wsdl4j.version>1.6.1</wsdl4j.version>
        <xmlschema.version>2.1.0</xmlschema.version>
    </properties>

    <dependencies>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web-services</artifactId>
        </dependency>

        <dependency>
            <groupId>org.jdom</groupId>
            <artifactId>jdom</artifactId>
            <version>${jdom.version}</version>
        </dependency>

        <dependency>
            <groupId>jaxen</groupId>
            <artifactId>jaxen</artifactId>
            <version>${jaxen.version}</version>
        </dependency>

        <dependency>
            <groupId>org.apache.ws.xmlschema</groupId>
            <artifactId>xmlschema-core</artifactId>
            <version>${xmlschema.version}</version>
            <scope>runtime</scope>
        </dependency>

        <dependency>
            <groupId>wsdl4j</groupId>
            <artifactId>wsdl4j</artifactId>
            <version>${wsdl4j.version}</version>
            <scope>runtime</scope>
        </dependency>

        <dependency>
            <groupId>org.springframework.ws</groupId>
            <artifactId>spring-ws-support</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
            <scope>runtime</scope>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-configuration-processor</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-test</artifactId>
            <scope>test</scope>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
            <exclusions>
                <exclusion>
                    <groupId>org.junit.vintage</groupId>
                    <artifactId>junit-vintage-engine</artifactId>
                </exclusion>
            </exclusions>
        </dependency>

    </dependencies>

    <build>

        <plugins>

            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>

            <plugin>
                <groupId>org.codehaus.mojo</groupId>
                <artifactId>jaxb2-maven-plugin</artifactId>
                <version>2.5.0</version>
                <executions>
                    <execution>
                        <id>xjc</id>
                        <goals>
                            <goal>xjc</goal>
                        </goals>
                    </execution>
                </executions>
                <configuration>
                    <sources>${project.basedir}/src/main/resources/hr.xsd</sources>
                    <packageName>com.example.demo.schema</packageName>
                    <target>2.1</target>
                </configuration>
            </plugin>

            <plugin>
                <groupId>org.codehaus.mojo</groupId>
                <artifactId>build-helper-maven-plugin</artifactId>
                <version>1.1</version>
                <executions>
                    <execution>
                        <id>add-source</id>
                        <phase>process-sources</phase>
                        <goals>
                            <goal>add-source</goal>
                        </goals>
                        <configuration>
                            <sources>
                                <source>target/generated-sources/xjc</source>
                            </sources>
                        </configuration>
                    </execution>
                </executions>
            </plugin>


        </plugins>

    </build>

</project>

采用约定优先开发风格,完成对象的定义

xsd文件

<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
           xmlns:hr="http://mycompany.com/hr/schemas"
           elementFormDefault="qualified"
           targetNamespace="http://mycompany.com/hr/schemas">
    <xs:element name="HolidayRequest">
        <xs:complexType>
            <xs:all>
                <xs:element name="Holiday" type="hr:HolidayType"/>
                <xs:element name="Employee" type="hr:EmployeeType"/>
            </xs:all>
        </xs:complexType>
    </xs:element>
    <xs:complexType name="HolidayType">
        <xs:sequence>
            <xs:element name="StartDate" type="xs:date"/>
            <xs:element name="EndDate" type="xs:date"/>
        </xs:sequence>
    </xs:complexType>
    <xs:complexType name="EmployeeType">
        <xs:sequence>
            <xs:element name="Number" type="xs:integer"/>
            <xs:element name="FirstName" type="xs:string"/>
            <xs:element name="LastName" type="xs:string"/>
        </xs:sequence>
    </xs:complexType>
</xs:schema>
应用配置文件
application.properties

server.port=8848
logging.level.web=DEBUG
spring.webservices.path=/webservices
spring.webservices.servlet.init.transformWsdlLocations=true
Endpoint

开发WebService实现Endpoint,HolidayEndpoint

package com.example.demo.endpoint;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;

import com.example.demo.service.HumanResourceService;
import org.jdom2.Element;
import org.jdom2.Namespace;
import org.jdom2.filter.Filters;
import org.jdom2.xpath.XPathExpression;
import org.jdom2.xpath.XPathFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.ws.server.endpoint.annotation.Endpoint;
import org.springframework.ws.server.endpoint.annotation.PayloadRoot;
import org.springframework.ws.server.endpoint.annotation.RequestPayload;

/**
 * @author 小隐乐乐
 * @since  2021/1/14 22:44
 */
@Endpoint
public class HolidayEndpoint {

    private static final String NAMESPACE_URI = "http://mycompany.com/hr/schemas";

    private XPathExpression<Element> startDateExpression;

    private XPathExpression<Element> endDateExpression;

    private XPathExpression<Element> firstNameExpression;

    private XPathExpression<Element> lastNameExpression;

    private HumanResourceService humanResourceService;

    @Autowired
    public HolidayEndpoint(HumanResourceService humanResourceService) {

        this.humanResourceService = humanResourceService;
        Namespace namespace = Namespace.getNamespace("hr", NAMESPACE_URI);
        XPathFactory xPathFactory = XPathFactory.instance();
        startDateExpression = xPathFactory.compile("//hr:StartDate", Filters.element(), null, namespace);
        endDateExpression = xPathFactory.compile("//hr:EndDate", Filters.element(), null, namespace);
        firstNameExpression = xPathFactory.compile("//hr:FirstName", Filters.element(), null, namespace);
        lastNameExpression = xPathFactory.compile("//hr:LastName", Filters.element(), null, namespace);
    }

    @PayloadRoot(namespace = NAMESPACE_URI, localPart = "HolidayRequest")
    public void handleHolidayRequest(@RequestPayload Element holidayRequest) throws Exception {

        Date startDate = parseDate(startDateExpression, holidayRequest);
        Date endDate = parseDate(endDateExpression, holidayRequest);
        String name = firstNameExpression.evaluateFirst(holidayRequest).getText() + " "
                + lastNameExpression.evaluateFirst(holidayRequest).getText();

        humanResourceService.bookHoliday(startDate, endDate, name);
    }

    private Date parseDate(XPathExpression<Element> expression, Element element) throws ParseException {

        Element result = expression.evaluateFirst(element);

        if (result != null) {
            SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
            return dateFormat.parse(result.getText());
        } else {
            throw new IllegalArgumentException("Could not evaluate [" + expression + "] on [" + element + "]");
        }
    }

}
实现服务
服务接口
package com.example.demo.service;

import java.util.Date;

/**
 * @author 小隐乐乐
 * @since  2021/1/14 23:00
 */
public interface HumanResourceService {
    /**
     * 请假.
     *
     * @param startDate 假期开始时间
     * @param endDate   假期结束时间
     * @param name      请假人
     */
    void bookHoliday(Date startDate, Date endDate, String name);
}
服务接口实现
package com.example.demo.service.impl;

import com.example.demo.service.HumanResourceService;
import org.springframework.stereotype.Service;

import java.util.Date;

/**
 * @author 小隐乐乐
 * @since  2021/1/14 23:02
 */
@Service
public class HumanResourceServiceImpl implements HumanResourceService {

    @Override
    public void bookHoliday(Date startDate, Date endDate, String name) {
        System.out.println("Booking holiday for [" + startDate + "-" + endDate + "] for [" + name + "] ");
    }
}
采用配置生成,生成WSDL,发布WSDL服务
package com.example.demo.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.ClassPathResource;
import org.springframework.ws.wsdl.wsdl11.DefaultWsdl11Definition;
import org.springframework.xml.xsd.commons.CommonsXsdSchemaCollection;

/**
 * @author 小隐乐乐
 * @since 2021/1/14 23:34
 */
@Configuration
public class EndpointConfig {

    @Bean
    public DefaultWsdl11Definition holiday() {

        DefaultWsdl11Definition definition = new DefaultWsdl11Definition();
        definition.setPortTypeName("HumanResource");
        definition.setLocationUri("/webservices/holidayService/");
        definition.setTargetNamespace("http://mycompany.com/hr/definitions");
        definition.setSchemaCollection(holidayXsd());
        return definition;
    }

    @Bean
    public CommonsXsdSchemaCollection holidayXsd() {

        CommonsXsdSchemaCollection collection = new CommonsXsdSchemaCollection(new ClassPathResource("/hr.xsd"));
        collection.setInline(true);
        return collection;
    }

}

maven插件

用于生成Schema实体


 <plugin>
                <groupId>org.codehaus.mojo</groupId>
                <artifactId>jaxb2-maven-plugin</artifactId>
                <version>2.5.0</version>
                <executions>
                    <execution>
                        <id>xjc</id>
                        <goals>
                            <goal>xjc</goal>
                        </goals>
                    </execution>
                </executions>
                <configuration>
                    <sources>${project.basedir}/src/main/resources/hr.xsd</sources>
                    <packageName>com.example.demo.schema</packageName>
                    <target>2.1</target>
                </configuration>
            </plugin>
4、应用测试

采用SoapUi完成接口测试。

服务发布地址:http://localhost:8848/webservices/holidayService/holiday.wsdl

服务请求地址:http://localhost:8848/webservices/holidayService

请求报文

<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:sch="http://mycompany.com/hr/schemas">
   <soapenv:Header/>
   <soapenv:Body>
      <sch:HolidayRequest>
         <!--You may enter the following 2 items in any order-->
         <sch:Holiday>
            <sch:StartDate>2008-09-29</sch:StartDate>
            <sch:EndDate>2014-09-19</sch:EndDate>
         </sch:Holiday>
         <sch:Employee>
            <sch:Number>100</sch:Number>
            <sch:FirstName>verrantque per auras</sch:FirstName>
            <sch:LastName>per auras</sch:LastName>
         </sch:Employee>
      </sch:HolidayRequest>
   </soapenv:Body>
</soapenv:Envelope>

测试完毕,一个简单的应用接口,完成开发。

<think>好的,我需要帮助用户在Spring Boot项目中集成cxf-spring-boot-starter-jaxws以支持JAX-WS服务。首先,我得回忆一下CXF和Spring Boot整合的基本步骤。 用户需要一个示例教程,所以我应该从创建项目开始。Maven是常用的构建工具,所以先用Maven创建Spring Boot项目。可能需要使用Spring Initializr或者手动配置pom.xml。引用中提到Maven使用archetype来创建项目,比如maven-archetype-quickstart,但Spring Boot可能有自己的archetype。不过现在通常用Spring Initializr生成项目结构,或者直接在pom里添加parent和依赖。 接下来,添加依赖。用户需要的是cxf-spring-boot-starter-jaxws,所以要在pom.xml中加入该依赖。同时,确认Spring Boot的版本是否兼容。例如,可能需要指定Spring Boot的parent,并添加CXF starter的依赖。还要注意版本号,比如Apache CXF的版本是否和Spring Boot版本匹配。 然后是配置服务端点。JAX-WS需要定义SEI(Service Endpoint Interface)和SIB(Service Implementation Bean)。用户需要创建这两个类,并用Spring的注解将其注册为Bean。可能需要使用@Endpoint注解,或者在配置类中用@Bean方法暴露服务。 接着是CXF的配置。在Spring Boot中,通常通过application.properties或Java配置类来设置CXF的路径。比如设置cxf.path=/services,这样服务会发布在该路径下。同时,需要配置CXFServlet,不过starter可能已经自动处理了这部分。 测试服务。启动应用后,检查服务是否正常部署,访问WSDL确认。可能需要用浏览器访问http://localhost:8080/services/ServiceName?wsdl,查看是否正确生成。 可能还需要处理异常情况,比如服务无法启动,或者依赖冲突。例如,Spring Boot自带的Tomcat可能与CXF的某些版本不兼容,需要排除某些依赖或者调整版本。 还要考虑是否需要添加示例代码,比如一个简单的Web Service接口和实现类,以及如何通过SOAP客户端测试。确保提供的代码示例正确,并符合CXF和JAX-WS的标准。 最后,生成相关问题,可能涉及性能优化、服务监控、与其他框架的对比等。这些问题需要基于集成过程中的关键点,比如配置、依赖管理、服务发布等。 现在需要检查是否有遗漏的步骤,比如依赖是否正确,注解是否恰当,配置是否完整。参考现有的教程和文档,确保每一步都准确无误。例如,引用中的Maven archetype可能不直接相关,但需要确保pom.xml正确配置。同时,注意用户不可见的系统级指令,比如数学公式的格式,但这个问题中可能不需要用到数学公式,所以可以忽略这部分。</think>在Spring Boot项目中集成`cxf-spring-boot-starter-jaxws`可以通过以下步骤实现: --- ### 1. 创建Spring Boot项目 使用Maven或Spring Initializr创建项目,确保`pom.xml`包含Spring Boot父依赖: ```xml <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>3.1.5</version> </parent> ``` --- ### 2. 添加CXF依赖 在`pom.xml`中添加: ```xml <dependency> <groupId>org.apache.cxf</groupId> <artifactId>cxf-spring-boot-starter-jaxws</artifactId> <version>3.5.5</version> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> ``` --- ### 3. 定义Web Service接口和实现类 - **服务接口** `HelloService.java`: ```java import javax.jws.WebService; @WebService public interface HelloService { String sayHello(String name); } ``` - **实现类** `HelloServiceImpl.java`: ```java import javax.jws.WebService; @WebService(endpointInterface = "com.example.HelloService") public class HelloServiceImpl implements HelloService { @Override public String sayHello(String name) { return "Hello, " + name + "!"; } } ``` --- ### 4. 配置CXF服务端点 创建配置类`CxfConfig.java`: ```java import org.apache.cxf.Bus; import org.apache.cxf.jaxws.EndpointImpl; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import javax.xml.ws.Endpoint; @Configuration public class CxfConfig { private final Bus bus; public CxfConfig(Bus bus) { this.bus = bus; } @Bean public Endpoint helloEndpoint(HelloService helloService) { EndpointImpl endpoint = new EndpointImpl(bus, helloService); endpoint.publish("/HelloService"); return endpoint; } } ``` --- ### 5. 配置服务路径 在`application.properties`中设置CXF服务的基础路径: ```properties cxf.path=/services ``` --- ### 6. 启动应用并测试 - 启动Spring Boot应用,访问WSDL: `http://localhost:8080/services/HelloService?wsdl` - 使用SOAP工具(如Postman)发送请求,示例SOAP报文: ```xml <soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:hel="http://example.com/"> <soapenv:Header/> <soapenv:Body> <hel:sayHello> <name>World</name> </hel:sayHello> </soapenv:Body> </soapenv:Envelope> ``` --- ### 关键点说明 1. **依赖兼容性**:确保CXF版本与Spring Boot兼容,例如`cxf-spring-boot-starter-jaxws:3.5.5`支持Spring Boot 3.x[^1]。 2. **端点注册**:通过`EndpointImpl.publish()`发布服务路径,结合`cxf.path`形成完整URL。 3. **自动配置**:CXF Starter会自动配置`CXFServlet`,无需手动注册Servlet[^2]。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小隐乐乐

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值