JavaRush /Blog Java /Random-PL /Tworzenie prostej aplikacji internetowej z wykorzystaniem...
Стас Пасинков
Poziom 26
Киев

Tworzenie prostej aplikacji internetowej z wykorzystaniem serwletów i jsp (część 1)

Opublikowano w grupie Random-PL
Poziom wiedzy wymagany do zrozumienia artykułu: znasz już mniej więcej Java Core i chciałbyś przyjrzeć się technologiom JavaEE oraz programowaniu webowemu. Ma to największy sens, jeśli aktualnie studiujesz zadanie Kolekcje Java, które obejmuje tematy zbliżone do artykułu. Tworzenie prostej aplikacji internetowej z wykorzystaniem serwletów i jsp (część 1) - 1Materiał ten stanowi logiczną kontynuację mojego artykułu Tworzenie prostego projektu internetowego w IntelliJ Idea Enterprise . Pokazałem w nim jak stworzyć działający szablon projektu internetowego. Tym razem pokażę Ci, jak stworzyć prostą, ale ładną aplikację internetową, korzystając z technologii Java Servlet API i JavaServer Pages API. Nasza aplikacja będzie miała stronę główną z dwoma linkami:
  • do strony dodawania użytkownika;
  • do strony widoku listy użytkowników.
Nadal będę używać IntelliJ Idea Enterprise Edition, Apache Maven (wystarczy uwzględnić kilka zależności) i Apache Tomcat. Na koniec „udekorujemy” naszą aplikację wykorzystując framework W3.CSS . Zakładamy, że w tej chwili masz już pusty projekt, który będziemy tutaj rozwijać. Jeśli nie, przejrzyj pierwszy artykuł i zrób to. Zajmie to tylko kilka minut :)

Trochę o strukturze przyszłej aplikacji

Nasza strona główna ( / ) będzie najzwyklejszą statyczną stroną HTML z nagłówkiem i dwoma linkami/przyciskami:
  • dodaj nowego użytkownika (zostanie wysłany do /add );
  • przeglądać listę użytkowników (wysyła do /list ).
Tomcat przechwyci żądania kierowane na te adresy i wyśle ​​je do jednego z dwóch serwletów, które stworzymy (mapowanie opiszemy w pliku web.xml ). Z kolei serwlety będą przetwarzać żądania, przygotowywać dane (lub zapisywać je, jeśli użytkownik zostanie dodany) i przekazywać kontrolę do odpowiednich plików jsp, które już „wyrenderują” wynik. Dane będziemy przechowywać na najczęstszej liście (Lista).

Stwórzmy statyczną stronę główną

Jeśli w folderze internetowym znajduje się plik Index.jsp , usuń go. Zamiast tego w tym folderze utworzymy prosty plik HTML o nazwie indeks.html :
<!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>    <!-- buttons 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 tytule podajemy tytuł naszej strony. W treści strony mamy dwa główne elementy div: nagłówek (header) i content (content). W treści mamy uchwyt na nasze przyciski, a właściwie dwa przyciski, które po kliknięciu wysyłane są pod odpowiednie adresy. Możesz uruchomić projekt i zobaczyć, jak wygląda teraz. Jeśli klikniesz przyciski, otworzą się strony z błędem 404, ponieważ jeszcze ich nie mamy. Ale to sugeruje, że przyciski działają. Zaznaczę, że nie jest to opcja najbardziej uniwersalna, bo jeśli nagle wyłączymy JavaScript, te przyciski nie będą przydatne w przeglądarce. Załóżmy jednak, że nikt nie wyłączył JavaScriptu :). Oczywiste jest, że można zastosować proste linki, ale ja wolę przyciski. Robisz to, co lubisz najbardziej. I nie patrz na to, że w moich przykładach będzie dużo divów . Wtedy wypełnimy je stylizacjami i wszystko będzie wyglądało piękniej :).

Utwórz pliki jsp, aby wyrenderować wynik

