Wiedza wymagana do zrozumienia artykułu: Masz już mniej więcej rozeznanie w Java Core i chciałbyś przyjrzeć się technologiom JavaEE i programowaniu WWW . Najrozsądniej byłoby, gdybyś obecnie studiował zadanie Java Collections , które dotyczy tematów zbliżonych do tego artykułu.
Ten materiał jest logiczną kontynuacją mojego artykułu Tworzenie najprostszego projektu webowego w IntelliJ Idea Enterprise . W tym artykule pokazałem, jak utworzyć działający szablon projektu internetowego. Tym razem pokażę Ci, jak stworzyć prostą, ale bardzo atrakcyjną aplikację internetową, używając Java Servlet API i JavaServer Pages API . Nasza aplikacja będzie miała stronę główną z dwoma linkami:
Zaczynajmy. Najpierw przygotuj plik POM . Gdzieś po wpisie /version , ale przed /project wstaw następującą informację:
Przekażmy kontrolę z serwletów do plików JSP. Zmienimy kod naszych metod w następujący sposób:
- link do strony dodawania użytkowników;
- link do listy użytkowników.
Trochę o strukturze naszej przyszłej aplikacji
Nasza strona główna (/) będzie najzwyklejszą statyczną stroną HTML z nagłówkiem i dwoma linkami/przyciskami:- dodaj nowego użytkownika (przechodzi do / add );
- przeglądać listę użytkowników (przechodzi do / list ).
Utwórz statyczną stronę główną
Jeśli plik index.jsp znajduje się w folderze internetowym, usuń go. Zamiast tego utwórz prosty plik HTML o nazwie index.html w tym folderze:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>My super project!</title>
</head>
<body>
<!-- header -->
<div>
<h1>Super app!<//h1>
</div>
<div> <!-- content -->
<div> <!-- button holder -->
<button onclick="location.href='/list'">List users<//button>
<button onclick="location.href='/add'">Add user<//button>
</div>
</div>
</body>
</html>
Nie ma tu nic skomplikowanego. W tagu tytułu podajemy tytuł naszej strony. W treści strony mamy dwa główne elementy div: header i content . Div zawartości zawiera uchwyt na nasze przyciski. I tam mamy dwa przyciski, które jednym kliknięciem przenoszą Cię pod odpowiedni adres. Możesz uruchomić projekt i zobaczyć, jak wygląda teraz. Jeśli klikniesz przyciski, otrzymasz strony błędów 404, ponieważ odpowiednie strony jeszcze nie istnieją. Ale możemy powiedzieć, że przyciski działają. Pamiętaj, że nie jest to najbardziej uniwersalne podejście: jeśli JavaScript jest wyłączony w przeglądarce, te przyciski nie będą działać. Ale założymy, że nikt nie wyłącza JavaScriptu. :) Oczywiście można sobie poradzić z prostymi linkami, ale ja wolę przyciski. Możesz to zrobić jak wolisz. I nie martw się tym faktem, że moje przykłady będą miały dużo elementów div . Później uzupełnimy je stylami i wszystko będzie wyglądać piękniej. :)
Utwórz pliki JSP, aby wyrenderować wynik
W tym samym katalogu internetowym utwórz folder, w którym dodamy nasze pliki JSP . Nazwałem to ' widokami ', ale znowu można improwizować. W tym folderze utworzymy dwa pliki JSP:- add.jsp — strona służąca do dodawania użytkowników;
- list.jsp — strona wyświetlająca listę użytkowników.
Utwórz dwa serwlety
Serwlety będą odbierać i przetwarzać żądania wysyłane przez Tomcat . W folderze src/main/java utwórz pakiet aplikacji , w którym umieścimy nasz kod źródłowy. Trafią tam również inne paczki. Aby zapobiec tworzeniu się tych pakietów wewnątrz siebie, utworzymy klasę w pakiecie aplikacji (usuniemy ją później). Teraz utwórz trzy różne pakiety w pakiecie aplikacji :- encje — tutaj trafiają nasze encje (klasa opisująca obiekty użytkownika);
- model — tutaj idzie nasz model (porozmawiamy o tym trochę później);
- serwlety — i właśnie tam trafiają nasze serwlety.
- AddServlet — przetwarza żądania wysłane do / add ;
- ListServlet — przetwarza żądania wysyłane do / list .
Łączenie zależności w Maven
Tomcat 9. * implementuje specyfikacje Servlet 4.0 i JavaServer Pages 2.3 . Tak napisano w drugim wierszu pierwszego akapitu oficjalnej dokumentacji Tomcat 9. Oznacza to, że jeśli tak jak ja używasz tej wersji Tomcata , to kod, który napiszesz i uruchomisz, będzie korzystał z tych wersji. Ale chcielibyśmy mieć te specyfikacje w naszym projekcie, aby nasz kod, który ich używa, przynajmniej kompilował się pomyślnie. Aby to zrobić, musimy załadować je do naszego projektu. Tu na ratunek przychodzi Maven .
Ogólna zasada jest taka: jeśli chcesz podłączyć coś do swojego projektu za pomocą Mavena:
|
<dependencies>
</dependencies>
Robimy to, aby wskazać, że wymienimy wymagane zależności w tych tagach. Teraz przejdź do mvnrepository.com . U góry znajduje się pole wyszukiwania. Aby rozpocząć, wyszukaj „ servlet ”. Pierwszy wynik, który został użyty ponad siedem tysięcy razy, nam odpowiada. Pamiętaj, że potrzebujemy wersji 4.0 (dla Tomcat 9). Inne wersje mogą być odpowiednie dla starszych implementacji. Jest to dość nowa wersja, więc nie ma zbyt wielu zastosowań. Ale potrzebujemy tego. Zostanie otwarta strona, na której można uzyskać kod tej zależności dla różnych menedżerów pakietów lub po prostu go pobrać. Ale ponieważ chcemy połączyć go za pomocą Mavena, wybierzemy kod na karcie Maven. Kopiujemy i wklejamy do sekcji zależności naszego pliku POM. Jeśli otrzymasz powiadomienie z pytaniem, czy chcesz włączyć automatyczne importowanie w prawym dolnym rogu IDEA , śmiało i zaakceptuj to. Jeśli przypadkowo odmówiłeś, przejdź do „ Ustawień ” i włącz automatyczny import ręcznie: Ustawienia (Ctrl + Alt + S) -> Kompilacja, wykonanie, wdrożenie -> Maven -> Importowanie .i pliki konfiguracyjne IDEA dla tego projektu zsynchronizowane. Kierując się tą samą zasadą, znajdziemy i połączymy JavaServer Pages 2.3 (szukaj „JSP”). A ponieważ już uruchomiliśmy Mavena, powiedzmy mu, że nasze pliki źródłowe są zgodne ze składnią Javy 8 i że musimy skompilować je do kodu bajtowego dla tej wersji. Po wszystkich tych krokach nasz pom.xml będzie wyglądał mniej więcej tak:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>cc.codegym.info.fatfaggy</groupId>
<artifactId>my-super-project</artifactId>
<version>1.0-SNAPSHOT</version>
<properties>
<maven.compile.source>1.8</maven.compile.source>
<maven.compile.target>1.8</maven.compile.target>
</properties>
<dependencies>
<!-- Servlet API 4.0 for tomcat 9 -->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>4.0.0</version>
<scope>provided</scope>
</dependency>
<!-- JavaServer Pages API 2.3 for tomcat 9 -->
<dependency>
<groupId>javax.servlet.jsp</groupId>
<artifactId>javax.servlet.jsp-api</artifactId>
<version>2.3.1</version>
<scope>provided</scope>
</dependency>
</dependencies>
</project>
Zmień nasze serwlety w prawdziwe serwlety
W tej chwili stworzona przez nas para serwletów to tak naprawdę zwykłe klasy. Nie mają żadnej funkcjonalności. Ale teraz połączyliśmy Servlet API z naszym projektem i odpowiednio możemy używać jego klas. Aby nasze serwlety były „prawdziwe”, wystarczy, że odziedziczą klasę HttpServlet .Mapowanie lub znaczniki
Teraz dobrze byłoby jakoś powiedzieć Tomcatowi , że żądania adresu / add są przetwarzane przez nasz AddServlet , a żądania adresu / list są obsługiwane przez ListServlet . Ten proces nazywa się mapowaniem (znacznikami). Odbywa się to w web.xml na tej samej zasadzie:- na początek opisz serwlet (podaj nazwę i podaj ścieżkę do samej klasy);
- następnie powiąż ten serwlet z określonym adresem (podaj nazwę serwletu, którą właśnie mu nadaliśmy, oraz podaj adres, którego żądania mają być wysyłane do tego serwletu).
<servlet>
<servlet-name>add</servlet-name>
<servlet-class>app.servlets.AddServlet</servlet-class>
</servlet>
Teraz powiąż go z adresem:
<servlet-mapping>
<servlet-name>add</servlet-name>
<url-pattern>/add</url-pattern>
</servlet-mapping>
Jak widać, nazwa-servletu jest taka sama w obu przypadkach. W rezultacie Tomcat wie, że jeśli odebrane zostanie żądanie /add, musi ono zostać wysłane do app.servlets.AddServlet. To samo robimy z drugim serwletem. Ostatecznie nasz plik web.xml zawiera w przybliżeniu następującą treść:
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
version="3.1">
<!-- add servlet -->
<servlet>
<servlet-name>add</servlet-name>
<servlet-class>app.servlets.AddServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>add</servlet-name>
<url-pattern>/add</url-pattern>
</servlet-mapping>
<!-- list servlet -->
<servlet>
<servlet-name>list</servlet-name>
<servlet-class>app.servlets.ListServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>list</servlet-name>
<url-pattern>/list</url-pattern>
</servlet-mapping>
</web-app>
Nawiasem mówiąc, nie stworzyliśmy znaczników dla strony głównej (/). Faktem jest, że w tym przypadku nie jest nam to potrzebne. Nasza strona główna to prosty plik HTML, który wyświetla tylko dwa przyciski. Nie ma dynamicznej zawartości, więc nie musimy tworzyć osobnego serwletu dla żądań z / , który nie zrobi nic poza przekazaniem wykonania do jakiejś strony JSP (która również musiałaby zostać utworzona), aby narysować dla nas dwa przyciski. Nie potrzebujemy tego. Strona statyczna nam odpowiada. Kiedy Tomcat otrzyma żądanie, sprawdzi, czy istnieje pojedynczy serwlet, który mógłby przetworzyć żądanie dla tego adresu, a następnie zobaczy, że ten adres faktycznie zawiera już gotowy plik HTML, które będzie obsługiwał. Możemy ponownie uruchomić naszą aplikację (zrestartować serwer lub ponownie ją wdrożyć – jak wolisz) i upewnić się, że strona główna jest renderowana, nic się nie popsuło, a przejścia następują po kliknięciu przycisków (choć znowu pojawia się błąd). Nawiasem mówiąc, podczas gdy wcześniej mieliśmy błąd 404, teraz mamy błąd 405. Oznacza to, że mapowanie zadziałało i aplety zostały znalezione, ale nie miały odpowiedniej metody obsługi żądania.
Krótka dygresja: co dzieje się „pod maską”?
Pewnie już zastanawiałeś się, jak działa nasza aplikacja w Tomcat. Co się tam dzieje? A gdzie jest metoda main()? Gdy tylko przejdziesz do localhost:8080 w przeglądarce, przeglądarka wyśle żądanie na ten adres za pomocą protokołu HTTP. Mam nadzieję, że już wiesz, że istnieje wiele różnych typów żądań, a najpopularniejsze to GET i POST. Na każdą prośbę należy odpowiedzieć. Oczekuje się, że żądanie GET otrzyma odpowiedź w postaci gotowego do użycia kodu HTML, zwróconego do przeglądarki. Następnie przeglądarka zastępuje kod wszystkimi ładnymi literami, przyciskami i formularzami. Żądanie POST jest nieco bardziej interesujące, ponieważ zawiera również pewne informacje. Załóżmy na przykład, że wprowadzasz poświadczenia w formularzu rejestracji lub logowania w witrynie internetowej i klikasz „Wyślij”. Powoduje to wysłanie żądania POST z Twoimi danymi osobowymi na serwer. Serwer otrzymuje te informacje, przetwarza je i zwraca odpowiedź (na przykład stronę HTML z Twoim profilem). Główna różnica między nimi polega na tym, że żądania GET służą tylko do pobierania danych z serwera, podczas gdy żądania POST niosą pewne informacje (a dane na serwerze mogą się zmieniać). Na przykład, gdy przesyłasz swoje zdjęcie na serwer, jest ono przenoszone tam w żądaniu POST, a serwer dodaje je do bazy danych, czyli następuje zmiana. Wróćmy teraz do Tomcata. Kiedy otrzymuje żądanie od klienta, sprawdza adres. Sprawdza, czy istnieje odpowiedni serwlet do przetwarzania żądań dla tego adresu (lub dostępnego zasobu, który można natychmiast zwrócić). Jeśli nie znajdzie czegoś do zwrócenia, następnie odpowiada błędem 404 zamiast strony HTML. Ale jeśli znajdzie odpowiedni aplet „siedzący” pod tym adresem, wtedy sprawdza typ żądania (GET, POST lub coś innego) i pyta aplet, czy ma metodę, która może obsłużyć tego typu zapytanie. Jeśli aplet mówi, że nie wie, jak obsłużyć ten typ, to wtedyTomcat zwraca kod 405. I tak właśnie stało się w naszym projekcie. Ale jeśli zostanie znaleziony odpowiedni serwlet i ma odpowiednią metodę, Tomcat tworzy obiekt serwletu, uruchamia go w nowym wątku(co pozwala mu działać samodzielnie), a Tomcat kontynuuje własną pracę, akceptując i wysyłając żądania. Dodatkowo Tomcat tworzy jeszcze dwa obiekty: HttpServletRequest (który będę w skrócie nazywał „żądaniem”) oraz HttpServletResponse (który będę nazywał „odpowiedzią”). Umieszcza wszystkie dane otrzymane z żądania klienta w pierwszym obiekcie, więc wszystkie te dane można z niego wydobyć. A potem po tym wszystkim przekazuje te dwa te obiekty do odpowiedniej metody serwletu, który został uruchomiony w osobnym wątku. Gdy tylko aplet zakończy swoją pracę i otrzyma odpowiedź gotową do wysłania do klienta, macha flagą do Tomcata, mówiąc: „Skończyłem. Wszystko jest gotowe”. Tomcat odbiera odpowiedź i wysyła ją do klienta. Dzięki temu Tomcat może odbierać żądania i wysyłać odpowiedzi, bez rozpraszania się, a całą pracę wykonują serwlety działające w osobnych wątkach. Oznacza to, że kiedy piszemy kod serwletu, określamy, jaka praca zostanie wykonana. Możesz myśleć o metodzie main() jako o ulokowanej wewnątrz samego Tomcata (tak, jest napisana w Javie), a kiedy „uruchamiamy” Tomcata, uruchamiana jest metoda main().Używaj serwletów do przechwytywania metod GET i wysyłania bardzo prostych odpowiedzi
W tej chwili nasze serwlety nie mają odpowiednich metod (GET), więc Tomcat zwraca błąd 405. Stwórzmy je! Klasa HttpServlet, którą dziedziczymy w naszych serwletach, deklaruje różne metody. Aby przypisać metodom określony kod, po prostu je nadpisujemy. W takim przypadku musimy nadpisaćdoGet()
metodę w obu serwletach.
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
}
Jak widać, ta metoda przyjmuje dwa argumenty: req (żądanie) i resp (odpowiedź). Są to dokładnie te obiekty, które Tomcat tworzy i zapełnia dla nas, gdy wywołuje odpowiednią metodę w serwlecie. Na początek utworzymy najprostsze odpowiedzi. Aby to zrobić, weźmiemy obiekt resp i pobierzemy z niego obiekt PrintWriter. Ten typ obiektu służy do tworzenia odpowiedzi. Użyjemy go do wyświetlenia prostego ciągu znaków.
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
PrintWriter writer = resp.getWriter();
writer.println("GET method from AddServlet");
}
Zrobimy coś podobnego w ListServlet, a następnie zrestartujemy nasz serwer. Jak widać wszystko działa! Klikając na przyciski, otrzymujesz strony z tekstem, który „napisaliśmy” za pomocą PrintWriter. Ale pliki JSP, które przygotowaliśmy do generowania stron z odpowiedziami, nie są używane. To po prostu dlatego, że nigdy nie są wykonywane. Nasz aplet sam tworzy odpowiedź i kończy działanie, sygnalizując Tomcatowi, że jest gotowy do udzielenia odpowiedzi klientowi. Tomcat po prostu pobiera odpowiedź i odsyła ją z powrotem do klienta.
- z obiektu request uzyskujemy obiekt requestera i przekazujemy mu adres strony JSP, na którą chcemy przekazać kontrolę;
- używamy tego obiektu do przekazania kontroli na określoną stronę JSP, nie zapominając o przekazaniu obiektów żądania i odpowiedzi, które otrzymaliśmy od Tomcata.
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
RequestDispatcher requestDispatcher = req.getRequestDispatcher("views/add.jsp");
requestDispatcher.forward(req, resp);
}
W tagu body stron JSP możesz dodać coś, abyśmy mogli wyraźnie zobaczyć, która strona jest wyświetlana. Gdy to zrobisz, zrestartuj serwer i sprawdź. Klikamy przyciski na stronie głównej i otwierają się strony, co oznacza, że żądania są wysyłane do serwletów. Następnie kontrola jest przekazywana do stron JSP, które są teraz renderowane. To wszystko na teraz. W kolejnej części artykułu zajmiemy się funkcjonalnością naszej aplikacji.
GO TO FULL VERSION