Spring Boot服务读取消费者SOAP请求体为空问题问询
Spring Boot读取SOAP请求体为null的解决方法
你的问题核心在于:消费者发送的SOAP请求是包裹在Envelope(信封)和Body结构中的,直接用@RequestBody绑定Request对象会因为根节点不匹配、命名空间未正确映射导致解析失败,最终请求体为null。以下是具体解决方案:
1. 定义SOAP信封映射实体类
首先需要创建对应SOAP信封结构的实体类,用JAXB注解处理命名空间和节点映射:
SoapEnvelope.java
import jakarta.xml.bind.annotation.*; @XmlRootElement(name = "Envelope", namespace = "http://schemas.xmlsoap.org/soap/envelope/") @XmlAccessorType(XmlAccessType.FIELD) public class SoapEnvelope { @XmlElement(name = "Body", namespace = "http://schemas.xmlsoap.org/soap/envelope/") private SoapBody body; // Getter & Setter public SoapBody getBody() { return body; } public void setBody(SoapBody body) { this.body = body; } @XmlAccessorType(XmlAccessType.FIELD) public static class SoapBody { @XmlElement(name = "Request", namespace = "http://www.test.com/bs/testing") private Request request; // Getter & Setter public Request getRequest() { return request; } public void setRequest(Request request) { this.request = request; } } }
修正原有实体类的命名空间注解
确保你的Request、Message等实体类正确添加命名空间映射:
Request.java
import jakarta.xml.bind.annotation.*; @XmlAccessorType(XmlAccessType.FIELD) @XmlType(namespace = "http://www.test.com/bs/testing") public class Request { @XmlElement(name = "message", namespace = "http://www.test.com/bs/testing") private Message message; // Getter & Setter public Message getMessage() { return message; } public void setMessage(Message message) { this.message = message; } }
Message.java
import jakarta.xml.bind.annotation.*; @XmlAccessorType(XmlAccessType.FIELD) @XmlType(namespace = "http://www.test.com/bs/testing") public class Message { @XmlElement(name = "m_control", namespace = "http://www.test.com/bs/testing") private MControl mControl; @XmlElement(name = "person", namespace = "http://www.test.com/bs/testing") private Person person; // Getter & Setter public MControl getMControl() { return mControl; } public void setMControl(MControl mControl) { this.mControl = mControl; } public Person getPerson() { return person; } public void setPerson(Person person) { this.person = person; } }
MControl、Person等子实体类同理,需为每个字段添加对应命名空间的@XmlElement注解。
2. 修改控制器代码解析SOAP信封
将控制器的入参改为SoapEnvelope,从信封中提取真正的Request对象:
@RestController @RequiredArgsConstructor @Slf4j public class SoapController { private final SoapService soapService; @RequestMapping(value = "/validate/getResponse", method = RequestMethod.POST, consumes = MediaType.APPLICATION_XML_VALUE, produces = MediaType.APPLICATION_XML_VALUE) public ResponseEntity<Response> readSOAPRequest(@RequestBody SoapEnvelope soapEnvelope) throws Exception { Request request = soapEnvelope.getBody().getRequest(); log.info("Request++: " + request.getMessage().getPerson().getForename()); Response response = soapService.callService(request); return ResponseEntity.ok(response); // 修正返回方式,用ResponseEntity正确包装响应 } }
3. 确保JAXB依赖齐全(Spring Boot 3.x需额外添加)
如果使用Spring Boot 3.x,由于Jakarta EE的变更,需要手动引入JAXB相关依赖:
<!-- pom.xml --> <dependency> <groupId>jakarta.xml.bind</groupId> <artifactId>jakarta.xml.bind-api</artifactId> </dependency> <dependency> <groupId>org.glassfish.jaxb</groupId> <artifactId>jaxb-runtime</artifactId> <scope>runtime</scope> </dependency>
核心原因说明
消费者发送的SOAP请求根节点是soapenv:Envelope,而非直接的ver:Request,Spring默认的XML解析无法跳过信封结构直接绑定内部节点,必须先解析完整的SOAP信封,再逐层提取业务请求对象。
内容的提问来源于stack exchange,提问作者Willingtolearn
相关产品推荐
相关产品推荐