W tym samym katalogu internetowym utworzymy folder, w którym będziemy umieszczać nasze pliki jsp . Nazwałem to widokami i znowu możesz improwizować. W tym folderze utworzymy dwa pliki jsp:
  • add.jsp — strona dodawania użytkowników;
  • list.jsp - strona wyświetlająca listę użytkowników.
Nadajmy im odpowiednie nagłówki stron. Coś w stylu „Dodaj nowego użytkownika” i „Lista użytkowników” i na razie tak to zostawimy.

Stwórzmy dwa serwlety

Serwlety będą akceptować i przetwarzać żądania przekazywane im przez Tomcat. W folderze src/main/Java utworzymy pakiet aplikacji , który będzie zawierał nasze źródła. Tam będziemy mieli więcej różnych pakietów. Dlatego, aby te pakiety nie tworzyły się wewnątrz siebie, utwórzmy jakąś klasę w pakiecie aplikacji (następnie ją usuń). Utwórzmy teraz trzy różne pakiety w pakiecie aplikacji :
  • encje - tutaj będą znajdować się nasze encje (sama klasa, która będzie opisywać obiekty użytkownika);
  • model - nasz model będzie tutaj (więcej o tym nieco później);
  • serwlety - cóż, tutaj będą nasze serwlety.
Następnie możesz bezpiecznie usunąć tę klasę z pakietu aplikacji (oczywiście jeśli ją utworzyłeś). Utwórzmy dwie klasy w pakiecie serwletów :
  • AddServlet – przetwarza żądania otrzymane w /add ;
  • ListServlet – przetwarza żądania otrzymane w /list .

Łączenie zależności w Maven

Tomcat w wersji 9.* implementuje specyfikacje Servlet w wersji 4.0 i JavaServer Pages w wersji 2.3. Jest to napisane w oficjalnej dokumentacji Tomcata 9 w pierwszym akapicie w drugim wierszu. Oznacza to, że jeśli tak jak ja używasz tej wersji Tomcata, kod, który piszemy i wysyłamy do uruchomienia, będzie korzystał z dokładnie określonych wersji. Chcielibyśmy jednak mieć te specyfikacje w naszym projekcie, aby nasz kod, który je wykorzystuje, przynajmniej pomyślnie się skompilował. W tym celu musimy załadować je do naszego projektu. Tutaj na ratunek przychodzi Maven.

Ogólna zasada jest następująca: jeśli chcesz połączyć coś ze swoim projektem za pomocą Mavena:

  • przejdź do strony repozytorium Maven;
  • poszukaj tam potrzebnej biblioteki i wersji, której potrzebujesz;
  • otrzymasz kod zależności, który należy wstawić do pliku pom.xml;
  • wstawić! :)
Zacznijmy więc. Najpierw przygotujmy plik pom . Gdzieś po /version , ale przed /project , wstaw następujące polecenie:
<dependencies>

</dependencies>
Dlatego wskazaliśmy, że wewnątrz tych tagów wyszczególnimy potrzebne nam zależności. Teraz przejdź do mvnrepository.com , na górze pojawi się pole wyszukiwania. Najpierw wpisz servlet w wyszukiwarce. Odpowiada nam pierwszy wynik, w którym znajduje się ponad siedem tysięcy zastosowań. Pamiętamy, że potrzebujemy wersji 4.0 (dla Tomcat 9; dla innych wersji mogą być odpowiednie starsze implementacje). To całkiem nowa wersja, więc nie ma zbyt wielu zastosowań, ale tej właśnie potrzebujemy. Otworzy się strona, na której możesz uzyskać kod tej zależności dla różnych menedżerów pakietów, a nawet możesz go po prostu pobrać. Ponieważ jednak chcemy połączyć go za pomocą Mavena, wybieramy kod na karcie Maven. Kopiujemy i wklejamy do naszego pliku pom w sekcji zależności. Jeśli w prawym dolnym rogu IDEA pojawi się powiadomienie z pytaniem, czy chcemy włączyć automatyczny import, wyrażamy zgodę. 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 Spowoduje to zachowanie pliku pom i plików konfiguracyjnych IDEA dla tego projekt zsynchronizowany. Teraz na tej samej zasadzie znajdziemy i połączymy JavaServer Pages w wersji 2.3 (w wyszukiwarce wpisz jsp). A ponieważ zajęliśmy się już Mavenem, od razu powiedzmy mu, że nasze źródła są zgodne ze składnią Java 8 i że należy je skompilować do kodu bajtowego tej samej wersji. Po tych wszystkich manipulacjach 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>ru.javarush.info.fatfaggy</groupId>
    <artifactId>my-super-project</artifactId>
    <version>1.0-SNAPSHOT</version>

    <properties>
        <maven.compiler.source>1.8</maven.compile.source>
        <maven.compiler.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>

