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. С помощью дебага или вывода в консоль вы можете посмотреть как обрабатываются различные сообщения.