soapenv services java spring http header spring-ws

java - services - Configuración dinámica de un encabezado HTTP con el cliente Spring-WS



web service client soap header java (7)

¿Cómo se configura dinámicamente un encabezado HTTP personalizado (no un encabezado SOAP) en el lado del cliente cuando se usa Spring-WS?


Al usar Spring Integration 3 y Spring Integration-WS, se puede usar el siguiente código para manejar la solicitud:

public boolean handleRequest(MessageContext messageContext) throws WebServiceClientException { TransportContext context = TransportContextHolder.getTransportContext(); HttpUrlConnection connection = (HttpUrlConnection) context .getConnection(); connection.getConnection().addRequestProperty("HEADERNAME", "HEADERVALUE"); return true; }

El Interceptor se puede conectar a la pasarela de salida de la siguiente manera:

<ws:outbound-gateway ... interceptor="addPasswordHeaderInterceptor" > </ws:outbound-gateway> <bean id="addPasswordHeaderInterceptor class="com.yourfirm.YourHttpInterceptor" />


Ejemplo de método con java 1.8: Cómo agregar un encabezado HTTP:

public void executeObjectWebservice(String id) { ExecuteObject request = new ExecuteObject(); getWebServiceTemplate().marshalSendAndReceive("http://url/webservice-test/uc4ws", new ObjectFactory().createExecuteObject(request), new WebServiceMessageCallback() { public void doWithMessage(WebServiceMessage message) throws IOException { TransportContext context = TransportContextHolder.getTransportContext(); HttpUrlConnection connection = (HttpUrlConnection) context.getConnection(); connection.addRequestHeader("ID", id); } }); }

Explicación : use getWebServiceTemplate (). MarshalSendAndReceive como se describe, por ejemplo, aquí: https://spring.io/guides/gs/consuming-web-service/

El primer parámetro es el URI, el segundo es el objeto que se enviará con la solicitud. Como tercer parámetro puede agregar como función

new WebServiceMessageCallback()

donde se anula el public void doWithMessage . Este método se llama antes de que se envíe la solicitud. Dentro de usted puede acceder al mensaje y agregar un encabezado de solicitud a través de

TransportContext context = TransportContextHolder.getTransportContext(); HttpUrlConnection connection = (HttpUrlConnection) context.getConnection(); connection.addRequestHeader("ID", id);


El método webServiceTemplate.marshalSendAndReceive (request) de Spring usa internamente HttpComponentsMessageSender para enviar el mensaje SOAP a través de la red y esto también usa WebServiceConnection para establecer una conexión http con el servidor. Todo lo que tiene que hacer es escribir su propio HttpComponentsMessageSender y configurar la cookie dentro de PostMethod.

Código del remitente:

package com.swap.ws.sender; import java.io.IOException; import java.net.URI; import javax.annotation.Resource; import org.apache.http.client.methods.HttpPost; import org.apache.log4j.Logger; import org.springframework.stereotype.Service; import org.springframework.ws.transport.WebServiceConnect ion; import org.springframework.ws.transport.http.HttpComponen tsConnection; /** * * @author swapnil Z */ @Service("urlMessageSender") public class CustomHttpComponentsMessageSender extends org.springframework.ws.transport.http.HttpComponen tsMessageSender { private static Logger _logger = Logger.getLogger(""); @Override public WebServiceConnection createConnection(URI uri) throws IOException { String cookie = null; HttpComponentsConnection conn = (HttpComponentsConnection) super .createConnection(uri); HttpPost postMethod = conn.getHttpPost(); cookie = "<Your Custom Cookie>"; postMethod.addHeader("Cookie", cookie); return conn; } }

Configuración de primavera:

<bean id="messageFactory" class="org.springframework.ws.soap.saaj.SaajSoapMe ssageFactory" /> <bean id="marshaller" class="org.springframework.oxm.jaxb.Jaxb2Marshalle r"> <property name="contextPath" value="com.swap.provision" /> </bean> <bean id="webServiceTemplate" class="org.springframework.ws.client.core.WebServi ceTemplate"> <constructor-arg ref="messageFactory" /> <property name="marshaller" ref="marshaller"></property> <property name="unmarshaller" ref="marshaller"></property> <property name="messageSender" ref="urlMessageSender"/> <property name="defaultUri" value=<Server URL> /> </bean>