Przekształcenie naszych serwletów w prawdziwe serwlety

W tym momencie kilka utworzonych przez nas serwletów to tak naprawdę zwykłe klasy. Nie mają żadnej funkcjonalności. Ale teraz połączyliśmy API Servletów z naszym projektem i jeśli tak, możemy używać stamtąd klas. Aby uczynić nasze serwlety „prawdziwymi” serwletami, wystarczy je odziedziczyć z klasy HttpServlet .

Mapowanie lub partycjonowanie

Teraz byłoby miło w jakiś sposób poinformować Tomcata, aby żądania z /add były obsługiwane przez nasz serwlet AddServlet , a zatem żądania z /list były obsługiwane przez serwlet ListServlet . Proces ten nazywany jest mapowaniem . Odbywa się to w pliku web.xml zgodnie z następującą zasadą:
  • najpierw opisujemy serwlet (podajemy nazwę i wskazujemy ścieżkę do samej klasy);
  • następnie wiążemy ten serwlet z konkretnym adresem (pokazujemy nazwę serwletu, który właśnie mu nadaliśmy oraz wskazujemy adres, z którego mają być wysyłane żądania do tego serwletu).
Opiszmy serwlet:
<servlet>
    <servlet-name>add</servlet-name>
    <servlet-class>app.servlets.AddServlet</servlet-class>
</servlet>
Teraz wiążemy go z adresem:
<servlet-mapping>
    <servlet-name>add</servlet-name>
    <url-pattern>/add</url-pattern>
</servlet-mapping>
Jak widać, nazwa serwletu jest taka sama w obu przypadkach. Dzięki temu Tomcat wie, że jeżeli żądanie przyjdzie pod adres /add , to należy je przekazać do serwletu app.servlets.AddServlet . To samo robimy z drugim serwletem. W rezultacie nasz plik web.xml ma w przybliżeniu następującą zawartość:
<?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 utworzyliśmy tutaj znaczników dla strony głównej (at / ). Faktem jest, że w tym przypadku nie jest nam to potrzebne. Nasza strona główna to prosty plik HTML , który wyświetla po prostu dwa przyciski. Nie ma treści dynamicznej, więc nie ma sensu tworzyć dla niej osobnego serwletu, na który będą wysyłane żądania z adresu / , a który nie będzie robił nic poza przeniesieniem wykonania na jakiś jsp (co też by musiało być utworzony), który rysowałby, gdybyśmy tylko mieli dwa przyciski. Nie potrzebujemy tego; jesteśmy zadowoleni z zasobu statycznego. Kiedy Tomcat odbierze żądanie, sprawdzi, czy pod takim adresem nie ma ani jednego serwletu, który mógłby przetworzyć żądanie, po czym zobaczy, że pod tym adresem rzeczywiście znajduje się gotowy plik html , który pomyślnie wyśle . Możemy uruchomić naszą aplikację ponownie (zrestartować serwer lub ponownie wdrożyć, jak chcesz) i upewnić się, że strona główna jest renderowana, nic nie jest zepsute, kiedy klikamy przyciski, pojawiają się przejścia, ale na razie jest też błąd pisemny. Nawiasem mówiąc, jeśli wcześniej występował błąd 404, teraz mamy błąd 405. Oznacza to, że mapowanie zadziałało, serwlety zostały znalezione, ale po prostu nie miały odpowiednich metod przetworzenia żądania. Jeśli na tym etapie nadal pojawia się błąd 404, mimo że wszystko zostało zrobione poprawnie, być może powinieneś poprawić konfigurację wdrożenia w pomyśle. W tym celu należy przejść do opcji Edytuj konfiguracje (na górze przy przycisku start), przejść do zakładki Wdrożenie po prawej stronie okna i upewnić się, że w kontekście aplikacji jest to po prostu wskazane /

