HandlerChain в java SOAP веб-сервисе. Клиентская часть
HandlerChain в java SOAP веб-сервисе. Клиентская часть работы с веб-сервисом.
Используемые технологии и библиотеки
- Apache CXF 3.1.6
- Spring MVC 4.3.0.Release
1. Описание задачи
Написать клиентскую часть работы с SOAP веб-сервисом с использованием цепочки обработчиков (HandlerChain). Создать java классы для работы с веб-сервисом на основании описания wsdl.
Описание серверной части находится в статье — HandlerChain в java SOAP веб-сервисе. Применение цепочки handler’ов.
2. Структура проекта
Код запуска клиента находится в JavaStudyWS. Handler клиентской части описан в ClientHandler. Так же были автоматически сгенерированы классы на основе файла описания wsdl. В client-handler.xml находится описание класса обработчика ClientHandler.
3. Классы на основе wsdl
Все классы в пакете ws.soap были сгенерированы автоматически с помощью утилиты wsimport из JDK Java 1.8. Как это сделать описано в Создание Java классов на основании wsdl описания soap веб-сервиса с помощью wsimport. Описание каждого сгенерированного класса в отдельности не является частью этой статьи. Все настройки после импорта остались по умолчанию и не были изменены.
4. Handler на клиенте
Для изменения soap сообщения на клиенте был также добавлен обработчик ClientHandler.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 | package ru.javastudy.handlers; import javax.xml.namespace.QName; import javax.xml.soap.*; import javax.xml.ws.handler.MessageContext; import javax.xml.ws.handler.soap.SOAPHandler; import javax.xml.ws.handler.soap.SOAPMessageContext; import java.io.IOException; import java.util.Set; /**  * Created for JavaStudy.ru on 12.06.2016.  */ public class ClientHandler implements SOAPHandler<SOAPMessageContext> {     public boolean handleMessage(SOAPMessageContext context) {         System.out.println("ClientHandler handleMessage..");         Boolean outBoundProperty = (Boolean) context.get(MessageContext.MESSAGE_OUTBOUND_PROPERTY);         //if this is a request (outgoing message), true for outbound messages, false for inbound         if(outBoundProperty) {             try {                 SOAPMessage message = context.getMessage();                 SOAPEnvelope envelope = message.getSOAPPart().getEnvelope();                 SOAPHeader header = envelope.getHeader();                 //if no header that we'll add one                 if (header == null) {                     header = envelope.addHeader();                 }                 //add password for later check on server side                 String password = "Life for Ner'Zhul";                 //add soap header name as 'password'                 QName qName = new QName("http://localhost", "password");                 SOAPHeaderElement soapHeaderElement = header.addHeaderElement(qName);                 soapHeaderElement.setActor(SOAPConstants.URI_SOAP_ACTOR_NEXT);                 soapHeaderElement.addTextNode(password);                 message.saveChanges();                 //write to console for debug                 message.writeTo(System.out);             } catch (SOAPException e) {                 e.printStackTrace();             } catch (IOException e) {                 e.printStackTrace();             }         }         //continue other handler chain         return true;     }     public Set<QName> getHeaders() {         System.out.println("ClientHandler getHeaders..");         return null;     }     public boolean handleFault(SOAPMessageContext context) {         System.out.println("ClientHandler handleFault..");         return false;     }     public void close(MessageContext context) {         System.out.println("ClientHandler close..");     } } | 
Аналогично коду серверной части вначале проверяется тип сообщения. Если это запрос (request), то мы добавляем в него элемент с именем ‘password’. Именно значение этого элемента проверяется в аналогичном обработчике серверной части.
5. Soap клиент с Handler’ом
Для запуска клиента и выполнения запроса к веб-сервису серверной части необходимы всего несколько строк кода.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | package ru.javastudy.client; import ru.javastudy.ws.soap.HelloSoap; import ru.javastudy.ws.soap.WebserviceSEI; /**  * Created for JavaStudy.ru on 09.06.2016.  */ public class JavaStudyWS {     public static void main(String[] args) {         HelloSoap soap = new HelloSoap();         WebserviceSEI sei = soap.getHelloSoapPort();         System.out.println(sei.getGoods());     } } | 
5.1. Запуск
Сначала запускаем серверную часть и проверяем доступность описания по ссылке http://localhost:8080/soap/webserviceSEI?wsdl (порт и путь могут быть другими).
Теперь при запуске клиента получим вывод в консоль:
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | Connected to the target VM, address: '127.0.0.1:60099', transport: 'socket' ClientHandler getHeaders.. ClientHandler handleMessage.. <S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/" xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"><SOAP-ENV:Header><password xmlns="http://localhost" SOAP-ENV:actor="http://schemas.xmlsoap.org/soap/actor/next">Life for Ner'Zhul</password></SOAP-ENV:Header><S:Body><ns2:getGoods xmlns:ns2="http://soap.ws.javastudy.ru/"/></S:Body></S:Envelope>ClientHandler handleFault.. ClientHandler close.. Disconnected from the target VM, address: '127.0.0.1:60099', transport: 'socket' Exception in thread "main" com.sun.xml.internal.ws.fault.ServerSOAPFaultException: Client received SOAP Fault from server: For the Lich King! Please see the server log to find more detail regarding exact cause of the failure. 	at com.sun.xml.internal.ws.fault.SOAP11Fault.getProtocolException(SOAP11Fault.java:178) 	at com.sun.xml.internal.ws.fault.SOAPFaultBuilder.createException(SOAPFaultBuilder.java:116) 	at com.sun.xml.internal.ws.client.sei.StubHandler.readResponse(StubHandler.java:238) 	at com.sun.xml.internal.ws.db.DatabindingImpl.deserializeResponse(DatabindingImpl.java:189) 	at com.sun.xml.internal.ws.db.DatabindingImpl.deserializeResponse(DatabindingImpl.java:276) 	at com.sun.xml.internal.ws.client.sei.SyncMethodHandler.invoke(SyncMethodHandler.java:104) 	at com.sun.xml.internal.ws.client.sei.SyncMethodHandler.invoke(SyncMethodHandler.java:77) 	at com.sun.xml.internal.ws.client.sei.SEIStub.invoke(SEIStub.java:147) 	at com.sun.proxy.$Proxy32.getGoods(Unknown Source) 	at ru.javastudy.client.JavaStudyWS.main(JavaStudyWS.java:15) Process finished with exit code 1 | 
Exception выбрасывается на серверной части после проверки элемента password. С помощью дебага или вывода в консоль вы можете посмотреть как обрабатываются различные сообщения.