Después de esto simplemente obtengo bean webServiceTemplate y llamo al método marshalSendAndReceive. Por lo tanto, cada solicitud tendrá su cookie personalizada establecida antes de hacer una llamada HTTP.


El siguiente fragmento ha sido probado con Spring 4.0. Agrega un WebServiceMessageCallback a un org.springframework.ws.client.core.WebServiceTemplate

final String DYNAMICVALUE = "myDynamo"; WebServiceMessageCallback wsCallback = new WebServiceMessageCallback() { public void doWithMessage(WebServiceMessage message) { try { SoapMessage soapMessage = (SoapMessage)message; SoapHeader header = soapMessage.getSoapHeader(); header.addAttribute(new QName("myHeaderElement"), DYNAMICVALUE); } catch (Exception e) { e.printStackTrace(); } } }; JAXBElement<MyWsResponse> response = (JAXBElement<MyWsResponse>) wsTemplate.marshalSendAndReceive(MyWsOP, wsCallback);


En realidad, es una versión actualizada de la respuesta de , pero proporciona una nueva API Spring-WS, métodos abreviados de Java 8 y se preocupa por crear una instancia de WebServiceMessageCallback con un método separado.

Creo que es más obvio y autosuficiente.

final class Service extends WebServiceGatewaySupport { /** * @param URL the URI to send the message to * @param payload the object to marshal into the request message payload * @param headers HTTP headers to add to the request */ public Object performRequestWithHeaders(String URL, Object payload, Map<String, String> headers) { return getWebServiceTemplate() .marshalSendAndReceive(URL, payload, getRequestCallback(headers)); } /** * Returns a {@code WebServiceMessageCallback} instance with custom HTTP headers. */ private WebServiceMessageCallback getRequestCallback(Map<String, String> headers) { return message -> { TransportContext context = TransportContextHolder.getTransportContext(); HttpUrlConnection connection = (HttpUrlConnection)context.getConnection(); addHeadersToConnection(connection, headers); }; } /** * Adds all headers from the {@code headers} to the {@code connection}. */ private void addHeadersToConnection(HttpUrlConnection connection, Map<String, String> headers){ headers.forEach((name, value) -> { try { connection.addRequestHeader(name, value); } catch (IOException e) { e.printStackTrace(); // or whatever you want } }); } }


ClientInterceptor funciona muy bien para el valor del encabezado estático. Pero no es posible usarlo cuando se debe aplicar un valor diferente para cada solicitud. En ese caso, WebServiceMessageCallback es útil:

final String dynamicParameter = //... webServiceOperations.marshalSendAndReceive(request, new WebServiceMessageCallback() { void doWithMessage(WebServiceMessage message) { TransportContext context = TransportContextHolder.getTransportContext(); CommonsHttpConnection connection = (CommonsHttpConnection) context.getConnection(); PostMethod postMethod = connection.getPostMethod(); postMethod.addRequestHeader( "fsreqid", dynamicParameter ); } }


public class AddHttpHeaderInterceptor implements ClientInterceptor { public boolean handleFault(MessageContext messageContext) throws WebServiceClientException { return true; } public boolean handleRequest(MessageContext messageContext) throws WebServiceClientException { TransportContext context = TransportContextHolder.getTransportContext(); CommonsHttpConnection connection = (CommonsHttpConnection) context.getConnection(); PostMethod postMethod = connection.getPostMethod(); postMethod.addRequestHeader( "fsreqid", "123456" ); return true; } public boolean handleResponse(MessageContext messageContext) throws WebServiceClientException { return true; } }

config:

<bean id="webServiceTemplate" class="org.springframework.ws.client.core.WebServiceTemplate"> ... <property name="interceptors"> <list> <bean class="com.blah.AddHttpHeaderInterceptor" /> </list> </property> </bean>