JavaRush /Java-Blog /Random-DE /Einführung in Maven, Spring, MySQL, Hibernate und die ers...
Макс
Level 41

Einführung in Maven, Spring, MySQL, Hibernate und die erste CRUD-Anwendung (Teil 2)

Veröffentlicht in der Gruppe Random-DE
Guten Tag. In diesem Artikel möchte ich meine erste Begegnung mit Dingen wie Maven, Spring, Hibernate, MySQL und Tomcat beim Erstellen einer einfachen CRUD-Anwendung teilen. Dies ist der zweite Teil von 4. Der Artikel richtet sich in erster Linie an diejenigen, die hier bereits 30–40 Level abgeschlossen haben, sich aber noch nicht über reines Java hinausgewagt haben und gerade erst anfangen (oder gerade dabei sind), in die offene Welt einzusteigen all diese Technologien, Frameworks und andere unbekannte Wörter. Dies ist der zweite Teil des Artikels „Einführung in Maven, Spring, MySQL, Hibernate und die erste CRUD-Anwendung“. Den ersten Teil können Sie über diesen Link einsehen: Einführung in Maven, Spring, MySQL, Hibernate und die erste CRUD-Anwendung (Teil 1)

Inhalt:

Nun, machen wir weiter, versuchen wir nun, eine ganze Sammlung von Filmen zusammenzuzaubern. In unserer kleinen und einfachen Anwendung kann man natürlich einfach dummerweise die ganze Logik direkt in den Controller stecken, aber wie bereits erwähnt, ist es besser, sofort zu lernen, wie man alles richtig macht. Lassen Sie uns daher mehrere Ebenen erstellen. Wir werden ein DAO haben , das für die Arbeit mit Daten verantwortlich ist, einen Service , in dem es alle möglichen anderen Logiken geben wird, und der Controller wird nur Anfragen verarbeiten und die notwendigen Servicemethoden aufrufen.

Datenzugriffsobjekt

Data Access Object (DAO) ist ein solches Entwurfsmuster. Der Sinn besteht darin, eine spezielle Ebene zu schaffen, die ausschließlich für den Zugriff auf Daten verantwortlich ist (Arbeiten mit einer Datenbank oder einem anderen Speichermechanismus). Im Paket daoerstellen wir eine Schnittstelle, FilmDAOin der es Methoden wie Hinzufügen, Löschen usw. gibt. Ich habe sie etwas anders genannt, aber sie entsprechen den grundlegenden CRUD- Operationen ( Erstellen , Lesen , Aktualisieren , Löschen ).

Es ist hier erwähnenswert, dass es neben DAO auch einen Ansatz wie Repository gibt, sie scheinen sehr ähnlich zu sein, beide werden für die Arbeit mit Daten verwendet. Ich habe noch nicht herausgefunden, welche Merkmale diese Ansätze haben und worin der Unterschied zwischen ihnen besteht. Daher kann es sein, dass ich mich hier irre und dies als Repository und nicht als Tao bezeichnet werden sollte, oder vielleicht ist es etwas dazwischen. Aber in den meisten Beispielen, die ich gesehen und studiert habe, wird dies DAO genannt, daher werde ich es wahrscheinlich genauso nennen. Gleichzeitig werde ich vielleicht irgendwo weiter unten im Text das Wort „Repository“ verwenden. Sollte ich hier irgendwo falsch liegen, verzeihen Sie mir bitte.

package testgroup.filmography.dao;

import testgroup.filmography.model.Film;

import java.util.List;

public interface FilmDAO {
    List<Film> allFilms();
    void add(Film film);
    void delete(Film film);
    void edit(Film film);
    Film getById(int id);
}
Jetzt brauchen wir seine Umsetzung. Wir werden die Datenbank noch nicht verbinden, es ist immer noch ein wenig beängstigend. Zum Üben und Eingewöhnen simulieren wir zunächst die Speicherung im Speicher und erstellen eine Liste mit mehreren Filmen. Um die Liste zu speichern, verwenden wir nicht List, sondern Map, um es bequemer zu machen, einen bestimmten Film anhand seines abzurufen id, ohne die gesamte Liste durchgehen zu müssen. Zur Generierung idverwenden wir AtomicInteger . Lassen Sie uns eine Klasse erstellen FilmDAOImpl, alle Methoden implementieren und die Karte ausfüllen. So ähnlich.
package testgroup.filmography.dao;

