Spring Web Service Web Service SOAP WSDL Spring-WS server side

Spring Web Service ─ Web Service 簡介與 Server 端實作

吳沛芸 Peiiun Wu 2020/07/24 11:38:14
49

前言

 

什麼是Web Service

 
https://en.wikipedia.org/wiki/Web_service
Web services architecture

 

Spring Web Service

 
Spring-WS modules
Spring-WS modules

建立Web Service Provider

<dependency>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-web-services</artifactId>
</dependency>
<dependency>
	<groupId>wsdl4j</groupId>
	<artifactId>wsdl4j</artifactId>
</dependency>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
	targetNamespace="http://www.example.com/book"
	xmlns:tns="http://www.example.com/book" elementFormDefault="qualified">
	<xs:element name="getBookRequest">
		<xs:complexType>
			<xs:sequence>
				<xs:element name="isbn" type="xs:string" />
			</xs:sequence>
		</xs:complexType>
	</xs:element>
	<xs:element name="getBookResponse">
		<xs:complexType>
			<xs:sequence>
				<xs:element name="book" type="tns:book" />
			</xs:sequence>
		</xs:complexType>
	</xs:element>
	<xs:complexType name="book">
		<xs:sequence>
			<xs:element name="isbn" type="xs:string" />
			<xs:element name="name" type="xs:string" />
			<xs:element name="author" type="xs:string" />
			<xs:element name="publishing" type="xs:string" />
			<xs:element name="edition" type="xs:int" />
		</xs:sequence>
	</xs:complexType>
</xs:schema>

 

<plugin>
	<groupId>org.codehaus.mojo</groupId>
	<artifactId>jaxb2-maven-plugin</artifactId>
	<version>1.6</version>
	<executions>
		<execution>
			<id>xjc</id>
			<goals>
				<goal>xjc</goal>
			</goals>
		</execution>
	</executions>
	<configuration>
		<schemaDirectory>${project.basedir}/src/main/resources/</schemaDirectory>
		<outputDirectory>${project.basedir}/src/main/java</outputDirectory>
		<clearOutputDir>false</clearOutputDir>
	</configuration>
</plugin>
 
 xjc [目標路徑] <schema file/URL/dir/jar>
package com.example.demo;

import java.util.HashMap;
import java.util.Map;
import javax.annotation.PostConstruct;
import org.springframework.stereotype.Component;
import org.springframework.util.Assert;
import com.example.book.Book;

@Component
public class BookRepository {
    private static final Map<String, Book> books = new HashMap<>();

    @PostConstruct
    public void initData() {
        Book harryPotterI = new Book();
        harryPotterI.setIsbn("9573317249");
        harryPotterI.setName("哈利波特:神秘的魔法石");;
        harryPotterI.setAuthor("J. K. 羅琳");
        harryPotterI.setPublishing("1997");
        harryPotterI.setEdition(1);

        books.put(harryPotterI.getIsbn(), harryPotterI);

        Book iceAndFireI = new Book();
        iceAndFireI.setIsbn("9789861856216");
        iceAndFireI.setName("冰與火之歌:權力遊戲");;
        iceAndFireI.setAuthor("喬治馬汀");
        iceAndFireI.setPublishing("2011");
        iceAndFireI.setEdition(1);

        books.put(iceAndFireI.getIsbn(), iceAndFireI);

        Book lordOfRingsI = new Book();
        lordOfRingsI.setIsbn("9789570841008");
        lordOfRingsI.setName("魔戒首部曲:魔戒現身");;
        lordOfRingsI.setAuthor("托爾金");
        lordOfRingsI.setPublishing("2001");
        lordOfRingsI.setEdition(1);

        books.put(lordOfRingsI.getIsbn(), lordOfRingsI);

    }

    public Book findBookByIsbn(String isbn) {
        Assert.notNull(isbn, "The isbn must not be null!");
        return books.get(isbn);
    }
}
 
package com.example.demo;

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;
import org.springframework.ws.server.endpoint.annotation.ResponsePayload;
import com.example.book.Book;
import com.example.book.GetBookRequest;
import com.example.book.GetBookResponse;

@Endpoint
public class BookEndpoint {

    private static final String NAMESPACE_URI = "http://www.example.com/book";

    @Autowired
    BookRepository bookRepository;

    @PayloadRoot(namespace = NAMESPACE_URI, localPart = "getBookRequest")
    public @ResponsePayload GetBookResponse getBookByIsbn(@RequestPayload GetBookRequest request)
            throws InterruptedException {
        GetBookResponse response = new GetBookResponse();
        Book book = bookRepository.findBookByIsbn(request.getIsbn());
        response.setBook(book);
        return response;
    }
}
 
package com.example.demo;

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.transport.http.MessageDispatcherServlet;
import org.springframework.ws.wsdl.wsdl11.DefaultWsdl11Definition;
import org.springframework.xml.xsd.SimpleXsdSchema;
import org.springframework.xml.xsd.XsdSchema;

