Dzisiaj kontynuacja lekcji o Web Services — poznamy bliżej technolgię SOAP oraz sposób, w jaki możemy z niej korzystać.
Ta lekcja omawia tylko jedno z podejść do tworzenia serwisów SOAPowych, tzw. Code-first approach. W tym podejściu najpierw tworzymy kod (mówiąc dokładniej, interfejs w języku programowania) i na tej podstawie pozwalamy bibliotekom samodzielnie wygenerować pliki WSDL i wszystkie inne potrzebne elementy. To podejście jest prostsze i można je wykorzystać, jeśli tworzymy nowe API lub integrujemy tylko pojedyncze systemy. Powodem jest to, że każda zmiana w naszych klasach potencjalnie wpływa na zmianę definicji Web Service (czyli pliku WSDL) przez co klienci, którzy używają naszego serwisu mogą przestać działać.
Drugie podejście, to contract-first, w którym to najpierw mamy kontrakt (np. plik WSDL albo plik XSD opisujący wszystkie elementy) i na tej podstawie generujemy kod. Takie podejście jest lepsze np. kiedy nasz system ma zastąpić istniejący już system w sposób niezauważalny dla jego użytkowników — podejście contract-first gwarantuje, że z punktu widzenia użytkowników WebService będzie wyglądał dokładnie tak, jak tego oczekujemy. Jest to jednak bardziej problematyczne w implementacji i wymaga większej wiedzy, dlatego w tej lekcji skupimy się jedynie na pierwszym podejściu dla zrozumienia podstawowych konceptów.
Lekcja
W tej części lekcji będziemy korzystali z biblioteki o nazwie CXF. Biblioteka ta wewnętrznie korzysta ze Springa, także jej integracja z istniejącą aplikacją webową nie stanowi problemu. Jest to jeden z najpopularniejszych frameworków, który pozwala nie tylko udostępniać serwisy (produkować), ale także z nich korzystać (konsumować). Aby dodać bibliotekę CXF do projektu, dodajemy następujące dependency:
<dependency>
<groupId>org.apache.cxf</groupId>
<artifactId>cxf-rt-frontend-jaxws</artifactId>
<version>3.0.4</version>
</dependency>
<dependency>
<groupId>org.apache.cxf</groupId>
<artifactId>cxf-rt-transports-http</artifactId>
<version>3.0.4</version>
</dependency>
<dependency>
<groupId>org.apache.cxf</groupId>
<artifactId>cxf-rt-transports-http-jetty</artifactId>
<version>3.0.4</version>
</dependency>
Teraz możemy już przystąpić do implementacji naszego serwisu.
Wystawiamy web service
Zmiany w web.xml
Przede wszystkim musimy dokonać paru zmian w pliku web.xml, a dokładniej dodać servlet, który pozwoli CXF obsługiwać wywołania SOAPowe niezależnie od naszego DispatcherServlet. W tym celu do pliku web.xml dodajemy następujący fragment:
<servlet>
<servlet-name>CXFServlet</servlet-name>
<display-name>CXF Servlet</display-name>
<servlet-class>org.apache.cxf.transport.servlet.CXFServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>CXFServlet</servlet-name>
<url-pattern>/api/soap/*</url-pattern>
</servlet-mapping>
Zwróć uwagę, na mapowanie (tag <servlet-mapping>)! Tutaj musimy podać wzór adresu, pod jakim będziemy udostępniali nasze web services. Jeśli wybierzesz inny adres, pamiętaj aby zaktualizować go także w tym miejscu.
Dodajemy klasę
Teraz zajmiemy się samą implementacją. Serwisy webowe implementujemy podobnie jak normalne serwisy, jedyne co się zmiena to adnotacje, których używamy. Dla przykładu napiszemy prosty serwis, który zawsze odpowiada ‘pong’ na każde zapytanie. Pamietaj, że taki serwis też jest beanem Spring’a, więc możesz używać wszystkich jego dobrodziejstw, włącznie z @Autowired. Poniżej mamy dwie klasy:
package pl.kobietydokodu;
import javax.jws.WebService;
import javax.jws.WebMethod;
@WebService
public interface PongServiceInterface {
@WebMethod(operationName="ping")
public String ping();
}
package pl.kobietydokodu;
import javax.jws.WebService;
@WebService(endpointInterface="pl.kobietydokodu.PongServiceInterface", serviceName="PongService")
public class PongServiceImpl implements PongServiceInterface {
@Override
public String ping() {
return "pong";
}
}
Pierwsza z nich to interfejs, który określa, jak metody będą widoczne dla klienta (tzn. pod jaką nazwą). Druga klasa to implementacja tego interfejsu, czyli konkretna funkcjonalność w Javie, która realizuje naszą logikę. Do kompletu potrzebujemy tylko zmiany w pliku rootContext.xml, dodając nasz web service:
<jaxws:endpoint id="PongService" implementor="pl.kobietydokodu.PongServiceImpl" address="/api/soap/pong"/>
Zwróć uwagę, że adres (atrybut address) pasuje do wzorca, który zapisaliśmy w pliku web.xml w poprzednim kroku! Implementor to pełna nazwa kwalifikowana (czyli nazwa pakietu + nawa klasy) naszej implementacji.
Pamiętaj też, aby dodać namespace jaxws (http://cxf.apache.org/jaxws -> http://cxf.apache.org/schemas/jaxws.xsd) do pliku XML!
I koniec! Tyle wystarczy, żeby nasz kod stał się serwisem webowym :)
Zobaczmy teraz, jak utworzyć klienta naszego serwisu.
Korzystamy z web service
Korzystanie z WebService jest równie proste, co jego tworzenie. Zakładając, że mamy dostęp do klasy interfejsu, w pliku webContext wystarczy dodać następujący zapis:
<jaxws:client id="pongClient" serviceClass="pl.kobietydokodu.PongServiceInterface" address="http://localhost:8080/api/soap/pong" />
W dowolnym miejscu kodu możemy wtedy skorzystać z funkcji Autowire:
@Autowired
PongServiceInterface pongService;
Aby móc korzystać z naszego web service. Oczywiście w deklaracji musimy podać właściwy adres (prawdopodobnie nie będzie to localhost).
Podsumowanie
W tej lekcji nauczyłąś się tworzyć i używać serwisy typu REST oraz SOAP. Wiedza ta oczywiście nie pokrywa wszystkich obszarów działania web services, ale wystarczy, żebyś samodzielnie szukała i zdobywała dalszą wiedzę w zależności od potrzeb. Serwisy webowe to bardzo potężne narzędzie, które znajduje zastosowanie w wielu dziedzinach i z pewnością spotkasz je w swojej karierze bardzo szybko.
Jeśli uważasz powyższą lekcję za przydatną, mamy małą prośbę: polub nasz fanpage. Dzięki temu będziesz zawsze na bieżąco z nowymi treściami na blogu ( i oczywiście, z nowymi częściami kursu Javy). Dzięki!