import testgroup.filmography.model.Film;

import java.util.*;

public class FilmDAOImpl implements FilmDAO {
    private static final AtomicInteger AUTO_ID = new AtomicInteger(0);
    private static Map<Integer, Film> films = new HashMap<>();

    static {
        Film film1 = new Film();
        film1.setId(AUTO_ID.getAndIncrement());
        film1.setTitle("Inception");
        film1.setYear(2010);
        film1.setGenre("sci-fi");
        film1.setWatched(true);
        films.put(film1.getId(), film1);

        // + film2, film3, film4, ...
    }
    @Override
    public List<Film> allFilms() {
        return new ArrayList<>(films.values());
    }

    @Override
    public void add(Film film) {
        film.setId(AUTO_ID.getAndIncrement());
        films.put(film.getId(), film);
    }

    @Override
    public void delete(Film film) {
        films.remove(film.getId());
    }

    @Override
    public void edit(Film film) {
        films.put(film.getId(), film);
    }

    @Override
    public Film getById(int id) {
        return films.get(id);
    }
}

Service

Fügen wir nun eine Serviceschicht hinzu. Im Prinzip ist es in diesem Beispiel durchaus möglich, darauf zu verzichten und uns auf DAO zu beschränken; die Anwendung wird sehr einfach sein und eine komplexe Logik im Dienst ist nicht geplant. Aber plötzlich möchten Sie dem Projekt in Zukunft alle möglichen Komplikationen und interessanten Dinge hinzufügen, also lassen Sie es der Vollständigkeit halber so. Im Moment werden einfach Methoden vom DAO aufgerufen. Lassen Sie uns eine Schnittstelle im Paket serviceerstellen FilmService.
package testgroup.filmography.service;

import testgroup.filmography.model.Film;

import java.util.List;

public interface FilmService {
    List<Film> allFilms();
    void add(Film film);
    void delete(Film film);
    void edit(Film film);
    Film getById(int id);
}
Und seine Umsetzung:
package testgroup.filmography.service;

import testgroup.filmography.dao.FilmDAO;
import testgroup.filmography.dao.FilmDAOImpl;
import testgroup.filmography.model.Film;

import java.util.List;

public class FilmServiceImpl implements FilmService {
    private FilmDAO filmDAO = new FilmDAOImpl();

    @Override
    public List<Film> allFilms() {
        return filmDAO.allFilms();
    }

    @Override
    public void add(Film film) {
        filmDAO.add(film);
    }

    @Override
    public void delete(Film film) {
        filmDAO.delete(film);
    }

    @Override
    public void edit(Film film) {
        filmDAO.edit(film);
    }

    @Override
    public Film getById(int id) {
        return filmDAO.getById(id);
    }
}
Die Projektstruktur sieht nun so aus:
Einführung in Maven, Spring, MySQL, Hibernate und die erste CRUD-Anwendung (Teil 2) – 1

Controller und Ansichten

Lassen Sie uns nun an den Controller-Methoden und dem Füllen der Seiten arbeiten. Beim Ausfüllen der Seiten benötigen wir einige Techniken. Um beispielsweise eine Liste von Filmen anzuzeigen, benötigen wir eine Schleife. Wenn wir beispielsweise eine Beschriftung ändern möchten, benötigen wir abhängig von den Parametern Bedingungen usw. Das JSP-Format (JavaServer Pages) ermöglicht die Verwendung von Java-Code-Einfügungen, mit denen all dies implementiert werden kann. Aber ich möchte auf der Seite keinen Java-Code gemischt mit HTML-Code verwenden. Es wäre zumindest sehr hässlich. Glücklicherweise gibt es zur Lösung dieses Problems so etwas Wunderbares wie JSTL (JavaServer Pages Standard Tag Library) oder die JSP Standard Tag Library. Es ermöglicht uns, eine ganze Reihe zusätzlicher Tags in unseren JSP-Seiten für eine Vielzahl von Anforderungen zu verwenden. Verbinden wir es mit pom.xml:
<dependency>
      <groupId>jstl</groupId>
      <artifactId>jstl</artifactId>
      <version>1.2</version>
</dependency>
Werfen wir nun einen Blick auf den Controller. Lassen Sie uns zunächst die Erstellung des Objekts von dort entfernen Film. Dies wurde zu Testzwecken durchgeführt und wir benötigen nichts anderes. Fügen wir dort einen Dienst hinzu und rufen seine Methoden auf.
public class FilmController {
    private FilmService filmService = new FilmServiceImpl();
Nun, dementsprechend werden wir für jeden Fall Methoden erstellen, hinzufügen, löschen usw. Zuerst eine Methode, um die Hauptseite mit einer Liste von Filmen anzuzeigen:
@RequestMapping(method = RequestMethod.GET)
    public ModelAndView allFilms() {
        List<Film> films = filmService.allFilms();
        ModelAndView modelAndView = new ModelAndView();
        modelAndView.setViewName("films");
        modelAndView.addObject("filmsList", films);
        return modelAndView;
    }
Hier gibt es nichts Neues. Wir erhalten eine Liste der Filme vom Dienst und fügen sie dem Modell hinzu. Lassen Sie uns nun die Hauptseite erstellen films.jsp, die diese Methode zurückgibt:
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<html>
<head>
<title>FILMS</title>
</head>
<body>

<h2>Films</h2>
<table>
    <tr>
        <th>id</th>
        <th>title</th>
        <th>year</th>
        <th>genre</th>
        <th>watched</th>
        <th>action</th>
    </tr>
    <c:forEach var="film" items="${filmsList}">
        <tr>
            <td>${film.id}</td>
            <td>${film.title}</td>
            <td>${film.year}</td>
            <td>${film.genre}</td>
            <td>${film.watched}</td>
            <td>
                <a href="/edit/${film.id}">edit</a>
                <a href="/delete/${film.id}">delete</a>
            </td>
        </tr>
    </c:forEach>
</table>

<h2>Add</h2>
<c:url value="/add" var="add"/>
<a href="${add}">Add new film</a>
</body>
</html>
Schauen wir uns diese Seite genauer an, um zu sehen, was was ist. <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> – hier ist der JSTL-Kern verbunden, der die Haupt-Tags zum Erstellen von Zyklen, Bedingungen usw. enthält .
  • <table>— Tag zum Erstellen einer Tabelle.
  • <tr>- Tischreihe
  • <th>- Spaltenüberschrift
  • <td>— Tabellenzelle
Zuerst erstellen wir eine Tabellenkopfzeile mit den Namen der Spalten. Dann <c:forEach var="film" items="${filmsList}">gehen wir in einer Schleife (die wir dem JSTL-Kern entnommen haben) alle Elemente der übergebenen Liste durch ( filmsList), filmerstellen für jedes Element ( ) eine neue Zeile und schreiben den entsprechenden Wert in jede Zelle. Hier gibt es einen Punkt, die Aufnahme scheint film.idals verstanden werden zu müssen film.getId(), d. h. Es wird nicht direkt auf das Feld zugegriffen, sondern der Getter aufgerufen. In der letzten Spalte ( action) machen wir Links zum Löschen und Bearbeiten (wir werden jetzt die entsprechenden Methoden erstellen). Unten finden Sie einen Link zur Methode zum Hinzufügen eines neuen Films. So sieht es aus: Schauen wir uns als Nächstes die Methode an, die die Bearbeitungsseite für einen bestimmten Film zurückgibt:
@RequestMapping(value = "/edit/{id}", method = RequestMethod.GET)
    public ModelAndView editPage(@PathVariable("id") int id) {
        Film film = filmService.getById(id);
        ModelAndView modelAndView = new ModelAndView();
        modelAndView.setViewName("editPage");
        modelAndView.addObject("film", film);
        return modelAndView;
    }
Hier ist etwas Neues aufgetaucht – das ist eine Anmerkung @PathVariable. Es zeigt an, dass dieser Parameter ( int id) aus der Adressleiste abgerufen wird. Um die Position dieses Parameters in der Adressleiste anzugeben, wird die Konstruktion verwendet {id}(übrigens, wenn der Variablenname wie in diesem Fall derselbe ist, müssen Sie ihn nicht in Klammern angeben, sondern einfach schreiben @PathVariable int id). Deshalb haben wir auf der Hauptseite für jeden Film Links erstellt, die darauf hinweisen id:
<a href="/edit/${film.id}">edit</a>
Dann wird dieser Wert dem Methodenparameter zugewiesen und dann verwenden wir ihn, um über den Dienst einen bestimmten Film aus dem Repository abzurufen und ihn dem Modell hinzuzufügen. Dies war die Methode zum Abrufen der Bearbeitungsseite. Jetzt benötigen wir eine Methode zum Bearbeiten selbst:
@RequestMapping(value = "/edit", method = RequestMethod.POST)
    public ModelAndView editFilm(@ModelAttribute("film") Film film) {
        ModelAndView modelAndView = new ModelAndView();
        modelAndView.setViewName("redirect:/");
        filmService.edit(film);
        return modelAndView;
    }
In der Methode editPagehaben wir dem Modell ein Attribut hinzugefügt:
modelAndView.addObject("film", filmService.getById(id));
Und jetzt erhalten wir mit Hilfe von Annotationen @ModelAttributedieses Attribut und können es ändern. Anforderungsmethode POST, da wir hier die Daten übergeben. „ redirect:/“ bedeutet, dass wir nach Ausführung dieser Methode zur Adresse „ /“ weitergeleitet werden, d. h. Die Methode wird ausgeführt allFilmsund wir kehren zur Hauptseite zurück. Jetzt erstellen wir die Seite selbst editPage.jsp:
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<html>
<head>
    <title>Edit</title>
</head>
<body>
<c:url value="/edit" var="var"/>
<form action="${var}" method="POST">
    <input type="hidden" name="id" value="${film.id}">
    <label for="title">Title</label>
    <input type="text" name="title" id="title">
    <label for="year">Year</label>
    <input type="text" name="year" id="year">
    <label for="genre">Genre</label>
    <input type="text" name="genre" id="genre">
    <label for="watched">Watched</label>
    <input type="text" name="watched" id="watched">
    <input type="submit" value="Edit film">
</form>
</body>
</html>
  • <form>— ein Formular zum Sammeln und Senden von Daten mit Angabe, wer diese Daten verarbeiten wird ( /edit)
  • <input>— Oberflächenelemente für die Benutzerinteraktion (Schaltflächen, Eingabefelder usw.)
  • <label>- Textbeschriftung
Wenn Sie also auf die Schaltfläche klicken, <input type="submit" value="Edit film">werden die Daten aus dem Formular an den Server gesendet (ein unsichtbares Feld mit dem Wert wurde speziell hinzugefügt, iddamit der Server weiß, welcher Datensatz in der Datenbank aktualisiert werden muss). In der Methode editFilmwerden sie den entsprechenden Attributfeldern zugeordnet film. Wir kehren dann mit einer aktualisierten Liste zur Hauptseite zurück. Die Bearbeitungsseite sieht folgendermaßen aus: Beginnen wir nun mit dem Hinzufügen neuer Filme zur Liste. Hierzu benötigen Sie zusätzlich ein Formular zur Dateneingabe und -übermittlung. Sie können ein Formular auf der Hauptseite erstellen oder eine separate Seite erstellen, z editPage.jsp. Andererseits ist das Formular zum Hinzufügen genau das gleiche wie zum Bearbeiten, d. h. 4 Eingabefelder und ein Absenden-Button. Warum also eine neue Seite erstellen? Verwenden wir editPage.jsp. Methode zum Abrufen der Seite:
@RequestMapping(value = "/add", method = RequestMethod.GET)
    public ModelAndView addPage() {
        ModelAndView modelAndView = new ModelAndView();
        modelAndView.setViewName("editPage");
        return modelAndView;
    }
In der Methode editPagehaben wir zusätzlich das Attribut übergeben, um es später zu ändern, aber hier erhalten wir einfach die Seite. Und die Methode zum Hinzufügen:
@RequestMapping(value = "/add", method = RequestMethod.POST)
    public ModelAndView addFilm(@ModelAttribute("film") Film film) {
        ModelAndView modelAndView = new ModelAndView();
        modelAndView.setViewName("redirect:/");
        filmService.add(film);
        return modelAndView;
    }
Da wir das Attribut hier nicht übergeben haben, wird hier ein neues Objekt erstellt Film. Nun, im Grunde gibt es hier nichts Neues. Erwähnenswert ist auch, dass wir beide Methoden unter „ /add“ zur Verfügung haben. Dies ist dadurch möglich, dass sie auf unterschiedliche Arten von Anfragen reagieren. Indem wir dem Link auf der Hauptseite folgen, stellen wir eine GET-Anfrage, die uns zur addPage. Und wenn wir auf der Seite zum Hinzufügen auf die Schaltfläche zum Senden von Daten klicken, wird eine POST-Anfrage gestellt und die addFilm. Um einen neuen Film hinzuzufügen, haben wir uns entschieden, dieselbe Seite wie für die Bearbeitung zu verwenden. Dort werden die Daten aber an die Adresse „ /edit“ gesendet:
<c:url value="/edit" var="var"/>
<form action="${var}" method="POST">
    <input type="submit" value="Edit film">
</form>
Wir müssen die Seite ein wenig optimieren, damit sie sich beim Hinzufügen und Bearbeiten anders verhält. Um dieses Problem zu lösen, verwenden wir die Bedingungen aus derselben JSTL-Kernbibliothek:
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<html>
<head>
    <c:if test="${empty film.title}">
        <title>Add</title>
    </c:if>
    <c:if test="${!empty film.title}">
        <title>Edit</title>
    </c:if>
</head>
<body>
<c:if test="${empty film.title}">
    <c:url value="/add" var="var"/>
</c:if>
<c:if test="${!empty film.title}">
    <c:url value="/edit" var="var"/>
</c:if>
<form action="${var}" method="POST">
    <c:if test="${!empty film.title}">
        <input type="hidden" name="id" value="${film.id}">
    </c:if>
    <label for="title">Title</label>
    <input type="text" name="title" id="title">
    <label for="year">Year</label>
    <input type="text" name="year" id="year">
    <label for="genre">Genre</label>
    <input type="text" name="genre" id="genre">
    <label for="watched">Watched</label>
    <input type="text" name="watched" id="watched">
    <c:if test="${empty film.title}">
        <input type="submit" value="Add new film">
    </c:if>
    <c:if test="${!empty film.title}">
        <input type="submit" value="Edit film">
    </c:if>
</form>
</body>
</html>
Diese. Wir überprüfen gerade das Feld film.title. Wenn es leer ist, handelt es sich um einen neuen Film. Wir müssen alle Daten dafür eingeben und ihn zur Liste hinzufügen. Wenn dieses Feld nicht leer ist, handelt es sich um einen Film aus der Liste und Sie müssen ihn nur ändern. Das. Wir erhalten zwei Versionen unserer Seite: Nun, die letzte Controller-Methode zum Entfernen eines Films aus der Liste:
@RequestMapping(value="/delete/{id}", method = RequestMethod.GET)
    public ModelAndView deleteFilm(@PathVariable("id") int id) {
        ModelAndView modelAndView = new ModelAndView();
        modelAndView.setViewName("redirect:/");
        Film film = filmService.getById(id);
        filmService.delete(film);
        return modelAndView;
    }
Ich denke, es ist hier nicht nötig, etwas zu kommentieren, das alles wurde bereits berücksichtigt. Auf diese Adresse haben wir bereits auf der Hauptseite verlinkt. Nun, hier scheint alles fertig zu sein. Sie können es erneut ausführen und sehen, wie alles funktioniert.

Repository und Service als Spring-Komponenten

Nehmen wir noch eine kleine Korrektur vor. Tatsache ist, dass unser Speicher und unser Service jetzt nur noch Klassen sind und wir, um sie nutzen zu können, selbst ein Klassenobjekt erstellen müssen ( new FilmServiceImpl()). Aber wir haben Spring aus einem bestimmten Grund verbunden , also lassen Sie ihn diese Angelegenheit selbst kontrollieren. Um unsere Klassen unter die Kontrolle von Spring zu stellen, müssen wir angeben, dass es sich um Komponenten handelt. Dazu markieren wir sie mit speziellen Anmerkungen:
@Repository
public class FilmDAOImpl implements FilmDAO {
@Service
public class FilmServiceImpl implements FilmService {
Anmerkungen @Repositoryund @Service, sowie @Controllersind abgeleitet von @Component. Was die spezifischen Merkmale und Unterschiede dieser drei Annotationen sind und wie sie sich von einer einfachen Komponente unterscheiden, sollte separat in der Dokumentation oder den Leitfäden nachgelesen werden. Im Moment reicht es zu wissen, dass diese Annotationen Spring mitteilen, dass es sich bei diesen Klassen um ein Repository bzw. einen Dienst handelt. Und jetzt müssen wir keine konkreten Objekte dieser Klassen mehr selbst erstellen:
private FilmService filmService = new FilmServiceImpl();
Stattdessen können Sie das Feld mit einer speziellen Anmerkung markieren und Spring wählt die entsprechende Implementierung aus:
@Autowired
private FilmService filmService;
Die Annotation @Autowired(automatische Bindung) teilt Spring mit, dass es sich mit seinem Kontext befassen und hier eine geeignete Bean ersetzen soll. Sehr bequem. Wenn wir früher Schnittstellen verwendet haben, um uns nicht um die spezifische Implementierung von Methoden zu kümmern, müssen wir uns jetzt nicht einmal um die Implementierung der Schnittstelle selbst kümmern und kennen sogar ihren Namen. Der Grundgedanke ist, dass die Verwendung der automatischen Bindung für ein Feld nicht empfohlen wird; es ist besser, einen Konstruktor oder Setter zu verwenden. Lesen Sie mehr dazu in der Dokumentation. Für uns ist das grundsätzlich nicht wichtig, wir können es getrost so belassen. Aber da die Idee es verlangt, werden wir respektieren, dass alles schön und ohne gelbe Warnungen ist. Erstellen wir in der Controller-Klasse einen Setter und kommentieren ihn:
@Controller
public class FilmController {

    private FilmService filmService;

    @Autowired
    public void setFilmService(FilmService filmService) {
        this.filmService = filmService;
    }
Und auf ähnliche Weise erstellen wir einen Setter für FilmDAOin der Klasse FilmServiceImpl. Fortsetzung folgt... Einführung in Maven, Spring, MySQL, Hibernate und die erste CRUD-Anwendung (Teil 1) Einführung in Maven, Spring, MySQL, Hibernate und die erste CRUD-Anwendung (Teil 2) Einführung in Maven, Spring, MySQL, Hibernate und die erste CRUD-Anwendung (Teil 3) Einführung in Maven, Spring, MySQL, Hibernate und die erste CRUD-Anwendung (Teil 4)
Kommentare
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION