【问题标题】:How to add SOAP headers to a SOAP request using JAX-WS?如何使用 JAX-WS 将 SOAP 标头添加到 SOAP 请求?
【发布时间】:2012-09-12 12:49:03
【问题描述】:

我们需要使用其他团队开发的 web 服务。使用JAX-WS 生成网络服务。我们正在使用 wsimport 来生成客户端存根。

问题是我需要将以下信息作为标头与 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

【问题讨论】:

    标签: soap jax-ws soapheader


    【解决方案1】:

    使用@WebParam 注释的参数header = true

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

    header = true, mode = Mode.OUT 表示参数headerParam 将仅在标头中输出。
    如果您希望在输入和输出中使用此参数,请设置为 Mode.INOUT

    【讨论】:

      【解决方案2】:

      我必须将用户凭据添加到标题中,所以我做了这样的:

      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 服务的每次调用都带有传递给此标头的用户名和密码。您可以轻松地将其更改为适用于您的情况。

      编辑

      上面的代码使用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&lt;SOAPMessageContext&gt; 接口,覆盖其方法,然后您可以使用SOAP 消息做任何您想做的事情。

      【讨论】:

      • 感谢您的回复。您可以发布 Header 类的完全限定名称吗?就是想看看是不是来自jaxws api。
      • 标头不是来自 JAX-WS 而是来自 CXF,我已经编辑了如何修改 JAX-WS 中的标头的答案。
      猜你喜欢
      • 2011-01-20
      • 2010-10-24
      • 2011-05-02
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-11-27
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多