[七日打卡]大多數人忽略了的Spring官方項目,Spring Web Services

一、什麼是Spring Web Service?

首先,不知道Web service的小夥伴,還須要,去了解下Web service 的相關知識再來看這篇文章。本文基於官方文檔,做爲基礎。java

Spring Web Services(Spring-WS)是Spring社區的產品,致力於建立文檔驅動的Web服務。Spring Web Services旨在促進約定優先SOAP服務的開發,從而容許使用多種處理XML有效負載的方式之一來建立靈活的Web服務。該產品基於Spring自己,這意味着您能夠將諸如依賴項注入之類的Spring概念用做Web服務的組成部分。web

人們使用Spring-WS的緣由有不少,可是大多數人在找到了遵循Web服務最佳實踐所缺少的替代SOAP堆棧以後纔開始使用它。Spring-WS使最佳實踐變得容易。這包括諸如WS-I基本概要文件,合同優先開發之類的實踐,以及合同與實施之間的鬆散耦合。spring

若是大家項目裏,還在使用Web Service 做爲服務發佈,那麼它將是最佳實踐。express

二、爲何Spring-WS要用約定優先開發

衆所周知,建立Web服務時,有兩種開發樣式:(約定滯後)Contract Last和(約定優先)Contract First。當使用Contract Last方法時,將從Java代碼開始,而後從中生成Web服務契約(WSDL)。當使用契約優先時,首先要使用WSDL契約,而後使用Java來實現所述契約。 什麼意思呢,也就是WSDL的誕生的問題,如何產生。apache

Spring-WS僅支持契約優先的開發風格。markdown

緣由總結來看有如下幾點:app

能夠支持更復雜的對象定義,java有侷限dom

程序更加健壯maven

性能更優越,Java轉Xml相較而言,差一點ide

重用性好

擴展性強,採用配置文件,改動小

三、採用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>
複製代碼

四、應用測試

採用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>
複製代碼

測試完畢,一個簡單的應用接口,完成開發。

相關文章
相關標籤/搜索