使用CXF 3.5.9如何强制修改SOAP响应中的ns2标签为a标签
解决CXF 3.5.9中SOAP响应命名空间前缀替换问题
要把SOAP响应里的<ns2:>前缀强制换成<a:>,可以用下面两种靠谱的方法:
方法一:配置自定义命名空间前缀映射(推荐)
CXF支持通过NamespacePrefixMapper指定命名空间对应的前缀,直接配置就能替换默认生成的ns2这类自动前缀。
- 实现自定义的NamespacePrefixMapper:
import com.sun.xml.bind.marshaller.NamespacePrefixMapper; public class CustomNamespacePrefixMapper extends NamespacePrefixMapper { @Override public String getPreferredPrefix(String namespaceUri, String suggestion, boolean requirePrefix) { // 匹配你的服务命名空间,返回指定前缀 if ("http://www.example.com/service/".equals(namespaceUri)) { return "a"; } // 其他命名空间沿用默认前缀 return suggestion; } }
- 配置到CXF端点:
如果用Spring配置:
<jaxws:endpoint id="authService" implementor="com.example.AuthServiceImpl" address="/AuthService"> <jaxws:properties> <entry key="jaxb.namespacePrefixMapper" value-ref="customNamespacePrefixMapper"/> </jaxws:properties> </jaxws:endpoint> <bean id="customNamespacePrefixMapper" class="com.example.CustomNamespacePrefixMapper"/>
如果用代码创建端点:
AuthServiceImpl serviceImpl = new AuthServiceImpl(); Endpoint endpoint = Endpoint.publish("/AuthService", serviceImpl); Map<String, Object> props = new HashMap<>(); props.put("jaxb.namespacePrefixMapper", new CustomNamespacePrefixMapper()); endpoint.setProperties(props);
方法二:编写正确的出站拦截器
如果配置映射器没生效,或者需要更灵活的XML内容处理,可以写一个出站拦截器,在SOAP消息发送前修改内容:
import org.apache.cxf.binding.soap.SoapMessage; import org.apache.cxf.interceptor.Fault; import org.apache.cxf.phase.AbstractPhaseInterceptor; import org.apache.cxf.phase.Phase; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.InputStream; import java.io.OutputStream; import java.nio.charset.StandardCharsets; public class SoapPrefixReplaceInterceptor extends AbstractPhaseInterceptor<SoapMessage> { public SoapPrefixReplaceInterceptor() { // 选择在消息准备发送的阶段拦截 super(Phase.MESSAGE_OUT); } @Override public void handleMessage(SoapMessage message) throws Fault { try { // 替换输出流,捕获生成的SOAP XML OutputStream originalOut = message.getContent(OutputStream.class); ByteArrayOutputStream baos = new ByteArrayOutputStream(); message.setContent(OutputStream.class, baos); // 执行后续拦截器,让内容写入临时流 message.getInterceptorChain().doIntercept(message); // 读取XML内容,替换前缀和命名空间声明 String soapXml = baos.toString(StandardCharsets.UTF_8.name()); soapXml = soapXml.replaceAll("xmlns:ns2=\"http://www.example.com/service/\"", "xmlns:a=\"http://www.example.com/service/\""); soapXml = soapXml.replaceAll("<ns2:", "<a:"); soapXml = soapXml.replaceAll("</ns2:", "</a:"); // 将修改后的内容写回原输出流 InputStream is = new ByteArrayInputStream(soapXml.getBytes(StandardCharsets.UTF_8)); byte[] buffer = new byte[1024]; int len; while ((len = is.read(buffer)) != -1) { originalOut.write(buffer, 0, len); } originalOut.flush(); // 恢复消息的输出流配置 message.setContent(OutputStream.class, originalOut); } catch (Exception e) { throw new Fault(e); } } }
将拦截器添加到出站链:
Spring配置方式:
<jaxws:endpoint id="authService" implementor="com.example.AuthServiceImpl" address="/AuthService"> <jaxws:outInterceptors> <bean class="com.example.SoapPrefixReplaceInterceptor"/> </jaxws:outInterceptors> </jaxws:endpoint>
代码方式:
AuthServiceImpl serviceImpl = new AuthServiceImpl(); Endpoint endpoint = Endpoint.publish("/AuthService", serviceImpl); endpoint.getOutInterceptors().add(new SoapPrefixReplaceInterceptor());
验证效果
配置完成后,就能得到你期望的响应格式:
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"> <soapenv:Body> <a:authResponse status="fail" xmlns:a="http://www.example.com/service/"> <errorMessage>user not found</errorMessage> </a:authResponse> </soapenv:Body> </soapenv:Envelope>
内容的提问来源于stack exchange,提问作者almotawir
相关产品推荐
相关产品推荐

