В эпоху RESTful Web Services у меня появилась возможность использовать SOAP Web Service. Чтобы сделать то же самое, я выбрал Spring , потому что мы уже используем Spring в качестве серверной среды в нашем проекте, и, во-вторых, он предоставляет интуитивно понятный способ взаимодействия сервисов с четко определенными границами для обеспечения возможности повторного использования и переносимости через WebServiceTemplate .
Предполагая, что вы уже знаете о веб-службах SOAP, давайте начнем создавать мыльный сервис hello-world, работающий на порту 9999 и клиенте, который будет использовать то же самое, выполнив следующие шаги:
Шаг 1 : Перейдите на start.spring.io и создайте новый мыльный сервер проекта с добавлением веб-стартеров на основе следующего изображения:
Шаг 2. Отредактируйте SoapServerApplication.java, чтобы опубликовать службу hello-world в конечной точке — http: // localhost: 9999 / service / hello-world , следующим образом:
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
|
package com.arpit.soap.server.main; import javax.xml.ws.Endpoint; import org.springframework.beans.factory.annotation.Value; import org.springframework.boot.CommandLineRunner; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import com.arpit.soap.server.service.impl.HelloWorldServiceImpl; @SpringBootApplication public class SoapServerApplication implements CommandLineRunner { @Value ( "${service.port}" ) private String servicePort; @Override public void run(String... args) throws Exception { + "/service/hello-world" , new HelloWorldServiceImpl()); } public static void main(String[] args) { SpringApplication.run(SoapServerApplication. class , args); } } |
Шаг 3: Измените application.properties, указав имя приложения, порт и номер порта службы hello-world , следующим образом:
1
2
3
4
5
|
server.port= 9000 spring.application.name=soap-server ## Soap Service Port service.port= 9999 |
Шаг 4. Создайте дополнительные пакеты как com.arpit.soap.server.service и com.arpit.soap.server.service.impl для определения веб-службы и ее реализации следующим образом:
HelloWorldService.java
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
|
package com.arpit.soap.server.service; import javax.jws.WebMethod; import javax.jws.WebParam; import javax.jws.WebService; import com.arpit.soap.server.model.ApplicationCredentials; @WebService public interface HelloWorldService { @WebMethod (operationName = "helloWorld" , action = "https://aggarwalarpit.wordpress.com/hello-world/helloWorld" ) String helloWorld( final String name, @WebParam (header = true ) final ApplicationCredentials credential); } |
Указанный выше @WebService помечает класс Java как реализующий веб-службу или интерфейс Java как определяющий интерфейс веб-службы.
Указанный выше @WebMethod помечает метод Java как операцию веб-службы.
@WebParam, указанный выше, настраивает сопоставление отдельного параметра с частью сообщения веб-службы и элементом XML.
HelloWorldServiceImpl.java
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
|
package com.arpit.soap.server.service.impl; import javax.jws.WebService; import com.arpit.soap.server.model.ApplicationCredentials; import com.arpit.soap.server.service.HelloWorldService; @WebService (endpointInterface = "com.arpit.soap.server.service.HelloWorldService" ) public class HelloWorldServiceImpl implements HelloWorldService { @Override public String helloWorld( final String name, final ApplicationCredentials credential) { return "Hello World from " + name; } } |
Шаг 5: Перейдите в каталог мыльного сервера и выполните команду: mvn spring-boot: run . После запуска откройте http: // localhost: 9999 / service / hello-world? Wsdl, чтобы просмотреть WSDL для службы hello-world .
Далее мы создадим мыльный клиент, который будет использовать наш недавно созданный сервис hello-world .
Шаг 6: Перейдите к файлу start.spring.io и создайте новый мыльный клиент проекта, добавив стартеры Web, Web Services, на основе следующего изображения:
Шаг 7: Отредактируйте SoapClientApplication.java, чтобы создать запрос к веб-сервису hello-world , отправив его на soap-сервер вместе с заголовком и получить от него ответ следующим образом:
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
|
package com.arpit.soap.client.main; import java.io.IOException; import java.io.StringWriter; import javax.xml.bind.JAXBElement; import javax.xml.transform.Transformer; import javax.xml.transform.TransformerException; import javax.xml.transform.TransformerFactory; import javax.xml.transform.stream.StreamResult; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.beans.factory.annotation.Value; import org.springframework.boot.CommandLineRunner; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.context.annotation.ComponentScan; import org.springframework.ws.WebServiceMessage; import org.springframework.ws.client.core.WebServiceMessageCallback; import org.springframework.ws.client.core.WebServiceTemplate; import org.springframework.ws.soap.SoapMessage; import org.springframework.xml.transform.StringSource; import com.arpit.soap.server.service.ApplicationCredentials; import com.arpit.soap.server.service.HelloWorld; import com.arpit.soap.server.service.HelloWorldResponse; import com.arpit.soap.server.service.ObjectFactory; @SpringBootApplication @ComponentScan ( "com.arpit.soap.client.config" ) public class SoapClientApplication implements CommandLineRunner { @Autowired @Qualifier ( "webServiceTemplate" ) private WebServiceTemplate webServiceTemplate; @Value ( "#{'${service.soap.action}'}" ) private String serviceSoapAction; @Value ( "#{'${service.user.id}'}" ) private String serviceUserId; @Value ( "#{'${service.user.password}'}" ) private String serviceUserPassword; public static void main(String[] args) { SpringApplication.run(SoapClientApplication. class , args); System.exit( 0 ); } public void run(String... args) throws Exception { final HelloWorld helloWorld = createHelloWorldRequest(); @SuppressWarnings ( "unchecked" ) final JAXBElement<HelloWorldResponse> jaxbElement = (JAXBElement<HelloWorldResponse>) sendAndRecieve(helloWorld); final HelloWorldResponse helloWorldResponse = jaxbElement.getValue(); System.out.println(helloWorldResponse.getReturn()); } private Object sendAndRecieve(HelloWorld seatMapRequestType) { return webServiceTemplate.marshalSendAndReceive(seatMapRequestType, new WebServiceMessageCallback() { public void doWithMessage(WebServiceMessage message) throws IOException, TransformerException { SoapMessage soapMessage = (SoapMessage) message; soapMessage.setSoapAction(serviceSoapAction); org.springframework.ws.soap.SoapHeader soapheader = soapMessage .getSoapHeader(); final StringWriter out = new StringWriter(); webServiceTemplate.getMarshaller().marshal( getHeader(serviceUserId, serviceUserPassword), new StreamResult(out)); Transformer transformer = TransformerFactory .newInstance().newTransformer(); transformer.transform( new StringSource(out.toString()), soapheader.getResult()); } }); } private Object getHeader( final String userId, final String password) { final https.aggarwalarpit_wordpress.ObjectFactory headerObjectFactory = new https.aggarwalarpit_wordpress.ObjectFactory(); final ApplicationCredentials applicationCredentials = new ApplicationCredentials(); applicationCredentials.setUserId(userId); applicationCredentials.setPassword(password); final JAXBElement<ApplicationCredentials> header = headerObjectFactory .createApplicationCredentials(applicationCredentials); return header; } private HelloWorld createHelloWorldRequest() { final ObjectFactory objectFactory = new ObjectFactory(); final HelloWorld helloWorld = objectFactory.createHelloWorld(); helloWorld.setArg0( "Arpit" ); return helloWorld; } } |
Шаг 8: Затем создайте дополнительный пакет com.arpit.soap.client.config для настройки WebServiceTemplate следующим образом:
ApplicationConfig.java
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
|
package com.arpit.soap.client.config; import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.support.PropertySourcesPlaceholderConfigurer; import org.springframework.oxm.jaxb.Jaxb2Marshaller; import org.springframework.web.servlet.config.annotation.EnableWebMvc; import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter; import org.springframework.ws.client.core.WebServiceTemplate; import org.springframework.ws.soap.saaj.SaajSoapMessageFactory; import org.springframework.ws.transport.http.HttpComponentsMessageSender; @Configuration @EnableWebMvc public class ApplicationConfig extends WebMvcConfigurerAdapter { @Value ( "#{'${service.endpoint}'}" ) private String serviceEndpoint; @Value ( "#{'${marshaller.packages.to.scan}'}" ) private String marshallerPackagesToScan; @Value ( "#{'${unmarshaller.packages.to.scan}'}" ) private String unmarshallerPackagesToScan; @Bean public static PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer() { return new PropertySourcesPlaceholderConfigurer(); } @Bean public SaajSoapMessageFactory messageFactory() { SaajSoapMessageFactory messageFactory = new SaajSoapMessageFactory(); messageFactory.afterPropertiesSet(); return messageFactory; } @Bean public Jaxb2Marshaller marshaller() { Jaxb2Marshaller marshaller = new Jaxb2Marshaller(); marshaller.setPackagesToScan(marshallerPackagesToScan.split( "," )); return marshaller; } @Bean public Jaxb2Marshaller unmarshaller() { Jaxb2Marshaller unmarshaller = new Jaxb2Marshaller(); unmarshaller.setPackagesToScan(unmarshallerPackagesToScan.split( "," )); return unmarshaller; } @Bean public WebServiceTemplate webServiceTemplate() { WebServiceTemplate webServiceTemplate = new WebServiceTemplate( messageFactory()); webServiceTemplate.setMarshaller(marshaller()); webServiceTemplate.setUnmarshaller(unmarshaller()); webServiceTemplate.setMessageSender(messageSender()); webServiceTemplate.setDefaultUri(serviceEndpoint); return webServiceTemplate; } @Bean public HttpComponentsMessageSender messageSender() { HttpComponentsMessageSender httpComponentsMessageSender = new HttpComponentsMessageSender(); return httpComponentsMessageSender; } } |
Шаг 9: Отредактируйте application.properties, указав имя приложения, порт и настройки мыльного веб-сервиса hello-world следующим образом:
01
02
03
04
05
06
07
08
09
10
11
|
server.port= 9000 spring.application.name=soap-client ## Soap Service Configuration service.endpoint=http: //localhost:9999/service/hello-world service.soap.action=https: //aggarwalarpit.wordpress.com/hello-world/helloWorld service.user.id=arpit service.user.password=arpit marshaller.packages.to.scan=com.arpit.soap.server.service unmarshaller.packages.to.scan=com.arpit.soap.server.service |
Точка service.endpoint, указанная выше, представляет собой URL-адрес, предоставленный пользователю службы для вызова служб, предоставляемых поставщиком услуг.
service.soap.action указывает, какой процесс или программу необходимо вызвать, когда запрос отправляет запрос службы, а также определяет относительный путь процесса / программы.
marshaller.packages.to.scan указывает пакеты для сканирования во время сортировки перед отправкой запроса на сервер.
unmarshaller.packages.to.scan указывает пакеты для сканирования во время демаршаллинга после получения запроса от сервера.
Теперь мы сгенерируем Java-объекты из WSDL с помощью wsimport и скопируем его в проект soap-client, выполнив следующую команду на терминале:
1
|
wsimport -keep -verbose http: //localhost:9999/service/hello-world?wsdl |
Шаг 10: Перейдите в каталог soap-client и выполните команду: mvn spring-boot: run . Как только команда завершится, мы увидим «Hello World from Arpit» как ответ от мыльного сервиса hello-world на консоли.
Во время работы, если вы получаете сообщение об ошибке — Невозможно выполнить маршалирование, введите «com.arpit.soap.server.service.HelloWorld» в качестве элемента, поскольку отсутствует аннотация @XmlRootElement, затем добавьте @XmlRootElement (name = «helloWorld», namespace = « Http://service.server.soap.arpit.com/ ») в com.arpit.soap.server.service.HelloWorld , где пространство имен должно соответствовать xmlns: ser, определенному в мыльном конверте, как показано ниже:
01
02
03
04
05
06
07
08
09
10
11
12
13
14
|
<soapenv:Envelope xmlns:soapenv= "http://schemas.xmlsoap.org/soap/envelope/" xmlns:ser= "http://service.server.soap.arpit.com/" > <soapenv:Header> <ser:arg1> <userId>arpit</userId> <password>arpit</password> </ser:arg1> </soapenv:Header> <soapenv:Body> <ser:helloWorld> <!--Optional:--> <arg0>Arpit</arg0> </ser:helloWorld> </soapenv:Body> </soapenv:Envelope> |
Полный исходный код размещен на github .
Ссылка: | Написание и использование веб-службы SOAP с помощью Spring от нашего партнера JCG Арпита Аггарвала в блоге |