2012-09-12 86 views
5

Necesitamos consumir servicios web desarrollados por otro equipo. Usando JAX-WS para generar los servicios web. Estamos utilizando wsimport para generar los stubs del lado del cliente.Cómo agregar encabezados SOAP a una solicitud SOAP utilizando JAX-WS?

El problema es que necesito para pasar la siguiente información como un encabezado junto con el cuerpo 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> 


Estamos utilizando:

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

para establecer el punto final.

¿Alguien puede sugerir cómo pasar los encabezados con la solicitud?

Gracias, VK

Respuesta

12

uso param header = true de @WebParam anotación

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

header = true, mode = Mode.OUT significa que PARAM headerParam será sólo de la producción en la cabecera.
Si desea que esta este parámetro en la entrada y en la producción, hacer Mode.INOUT

+0

Esta respuesta debería ser aceptada. Concisa y precisa –

6

he tenido que añadir credenciales de usuario en la cabecera así que hice de esta manera:

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); 
} 

Y todo funciona bien. Cada llamada al servicio web viene con nombre de usuario y contraseña pasados ​​a este encabezado. Puede cambiar esto fácilmente para que funcione en su caso.

EDITAR

El código anterior está usando CXF API para modificar cabecera. También he hecho esto usando JAX-WS. Lo hace casi lo mismo, modifica la cabecera para agregar las credenciales de usuario:

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; 
    } 
} 

Y definir este controlador en la configuración Spring así:

<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> 

Todo lo que necesita hacer es poner en práctica SOAPHandler<SOAPMessageContext> interfaz , anule sus métodos y luego puede hacer lo que quiera con un mensaje de SOAP.

+0

Gracias por su respuesta. ¿Puedes publicar el nombre completo de la clase de encabezado? Solo quiero saber si es de jaxws api. – ikvenu2000

+0

El encabezado no es de JAX-WS es de CXF, he editado la respuesta sobre cómo modificar el encabezado en JAX-WS. –

+0

Ese código JAX-WS funcionó perfectamente, ¡gracias! – kai

Cuestiones relacionadas