Для полноты картины и для помощи другим в подобных ситуациях я хотел бы проиллюстрировать самое чистое решение IMHO с использованием JAX-WS-handler-chain:
1) Подкласс вашего класса обслуживания (не класса порта) в другом (не сгенерированном) пакете. Поскольку сервисный класс (и весь его пакет), вероятно, был сгенерирован из WSDL, ваши изменения в подклассе не будут потеряны при обновлении вашего сервисного класса после изменения WSDL.
2) Аннотируйте свой подкласс службы следующим образом (импорт javax.jws.HandlerChain
):
@HandlerChain(file="HandlerChain.xml")
public class MyService extends GeneratedService {
3) Создайте файл с именем HandlerChain.xml
в том же пакете, что и ваш подкласс службы, т. Е. Рядом с MyService
, со следующим содержимым:
<?xml version="1.0" encoding="UTF-8"?>
<handler-chains xmlns="http://java.sun.com/xml/ns/javaee">
<handler-chain>
<handler>
<handler-name>co.codewizards.example.HttpHeaderExtensionSOAPHandler</handler-name>
<handler-class>co.codewizards.example.HttpHeaderExtensionSOAPHandler</handler-class>
</handler>
</handler-chain>
</handler-chains>
Вы можете добавить несколько <handler>
элементов, кстати.
И убедитесь, что этот файл действительно попадает в ваш JAR! Например, при использовании Maven вы должны поместить его либо в ${project}/src/main/resources/
(вместо ${project}/src/main/java/
), либо изменить конфигурацию сборки, включив ресурсы из папки java
! Я рекомендую последнее, потому что в папке resources
есть параллельная структура пакета, о которой часто забывают при рефакторинге.
4) Реализуйте свой HttpHeaderExtensionSOAPHandler
- аналогично этому:
import static com.google.common.base.Preconditions.*;
import java.util.*;
import javax.xml.namespace.QName;
import javax.xml.ws.handler.MessageContext;
import javax.xml.ws.handler.soap.SOAPHandler;
import javax.xml.ws.handler.soap.SOAPMessageContext;
import co.codewizards.webservice.WebserviceContext;
public class HttpHeaderExtensionSOAPHandler implements SOAPHandler<SOAPMessageContext> {
@Override
public boolean handleMessage(SOAPMessageContext context) {
checkNotNull(context, "context");
Boolean outboundProperty = (Boolean) context.get(MessageContext.MESSAGE_OUTBOUND_PROPERTY);
checkNotNull(outboundProperty, "outboundProperty");
if (outboundProperty.booleanValue()) {
WebserviceContext<?, ?> webserviceContext = WebserviceContext.getThreadWebserviceContextOrFail();
String something = (String) webserviceContext.___(); // my API method ;-)
@SuppressWarnings("unchecked")
Map<String, List<String>> requestHeaders = (Map<String, List<String>>) context.get(MessageContext.HTTP_REQUEST_HEADERS);
if (requestHeaders == null) {
requestHeaders = new HashMap<String, List<String>>();
context.put(MessageContext.HTTP_REQUEST_HEADERS, requestHeaders);
}
requestHeaders.put(MyService.MY_CONSTANT, Collections.singletonList(something));
}
return true;
}
@Override
public boolean handleFault(SOAPMessageContext context) { return true; }
@Override
public void close(MessageContext context) { }
@Override
public Set<QName> getHeaders() { return Collections.emptySet(); }
}
В моем примере выше (и в моем производительном коде) я получаю данные для передачи в заголовки HTTP-запроса из ThreadLocale
, то есть контекста моего текущего потока. Поскольку этот WebserviceContext
- мой пользовательский класс, вам нужно будет реализовать свой собственный способ доступа к вашим данным.