@EnableWs
@Configuration
public class WebServiceConfig {

    private static final String NAMESPACE_URI = "http://www.example.com/book";

    @Bean
    public ServletRegistrationBean messageDispatcherServlet(ApplicationContext applicationContext) {
        MessageDispatcherServlet servlet = new MessageDispatcherServlet();
        servlet.setApplicationContext(applicationContext);
        servlet.setTransformWsdlLocations(true);
        return new ServletRegistrationBean(servlet, "/bookService/*");
    }
		
    @Bean
    public XsdSchema bookSchema() {
        return new SimpleXsdSchema(new ClassPathResource("book.xsd"));
    }

    @Bean(name = "book")
    public DefaultWsdl11Definition defaultWsdl11Definition(XsdSchema bookSchema) {
        DefaultWsdl11Definition wsdl11Definition = new DefaultWsdl11Definition();
        wsdl11Definition.setPortTypeName("BookPort");
        wsdl11Definition.setLocationUri("/bookService");
        wsdl11Definition.setTargetNamespace(NAMESPACE_URI);
        wsdl11Definition.setSchema(bookSchema);
        return wsdl11Definition;
    }

}

專案資料夾結構:

專案資料夾結構

 

測試

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<wsdl:definitions xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" xmlns:sch="http://www.example.com/book" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:tns="http://www.example.com/book" targetNamespace="http://www.example.com/book">
    <wsdl:types>
        <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified" targetNamespace="http://www.example.com/book">
            <xs:element name="getBookRequest">
                <xs:complexType>
                    <xs:sequence>
                        <xs:element name="isbn" type="xs:string"/>
                    </xs:sequence>
                </xs:complexType>
            </xs:element>
            <xs:element name="getBookResponse">
                <xs:complexType>
                    <xs:sequence>
                        <xs:element name="book" type="tns:book"/>
                    </xs:sequence>
                </xs:complexType>
            </xs:element>
            <xs:complexType name="book">
                <xs:sequence>
                    <xs:element name="isbn" type="xs:string"/>
                    <xs:element name="name" type="xs:string"/>
                    <xs:element name="author" type="xs:string"/>
                    <xs:element name="publishing" type="xs:string"/>
                    <xs:element name="edition" type="xs:int"/>
                </xs:sequence>
            </xs:complexType>
        </xs:schema>
    </wsdl:types>
    <wsdl:message name="getBookRequest">
        <wsdl:part element="tns:getBookRequest" name="getBookRequest">
    </wsdl:part>
    </wsdl:message>
    <wsdl:message name="getBookResponse">
        <wsdl:part element="tns:getBookResponse" name="getBookResponse">
    </wsdl:part>
    </wsdl:message>
    <wsdl:portType name="BookPort">
        <wsdl:operation name="getBook">
            <wsdl:input message="tns:getBookRequest" name="getBookRequest">
    </wsdl:input>
            <wsdl:output message="tns:getBookResponse" name="getBookResponse">
    </wsdl:output>
        </wsdl:operation>
    </wsdl:portType>
    <wsdl:binding name="BookPortSoap11" type="tns:BookPort">
        <soap:binding style="document" transport="http://schemas.xmlsoap.org/soap/http"/>
        <wsdl:operation name="getBook">
            <soap:operation soapAction=""/>
            <wsdl:input name="getBookRequest">
                <soap:body use="literal"/>
            </wsdl:input>
            <wsdl:output name="getBookResponse">
                <soap:body use="literal"/>
            </wsdl:output>
        </wsdl:operation>
    </wsdl:binding>
    <wsdl:service name="BookPortService">
        <wsdl:port binding="tns:BookPortSoap11" name="BookPortSoap11">
            <soap:address location="http://localhost:8080/bookService"/>
        </wsdl:port>
    </wsdl:service>
</wsdl:definitions>
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"
                  xmlns:gs="http://www.example.com/book">
    <soapenv:Header/>
    <soapenv:Body>
        <gs:getBookRequest>
            <gs:isbn>9789861856216</gs:isbn>
        </gs:getBookRequest>
    </soapenv:Body>
</soapenv:Envelope>
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/">
    <SOAP-ENV:Header/>
    <SOAP-ENV:Body>
        <ns2:getBookResponse xmlns:ns2="http://www.example.com/book">
            <ns2:book>
                <ns2:isbn>9789861856216</ns2:isbn>
                <ns2:name>冰與火之歌:權力遊戲</ns2:name>
                <ns2:author>喬治馬汀</ns2:author>
                <ns2:poblishing>2011</ns2:poblishing>
                <ns2:edition>1</ns2:edition>
            </ns2:book>
        </ns2:getBookResponse>
    </SOAP-ENV:Body>
</SOAP-ENV:Envelope>

 

結語

吳沛芸 Peiiun Wu