Spring Integration:HTTP消息转SoapMessage及空请求处理问题
解决方案:同一端点处理SOAP与空POST请求的Spring Integration实现
核心思路
通过Http.inboundGateway统一接收所有POST请求,允许空请求体;利用自定义消息转换器自动将非空XML请求体转换为SoapMessage,再通过路由分别处理SOAP消息和空请求,全程借助Spring Integration及Spring WS的原生能力完成类型转换,无需手动实现String到SoapMessage的转换逻辑。
步骤1:配置依赖
确保项目引入Spring WS核心及SAAJ(SOAP with Attachments API for Java)依赖,用于SOAP消息处理:
<!-- Maven依赖示例 --> <dependency> <groupId>org.springframework.ws</groupId> <artifactId>spring-ws-core</artifactId> <version>3.1.2</version> </dependency> <dependency> <groupId>com.sun.xml.messaging.saaj</groupId> <artifactId>saaj-impl</artifactId> <version>1.5.3</version> </dependency>
步骤2:自定义Http消息转换器
实现AbstractHttpMessageConverter,自动识别空请求体并返回null,非空请求体则用Spring WS的SoapMessageFactory转换为SoapMessage:
import org.springframework.http.HttpInputMessage; import org.springframework.http.HttpOutputMessage; import org.springframework.http.MediaType; import org.springframework.http.converter.AbstractHttpMessageConverter; import org.springframework.http.converter.HttpMessageNotReadableException; import org.springframework.http.converter.HttpMessageNotWritableException; import org.springframework.ws.soap.SoapMessage; import org.springframework.ws.soap.SoapMessageFactory; import javax.xml.soap.SOAPException; import java.io.IOException; import java.util.Collections; public class CustomSoapHttpMessageConverter extends AbstractHttpMessageConverter<Object> { private final SoapMessageFactory soapMessageFactory; public CustomSoapHttpMessageConverter(SoapMessageFactory soapMessageFactory) { super(MediaType.TEXT_XML, MediaType.APPLICATION_XML, MediaType.APPLICATION_SOAP_XML); this.soapMessageFactory = soapMessageFactory; } @Override protected boolean supports(Class<?> clazz) { return SoapMessage.class.isAssignableFrom(clazz) || Void.class.isAssignableFrom(clazz); } @Override protected Object readInternal(Class<?> clazz, HttpInputMessage inputMessage) throws IOException, HttpMessageNotReadableException { InputStream body = inputMessage.getBody(); // 判断请求体是否为空 if (body.available() == 0) { return null; } try { // 利用Spring WS工厂将输入流转换为SoapMessage return soapMessageFactory.createWebServiceMessage(body); } catch (SOAPException e) { throw new HttpMessageNotReadableException("无法创建SOAP消息", e, inputMessage); } } @Override protected void writeInternal(Object payload, HttpOutputMessage outputMessage) throws IOException, HttpMessageNotWritableException { // 处理SOAP响应输出 if (payload instanceof SoapMessage) { ((SoapMessage) payload).writeTo(outputMessage.getBody()); } } }
步骤3:配置Http Inbound Gateway
配置统一接收端点,使用自定义转换器处理请求体转换,并允许空请求体:
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.http.HttpMethod; import org.springframework.integration.http.inbound.HttpRequestHandlingMessagingGateway; import org.springframework.messaging.MessageChannel; import org.springframework.ws.soap.saaj.SaajSoapMessageFactory; @Configuration public class IntegrationConfig { @Bean public HttpRequestHandlingMessagingGateway httpInboundGateway(SoapMessageFactory soapMessageFactory) { HttpRequestHandlingMessagingGateway gateway = new HttpRequestHandlingMessagingGateway(); // 设置端点路径及请求方法 gateway.setRequestMapping(mapping -> mapping.path("/mixed-endpoint").methods(HttpMethod.POST)); // 配置自定义消息转换器 gateway.setMessageConverters(Collections.singletonList(new CustomSoapHttpMessageConverter(soapMessageFactory))); // 允许空请求体 gateway.setEmptyPayloadAccepted(true); // 输出到请求路由通道 gateway.setOutputChannel(requestRoutingChannel()); return gateway; } @Bean public SoapMessageFactory soapMessageFactory() { // 使用SAAJ实现的SOAP消息工厂 return new SaajSoapMessageFactory(); } @Bean public MessageChannel requestRoutingChannel() { return new org.springframework.integration.channel.DirectChannel(); } }
步骤4:配置请求路由
根据请求体是否为null,将请求路由到不同的处理通道:
import org.springframework.context.annotation.Bean; import org.springframework.integration.dsl.IntegrationFlow; import org.springframework.integration.router.ExpressionEvaluatingRouter; import org.springframework.messaging.MessageChannel; @Configuration public class RouterConfig { @Bean public ExpressionEvaluatingRouter requestRouter() { // 通过SpEL表达式判断payload是否为空,路由到对应通道 ExpressionEvaluatingRouter router = new ExpressionEvaluatingRouter("payload == null ? 'emptyRequestChannel' : 'soapProcessingChannel'"); router.setChannelMapping("emptyRequestChannel", emptyRequestChannel()); router.setChannelMapping("soapProcessingChannel", soapProcessingChannel()); return router; } @Bean public IntegrationFlow routingFlow() { return IntegrationFlows.from(requestRoutingChannel()) .route(requestRouter()) .get(); } @Bean public MessageChannel emptyRequestChannel() { return new org.springframework.integration.channel.DirectChannel(); } @Bean public MessageChannel soapProcessingChannel() { return new org.springframework.integration.channel.DirectChannel(); } }
步骤5:实现业务处理逻辑
分别实现空请求和SOAP消息的处理流程:
import org.springframework.context.annotation.Bean; import org.springframework.integration.dsl.IntegrationFlow; import org.springframework.ws.soap.SoapMessage; @Configuration public class HandlerConfig { // 处理空请求的流程 @Bean public IntegrationFlow emptyRequestHandlerFlow() { return IntegrationFlows.from(emptyRequestChannel()) .handle((payload, headers) -> { // 自定义空请求处理逻辑,比如返回默认响应 return "空请求已处理"; }) .get(); } // 处理SOAP消息的流程,直接接收SoapMessage参数 @Bean public IntegrationFlow soapMessageHandlerFlow(SoapMessageService soapMessageService) { return IntegrationFlows.from(soapProcessingChannel()) .handle(soapMessageService) .get(); } @Bean public SoapMessageService soapMessageService() { return new SoapMessageService(); } } // 你的SOAP业务服务类,直接接收SoapMessage参数 public class SoapMessageService { public Object handleSoapMessage(SoapMessage soapMessage) { // 处理SOAP消息逻辑 return soapMessage.getSoapBody().getPayloadSource(); } }
方案优势
- 完全复用Spring原生能力:借助Spring WS的
SoapMessageFactory和消息转换器完成类型转换,无需手动解析XML字符串。 - 逻辑清晰解耦:通过路由分离空请求与SOAP请求的处理逻辑,便于维护扩展。
- 符合协议要求:统一端点接收所有请求,满足同一HTTP端点混合SOAP与空POST的协议需求。
内容的提问来源于stack exchange,提问作者Victoria Antolucci
相关产品推荐
相关产品推荐

