使用 Spring-WS 路由 WS-Addressing 响应
Route WS-Addressing response with Spring-WS
我在 SOAP Web 服务方面经验不多,尤其是在 WS-Addressing 方面。我正在尝试创建示例,其中根据 WS-Addressing 规范从服务器路由到另一台服务器而不是客户端的响应。但是我遇到了一些问题,我将在下面解释。
因此,有 3 个服务:Client、Server 和 Response-Receiver。
这是客户端的配置:
ClientConfiguration.java
@Configuration
public class ClientConfiguration {
@Bean
public Jaxb2Marshaller marshaller() {
Jaxb2Marshaller marshaller = new Jaxb2Marshaller();
marshaller.setContextPath("my.rinat.country.gen");
return marshaller;
}
@Bean
public CountryWsClient countryWsClient(Jaxb2Marshaller marshaller) {
CountryWsClient client = new CountryWsClient();
client.setMarshaller(marshaller);
client.setUnmarshaller(marshaller);
return client;
}
}
CountryWsClient.java
public class CountryWsClient extends WebServiceGatewaySupport {
public GetCountryResponse getCountry(String name) throws URISyntaxException {
GetCountryRequest request = new GetCountryRequest();
request.setName(name);
var callback = new ActionCallback(
new URI("http://www.rinat.my/country/getCountry"),
new Addressing10(),
new URI("http://localhost:8282/ws")
);
callback.setReplyTo(new EndpointReference(new URI("http://localhost:8282/ws")));
return (GetCountryResponse) getWebServiceTemplate().marshalSendAndReceive("http://localhost:8181/ws", request, callback);
}
}
服务器配置:
WsConfiguration.java
@Configuration
public class WsConfiguration extends WsConfigurationSupport {
public static final String ACTION = "http://www.rinat.my/country/getCountry";
@Bean
public ServletRegistrationBean<MessageDispatcherServlet> messageDispatcherServlet(ApplicationContext applicationContext) {
MessageDispatcherServlet servlet = new MessageDispatcherServlet();
servlet.setApplicationContext(applicationContext);
servlet.setTransformWsdlLocations(true);
return new ServletRegistrationBean<>(servlet, "/ws/*");
}
@Bean(name = "country-ws")
public DefaultWsdl11Definition defaultWsdl11Definition(XsdSchema schema) {
DefaultWsdl11Definition wsdl11Definition = new DefaultWsdl11Definition();
wsdl11Definition.setPortTypeName("CountryPort");
wsdl11Definition.setLocationUri("/ws");
wsdl11Definition.setTargetNamespace("http://www.rinat.my/country/gen");
wsdl11Definition.setSchema(schema);
Properties actions = new Properties();
actions.setProperty("getCountry", ACTION);
wsdl11Definition.setSoapActions(actions);
return wsdl11Definition;
}
@Bean
@Override
public AnnotationActionEndpointMapping annotationActionEndpointMapping() {
var mapping = super.annotationActionEndpointMapping();
mapping.setMessageSender(new HttpComponentsMessageSender());
return mapping;
}
@Bean
public XsdSchema schema() {
return new SimpleXsdSchema(new ClassPathResource("xsd/countries.xsd"));
}
}
CountryEndpoint.java
@Endpoint
public class CountryEndpoint {
private final Countries countries;
public CountryEndpoint(Countries countries) {
this.countries = countries;
}
@Action(WsConfiguration.ACTION)
@ResponsePayload
public GetCountryResponse getCountry(@RequestPayload final GetCountryRequest request) {
GetCountryResponse response = new GetCountryResponse();
response.setCountry(this.countries.findCountry(request.getName()));
return response;
}
}
并且 Response-Receiver 的配置几乎与服务器的配置相同,因为它们使用相同的 xsd-schemas:
WsConfiguration.java
@Configuration
public class WsConfiguration extends WsConfigurationSupport {
@Bean
public ServletRegistrationBean<MessageDispatcherServlet> messageDispatcherServlet(ApplicationContext applicationContext) {
MessageDispatcherServlet servlet = new MessageDispatcherServlet();
servlet.setApplicationContext(applicationContext);
servlet.setTransformWsdlLocations(true);
return new ServletRegistrationBean<>(servlet, "/ws/*");
}
@Bean(name = "country-ws")
public DefaultWsdl11Definition defaultWsdl11Definition(XsdSchema schema) {
DefaultWsdl11Definition wsdl11Definition = new DefaultWsdl11Definition();
wsdl11Definition.setPortTypeName("CountryPort");
wsdl11Definition.setLocationUri("/ws");
wsdl11Definition.setTargetNamespace("http://www.rinat.my/country/gen");
wsdl11Definition.setSchema(schema);
return wsdl11Definition;
}
@Bean
public XsdSchema schema() {
return new SimpleXsdSchema(new ClassPathResource("xsd/countries.xsd"));
}
}
CountryEndpoint.java
@Slf4j
@Endpoint
public class CountryEndpoint {
@PayloadRoot(namespace = "http://www.rinat.my/country/gen", localPart = "getCountryResponse")
@ResponsePayload
public void getCountry(@RequestPayload final GetCountryResponse response) {
var country = response.getCountry();
log.info("Country {} with the capital {}, population {}, and currency {}", country.getName(),
country.getCapital(), country.getPopulation(), country.getCurrency());
}
}
您可以在 github
查看完整示例
当我启动客户端的 WS-Addressing 请求(通过 /kick REST 控制器)时,Response-Receiver 收到来自服务器的响应,但它无法处理它,因为某些 "mustUnderstand headers" 问题(我不明白够了是什么)。这是 Response-Receiver 的日志:
2019-12-12 10:45:01.433 TRACE 17188 --- [nio-8282-exec-1] o.s.ws.server.MessageTracing.received : Received request [<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"><SOAP-ENV:Header xmlns:wsa="http://www.w3.org/2005/08/addressing"><wsa:To SOAP-ENV:mustUnderstand="1">http://localhost:8282/ws</wsa:To><wsa:Action>http://www.rinat.my/country/getCountryResponse</wsa:Action><wsa:MessageID>urn:uuid:340c83d7-6470-444e-b845-cea844e57400</wsa:MessageID><wsa:RelatesTo>urn:uuid:25e481a1-887b-4b28-a921-8615e1a08d83</wsa:RelatesTo></SOAP-ENV:Header><SOAP-ENV:Body><ns2:getCountryResponse xmlns:ns2="http://www.rinat.my/country/gen"><ns2:country><ns2:name>Poland</ns2:name><ns2:population>38186860</ns2:population><ns2:capital>Warsaw</ns2:capital><ns2:currency>PLN</ns2:currency></ns2:country></ns2:getCountryResponse></SOAP-ENV:Body></SOAP-ENV:Envelope>]
2019-12-12 10:45:01.441 WARN 17188 --- [nio-8282-exec-1] o.s.w.soap.server.SoapMessageDispatcher : Could not handle mustUnderstand headers: {http://www.w3.org/2005/08/addressing}To. Returning fault
2019-12-12 10:45:01.450 TRACE 17188 --- [nio-8282-exec-1] o.s.ws.server.MessageTracing.sent : Sent response [<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"><SOAP-ENV:Header/><SOAP-ENV:Body><SOAP-ENV:Fault><faultcode>SOAP-ENV:MustUnderstand</faultcode><faultstring xml:lang="en">One or more mandatory SOAP header blocks not understood</faultstring></SOAP-ENV:Fault></SOAP-ENV:Body></SOAP-ENV:Envelope>] for request [<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"><SOAP-ENV:Header xmlns:wsa="http://www.w3.org/2005/08/addressing"><wsa:To SOAP-ENV:mustUnderstand="1">http://localhost:8282/ws</wsa:To><wsa:Action>http://www.rinat.my/country/getCountryResponse</wsa:Action><wsa:MessageID>urn:uuid:340c83d7-6470-444e-b845-cea844e57400</wsa:MessageID><wsa:RelatesTo>urn:uuid:25e481a1-887b-4b28-a921-8615e1a08d83</wsa:RelatesTo></SOAP-ENV:Header><SOAP-ENV:Body><ns2:getCountryResponse xmlns:ns2="http://www.rinat.my/country/gen"><ns2:country><ns2:name>Poland</ns2:name><ns2:population>38186860</ns2:population><ns2:capital>Warsaw</ns2:capital><ns2:currency>PLN</ns2:currency></ns2:country></ns2:getCountryResponse></SOAP-ENV:Body></SOAP-ENV:Envelope>]
我将不胜感激。
我在 SOAP Web 服务方面经验不多,尤其是在 WS-Addressing 方面。我正在尝试创建示例,其中根据 WS-Addressing 规范从服务器路由到另一台服务器而不是客户端的响应。但是我遇到了一些问题,我将在下面解释。
因此,有 3 个服务:Client、Server 和 Response-Receiver。
这是客户端的配置:
ClientConfiguration.java
@Configuration
public class ClientConfiguration {
@Bean
public Jaxb2Marshaller marshaller() {
Jaxb2Marshaller marshaller = new Jaxb2Marshaller();
marshaller.setContextPath("my.rinat.country.gen");
return marshaller;
}
@Bean
public CountryWsClient countryWsClient(Jaxb2Marshaller marshaller) {
CountryWsClient client = new CountryWsClient();
client.setMarshaller(marshaller);
client.setUnmarshaller(marshaller);
return client;
}
}
CountryWsClient.java
public class CountryWsClient extends WebServiceGatewaySupport {
public GetCountryResponse getCountry(String name) throws URISyntaxException {
GetCountryRequest request = new GetCountryRequest();
request.setName(name);
var callback = new ActionCallback(
new URI("http://www.rinat.my/country/getCountry"),
new Addressing10(),
new URI("http://localhost:8282/ws")
);
callback.setReplyTo(new EndpointReference(new URI("http://localhost:8282/ws")));
return (GetCountryResponse) getWebServiceTemplate().marshalSendAndReceive("http://localhost:8181/ws", request, callback);
}
}
服务器配置:
WsConfiguration.java
@Configuration
public class WsConfiguration extends WsConfigurationSupport {
public static final String ACTION = "http://www.rinat.my/country/getCountry";
@Bean
public ServletRegistrationBean<MessageDispatcherServlet> messageDispatcherServlet(ApplicationContext applicationContext) {
MessageDispatcherServlet servlet = new MessageDispatcherServlet();
servlet.setApplicationContext(applicationContext);
servlet.setTransformWsdlLocations(true);
return new ServletRegistrationBean<>(servlet, "/ws/*");
}
@Bean(name = "country-ws")
public DefaultWsdl11Definition defaultWsdl11Definition(XsdSchema schema) {
DefaultWsdl11Definition wsdl11Definition = new DefaultWsdl11Definition();
wsdl11Definition.setPortTypeName("CountryPort");
wsdl11Definition.setLocationUri("/ws");
wsdl11Definition.setTargetNamespace("http://www.rinat.my/country/gen");
wsdl11Definition.setSchema(schema);
Properties actions = new Properties();
actions.setProperty("getCountry", ACTION);
wsdl11Definition.setSoapActions(actions);
return wsdl11Definition;
}
@Bean
@Override
public AnnotationActionEndpointMapping annotationActionEndpointMapping() {
var mapping = super.annotationActionEndpointMapping();
mapping.setMessageSender(new HttpComponentsMessageSender());
return mapping;
}
@Bean
public XsdSchema schema() {
return new SimpleXsdSchema(new ClassPathResource("xsd/countries.xsd"));
}
}
CountryEndpoint.java
@Endpoint
public class CountryEndpoint {
private final Countries countries;
public CountryEndpoint(Countries countries) {
this.countries = countries;
}
@Action(WsConfiguration.ACTION)
@ResponsePayload
public GetCountryResponse getCountry(@RequestPayload final GetCountryRequest request) {
GetCountryResponse response = new GetCountryResponse();
response.setCountry(this.countries.findCountry(request.getName()));
return response;
}
}
并且 Response-Receiver 的配置几乎与服务器的配置相同,因为它们使用相同的 xsd-schemas:
WsConfiguration.java
@Configuration
public class WsConfiguration extends WsConfigurationSupport {
@Bean
public ServletRegistrationBean<MessageDispatcherServlet> messageDispatcherServlet(ApplicationContext applicationContext) {
MessageDispatcherServlet servlet = new MessageDispatcherServlet();
servlet.setApplicationContext(applicationContext);
servlet.setTransformWsdlLocations(true);
return new ServletRegistrationBean<>(servlet, "/ws/*");
}
@Bean(name = "country-ws")
public DefaultWsdl11Definition defaultWsdl11Definition(XsdSchema schema) {
DefaultWsdl11Definition wsdl11Definition = new DefaultWsdl11Definition();
wsdl11Definition.setPortTypeName("CountryPort");
wsdl11Definition.setLocationUri("/ws");
wsdl11Definition.setTargetNamespace("http://www.rinat.my/country/gen");
wsdl11Definition.setSchema(schema);
return wsdl11Definition;
}
@Bean
public XsdSchema schema() {
return new SimpleXsdSchema(new ClassPathResource("xsd/countries.xsd"));
}
}
CountryEndpoint.java
@Slf4j
@Endpoint
public class CountryEndpoint {
@PayloadRoot(namespace = "http://www.rinat.my/country/gen", localPart = "getCountryResponse")
@ResponsePayload
public void getCountry(@RequestPayload final GetCountryResponse response) {
var country = response.getCountry();
log.info("Country {} with the capital {}, population {}, and currency {}", country.getName(),
country.getCapital(), country.getPopulation(), country.getCurrency());
}
}
您可以在 github
查看完整示例当我启动客户端的 WS-Addressing 请求(通过 /kick REST 控制器)时,Response-Receiver 收到来自服务器的响应,但它无法处理它,因为某些 "mustUnderstand headers" 问题(我不明白够了是什么)。这是 Response-Receiver 的日志:
2019-12-12 10:45:01.433 TRACE 17188 --- [nio-8282-exec-1] o.s.ws.server.MessageTracing.received : Received request [<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"><SOAP-ENV:Header xmlns:wsa="http://www.w3.org/2005/08/addressing"><wsa:To SOAP-ENV:mustUnderstand="1">http://localhost:8282/ws</wsa:To><wsa:Action>http://www.rinat.my/country/getCountryResponse</wsa:Action><wsa:MessageID>urn:uuid:340c83d7-6470-444e-b845-cea844e57400</wsa:MessageID><wsa:RelatesTo>urn:uuid:25e481a1-887b-4b28-a921-8615e1a08d83</wsa:RelatesTo></SOAP-ENV:Header><SOAP-ENV:Body><ns2:getCountryResponse xmlns:ns2="http://www.rinat.my/country/gen"><ns2:country><ns2:name>Poland</ns2:name><ns2:population>38186860</ns2:population><ns2:capital>Warsaw</ns2:capital><ns2:currency>PLN</ns2:currency></ns2:country></ns2:getCountryResponse></SOAP-ENV:Body></SOAP-ENV:Envelope>]
2019-12-12 10:45:01.441 WARN 17188 --- [nio-8282-exec-1] o.s.w.soap.server.SoapMessageDispatcher : Could not handle mustUnderstand headers: {http://www.w3.org/2005/08/addressing}To. Returning fault
2019-12-12 10:45:01.450 TRACE 17188 --- [nio-8282-exec-1] o.s.ws.server.MessageTracing.sent : Sent response [<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"><SOAP-ENV:Header/><SOAP-ENV:Body><SOAP-ENV:Fault><faultcode>SOAP-ENV:MustUnderstand</faultcode><faultstring xml:lang="en">One or more mandatory SOAP header blocks not understood</faultstring></SOAP-ENV:Fault></SOAP-ENV:Body></SOAP-ENV:Envelope>] for request [<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"><SOAP-ENV:Header xmlns:wsa="http://www.w3.org/2005/08/addressing"><wsa:To SOAP-ENV:mustUnderstand="1">http://localhost:8282/ws</wsa:To><wsa:Action>http://www.rinat.my/country/getCountryResponse</wsa:Action><wsa:MessageID>urn:uuid:340c83d7-6470-444e-b845-cea844e57400</wsa:MessageID><wsa:RelatesTo>urn:uuid:25e481a1-887b-4b28-a921-8615e1a08d83</wsa:RelatesTo></SOAP-ENV:Header><SOAP-ENV:Body><ns2:getCountryResponse xmlns:ns2="http://www.rinat.my/country/gen"><ns2:country><ns2:name>Poland</ns2:name><ns2:population>38186860</ns2:population><ns2:capital>Warsaw</ns2:capital><ns2:currency>PLN</ns2:currency></ns2:country></ns2:getCountryResponse></SOAP-ENV:Body></SOAP-ENV:Envelope>]
我将不胜感激。