Lekcja 1.1: Rozpoczęcie projektu

Forum

Instalacje / środowisko programistyczne

Rozpoczęcie projektu

00:08

Rozpoczynamy pierwszy przykład praktyczny, w ramach którego utworzymy nowy projekt, skonfigurujemy go, a także pokażemy na bazie prostego przykładu, na czym polega wy korzystanie interfejsów, czym jest wstrzykiwanie zależności, a także programowanie aspektowe. W pierwszym wariancie nie będziemy korzystali ze Springa, żeby pokazać, że mówimy o ogólnych zasadach programowania, o dobrych praktykach, które powinniśmy stosować niezależnie od biblioteki czy frameworka, który jest przez nas wykorzystywany. Jako typ projektu wybieramy Maven. Maven to rozwiązanie, które pozwala na to, żeby zarządzać zależnościami projektu np. takimi które, są potrzebne do tego, żeby wykorzystywać Springa. Alternatywą może być w naszym przypadku Gradle. Ja zdecydowałem się na wykorzystanie Mavena ze względu na to, że jest on po prostu nadal dużo bardziej popularny, jest też łatwiejszy w użyciu. Plusem korzystania z takich rozwiązań jak Maven czy Gradle jest możliwość otworzenia, zaimportowania projektu w dowolnym IDE. W związku z tym, jeżeli ktoś realizuje te przykłady, które będziemy wspólnie budowali, w innym środowisku programistycznym, to nie będzie miał problemu z otworzeniem, zaimportowaniem tego projektu, który będzie umieszczony na Githubie. Przechodzimy dalej. Nadajemy nazwę naszemu projektowi. Może to być spring-masterclass. Dodatkowo rozwijamy ustawienia, dotyczące konfiguracji Mavena i podajemy grupę pl.training.shop. W tym momencie możemy ukończyć tworzenie czystego projektu. Jeżeli środowisko programistyczne wyświetli nam informację o tym, czy chcemy uruchomić procesory dotyczące Lomboka, to oczywiście wybieramy opcję tak. Chcemy je uruchomić, bo inaczej ten plugin, który wcześniej instalowaliście do Lomboka, nie będzie prawidłowo działał. Pierwszą taką sensowną rzeczą, którą możemy zrobić, jest skonfigurowanie wersji Javy, z której będziemy korzystali. Czyli używając domyślnych properties na poziomie Mavena, możemy określić, że wykorzystujemy wersję Javy 11. Kolejna kwestia to jest kodowanie naszych plików źródłowych, kodowanie na poziomie naszego projektu. To również można ustawić za pomocą properties. Dobrze, teraz postaramy się dodać wymagane zależności. Tak jak mówiłem w części wstępnej, na razie nie będziemy korzystali jeszcze ze Springa, natomiast na pewno potrzebujemy zależności do Lomboka. Lombok to jest biblioteka, która pozwoli nam wygenerować w czasie kompilacji takie metody jak np. equals, hashcode, toString, metody typu get/set, konstruktory. Dzięki temu kod źródłowy naszych klas, zwłaszcza tych modelowych, będzie dużo bardziej czytelny, nie będzie zaśmiecony typowymi elementami, które i tak w większości przypadków po prostu generujemy z poziomu IDE. W związku z tym dodajmy zależność od Lomboka. Zwrócimy uwagę na to, że Lombok jest dodany w scope provided, co efektywnie oznacza, że nie będzie on ujmowany w wynikowym jar, po zbudowaniu naszej aplikacji. Teraz dodamy jeszcze jedną, zależność, żebyśmy mogli łatwo reprezentować wartości związane z pieniądzem, z rodzajem waluty. Żebyśmy mogli łatwo przeliczać te waluty między sobą czy też np. wykonywać jakiekolwiek operacje finansowe. Zwróćcie uwagę, że typ tej zależności został ustawiony jako pom. Chcemy dzisiaj pokazać programowanie przez interfejsy, czy wstrzykiwanie zależności, a z drugiej strony jeszcze nie mamy za dużo kodu. Ja zdecydowałem się, że zaimplementujemy fragment związany z płatnościami. Stworzymy usługę, która będzie pozwalała symulować takie płatności i przy okazji zademonstrować to, co było omówione w części teoretycznej. Czyli zacznijmy od tego, że stworzymy pakiet, który będzie się nazywał pl.training.shop. W ramach tego pakietu stworzymy klasę Application. To będzie nasza główna klasa startowa. Dodatkowo stworzymy jeszcze podpakiet payments. W ramach tego pakietu spróbujemy teraz zdefiniować podstawowe klasy modelowe. To będą trzy klasy. Pierwsza będzie się nazywała PaymentRequest i będzie potrzebna do tego, żeby rozpocząć proces płatności. Spróbujmy teraz taką klasę dodać. Dodajmy na poziomie tej klasy adnotację @Value, która pochodzi z Lomboka. Będzie ona sprawiała, że tak naprawdę ta klasa będzie niezmienna, będzie niemutowalna. Dodatkowo będą wygenerowane gettery do wszystkich pól, które dodamy, a pola będą oznaczone automatycznie jako prywatne. Czyli nie musimy dodawać słówka private na poziomie poszczególnych pól. Oczywiście standardowo dostarczona będzie też metoda equalshashcodee i toString. Jeżeli spróbujemy taką adnotację dodać i zobaczymy, że tej adnotacji nie widać, IDE nam tej adnotacji nie podpowiada w tej chwili, to znaczy, że prawdopodobnie nasz projekt jeszcze trzeba odświeżyć pod kątem Mavena. Trzeba reimportować ten projekt. Możemy to zrobić na przynajmniej dwa sposoby. Możemy wejść po prawej stronie, do tego menu bocznego, wybrać Maven, a następnie kliknąć odświeżenie projektu. Ewentualnie można też kliknąć na poziomie pom.xml, wybrać stąd opcję Maven -> reimport i to powinno spowodować dokładnie taki sam efekt. Ewentualnie możemy wejść do pliku pom.xml i użyć skrótu klawiszowego. Dla Windowsa i Linuksa będzie to
control-shift-o dla komputerów z systemem MacOS będzie to kombinacja command-shift-i. Dobrze, to teraz możemy, spróbować ponownie dodać adnotację @Value. Jednocześnie skorzystamy też z adnotacji @Builder@Builder to jest adnotacja, która powoduje, że Lombok będzie generował kod, który jest zgodny ze wzorcem Builder i będzie nam pozwalał w łatwy sposób konfigurować nasze obiekty modelowe, poprzez podanie wartości poszczególnych pól i zbudowanie odpowiedniej wariacji konfiguracyjnej takiego obiektu. Na poziomie PaymentRequest zdefiniujemy tylko dwa pola. Będzie to Long, który będzie reprezentował id oraz FastMoney, który będzie reprezentował walutę, pieniądze, czy kwotę tej płatności, którą chcemy zrealizować. Jest to wariant, który w ramach implementacji używa zwykłych, małych longów, dzięki czemu to rozwiązanie jest dużo bardziej efektywne, szybkie niż to oparte domyślnie o typ BigDecimal. Nasza pierwsza klasa modelowa jest zakończona. Możemy teraz spróbować zdefiniować status płatności. Ta płatność będzie mogła zmieniać swój stan w czasie, tzn. będzie mogła być rozpoczęta, potwierdzona, może się nie udać lub może zostać anulowana. Oczywiście w realnym projekcie tych stanów może być znacznie więcej, natomiast na nasze potrzeby te, które wymieniłem, będą zupełnie wystarczające. W związku z tym spróbujmy teraz zdefiniować wyliczenie. To wyliczenie nazwiemy PaymentStatus. W ramach takiego wyliczenia dodamy stany, o których mówiłem. Dobrze i teraz ostatnim krokiem do budowy naszego modelu będzie sama płatność. Dodajemy zatem klasę Payment. Taką klasę również oznaczamy adnotacjami Lombokowymi. Teraz definiujemy poszczególne pola. To będzie id, tym razem będzie to id typu String. Oprócz tego potrzebujemy oczywiście tej kwoty, na którą płatność będzie realizowana. Potrzebujemy pewnie też znacznika czasowego, a także statusu. W momencie, kiedy będziemy realizowali płatność, będziemy reagowali na to żądanie płatności, które będzie do nas przychodziło. Będziemy tworzyli nową płatność i będziemy przypisywali jej pewne specyficzne id, które pozwoli później taką płatność zidentyfikować. W związku z tym zacznijmy od tego, że stworzymy prosty generator, tych identyfikatorów dla płatności. Ponieważ nie ma sensu implementować jakiegoś własnego algorytmu, tym bardziej że jest to taki podstawowy przykład, wykorzystamy wbudowany typ, wbudowaną klasę z Javy. UUID pozwoli na generowanie unikalnych identyfikatorów, między innymi na podstawie takich parametrów jak na przykład bieżący czas, czy też parametry komputera, z którego korzystamy. W związku z tym utworzymy teraz nową klasę. Nazwiemy ją UUIDPaymentIdGenerator. I w ramach takiej kasy stworzymy sobie jedną metodę. Metodę nazwiemy getNext, a w tej metodzie po prostu zwrócimy wartość wygenerowaną przez klasę UUID. No dobrze kolejnym krokiem będzie dodanie usługi, która będzie przyjmowała PaymentRequest i konfigurowała Payment, m.in. korzystając z naszego generatora i zwracała go jako rezultat przeprocesowania takiego żądania płatności. W związku z tym dodamy teraz klasę FakePaymentService. Nazwa została przeze mnie wymyślona, dlatego że jakby udajemy, że realizujemy prawdziwą płatność. W związku z tym to dosyć mocno, czy dosyć dobrze oddaje, co w tej klasie, będzie się w środku działo. Zacznijmy od tego, że dodamy metodę process która będzie przyjmowała PaymentRequest i zwracała Payment. Teraz w ramach takiej metody spróbujemy skonfigurować nowy obiekty typu Payment, przypisać mu poszczególne wartości atrybutów i po prostu zwrócić do klienta. W tym celu skorzystamy z buildera wygenerowanego przez Lomboka. Ustawimy poszczególne elementy, czyli np. Money ustawimy sobie na wartość, którą otrzymaliśmy w ramach PaymentRequest. Teraz jeżeli chodzi o znacznik czasowy, to po prostu podstawimy bieżący czas. Jeżeli chodzi o status, to ustawimy go domyślnie na STARTED. Na koniec należy taki obiekt zbudować i nasza płatność jest prawie w całości skonfigurowana. Prawie dlatego, że brakuje nam identyfikatora. Specjalnie zostawiłem to na koniec, bo to wymaga wykorzystania naszego generatora, który został wcześniej stworzony. Na razie spróbujemy po prostu utworzyć nową instancję takiego generatora, na poziomie naszej klasy FakePaymentService. Ja już z góry mówię, że to nie jest najlepszy sposób, że to nie jest najlepsza praktyka, ale robimy to specjalnie, żeby się też trochę dowiedzieć dlaczego i jakie będą korzyści z tego, że będziemy później realizowali to w nieco inny sposób. Teraz dysponując generatorem, możemy spróbować przypisać brakujące id. Na koniec zwracamy naszą płatność z metody process. No i teraz wyobraźmy sobie, że zostaliśmy również poproszeni o to, aby każda taka wykonywana płatność była logowana na konsoli. Chodzi o to, żeby po prostu był ślad tego, że ta płatność będzie realizowana. W przyszłości oczywiście będziemy działali na poziomie bazy danych, ale na tę chwilę, żeby nie komplikować tego przykładu, chodzi tylko o to, żeby zalogować taką płatność na konsoli. To co może nam przyjść do głowy od razu, czy jako pierwsze rozwiązanie, to jest po prostu dodanie logowania na poziomie metody process. Okazuje się, że to znowu jest nie najlepszy pomysł, ale wyjdziemy od takiego wariantu po to, żeby również w tym wypadku pokazać za chwilę, że można to zrobić lepiej. Zrobimy sobie pomocniczą metodę, która będzie zwracała Stringa. Nazwijmy tę metodę createLogEntry i w ramach tej metody użyjemy String.format do tego, żeby wyświetlić odpowiednią informację. Ja przygotuję sobie stałą z szablonem naszego wpisu do logu. Tu warto skorzystać z takiego skrótu, szablonu prsf czyli private static final. Możemy dodać nowy element String, nazwijmy go LOG_FORMAT i spróbujmy dodać jakiś komunikat. Teraz wykorzystując ten format, możemy przygotować wpis, który pojawi się w logach. Potrzebujemy oczywiście Payment. Czyli możemy dodać go jako argument naszej metody, a teraz można wyciągnąć z tego Payment kwotę i wstawić do naszego szablonu. Pozostaje nam jeszcze zalogować całość na konsoli. W tym miejscu możemy skorzystać z Lomboka, z kolejnej adnotacji, którą otrzymujemy w ramach biblioteki Lombok. To jest adnotacja @Log. Dodając taką adnotację, powodujemy, że Lombok udostępni nam obiekt logera. Możemy z niego bezpośrednio skorzystać do zalogowania informacji o naszej płatności. Nasza klasa serwisowa jest skończona. Utworzymy jeszcze jedną klasę pomocniczą, która będzie pozwalała na to, żebyśmy mogli w łatwy sposób zdefiniować jakąś kwotę w lokalnej walucie. A więc dodamy klasę, którą nazwiemy LocalMoney i w ramach takiej klasy zdefiniujemy metodę statyczną zwracającą FastMoney, którą nazwiemy of. Jako argument wejściowy tej metody będziemy podawali kwotę. Ona będzie wyrażona jako Number, a my w środku, w tej metodzie będziemy pobierali bieżącą lokalizację. Na tej podstawie będziemy tworzyć walutę, a to z kolei pozwoli nam na utworzenie kwoty. Teraz pozostaje jeszcze tylko uzupełnić naszą główną klasę Application. W metodzie main spróbujemy stworzyć usługę PaymentService. Oczywiście potrzebujemy też żądania płatności, więc musimy je teraz utworzyć. Po raz kolejny możemy skorzystać z buildera i przede wszystkim określić kwotę. Pozostaje nam wykorzystać to żądanie płatności do tego, żeby wykonać metodę process z naszej usługi. Teraz przekazujemy to żądanie do metody process i otrzymujemy Payment. Na koniec spróbujmy tą otrzymaną płatność wypisać na konsoli po raz kolejny, używając Lomboka. W tym momencie jesteśmy gotowi do tego, żeby tę aplikację uruchomić. Po krótkiej chwili widać, że na konsoli mamy informację o tym, że płatność się odbyła. To jest efekt logowania na poziomie naszej usługi FakePaymentService, ale jednocześnie widzimy, gotową przygotowaną, skonfigurowaną, płatność, która ma zarówno id, kwotę, znacznik czasowy, jak i status i jest wypisana na konsoli jako rezultat wykonania metody process. Wydaje się, że ten kod działa, jest w porządku, natomiast tak jak mówiliśmy, za chwilę zobaczymy, że pewne elementy można tutaj było zrealizować dużo lepiej, dużo bardziej poprawnie, bo to pozwoli na to, żebyśmy kod mogli dużo łatwiej testować, ale też w perspektywie czasowej reagować na zmianę funkcjonalności, wymagań, które będą się pojawiały, odnośnie do tego, co nasza aplikacja ma robić.

Zaloguj się
Rejestracja jest darmowa!

Administratorem danych jest Sages Sp. z o.o. z siedzibą w Warszawie przy ul. Nowogrodzkiej 62c. Podanie danych jest dobrowolne. Osobie, której dane dotyczą przysługuje prawo wglądu do danych osobowych, ich zmiany oraz usunięcia w sposób określony w Polityce prywatności.

Please accept the Terms and Conditions to proceed.