Krótka dygresja liryczna: co dzieje się „pod maską”?

Pewnie zastanawiałeś się już jak działa nasza aplikacja w Tomcat? Co się tam dzieje? A gdzie jest metoda main() ? Gdy tylko wpiszesz localhost:8080 w przeglądarce i przejdziesz pod ten adres, przeglądarka wyśle ​​żądanie na ten adres za pośrednictwem protokołu http . Mam nadzieję, że już wiesz, że żądania mogą być różnego „typu”, najpopularniejsze to GET i POST . Każda prośba musi mieć odpowiedź. Żądanie GET oczekuje, że w odpowiedzi otrzyma gotowy kod HTML , który zostanie zwrócony przeglądarce, a przeglądarka pięknie zastąpi ten kod najróżniejszymi literami, przyciskami i formularzami. Żądanie POST jest nieco bardziej interesujące, ponieważ niesie ze sobą również pewne informacje. Przykładowo w formularzu rejestracji lub autoryzacji użytkownika podałeś swoje dane i kliknąłeś „wyślij”. W tym momencie do serwera zostało wysłane żądanie POST zawierające Twoje dane osobowe. Serwer przyjął te informacje, przetworzył je i zwrócił jakąś odpowiedź (na przykład stronę HTML z Twoim profilem). Zasadnicza różnica między nimi polega na tym, że żądania GET służą wyłącznie do odbioru danych z serwera, natomiast żądania POST niosą ze sobą pewne informacje, a dane na serwerze mogą ulec zmianie (np. gdy wrzucisz zdjęcie na serwer, wyśle ​​żądanie POST, a serwer doda je do bazy danych, czyli nastąpi jakaś zmiana. Wróćmy teraz do Tomcata. Kiedy otrzyma jakieś żądanie od klienta, sprawdza adres. Przeszukuje swoje dane, aby sprawdź, czy istnieje odpowiedni serwlet, który obsługiwałby żądania pod taki adres (lub gotowy zasób, który można od razu zwrócić).Jeśli nie znajdzie nic do zwrócenia, odpowiada nie stroną html, ale z odpowiedzią 404. Jeśli znajdzie odpowiedni serwlet, który „siedzi” pod tym adresem, sprawdza, jakiego typu żądanie otrzymał (GET, POST lub jakiś inny), a następnie pyta serwlet, czy posiada metodę, która mógłby obsłużyć tego typu żądanie.Jeśli serwlet powie, że nie może przetworzyć tego typu żądania, Tomcat odpowiada klientowi kodem 405. U nas właśnie to się przydarzyło. Jeśli jednak zostanie znaleziony odpowiedni serwlet i ma on odpowiednią metodę, Tomcat tworzy obiekt tego serwletu, uruchamia go w nowym wątku ( wątku ), co umożliwia pracę serwletu w osobnym wątku, a Tomcat kontynuuje pracę samodzielnie, odbieranie i wysyłanie żądań. Dodatkowo Tomcat tworzy jeszcze dwa obiekty: jeden typu HttpServletRequest (w przyszłości będę go w skrócie nazywał żądaniem) i drugi typu HttpServletResponse(nazwę to odpowiedzią). W pierwszym obiekcie umieszcza wszystkie dane, które otrzymał w żądaniu od klienta, dzięki czemu wszystkie te dane można wyciągnąć z tego obiektu. Cóż, po tym wszystkim przekazuje te dwa obiekty do odpowiedniej metody serwletu, która działa w osobnym wątku. Gdy tylko serwlet zakończy pracę i będzie miał odpowiedź gotową do wysłania do klienta, podnosi flagę do serwera Tomcat, mówiąc: „Skończyłem, wszystko jest gotowe”. Tomcat akceptuje odpowiedź i wysyła ją do klienta. Dzięki temu Tomcat może bez przerwy akceptować żądania i wysyłać odpowiedzi, podczas gdy cała praca jest wykonywana przez serwlety działające w oddzielnych wątkach. Odpowiednio, pisząc kod serwletu, definiujemy pracę, która zostanie wykonana. I tak, możesz myśleć o metodzie main() jako o samej metodzie Tomcat (tak, jest napisana w Javie), a kiedy „uruchamiamy” Tomcat, plik main().

Przechwytujemy metody GET za pomocą serwletów i wysyłamy proste odpowiedzi

W tej chwili nasze serwlety nie mają odpowiednich metod (GET), więc Tomcat zwraca nam błąd 405. Zróbmy je! Klasa HttpServlet , z której dziedziczymy nasze serwlety, definiuje różne metody. Aby ustawić jakiś kod dla metod, po prostu je nadpisujemy. W tym przypadku musimy zastąpić metodę doGet() w obu serwletach.
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {

}
Jak widać, metoda ta akceptuje dwa obiekty: req (żądanie) i resp (odpowiedź). To są te same obiekty, które Tomcat utworzy i zapełni dla nas, gdy wywoła odpowiednią metodę w tym serwlecie. Najpierw zróbmy najprostsze odpowiedzi. Aby to zrobić, weź obiekt resp i pobierz z niego obiekt PrintWriter , którego można użyć do tworzenia odpowiedzi. Cóż, za jego pomocą wydrukujemy prosty ciąg znaków.
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    PrintWriter writer = resp.getWriter();
    writer.println("Method GET from AddServlet");
}
Zrobimy coś podobnego w serwlecie ListServlet , po czym ponownie uruchomimy nasz serwer. Jak widać wszystko działa! Po kliknięciu przycisków otwierają się strony z tekstem, który „nagraliśmy” za pomocą PrintWriter . Tyle, że nasze jsp , które przygotowaliśmy do generowania stron z odpowiedziami, nie są w żaden sposób wykorzystywane. Dzieje się tak dlatego, że egzekucja po prostu do nich nie dociera. Sam serwer generuje teraz odpowiedź i kończy pracę, sygnalizując Tomcatowi, że ma gotową odpowiedź dla klienta. Tomcat po prostu przyjmuje tę odpowiedź i odsyła ją do klienta. Przekazujemy kontrolę z serwletów do jsp. Zmieńmy kod naszych metod w ten sposób:
  • z obiektu request otrzymujemy obiekt menadżera żądań, gdzie przekazujemy adres jsp strony, na którą chcemy przekazać kontrolę;
  • korzystając z otrzymanego obiektu, przekazujemy kontrolę na określoną stronę jsp i nie zapomnij załączyć tam obiektów żądań 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 treści stron jsp (wewnątrz znacznika body) możemy napisać coś, abyśmy mogli wyraźnie zobaczyć, która strona jest wyświetlana. Następnie ponownie uruchamiamy serwer i sprawdzamy. Naciskane są przyciski na stronie głównej, otwierane są strony, co oznacza wysyłanie żądań do serwletów, po czym sterowanie przekazywane jest do stron jsp, które są już wyrenderowane. To wszystko. W dalszej części artykułu zajmiemy się funkcjonalnością naszej aplikacji.

Co jeszcze warto przeczytać:

Tworzenie prostego projektu internetowego w IntelliJ Idea Enterprise. Krok po kroku, ze zdjęciami


Mój czat
Komentarze
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION