JavaRush /Java Blog /Random-IT /Creare una semplice applicazione web utilizzando servlet ...
Стас Пасинков
Livello 26
Киев

Creare una semplice applicazione web utilizzando servlet e jsp (parte 2)

Pubblicato nel gruppo Random-IT
Creare una semplice applicazione web utilizzando servlet e jsp (parte 1) Livello di conoscenza richiesto per comprendere l'articolo: hai già più o meno capito Java Core e vorresti approfondire le tecnologie JavaEE e la programmazione web. Ha più senso se stai attualmente studiando la ricerca sulle raccolte Java, che copre argomenti vicini all'articolo.
Creare una semplice applicazione web utilizzando servlet e jsp (parte 2) - 1

Creazione di entità

Nel pacchetto entità creeremo una classe User e in essa ci saranno due variabili stringa private name e password . Creiamo costruttori (predefinito e uno che accetti entrambi i valori), getter/setter, sovrascriviamo il metodo toString() per ogni evenienza, così come i metodi equals() e hashCode() . Cioè, faremo tutto ciò che fa uno sviluppatore Java decente quando crea una classe.
public class User {
    private String name;
    private String password;

    public User() {
    }

    public User(String name, String password) {
        this.name = name;
        this.password = password;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    @Override
    public String toString() {
        return "User{" +
                "name='" + name + '\'' +
                ", password='" + password + '\'' +
                '}';
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;

        User user = (User) o;

        if (name != null ? !name.equals(user.name) : user.name != null) return false;
        return password != null ? password.equals(user.password) : user.password == null;

    }

    @Override
    public int hashCode() {
        int result = name != null ? name.hashCode() : 0;
        result = 31 * result + (password != null ? password.hashCode() : 0);
        return result;
    }
}
Ora possiamo iniziare a creare un elenco di utenti. Aggiungeremo gli utenti ad esso e da dove li porteremo per la visualizzazione. Tuttavia, c’è un problema. Non creiamo i nostri oggetti servlet, Tomcat lo fa per noi . Anche i metodi che sovrascriviamo in essi sono già definiti per noi e non possiamo aggiungere un parametro. Come possiamo quindi creare un elenco condiviso che sia visibile a entrambi i nostri servlet? Se creiamo semplicemente il nostro oggetto elenco in ogni servlet, risulterà che aggiungeremo gli utenti a un elenco e visualizzeremo l'elenco degli utenti che utilizzano il servlet ListServlet a un altro. Si scopre che abbiamo bisogno di un oggetto che sia comune a entrambi i servlet. In generale, abbiamo bisogno di un oggetto che sia comune a tutte le classi del nostro programma; l'unico oggetto per l'intero programma. Spero che tu abbia sentito qualcosa sui design pattern. E, forse, per alcuni questa è la prima vera necessità di utilizzare il pattern Singleton nel proprio programma. Puoi pervertirti e creare un fantastico Singleton con doppi controlli e sincronizzazione (sì, abbiamo un'applicazione multi-thread, poiché Tomcat esegue servlet in thread diversi), ma userò l'opzione con l'inizializzazione anticipata, poiché è abbastanza adatta qui abbastanza e si adatta ai nostri scopi.

Creazione di un modello

Creiamo una classe (e implementiamo al suo interno il pattern Singleton ) nel pacchetto modello e chiamiamola in modo insolito. Diciamo Modello . Creiamo un oggetto elenco di utenti privati ​​nella nostra classe e implementiamo due metodi: uno in modo da poter aggiungere un utente e il secondo per restituire un elenco di stringhe (nomi utente). Poiché il nostro oggetto utente è costituito da un nome e una password e non vorremmo "rivelare" le password degli utenti, avremo solo un elenco di nomi.
public class Model {
    private static Model instance = new Model();

    private List<User> model;

    public static Model getInstance() {
        return instance;
    }

    private Model() {
        model = new ArrayList<>();
    }

    public void add(User user) {
        model.add(user);
    }

    public List<String> list() {
        return model.stream()
                .map(User::getName)
                .collect(Collectors.toList());
    }
}

Un po' di mvc

Dato che hai sentito parlare di singleton , probabilmente hai sentito parlare di un altro modello di progettazione: MVC (model-view-controller, in russo model-view-controller o proprio come in inglese model-view-controller). La sua essenza è separare la logica aziendale dalla presentazione. Cioè, separare il codice che determina cosa fare dal codice che determina come visualizzare. View (view o semplicemente views) è responsabile della forma in cui vengono presentati alcuni dati. Nel nostro caso, le visualizzazioni sono le nostre pagine JSP. Ecco perché li ho inseriti in una cartella chiamata views . Il modello sono i dati effettivi con cui funziona il programma. Nel nostro caso si tratta di utenti (elenco di utenti). Ebbene, i controller sono l'anello di congiunzione tra loro. Prendono i dati dal modello e li passano alle visualizzazioni (o ricevono alcuni dati da Tomcat, li elaborano e li passano al modello). La logica aziendale (cosa dovrebbe fare esattamente il programma) deve essere descritta in essi e non nel modello o nella vista. Quindi ognuno fa la sua cosa:
  • il modello memorizza i dati;
  • le visualizzazioni disegnano una bella rappresentazione dei dati;
  • i titolari del trattamento si occupano del trattamento dei dati.
Ciò consente al programma di essere abbastanza semplice e gestibile, piuttosto che un mostruoso dump di tutto il codice in un'unica classe. MVC è adatto non solo per la programmazione web, ma è in quest'area che si trova particolarmente spesso (quasi sempre). Nel nostro caso, i servlet fungeranno da controller. Questa è una descrizione molto superficiale e breve del pattern, ma MVC non è l'argomento principale di questo articolo. Chi vuole saperne di più: Google in soccorso! Creare un modulo per aggiungere un utente Aggiungiamo al file add.jsp un modulo composto da due campi di immissione testo (uno normale, l'altro una password) e un pulsante per l'invio dei dati al server.
<form method="post">
    <label>Name:
        <input type="text" name="name"><br />
    </label>

    <label>Password:
        <input type="password" name="pass"><br />
    </label>
    <button type="submit">Submit</button>
</form>
Qui il modulo ha un attributo metodo con il valore post . Ciò significa che i dati di questo modulo verranno inviati al server sotto forma di richiesta POST. L' attributo action non è specificato, il che significa che la richiesta verrà inviata allo stesso indirizzo a cui siamo andati in questa pagina ( /add ). Pertanto, la nostra servlet, legata a questo indirizzo, dopo aver ricevuto una richiesta GET, restituisce questa jsp con il modulo per l'aggiunta di utenti, e se riceve una richiesta POST, significa che il modulo ha inviato lì i suoi dati (che estrarremo dal richiedere l'oggetto nel metodo doPost() Vale la pena notare che i campi di input hanno un parametro name (per un campo con un nome ha il valore name e per un campo con una password ha il valore pass ). Questo è un punto piuttosto importante. Poiché per ottenere questi dati (nome e password che verranno inseriti) dalla richiesta (già all'interno della servlet), utilizzeremo esattamente questi nome e pass . Ma ne parleremo più avanti. Il pulsante stesso per l'invio dei dati viene nuovamente realizzato sotto forma di pulsante e non come campo di output, come di solito è consuetudine. Non so quanto sia universale questa opzione, ma per me funziona (browser Chrome).

Elaborazione di una richiesta POST con un servlet

Torniamo al servlet AddServlet . Lascia che te lo ricordi: affinché la nostra servlet sia in grado di "catturare" le richieste GET, abbiamo sovrascritto il metodo doGet() dalla classe HttpServlet . Per insegnare alla nostra servlet a catturare anche le richieste POST, dobbiamo anche sovrascrivere il metodo doPost() . Riceve oggetti di richiesta e risposta simili da Tomcat , con cui lavoreremo. Per prima cosa, estraiamo dalla richiesta il nome e passiamo i parametri inviati dal modulo (se li hai nominati diversamente nel modulo, allora quelli saranno i nomi che scriverai). Successivamente, creeremo il nostro oggetto utente utilizzando i dati ricevuti. Quindi otterremo l'oggetto del modello e aggiungeremo l'utente creato al modello.
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    String name = req.getParameter("name");
    String password = req.getParameter("pass");
    User user = new User(name, password);
    Model model = Model.getInstance();
    model.add(user);
}

Passaggio dei dati da visualizzare

Passiamo alla servlet ListServlet . Qui è già stato implementato il metodo doGet() che trasferisce semplicemente il controllo alla vista list.jsp . Se non lo hai ancora, fallo per analogia con lo stesso metodo del servlet AddServlet . Ora sarebbe carino ottenere un elenco di nomi utente dal modello e passarli alla vista, che li riceverà e li visualizzerà bene. Per fare ciò, utilizzeremo nuovamente l'oggetto request che abbiamo ricevuto da Tomcat . Possiamo aggiungere un attributo a questo oggetto, dandogli un nome e, di fatto, l'oggetto stesso, che vorremmo trasferire in vista . A causa del fatto che quando trasferiamo il processo di esecuzione dal servlet alla vista, passiamo lì gli stessi oggetti di richiesta e risposta che il servlet stesso ha ricevuto, quindi aggiungendo il nostro elenco di nomi all'oggetto della richiesta, possiamo quindi da questa richiesta oggetto nella vista crea il nostro elenco di nomi utente e ottieni. Abbiamo finito con la classe ListServlet , quindi ecco il codice per l'intera classe:
package app.servlets;

import app.model.Model;

import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.List;

public class ListServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        Model model = Model.getInstance();
        List<String> names = model.list();
        req.setAttribute("userNames", names);

        RequestDispatcher requestDispatcher = req.getRequestDispatcher("views/list.jsp");
        requestDispatcher.forward(req, resp);
    }
}

Esecuzione del codice Java nei file JSP

È ora di iniziare a lavorare sul file list.jsp . Verrà eseguito solo quando ListServlet passa qui il processo di esecuzione. Inoltre, in quella servlet abbiamo già preparato un elenco di nomi utente dal modello e lo abbiamo passato qui nell'oggetto della richiesta. Poiché abbiamo un elenco di nomi, possiamo scorrerlo e stampare ciascun nome. Come ho già detto, i file jsp possono eseguire codice Java (che è ciò che li rende diversi dalle pagine html statiche). Per eseguire del codice è sufficiente inserire la seguente costruzione nel punto in cui ci serve:
<!-- html code -->
<%
    // java code
%>
<!-- html code -->
All'interno di questo costrutto abbiamo accesso a diverse variabili:
  • request è il nostro oggetto richiesta, che abbiamo passato dalla servlet, dove era semplicemente chiamato req ;
  • risposta - oggetto risposta, chiamato resp nella servlet ;
  • out è un oggetto del tipo JspWriter (ereditato dal solito Writer ), con l'aiuto del quale possiamo “scrivere” qualcosa direttamente nella pagina html stessa. La voce out.println("Ciao mondo!") è molto simile alla voce System.out.println("Ciao mondo!") , ma non confonderle!
    out.println() “scrive” nella pagina html e System.out.println scrive nell'output del sistema. Se chiami il metodo jsp System.out.println() all'interno della sezione con codice Java , vedrai i risultati nella console Tomcat e non nella pagina.

