Archiwa kategorii: Średnio zaawansowane

Wpisy dla programistów (także początkujących)

Jak wysłać maila z aplikacji webowej w Javie?

Po co mi maile?

Warunkiem utworzenia konta użytkownika jest podanie poprawnego adresu email, do którego dany użytkownik rzeczywiście ma dostęp.

W kolejnym wpisie omówię dokładniej proces weryfikacji. Na teraz istotne jest to, że moja aplikacja musi być w stanie wysłać do użytkownika maila z linkiem do uaktywnienia konta.

Jak to zrobić?

Korzystam z frameworka Spring Boot (czyli właściwie z nakładki ułatwiającej korzystanie z frameworka Spring zgodnie z zasadą “konwencja ponad konfiguracją”).

Kroki do realizacji mojego celu są następujące:

1. Dodaję zależność w pliku pom.xml:

2. Piszę kod tworzący i wysyłający wiadomości:

3. Ustawiam właściwości aplikacji

Co może pójść nie tak?

com.sun.mail.smtp.SMTPSendFailedException: 530 5.7.0 Must issue a STARTTLS command first.

Koniecznie jest nadanie wartości true właściwości spring.mail.properties.mail.smtp.starttls.enable, a najlepiej całej trójce kończącej powyższy listing.

javax.mail.AuthenticationFailedException: 534-5.7.9 Application-specific password required.

To akurat sprawa typowa dla serwisu GMail. Jeśli chcesz, żeby aplikacja łączyła się z kontem email i w Twoim imieniu wysyłała maile, musisz stworzyć specjalne hasło aplikacji, różne od hasła prywatnego. W każdej chwili możesz podejrzeć listę aplikacji, które korzystają z takiego hasła (na stronie https://security.google.com/settings/security/apppasswords), a także dowolną z nich zablokować.

Google uprzejmie zwraca uwagę, że nadal nie jest to najbezpieczniejsze rozwiązanie.

com.sun.mail.util.MailConnectException: Couldn’t connect to host.

Ten błąd pojawił się, kiedy przełączyłam konto z GMaila na adres email na mojej wirtualnej instancji obsługującej kilka domen. Początkowo myślałam, że Java Mail nie chce pracować z “wirtualnymi” adresami obsługiwanymi przez serwer SMTP w innej domenie. Ostatecznie okazało się jednak, że przyczyną błędu był nadmiarowy biały znak w pliku application.properties 🙂

Ciekawostka: tymczasowe maile

Wiele aplikacji wymusza na użytkowniku podanie działającego adresu email. Główne powody to:

  • zwiększenie prawdopodobieństwa, że mamy do czynienia z człowiekiem, a nie robotem,
  • umożliwienie spamowania 🙂
  • zabezpieczenie użytkownika przed literówką w adresie email, która mogłaby doprowadzić nawet do utraty konta w aplikacji (brak możliwości zresetowania hasła bez działającego adresu).

Wiele osób tworzy sobie dodatkowe konto email, które używane jest do rejestracji w mniej istotnych serwisach (sama mam osobne konto do zakupów internetowych). Zdarza się jednak, że adresu email żąda strona lub aplikacja, z którą na pewno już nigdy nie będziesz mieć nic wspólnego. Co wtedy zrobić?

Możesz założyć tzw. jednorazowe (ang. disposable) konto email, np. w serwisie Guerilla Mail. Poczta, która tam trafia, jest przechowywana przez godzinę niezależnie od tego, czy ktoś ja odczyta, czy nie.

Ocenę moralną pozostawiam Czytelnikowi.

Jak zacząć z MongoDB?

Wprowadzenie

Najwyższa pora dodać do mojej konkursowej aplikacji jakąś bazę danych. Od początku zakładałam, że z powodów edukacyjnych użyję bazy nierelacyjnej. Zdecydowałam się w końcu na MongoDB. Jest to jedna z popularnych baz nierelacyjnych obsługiwanych przez mojego dostawcę PaaS (Platform as a Service), tj. Pivotal Web Services.

Źródła

Swoją działalność w tym obszarze opieram na następujących źródłach:

Pierwsze kroki

Po instalacji serwera bazodanowego wykonuję następujące kroki:

  1. Uruchamiam proces serwera MongoDB:
  2. Przygotowuję rekord reprezentujący użytkownika mojego systemu (plik user.json). Rekordy w MongoDB mają postać dokumentów w standardzie JSON (w przybliżeniu). Wartościami pól mogą być również inne dokumenty oraz tablice (w tym tablice dokumentów). Dokumenty są przechowywane w ramach kolekcji. Kolekcja przypomina tablicę w relacyjnej bazie danych, tyle że zawarte w niej dokumenty wcale nie muszą mieć tej samej struktury. Dokumenty w kolekcji muszą mieć klucz główny o nazwie _id:
  3. Importuję rekord użytkownika do bazy danych:
  4. Dodaję sterownik MongoDB jako zależność w mavenowym pliku pom.xml.
  5. Łączę się z bazą danych z kodu w Javie:
  6. Wyszukuję użytkowników:
  7. Zmieniam wartość jednego z pól użytkownika (dokument d pełni tu rolę wzorca, według którego odnajdywany jest rekord z bazy):
  8. Nakładam indeks na nazwy użytkowników:

No i działa 🙂

Cały plik jest dostępny w GitHub.

Co dalej?

  1. Na serio dodać to do aplikacji 🙂
  2. Zastanowić się nad użyciem Hibernate.
  3. Zastanowić się, jak przechowywać zdjęcia.

Pozbywam się powtarzalnych fragmentów HTML przy użyciu Thymeleaf

Każdy programista wie, że duplikacja w kodzie źródłowym to zło, gdyż:

  • jeśli zduplikowany kod zawiera błąd, trzeba naprawić go w kilku miejscach (i z reguły o którymś się zapomina),
  • długi kod trudniej się czyta.

A jednak zadanie przerzucenia powtarzanych fragmentów HTML (jak nagłówek i stopka wyświetlane na wszystkich podstronach) do osobnych, reużywalnych plików wcale nie jest trywialne!

Mój plik index.html w oryginalnej postaci zawierał 71 linii, z czego około 50 było wspólnych z innymi szablonami (nagłówek, stopka, menu, załączane skrypty js). Zależało mi na wyodrębnieniu części wspólnych do własnych plików. Chociażby po to, żeby dodanie pozycji z menu nie musiało być odwzorowywane w pięciu miejscach.

Jakie miałam możliwości?

  1. Oprogramować operację include w JavaScripcie (lub użyć czyjegoś kodu, np. z W3Schools). Wady:
    • dużo JavaScriptu,
    • metoda z gatunku nieeleganckich hacków.
  2. Użyć znaczników HTML: object, embed lub nawet iframe. Wady:
    • dwa pierwsze znaczniki zostały zaprojektowane do osadzania na stronach obiektach takich jak filmy, choć da się ich użyć tak że do wstawienia dokumentu HTML,
    • wszystkie służą do dodania do strony kompletnego dokumentu, a nie fragmentu,
    • styl CSS obowiązujący na stronie nie zadziała na załączone w ten sposób fragmenty.
  3. Skorzystać z mechanizmu udostępnianego przez silnik szablonów, w tym wypadku Thymeleaf. Wady:
    • serwer wykonuje pracę, którą mógłby wykonać klient 🙂
    • ewentualna zmiana silnika szablonów staje się jeszcze bardziej kosztowna.

Zdecydowałam się na rozwiązanie numer 3. Jak to wygląda w praktyce?

Na wszystkich moich stronach powtarzał się poniższy fragment:

Przeniosłam go (wraz z innymi podobnymi elementami) do osobnego pliku _menus.html:

Dzięki temu mogę załączać go wszędzie tam, gdzie jest potrzebny, w następujący sposób:

Pułapka 1: Na początku umieściłam atrybuty id i class we fragmencie załączanym (w _menus.html). Zostały zjedzone 🙂

A co, jeśli fragment, który chcę załączyć, nie jest otoczony sensowną parą znaczników? Mogę wtedy użyć bloku, np.:

I załączyć go w analogiczny sposób:

W obecnej chwili index.html ma tylko 32 niepuste linie i dużo zyskał na czytelności, podobnie jak inne szablony.

Pułapka 2: Po wyodrębnieniu stopki do osobnego pliku, moim oczom ukazał się taki oto widok:

Problem z kodowaniem załączonego pliku
Problem z kodowaniem załączonego pliku

Wszystkie pliki mam zakodowane w UTF-8, takie samo kodowanie deklaruję w nagłówku HTML. Poczytałam trochę o problemach z kodowaniem na linii Spring/Thymeleaf, ale ostatecznie, ponieważ na teraz jest to jedyne wystąpienie polskiego znaku na mojej stronie, po prostu zmieniłam odpowiadającą za to linię na:

 

 

 

 

Czasami coś idzie nie tak… Moja własna strona błędu

Nadal w ramach Daj się poznać.

Podobny obrazek widział chyba każdy programista aplikacji webowej. Od czasu do czasu serwer Tomcat postanawia poinformować użytkownika aplikacji, że coś poszło nie tak. Informuje dość brutalnie, przynajmniej od strony stylistycznej. Co gorsza, przy okazji potrafi wyjawić przypadkowemu użytkownikowi dość dużo informacji na temat wnętrza programu.

Informacja o błędzie wygenerowana przez serwer Tomcat. W tym wypadku żądana strona nie istnieje.
Informacja o błędzie wygenerowana przez serwer Tomcat. W tym wypadku żądana strona nie istnieje. Czasami można w tym miejscu zobaczyć ciekawszy materiał, czyli stack trace.

Tego typu informacje przydają się do debugowania aplikacji na etapie jej powstawania, ale użytkownik końcowy nie powinien ich oglądać (chociażby z powodów estetycznych).

Jak sobie z tym poradzić? Framework Spring Boot automatycznie ustawia dla nas nieco tylko ładniejszą stronę błędu:

Whitelabel Error Page, czyli strona błędu generowana przez Spring Boot
Whitelabel Error Page, czyli strona błędu generowana przez Spring Boot

Mechanizm ten można wyłączyć we właściwościach aplikacji (application.properties):

Także zmiana domyślnego ViewResolver może usunąć tę wersję informacji o błędzie i przywrócić wersję tomcatową.

Jeśli zamiast strony prezentowanej przez Springa chcesz ustawić swoją własną, musisz zerknąć do dokumentacji wybranego przez Ciebie silnika szablonów. W przypadku Thymeleaf wystarczy dodać szablon o nazwie error.html:

Szablon błędu dla silnika Thymeleaf
Szablon błędu dla silnika Thymeleaf

Dzięki temu strona błędu może wyglądać na przykład tak:

error

Czy jest ładniejsza… Pozostawiam ocenie Czytelnika 😀

Historie komórkowe

Ten tekst miał nazywać się “Mobilna wersja strony: podejście 2” w nawiązaniu do Mobilna wersja strony w Spring Boot. Potrzebowałam do niego zrzutu ekranu z mojego telefonu, a jedno spojrzenie na niego wyzwoliło całą lawinę wspomnień… Które również zamieszczam poniżej.

@media

Najpierw krótko o konkretach: w poprzednim wpisie pokazywałam, jak Spring Boot pozwala stworzyć mobilną wersję strony i zarządza jej wyświetlaniem. Wychodzi jednak na to, że w dzisiejszych czasach istnieją lepsze metody. Prym wśród nich wiodą CSS3 i reguły @media. Logika odpowiedzialna za formatowanie informacji trafia w tym modelu dokładnie tam, gdzie powinna: do arkusza stylów. W arkuszu stylów, przy użyciu reguł @media, możemy podjąć decyzję na temat sposobu wyświetlania informacji w zależności od tego, jakie urządzenie korzysta ze strony (np. ekran czy drukarka?), jaką ma orientację (pozioma czy pionowa?) bądź rozdzielczość.

Prosty przykład ze strony W3Schools:

Kolor tła zostanie zmieniony na magentę (ekhem, fuksję), jeśli szerokość wyświetlacza wyniesie co najmniej 480 pikseli.

W swojej konkursowej aplikacji postanowiłam pójść po najmniejszej linii oporu – znalazłam darmowy szablon CSS implementujący ten mechanizm 🙂 Wygląda to obecnie tak:

Przeglądarka na PC
Przeglądarka na PC
Strona wyświetlona na ekranie Samsung Galaxy Xcover 3
Strona wyświetlona na ekranie  urządzenia mobilnego o niskiej rozdzielczości

Telefony 🙂

Co do kiepskiej jakości urządzeń mobilnych… Jestem specyficznym typem użytkownika: masowo rozbijam telefony. Nie rzucam nimi ze złości (od dobrych paru lat). Same wypadają: z kieszeni, z torebki, z samochodu. Kąpią się w wannie i w napojach. Psują się.

Przedstawiony powyżej zrzut ekranu pochodzi z mojego Samsung Galaxy Xcover 3. A było tak.

W połowie ubiegłego roku doszłam do wniosku, że nie stać mnie na kupowanie co dwa miesiące nowego dobrej klasy smartfona (w obliczu śmiertelnego wypadku poprzednika). Zdecydowałam się wtedy na zakup urządzenia niskiej klasy, za to w metalowej obudowie. Przesadziłam – nie działało na nim nawet quizzwanie. Na szczęście, problem szybko rozwiązał się sam. Pierwszego dnia telefon wypadł mi z ręki, kiedy przechodziłam przez przedpokój na piętrze. Pięknym lobem poszybował w stronę krętych schodów, po czym szybem w rogu spadł aż do samej piwnicy. Kiedy bez większych nadziei zeszłam na dół, okazało się, że urządzenie nadal działa, chociaż róg ma zauważalnie wgnieciony. Nabrałam do niego nowego szacunku. Dwa dni później wypadł mi z tylnej kieszenie spodni, kiedy szukałam kluczy na podjeździe – i zbił się na amen.

Wtedy wpadłam na radykalnie odmienny pomysł: kupić drogie i dobre urządzenie, o które będę drżeć i którego wobec finansowych rozterek z pewnością nie upuszczę na podłogę. Wybrałam najnowszy model Galaxy Note. Telefon był piękny, wygodny, szybki… Tyle że trafiłam na wadliwy egzemplarz, który restartował się w losowo wybranych momentach kilka razy dziennie. Przegapiłam (tygodniowy) termin na oddanie telefonu bez wyjaśnień w lokalnym Brand Store, ponieważ od razu pojechałam z nim na wakacje. Po powrocie najpierw wmawiano mi, że wyłączyłam telefon podczas aktualizacji i dlatego działa źle. Potem kilka razy zwracano mi go jako naprawiony – pierwszą rzeczą, jaką robił po włączeniu (najpierw w domu, potem już w sklepie), był restart. Pikanterii sprawie dodawał fakt, że byłam wtedy w bardzo zaawansowanej ciąży i brak sprawnego telefonu był coraz bardziej ryzykowny. Po około miesiącu użyłam na piśmie magicznego sformułowania “Miejski Rzecznik Konsumentów” i odzyskałam pieniądze. Nie chciałam już innego egzemplarza (o który dopominałam się od początku, ustaliwszy szybko, że problem jest sprzętowy i dotyczy konkretnej sztuki w ogólności dobrego modelu), bo nie miałam ochoty na jeszcze jedno spotkanie z serwisem.

Lato 2015, Mazury. Dawid i Gałgan ćwiczą pracę wodną. Ja łapię zasięg i reinstaluję Androida
Lato 2015, Mazury. Dawid i Gałgan ćwiczą pracę wodną. Ja łapię zasięg i reinstaluję Androida

Potem chciałam tanio i dobrze kupić One Plus. Powstrzymało mnie to, że właśnie pojawił się nowy model. Kosztował dokładnie tyle, co stary, ale do zakupu wymagane było posiadanie zaproszenia. Kto normalny kupiłby starą wersję, jeśli nowa kosztowała tyle samo?! A zaproszenie ciągle nie nadchodziło…

Wtedy wygasła umowa na usługi komórkowe w organizacji, do której należę i pojawiła się możliwość uzyskania bez dopłaty cuda w postaci Samsung Galaxy Xcover 3. Na kolana powala przede wszystkim rozdzielczość (480 x 800px), ale pancerny telefon nadal działa po dziesiątkach upadków, kąpieli i ugryzień. I takiego doświadczenia życzę wszystkim!

Wdrażam moją aplikację (która nadal nic nie robi) w chmurze Pivotal Web Services

Co to za aplikacja?

W ramach konkursu Daj się poznać pracuję nad aplikacją Szafbook, na którą pomysł został naszkicowany tutaj. Moim celem jest przede wszystkim nauczenie się nowych rzeczy, dlatego sama aplikacja solidnie kuleje i, jak w tytule, naprawdę nic jeszcze nie robi. Ale już da się wdrożyć!

Co to jest Pivotal Web Services?

Pivotal to firma z, oczywiście, San Francisco. Jeden z jej produktów to chmura i oprogramowanie Pivotal Cloud Foundry . Pivotal Web Services to ich instancja dostępna publicznie. Umożliwia łatwe wdrażanie aplikacji napisanych w następujących językach i frameworkach: Java, Grails, Play, Spring, Node.js, Ruby on Rails, Sinatra, Go.

Zachęcająca grafika ze strony Pivotal Web Services
Zachęcająca grafika ze strony Pivotal Web Services

Moja aplikacja jest napisana w Spring Boot. A więc do dzieła!

Jak wdrożyć aplikację?

  1. Wchodzimy na stronę http://run.pivotal.io/. Wita nas przyjazny komunikat o 87 dolarach w prezencie od firmy na cele testowania.

    1
    Bierzemy!
  2. Rejestrujemy się w serwisie. Musimy podać numer telefonu, żeby przepisać otrzymany kod.
  3. Firma uprzejmie prowadzi nas za rękę. Teraz pora na instalację PWS CLI, czyli konsoli do zarządzania aplikacją. Po instalacji logujemy się w sposób pokazany na stronie. 2
  4. Wdrażamy!

  5. Podglądamy efekt na stronie.

    Wdrożone!
    Wdrożone!
  6. Uczymy się korzystać z konsoli tekstowej oraz z widoku www.

Ile to kosztuje?

Cena to $0.03 za GB RAM na godzinę. Na stronie http://run.pivotal.io/pricing/ mamy wygodny suwak do obliczania kosztów:

Szacunkowe koszty utrzymania aplikacji
Szacunkowe koszty utrzymania aplikacji

$87 dostałam za darmo, na chwilę powinno wystarczyć.

Co dalej?

Przydałoby się to wdrażać automatycznie z GitHuba przez jakiś serwer ciągłej integracji.

PS.

  1. Dziękuję Marcinowi M. za podpowiedzi dotyczące wdrożenia w komentarzach pod pierwszym wpisem konkursowym.
  2. Poświęciłam wcześniej chwilę na rozpoznanie chmury OpenShift, ale dokumentacja była (dla mnie) znacznie mniej czytelna.

 

 

HTML5 na pomoc, czyli Firefox ssie

Na konkurs wymyśliłam sobie aplikację webową, no więc dłubię w formularzach. Staram się odpowiednio opisywać model danych (w Javie), na przykład:

Jednak niektóre typy danych są tradycyjnie kłopotliwe (polecam ten angielskojęzyczny artykuł na temat walidacji adresów email w oparciu o wyrażenia regularne).

Okazało się, że standard HTML5 opisuje specjalne typy pól wejściowych dla adresu email oraz daty. W kodzie strony wygląda to tak:

Email

Najpierw email. W Firefoksie mamy:

Walidacja adresu email w przeglądarce Firefox
Walidacja adresu email w przeglądarce Firefox

W Chrome podobnie, ale dostajemy trochę więcej informacji:

Walidacja adresu email w przeglądarce Google Chrome
Walidacja adresu email w przeglądarce Google Chrome

Data

Przy datach jest jeszcze ciekawiej.

Oto Chrome:

ch1
Pole do wprowadzania daty w Chrome, widok po załadowaniu
ch2
Pole do wprowadzania daty w Chrome, widok po najechaniu myszką i rozwinięciu menu

Co na to Firefox?

Firefox się nie wykazuje
Firefox się nie wykazuje

Firefox nic, Explorer oczywiście także.

Boję się przeglądarki Chrome. Google czyta moje maile i wie, czego szukam w Internecie. To, co wpisuję w pasku adresowym jest dla mnie ostatnią granicą… Ale w tej chwili chciałabym, żeby wszyscy użytkownicy korzystali właśnie z niej 🙂

 

Na co komu Maven?

Mój zalążek projektu kompiluję i buduję przy użyciu Mavena. Maven (ang. “spec”) to narzędzie do budowania projektów napisanych w Javie. Sam Maven także został napisany w tym języku. Maven pozwala w uporządkowany sposób zarządzać zagadnieniami takimi jak: kompilacja, testowanie, budowanie, wynajdowanie i pobieranie zależności, generowanie dokumentacji.

Po co mi Maven, skoro mogę zbudować projekt w moim IDE? Po pierwsze, IDE nie zawsze jest pod ręką i może nagle okazać się, że na komputerze kolegi nie da się zbudować pilnie poprawionej wersji kodu, gdyż brakuje pięciu bibliotek (a po ich pobraniu – pięciu kolejnych, wymaganych przez te pierwsze). Po drugie, jeśli kod ma być testowany, a nawet wdrażany automatycznie, to przecież potrzebna jest możliwość uruchomienia go z zewnątrz. Po trzecie wreszcie – Maven to cała masa udogodnień i gotowych rozwiązań.

Konfigurację projektu mavenowego umieszcza się w pliku pom.xml. Plik ten można napisać samemu, ale najczęściej jest on generowany przez jakiś inicjalizator. W moim wypadku był to wspomniany już wcześniej Spring Initializr, ale najczęściej szablon generuje sam Maven w oparciu o żądany “archetyp”. Poniższe wywołanie stworzy szkielet aplikacji webowej z odpowiednio zainicjalizowanym plikiem pom.xml:

Powstaje w ten sposób następująca struktura:

Wygląda znajomo?

Plik pom.xml mojego projektu wygląda tak:

Co oznaczają poszczególne elementy?

  • project: obowiązkowy znacznik najwyższego poziomu.
  • modelVersion: informacja o tym, z jakiego modelu DOM (Document Object Model) korzysta dany pom.xml. DOM w Mavenie zmienia się bardzo rzadko.
  • groupId: unikatowy identyfikator organizacji bądź grupy, która stworzyła projekt; najlepiej oparty o URL.
  • artifactId: nazwa głównego artefaktu generowanego przez projekt.
  • packaging: rodzaj wynikowego archiwum (e.g. JAR, WAR, EAR, etc.).
  • version: wersja powstałego artefaktu. SNAPSHOT oznacza wersję roboczą, do której się nie przywiązujemy.
  • name: wyświetlana (np. w dokumentacji) nazwa projektu.
  • description: krótki opis projektu
  • parent: (nieobowiązkowy) nadrzędny pom.xml, w którym zawarte są różne domyślne ustawienia projektu (np. kodowanie, konfiguracja pluginów).
  • properties: właściwości projektu. Ja podaję kodowanie źródeł oraz wersję Javy.
  • dependencies: zależności, czyli biblioteki potrzebne do zbudowania projektu. Jeśli nie ma ich na dysku, zostaną pobrane z repozytorium Mavena. Oprócz id grupy i artefaktu najczęściej trzeba podać także wersję, ale w tym wypadku wersjami podstawowych bibliotek zarządza wspomniany przed chwilą rodzic.
  • build: tu można zdefiniować podstawowe informacje na temat procesu budowania, np. lokalizację zasobów, profile budowania, niezbędne pluginy i ich konfiguracja. Pluginy w Mavenie mogą wszystko: potrafią przeprowadzić statyczną analizę kodu, przeformatować pliki itp. Moja aplikacja korzysta w tej chwili z pluginu Spring Boot Maven plugin, który umożliwia tworzenie uruchamialnych plików z aplikacją webową

Gdzie Maven przechowuje biblioteki?
Jeśli w systemie brakuje wymaganych bibliotek, Maven pobiera je ze zdalnego repozytorium http://mvnrepository.com lub innych wskazanych repozytoriówi umieszcza w repozytorium lokalnym.

Domyślna lokalizacja lokalnego repozytorium Mavena w systemie Windows
Domyślna lokalizacja lokalnego repozytorium Mavena w systemie Windows

Oto najważniejsze standardowe polecenia Mavena (kolejność nie jest przypadkowa):

  • validate: sprawdź, czy projekt jest skonfigurowany w sposób umożliwiający jego zbudowanie.
  • compile: skompiluj kod, jeśli zmienił się od poprzedniego razu
  • test: przetestuj kod (testy jednostkowe, niewymagające wdrożenia).
  • package: w oparciu o skompilowany kod utwórz wynikowe archiwum (np. JAR czy WAR).
  • integration-test: przeprowadź testy integracyjne (może obejmować wdrożenie).
  • verify: sprawdź jakość wynikowego archiwum.
  • install: zainstaluj archiwum w lokalnym repozytorium Mavena. Projekt stanie się wówczas dostępny jako zależność dla innych projektów.
  • deploy: wdróż!
  • clean: usuń wszystkie artefakty wygenerowane przez poprzednie buildy.
  • site: wygeneruj dokumentację (HTML w oparciu o Javadoc).

Jak to wygląda w moim projekcie? W oparciu o pom.xml powstanie plik szafbook-0.0.1-SNAPSHOT.jar. Mogę go uruchomić w konsoli – zawiera wbudowany serwer Tomcata, na którym odpali się moja aplikacja.

console
Maven w konsoli

Mavena można podpiąć pod wszystkie najważniejsze IDE. W Eclipse będzie to wyglądało tak:

Maven zintegrowany z Eclipse
Maven zintegrowany z Eclipse

W kolejnym wpisie postaram się odpowiedzieć (sobie) na pytanie, czy w przypadku mojego projektu warto porzucić Mavena na rzecz coraz popularniejszego systemu budowania Gradle.

Bonus: troubleshooting. Gdzie mój pom.xml?!  Eclipse domyślnie wyświetla pom.xml w postaci formularza. Poniższa ilustracja pokazuje, gdzie kliknąć, żeby dostać się do wersji tekstowej.

Przejście do wersji tekstowej w Eclipse
Przejście do wersji tekstowej w Eclipse

A więc do tego służy git rebase!

Miałam zakończyć raportowanie postępów w nauce systemu kontroli wersji Git, ale właśnie zrozumiałam coś istotnego.

Lubię często wysyłać stan pracy do repozytorium – czuję się wtedy bezpiecznie (chociaż akurat Eclipse jest dość pomocny jeśli chodzi o odzyskiwanie wersji z lokalnej historii). Podczas pracy nad poprzednim wpisem wysłałam do swojego lokalnego repozytorium Git masę głupich “testowych” commitów. Byłam przekonana, że nie zostawią śladu w ostatecznej wersji w GitHub. Tyle że… zostawiły! Przy wypychaniu zmian do repozytorium zdalnego przekazywana jest tam cała historia. O wstydzie, o chaosie!

Podczas dzisiejszych eksperymentów z silnikiem szablonów Thymeleaf, nauczona doświadczeniem oraz komentarzami do wcześniejszego wpisu, postanowiłam skorzystać z opcji git rebase -i, która pozwala interaktywnie uporządkować i scalić commity. W ten sposób do zdalnego repozytorium w serwisie GitHub trafi ostateczny i kontrolowany wynik mojej pracy, a nie poszczególne jej fragmenty.

A było tak:

1. Potrzebowałam trzech commitów, żeby przy użyciu Thymeleaf zwrócić użytkownikowi powitalną stronę:

Aktualny stan aplikacji (commit bbafde0)
Aktualny stan aplikacji (commit bbafde0)

2. Eclipse jak zwykle trzymał rękę na pulsie:

O trzy kroki do przodu względem zdalnej gałęzi master
O trzy kroki do przodu względem zdalnej gałęzi master

3. Nie potrafię użyć interaktywnego rebase w Eclipse, dlatego na chwilę przenoszę się do konsoli:

4. Konsola gita usłużenie wyświetla mi plik w edytorze vim, który to edytor zawsze jest mile widziany pod Windowsem (not):

Co mogę zrobić z moimi trzema commitami?
Co mogę zrobić z moimi trzema commitami?

Edycja pliku pociągnie za zmianę historii repozytorium. Na samej górze widać moje trzy commity i towarzyszące im opisy. Poniżej mam bardzo czytelną instrukcję. Słowo pick na początku każdej z trzech linii odpowiadających commitom mogę zamienić na jedną z dostępnych komend.

5. Oto mój wybór:

Zdecyduj się, człowieku!
Zdecyduj się, człowieku!

Zdecydowałam, że chcę wcielić dwa ostatnie commity do pierwszego i odrzucić ich opisy (fixup), a także zmienić opis pierwszego commita (reword).

6. Po zamknięciu i zapisaniu pliku pojawia się kolejny, w którym mogę edytować opis jedynego pozostałego przy życiu commita:

Nowy komentarz do commita
Nowy komentarz do commita

7. Wracam do konsoli, gdzie czeka na mnie podnoszący na duchu komunikat:

8. Wracam do Eclipse. Po odświeżeniu projektu widzę, że rzeczywiście commity w lokalnym repozytorium zostały scalone do jednego:

Tylko jeden krok do przodu względem zdalnej gałęzi master
Tylko jeden krok do przodu względem zdalnej gałęzi master

9. Wypycham kod do GitHuba. Tym razem na stronie widać jeden kompletny commit, a nie zbieraninę drobnicy, jak poprzednio.

Jeden commit zamiast trzech
Jeden commit zamiast trzech

PS. Zrozumiałam już, że mimo że jestem tu sama, nie powinnam pracować w gałęzi master. Mam natomiast wątpliwości związane z wypychaniem chwilowych branchy do GitHuba. Może wypowie się któryś z moich gitowych pomocników?

PS2. To jest czwarty wpis na temat Gita. Poprzednie to:

3.. 2.. 1.. Witaj, Spring Boot!

Dopiero teraz, przy piątym wpisie w ramach konkursu Daj się poznać, osiągnęłam etap aplikacji “Witaj Świecie”. No cóż. W tym artykule opowiem krótko co przy tej okazji zrobiłam i co mnie zaskoczyło. Kod jest, oczywiście, dostępny w GitHubie.

Szkielet aplikacji

Za radą Java Magazine, szkielet aplikacji wygenerowałam przy użyciu serwisu Spring Initializr.

Struktura projektu Spring Boot
Struktura projektu Spring Boot

Najważniejsze elementy w strukturze aplikacji to (tradycyjnie zresztą):

  • katalog src/main/java z kodem w języku Java (domyślnie wypełniany przez Spring Initializr jedną klasą o nazwie Application),
  • katalog src/test/java z testami jednostkowymi,
  • src/main/resources to miejsce na zasoby; podkatalog static ma zawierać pliki przetwarzane po stronie klienta (obrazki, javascript), a podkatalog templates szablony przetwarzane po stronie serwera,
  • plik pom.xml to informacje dla Mavena, którego wybrałam jako narzędzie do budowania mojego projektu; zawiera przede wszystkim listę potrzebnych mi bibliotek.
Hello World!

Aplikacja kompilowała się już w poprzedniej odsłonie, ale teraz zależało mi na jej uruchomieniu i wyświetleniu czegoś w przeglądarce. W oparciu o tutorial na stronie Springa powstał ten oto skomplikowany kontroler:

  • @RestController to adnotacja, która sprawi, że klasa będzie mogła obsługiwać żądania REST. Jej użycie jest równoważne zastosowaniu dwóch innych adnotacji: @Controller and @ResponseBody. W ten sposób tworzę kontroler, który zwraca dane tekstowe (a nie kod HTML).
  • @RequestMapping pozwala określić adres, pod jakim ma być dostępny kontroler. W naszym wypadku będzie to adres najwyższego rzędu.

Klasa uruchamiająca aplikację wygląda w najprostszej wersji tak:

  • Adnotacja @SpringBootApplication również grupuje kilka innych adnotacji. Być może najistotniejsza z nich to @ComponentScan. Dzięki niej pakiet, w którym umieściłam kod zostanie przeszukany pod kątem usług sieciowych – w ten sposób znaleziony zostanie HelloController.

Za radą tutoriala urozmaiciłam sobie efekt w konsoli dodając kod przeglądający ziarna (beans) dostępne w tzw. kontekście aplikacji.

Jak to wygląda w przeglądarce? Zerknij na nagłówek tego wpisu.

Poniżej przedstawiam dane wypisane w konsoli. Zwróć uwagę, że aplikacja webowa jest uruchamiania w wierszu poleceń z pliku JAR, a nie z pliku WAR wgranego na serwer. Jak to możliwe? Otóż przy aktualnej konfiguracji, wynikowy plik JAR zawiera wbudowaną wersję serwera Tomcat. Wielkość szafbook-0.0.1-SNAPSHOT.jar to 33 MB…

Głupie wtopy: co zrobiłam nie tak przy pierwszym podejściu

Problem 1: Aplikacja buduje się (przy użyciu Mavena) w Eclipse i nie buduje się na zewnątrz. Rozwiązanie: Instalacja w systemie Mavena 3 i przestawienie Eclipse na tę samą instalację (wcześniej Eclipse korzystał z instalacji wbudowanej, a w systemie miałam Mavena 2).

Problem 2: java.lang.UnsupportedClassVersionError Rozwiązanie: Zmiana wartości zmiennej  JAVA_HOME  w systemie na wersję Javy używaną przez projekt w Eclipse.

Problem 3: Aplikacja działa w przeglądarce, ale w konsoli mam “java.lang.IllegalStateException: Tomcat connector in failed state“. Rozwiązanie: Usunąć zduplikowane wywołanie SpringApplication.run 🙂 Sukcesem może zakończyć się tylko jedno z nich, potem port będzie już zajęty.

Co dalej?

Jeśli chodzi o rozwijanie projektu, to najbliższe prace poświęcone będą:

  1. Ciągłej Integracji,
  2. “M” w MVC, czyli modelowi danych.

Jeśli chodzi o blogowanie, to planuję wpisy bezpośrednio związane z rozwojem kodu, a dodatkowo:

  1. git rebase, którego znaczenie wreszcie zrozumiałam,
  2. Maven.
PS. Java Beans – ciekawostka lingwistyczna

W języku programowania Java istotną rolę pełnią tzw. “ziarenka”: JavaBeans oraz Enterprise JavaBeans. Dlaczego ziarenka? Otóż “Java” to w Stanach synonim słowa “kawa” (bardzo dużo kawy uprawiano na wyspie Jawie). Stąd pomysł, żeby najmniejsze samodzielne składowe aplikacji określić mianem “ziaren kawy”.

Oficjalne logo języka Java - parujący kubek z kawą
Oficjalne logo języka Java – parujący kubek z kawą