如何使用JAX-WS将SOAP头添加到SOAP请求?

问题描述:

我们需要使用其他团队开发的webservices。使用JAX-WS生成Web服务。我们使用wsimport来生成客户端存根。如何使用JAX-WS将SOAP头添加到SOAP请求?

的问题是,我需要通过以下信息作为头与SOAP体沿:

<soapenv:Header> 
    <ns1:HeaderData xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd" 
        xmlns:ns1="http://www.example.com/esb/data_type/HeaderData/v1"> 
     <ChannelIdentifier>ABC</ChannelIdentifier> 
    </ns1:HeaderData> 
</soapenv:Header> 


我们使用:

BindingProvider.getRequestContext().put(
    BindingProvider.ENDPOINT_ADDRESS_PROPERTY, 
    serviceConfig.getServiceEndPoint() 
); 

设置终点。

任何人都可以建议如何传递标头与请求?

谢谢, VK

使用PARAM header = true@WebParam注释

@WebMethod 
@WebResult String method(
     @WebParam String anotherParam 
     @WebParam(header = true, mode = Mode.OUT) Holder<String> headerParam) 

header = true, mode = Mode.OUT意味着PARAM headerParam将仅在首部输出。
如果你想这个这个PARAM输入和输出,使Mode.INOUT

+0

这个答案应该被接受。简洁而准确。 –

我不得不添加的用户凭据到页眉所以我做了这样的:

private void modifyRequest(String username, String password) { 
    UserCredentials authHeader = new UserCredentials(); 
    authHeader.setUsername(username); 
    authHeader.setPassword(password); 
    ArrayList<Header> headers = new ArrayList<Header>(1); 
    try { 
     Header soapHeader = new Header(new QName(TQIntegrationV2.TQIntegrationV2Soap.getNamespaceURI(), "UserCredentials"), authHeader, new JAXBDataBinding(UserCredentials.class)); 
     headers.add(soapHeader); 
    } catch (JAXBException ex) { 
     LOGGER.error("Exception trying to serialize header: {}", ex); 
    } 
    ((BindingProvider) proxy).getRequestContext().put(Header.HEADER_LIST, headers); 
} 

,一切工作正常。每次对Web服务的调用都附带传递给此标头的用户名和密码。你可以很容易地改变这个在你的情况下工作。

EDIT

上面的代码使用CXF API来修改标头。我也使用JAX-WS来完成此操作。它几乎是相同的,修改标题添加的用户凭据:

public class MyHandler implements SOAPHandler<SOAPMessageContext> { 

    private static final Logger LOGGER = LoggerFactory.getLogger(MyHandler.class); 

    private String username; 

    private String password; 

    /** 
    * Handles SOAP message. If SOAP header does not already exist, then method will created new SOAP header. The 
    * username and password is added to the header as the credentials to authenticate user. If no user credentials is 
    * specified every call to web service will fail. 
    * 
    * @param context SOAP message context to get SOAP message from 
    * @return true 
    */ 
    @Override 
    public boolean handleMessage(SOAPMessageContext context) { 
     try { 
      SOAPMessage message = context.getMessage(); 
      SOAPHeader header = message.getSOAPHeader(); 
      SOAPEnvelope envelope = message.getSOAPPart().getEnvelope(); 
      if (header == null) { 
       header = envelope.addHeader(); 
      } 
      QName qNameUserCredentials = new QName("https://your.target.namespace/", "UserCredentials"); 
      SOAPHeaderElement userCredentials = header.addHeaderElement(qNameUserCredentials); 

      QName qNameUsername = new QName("https://your.target.namespace/", "Username"); 
      SOAPHeaderElement username = header.addHeaderElement(qNameUsername); 
      username.addTextNode(this.username); 
      QName qNamePassword = new QName("https://your.target.namespace/", "Password"); 
      SOAPHeaderElement password = header.addHeaderElement(qNamePassword); 
      password.addTextNode(this.password); 

      userCredentials.addChildElement(username); 
      userCredentials.addChildElement(password); 

      message.saveChanges(); 
      //TODO: remove this writer when the testing is finished 
      StringWriter writer = new StringWriter(); 
      message.writeTo(new StringOutputStream(writer)); 
      LOGGER.debug("SOAP message: \n" + writer.toString()); 
     } catch (SOAPException e) { 
      LOGGER.error("Error occurred while adding credentials to SOAP header.", e); 
     } catch (IOException e) { 
      LOGGER.error("Error occurred while writing message to output stream.", e); 
     } 
     return true; 
    } 

    //TODO: remove this class after testing is finished 
    private static class StringOutputStream extends OutputStream { 

     private StringWriter writer; 

     public StringOutputStream(StringWriter writer) { 
      this.writer = writer; 
     } 

     @Override 
     public void write(int b) throws IOException { 
      writer.write(b); 
     } 
    } 

    @Override 
    public boolean handleFault(SOAPMessageContext context) { 
     LOGGER.debug("handleFault has been invoked."); 
     return true; 
    } 

    @Override 
    public void close(MessageContext context) { 
     LOGGER.debug("close has been invoked."); 
    } 

    @Override 
    public Set<QName> getHeaders() { 
     LOGGER.debug("getHeaders has been invoked."); 
     return null; 
    } 

    public void setUsername(String username) { 
     this.username = username; 
    } 

    public void setPassword(String password) { 
     this.password = password; 
    } 
} 

我在Spring配置定义该处理程序是这样的:

<bean id="soapHandler" class="your.package.MyHandler"> 
    <property name="username" value="testUser"/> 
    <property name="password" value="testPassword"/> 
</bean> 

<jaxws:client "..."> 
    <jaxws:handlers> 
     <ref bean="soapHandler"/> 
    </jaxws:handlers> 
</jaxws:client> 

所有你需要做的是落实SOAPHandler<SOAPMessageContext>接口,重写它的方法,然后你可以用SOAP消息做你想做的事。

+0

感谢您的回复。你能发布Header类的完全限定名吗?只是想找出它是否来自jaxws api。 – ikvenu2000

+0

头文件不是来自CXF的JAX-WS,而是编辑了如何修改JAX-WS头文件的答案。 –

+0

JAX-WS代码完美工作,谢谢! – kai