Puoi cercare altri oggetti disponibili all'interno di jsp qui . Utilizzando l' oggetto request , possiamo ottenere l'elenco dei nomi che sono stati passati dal servlet (abbiamo allegato l'attributo corrispondente a questo oggetto) e utilizzando l' oggetto out , possiamo visualizzare questi nomi. Facciamolo (per ora solo sotto forma di elenco html):
<ul>
    <%
        List<String> names = (List<String>) request.getAttribute("userNames");

        if (names != null && !names.isEmpty()) {
            for (String s : names) {
                out.println("<li>" + s + "</li>");
            }
        }
    %>
</ul>
Se abbiamo bisogno di visualizzare un elenco solo se ci sono utenti, e altrimenti visualizzare un avviso che non ci sono ancora utenti, possiamo riscrivere un po' questa sezione:
<%
    List<String> names = (List<String>) request.getAttribute("userNames");

    if (names != null && !names.isEmpty()) {
        out.println("<ui>");
        for (String s : names) {
            out.println("<li>" + s + "</li>");
        }
        out.println("</ui>");
    } else out.println("<p>There are no users yet!</p>");
%>
Ora che possiamo passare i dati dalle servlet alle visualizzazioni, possiamo migliorare leggermente il nostro AddServlet in modo che venga visualizzata una notifica quando un utente è stato aggiunto con successo. Per fare ciò, nel metodo doPost() , dopo aver aggiunto un nuovo utente al modello, possiamo aggiungere il nome di questo utente agli attributi dell'oggetto req e passare nuovamente il controllo alla vista add.jsp . E in esso è già creata una sezione con codice Java in cui viene effettuato un controllo per vedere se tale attributo è presente nella richiesta e, in tal caso, viene generato un messaggio che informa che l'utente è stato aggiunto con successo. Dopo queste modifiche, il codice servlet AddServlet completo sarà simile al seguente:
package app.servlets;

import app.entities.User;
import app.model.Model;

import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

public class AddServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        RequestDispatcher requestDispatcher = req.getRequestDispatcher("views/add.jsp");
        requestDispatcher.forward(req, resp);
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        String name = req.getParameter("name");
        String password = req.getParameter("pass");
        User user = new User(name, password);
        Model model = Model.getInstance();
        model.add(user);

        req.setAttribute("userName", name);
        doGet(req, resp);
    }
}
Qui, alla fine del metodo doPost() , impostiamo un attributo con il nome dell'utente aggiunto al modello, dopodiché chiamiamo il metodo doGet() , al quale passiamo la richiesta e la risposta corrente. E il metodo doGet() trasferisce già il controllo alla vista, dove invia un oggetto di richiesta con il nome dell'utente aggiunto allegato come attributo. Tutto ciò che resta è correggere add.jsp in modo che visualizzi tale notifica se tale attributo è presente. L' add.jsp finale è :
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
    <head>
        <title>Add new user</title>
    </head>

    <body>
        <div>
            <h1>Super app!</h1>
        </div>

        <div>
            <%
                if (request.getAttribute("userName") != null) {
                    out.println("<p>User '" + request.getAttribute("userName") + "' added!</p>");
                }
            %>
            <div>
                <div>
                    <h2>Add user</h2>
                </div>

                <form method="post">
                    <label>Name:
                        <input type="text" name="name"><br />
                    </label>
                    <label>Password:
                        <input type="password" name="pass"><br />
                    </label>
                    <button type="submit">Submit</button>
                </form>
            </div>
        </div>

        <div>
            <button onclick="location.href='/'">Back to main</button>
        </div>
    </body>
</html>
Il corpo della pagina è composto da:
  • div-a con intestazione;
  • contenitore div per il contenuto, controlla se esiste un attributo con il nome utente;
  • div con un modulo per aggiungere utenti;
  • e alla fine c'è un footer con un pulsante per tornare alla pagina principale.
Potrebbe sembrare che ci siano troppi div, ma li useremo più tardi quando aggiungeremo gli stili. Il file list.jsp finale è:
<%@ page import="java.util.List" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
    <head>
        <title>Users</title>
    </head>

    <body>
        <div>
            <h1>Super app!</h1>
        </div>

        <div>
            <div>
                <div>
                    <h2>Users</h2>
                </div>
                <%
                    List<String> names = (List<String>) request.getAttribute("userNames");

                    if (names != null && !names.isEmpty()) {
                        out.println("<ui>");
                        for (String s : names) {
                            out.println("<li>" + s + "</li>");
                        }
                        out.println("</ui>");
                    } else out.println("<p>There are no users yet!</p>");
                %>
            </div>
        </div>

        <div>
            <button onclick="location.href='/'">Back to main</button>
        </div>
    </body>
</html>
Pertanto, disponiamo di un'applicazione Web completamente funzionante in grado di memorizzare e aggiungere utenti, nonché visualizzare un elenco dei loro nomi. Non resta che abbellirlo... :)

Aggiunta di stili. Utilizziamo il framework W3.CSS

Al momento la nostra applicazione funziona, ma è assolutamente pazzesca. Pertanto, aggiungeremo uno sfondo, un colore del testo e dei pulsanti, elenchi di stili, effettueremo l'allineamento, aggiungeremo rientri e simili. Se scrivi gli stili manualmente, può richiedere molto tempo e nervi. Pertanto, suggerisco di utilizzare il framework CSS W3.CSS. Dispone già di classi con stili già pronte, non resta che posizionare le classi CSS che vogliamo applicare nei posti giusti. Per aggiungerli alle nostre pagine, includeremo prima un file con gli stili. Questo può essere fatto in due modi:
  1. attraversa le nostre pagine e nella sezione head inserisci un collegamento diretto al file con gli stili

    <link rel="stylesheet" href="https://www.w3schools.com/w3css/4/w3.css">

    Questa opzione è adatta se disponi di una connessione Internet costante. Quindi, quando apri le tue pagine su un server locale, gli stili verranno estratti da Internet.


  2. Se vuoi avere tutti gli stili localmente e non dipendere da una connessione Internet, scarica il file con gli stili e posizionalo da qualche parte all'interno della cartella web (ad esempio web/styles/w3.css ), quindi esamina tutti i nostri pagine ( index.html, add.jsp, list.jsp ) e inserisci un collegamento a questo file con gli stili all'interno della sezione head

    <link rel="stylesheet" href="styles/w3.css">

    Successivamente, esamina i tag e aggiungi gli stili che ti piacciono. Non mi soffermerò su questo in dettaglio, ma fornirò immediatamente le mie versioni già pronte dei miei tre file con classi di stile organizzate.

indice.html

<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Super app!</title>
        <link rel="stylesheet" href="https://www.w3schools.com/w3css/4/w3.css">
    </head>

    <body class="w3-light-grey">
        <div class="w3-container w3-blue-grey w3-opacity w3-right-align">
            <h1>Super app!</h1>
        </div>

        <div class="w3-container w3-center">
            <div class="w3-bar w3-padding-large w3-padding-24">
                <button class="w3-btn w3-hover-light-blue w3-round-large" onclick="location.href='/list'">List users</button>
                <button class="w3-btn w3-hover-green w3-round-large" onclick="location.href='/add'">Add user</button>
            </div>
        </div>
    </body>
</html>

aggiungi.jsp

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
    <head>
        <title>Add new user</title>
        <link rel="stylesheet" href="https://www.w3schools.com/w3css/4/w3.css">
    </head>

    <body class="w3-light-grey">
        <div class="w3-container w3-blue-grey w3-opacity w3-right-align">
            <h1>Super app!</h1>
        </div>

        <div class="w3-container w3-padding">
            <%
                if (request.getAttribute("userName") != null) {
                    out.println("<div class=\"w3-panel w3-green w3-display-container w3-card-4 w3-round\">\n" +
                            "   <span onclick=\"this.parentElement.style.display='none'\"\n" +
                            "   class=\"w3-button w3-margin-right w3-display-right w3-round-large w3-hover-green w3-border w3-border-green w3-hover-border-grey\">×</span>\n" +
                            "   <h5>User '" + request.getAttribute("userName") + "' added!</h5>\n" +
                            "</div>");
                }
            %>
            <div class="w3-card-4">
                <div class="w3-container w3-center w3-green">
                    <h2>Add user</h2>
                </div>
                <form method="post" class="w3-selection w3-light-grey w3-padding">
                    <label>Name:
                        <input type="text" name="name" class="w3-input w3-animate-input w3-border w3-round-large" style="width: 30%"><br />
                    </label>
                    <label>Password:
                        <input type="password" name="pass" class="w3-input w3-animate-input w3-border w3-round-large" style="width: 30%"><br />
                    </label>
                    <button type="submit" class="w3-btn w3-green w3-round-large w3-margin-bottom">Submit</button>
                </form>
            </div>
        </div>

        <div class="w3-container w3-grey w3-opacity w3-right-align w3-padding">
            <button class="w3-btn w3-round-large" onclick="location.href='/'">Back to main</button>
        </div>
    </body>
</html>

list.jsp

<%@ page import="java.util.List" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
    <head>
        <title>Users list</title>
        <link rel="stylesheet" href="https://www.w3schools.com/w3css/4/w3.css">
    </head>

    <body class="w3-light-grey">
        <div class="w3-container w3-blue-grey w3-opacity w3-right-align">
            <h1>Super app!</h1>
        </div>

        <div class="w3-container w3-center w3-margin-bottom w3-padding">
            <div class="w3-card-4">
                <div class="w3-container w3-light-blue">
                    <h2>Users</h2>
                </div>
                <%
                    List<String> names = (List<String>) request.getAttribute("userNames");

                    if (names != null && !names.isEmpty()) {
                        out.println("<ul class=\"w3-ul\">");
                        for (String s : names) {
                            out.println("<li class=\"w3-hover-sand\">" + s + "</li>");
                        }
                        out.println("</ul>");

                    } else out.println("<div class=\"w3-panel w3-red w3-display-container w3-card-4 w3-round\">\n"
+
                            "   <span onclick=\"this.parentElement.style.display='none'\"\n" +
                            "   class=\"w3-button w3-margin-right w3-display-right w3-round-large w3-hover-red w3-border w3-border-red w3-hover-border-grey\">×</span>\n" +
                            "   <h5>There are no users yet!</h5>\n" +
                            "</div>");
                %>
            </div>
        </div>

        <div class="w3-container w3-grey w3-opacity w3-right-align w3-padding">
            <button class="w3-btn w3-round-large" onclick="location.href='/'">Back to main</button>
        </div>
    </body>
</html>
Questo è tutto :) Se hai ancora domande o commenti o, al contrario, qualcosa non funziona, lascia un commento. UPD: se riscontri problemi con un errore 404 quando clicchi sui pulsanti, anche se tutto è stato fatto correttamente, forse dovresti correggere la configurazione di distribuzione nell'idea. Per fare questo, bisogna andare su Modifica configurazioni (in alto vicino al pulsante di avvio), andare nella scheda Distribuzione sul lato destro della finestra e assicurarsi che nel Contesto applicazione sia semplicemente indicato / Bene, io' Allegherò un paio di screenshot di ciò che è venuto fuori da tutto questo.
Creare una semplice applicazione web utilizzando servlet e jsp (parte 2) - 2
Creare una semplice applicazione web utilizzando servlet e jsp (parte 2) - 3
Creare una semplice applicazione web utilizzando servlet e jsp (parte 2) - 4
E infine , se vuoi esercitarti con questo progetto, puoi provare:
  • crea un servlet e un jsp per eliminare un utente e un altro paio per cambiare/modificare un utente esistente. Otterrai una vera applicazione web CrUD :) su servlet));
  • sostituire l'elenco (List) con il lavoro con un database in modo che gli utenti aggiunti non scompaiano dopo aver riavviato il server :)
Buona fortuna!
Commenti
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION