如何在JAX-WS中自定义SOAP响应信封的<soapenv:Header>部分?
自定义JAX-WS SOAP响应Header的几种实现方式
嘿,我来帮你搞定JAX-WS里自定义SOAP响应Header的需求!根据你的场景,我整理了几种实用的方法,你可以根据自己的需求选最合适的:
方法1:用SOAP Handler(最灵活,全局生效)
如果你的Web服务所有方法都需要添加相同的自定义Header,或者Header的逻辑比较复杂,推荐用Handler的方式。它能统一拦截请求和响应,自定义SOAP信封的内容。
步骤1:创建自定义SOAP Handler类
import javax.xml.namespace.QName; import javax.xml.soap.*; import javax.xml.ws.handler.MessageContext; import javax.xml.ws.handler.soap.SOAPHandler; import javax.xml.ws.handler.soap.SOAPMessageContext; import java.util.Set; public class CustomResponseHeaderHandler implements SOAPHandler<SOAPMessageContext> { @Override public Set<QName> getHeaders() { // 返回你要处理的Header的QName,这里可以自定义 return Set.of(new QName("http://your-custom-namespace.com", "CustomHeader")); } @Override public boolean handleMessage(SOAPMessageContext context) { // 判断是响应消息(OUTBOUND)才处理 Boolean isOutbound = (Boolean) context.get(MessageContext.MESSAGE_OUTBOUND_PROPERTY); if (isOutbound) { try { SOAPMessage soapMsg = context.getMessage(); SOAPEnvelope envelope = soapMsg.getSOAPPart().getEnvelope(); SOAPHeader header = envelope.getHeader(); // 如果Header不存在,创建一个 if (header == null) { header = envelope.addHeader(); } // 创建自定义Header元素,这里替换成你需要的内容 QName customHeaderQName = new QName("http://your-custom-namespace.com", "CustomHeader", "custom"); SOAPHeaderElement customHeader = header.addHeaderElement(customHeaderQName); // 添加Header的子元素,比如用户信息、签名等 SOAPElement userId = customHeader.addChildElement("UserId", "custom"); userId.addTextNode("123456"); SOAPElement timestamp = customHeader.addChildElement("Timestamp", "custom"); timestamp.addTextNode(String.valueOf(System.currentTimeMillis())); // 保存修改后的消息 soapMsg.saveChanges(); } catch (SOAPException e) { e.printStackTrace(); return false; } } return true; } @Override public boolean handleFault(SOAPMessageContext context) { // 处理错误消息的逻辑,可选 return true; } @Override public void close(MessageContext context) { // 资源清理,可选 } }
步骤2:注册Handler到Web服务
有两种注册方式:
- 方式A:用@HandlerChain注解
在你的Web服务实现类上添加注解,指定Handler配置文件:
import javax.jws.WebMethod; import javax.jws.WebService; import javax.xml.ws.HandlerChain; @WebService @HandlerChain(file = "handler-chain.xml") public class YourWebService { @WebMethod public String yourMethod(String param) { return "Response: " + param; } }
然后在src/main/resources下创建handler-chain.xml:
<?xml version="1.0" encoding="UTF-8"?> <handler-chains xmlns="http://java.sun.com/xml/ns/javaee"> <handler-chain> <handler> <handler-name>CustomResponseHeaderHandler</handler-name> <handler-class>com.yourpackage.CustomResponseHeaderHandler</handler-class> </handler> </handler-chain> </handler-chains>
- 方式B:在sun-jaxws.xml中配置
如果是用GlassFish等支持Sun JAX-WS的容器,可以在WEB-INF下创建sun-jaxws.xml:
<?xml version="1.0" encoding="UTF-8"?> <endpoints xmlns="http://java.sun.com/xml/ns/jax-ws/ri/runtime" version="2.0"> <endpoint name="YourWebService" implementation="com.yourpackage.YourWebService" url-pattern="/your-service-url"> <handler-chains> <handler-chain> <handler> <handler-name>CustomResponseHeaderHandler</handler-name> <handler-class>com.yourpackage.CustomResponseHeaderHandler</handler-class> </handler> </handler-chain> </handler-chains> </endpoint> </endpoints>
方法2:用@WebParam(header=true)(简单Header,单个方法生效)
如果只是某个WebMethod需要添加简单的Header参数,直接用注解就能让JAX-WS自动生成对应的Header,不用写Handler。
示例代码:
import javax.jws.WebMethod; import javax.jws.WebParam; import javax.jws.WebService; import javax.xml.ws.Holder; @WebService public class YourWebService { @WebMethod public String yourMethod( @WebParam(name = "InputParam") String inputParam, // 输出Header参数,用Holder包装 @WebParam(name = "CustomHeader", header = true, mode = WebParam.Mode.OUT) Holder<String> customHeader) { // 设置Header的值 customHeader.value = "This is a custom header value"; return "Response: " + inputParam; } }
这种方式会在响应的SOAP Header里自动添加一个<CustomHeader>元素,值就是你设置的内容。适合简单的场景,不用写复杂的Handler。
方法3:直接操作SOAPMessageContext(方法内部动态生成)
如果你需要在WebMethod内部根据业务逻辑动态生成Header,可以直接获取SOAPMessageContext来操作。
示例代码:
import javax.jws.WebMethod; import javax.jws.WebService; import javax.xml.soap.*; import javax.xml.ws.WebServiceContext; import javax.xml.ws.handler.MessageContext; import javax.annotation.Resource; @WebService public class YourWebService { // 注入WebServiceContext @Resource private WebServiceContext webServiceContext; @WebMethod public String yourMethod(String param) { MessageContext msgContext = webServiceContext.getMessageContext(); Boolean isOutbound = (Boolean) msgContext.get(MessageContext.MESSAGE_OUTBOUND_PROPERTY); if (isOutbound) { try { SOAPMessage soapMsg = (SOAPMessage) msgContext.get(MessageContext.SOAP_MESSAGE); SOAPEnvelope envelope = soapMsg.getSOAPPart().getEnvelope(); SOAPHeader header = envelope.getHeader(); if (header == null) { header = envelope.addHeader(); } // 自定义Header内容,和Handler里的逻辑类似 QName qName = new QName("http://your-namespace", "DynamicHeader", "dyn"); SOAPHeaderElement headerElement = header.addHeaderElement(qName); headerElement.addTextNode("Dynamic header generated in method"); soapMsg.saveChanges(); } catch (SOAPException e) { e.printStackTrace(); } } return "Response: " + param; } }
注意事项
- 一定要注意命名空间的正确性,自定义Header的命名空间要和你目标SOAP信封的命名空间匹配,否则可能解析失败。
- 如果是处理响应,一定要判断
MESSAGE_OUTBOUND_PROPERTY为true,避免修改请求消息。 - 不同的JAX-WS实现(比如Metro、CXF)可能有细微差别,上面的代码基于标准JAX-WS API,大部分容器都支持。
内容的提问来源于stack exchange,提问作者lrente
相关产品推荐
相关产品推荐

