JavaRush /Blog Java /Random-FR /Introduction à Maven, Spring, MySQL, Hibernate et la prem...
Макс
Niveau 41

Introduction à Maven, Spring, MySQL, Hibernate et la première application CRUD (partie 2)

Publié dans le groupe Random-FR
Bon après-midi. Dans cet article, j'aimerais partager ma première rencontre avec des éléments comme Maven, Spring, Hibernate, MySQL et Tomcat en train de créer une application CRUD simple. Il s'agit de la deuxième partie de 4. L'article est principalement destiné à ceux qui ont déjà terminé 30 à 40 niveaux ici, mais qui ne se sont pas encore aventurés au-delà du Java pur et qui commencent tout juste (ou sont sur le point de commencer) à entrer dans le monde ouvert avec toutes ces technologies, frameworks et autres mots inconnus. Ceci est la deuxième partie de l'article "Introduction à Maven, Spring, MySQL, Hibernate et la première application CRUD". La première partie est visible en suivant ce lien : Introduction à Maven, Spring, MySQL, Hibernate et la première application CRUD (partie 1)

Contenu:

Eh bien, passons à autre chose, essayons maintenant d'évoquer tout un référentiel de films. Dans notre petite et simple application, bien sûr, vous pouvez simplement mettre toute la logique directement dans le contrôleur, mais, comme déjà noté, il est préférable d'apprendre immédiatement à tout faire correctement. Créons donc plusieurs calques. Nous aurons un DAO chargé de travailler avec les données, un Service , où il y aura toutes sortes d'autres logiques, et le Contrôleur traitera uniquement les demandes et appellera les méthodes de service nécessaires.

Objet d'accès aux données

L'objet d'accès aux données (DAO) est un tel modèle de conception. Le but est de créer une couche spéciale qui sera seule responsable de l'accès aux données (en travaillant avec une base de données ou un autre mécanisme de stockage). Dans le package, daonous créerons une interface FilmDAOdans laquelle il y aura des méthodes telles que l'ajout, la suppression, etc. Je les ai appelés un peu différemment, mais ils correspondent aux opérations de base CRUD ( C reate, Read , Update , D elete).

Il convient de noter ici qu'en plus du DAO, il existe également une approche telle que le référentiel, elles semblent très similaires, les deux sont utilisées pour travailler avec des données. Je n'ai pas encore compris quelles sont les caractéristiques de ces approches et quelle est la différence entre elles. Par conséquent, je peux me tromper ici et cela devrait être appelé un référentiel, et non un Tao, ou peut-être que c'est quelque chose entre les deux. Mais dans la plupart des exemples que j'ai vus et étudiés, cela s'appelle DAO, donc je l'appellerai probablement de la même manière. En même temps, peut-être plus loin dans le texte, j'utiliserai le mot référentiel. Dans tous les cas, si je me trompe quelque part, pardonnez-moi.

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);
}
Nous avons maintenant besoin de sa mise en œuvre. On ne connectera pas encore la base de données, ça fait quand même un peu peur. Pour s’entraîner et s’habituer, simulons d’abord le stockage en mémoire et créons une liste de plusieurs films. Pour stocker la liste, nous utiliserons not List, mais Map, pour faciliter la récupération d'un film spécifique par son id, sans parcourir la liste entière. Pour la génération id, nous utilisons AtomicInteger . Créons une classe FilmDAOImpl, implémentons toutes les méthodes et remplissons la carte. Quelque chose comme ca.
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

Ajoutons maintenant une couche de service. En principe, dans cet exemple, il est tout à fait possible de s'en passer, en se limitant au DAO, l'application sera très simple et aucune logique complexe n'est prévue dans le service. Mais tout à coup, à l'avenir, vous voudrez ajouter toutes sortes de complications et de choses intéressantes au projet, alors par souci d'exhaustivité, laissez tomber. Pour l’instant, il appellera simplement les méthodes du DAO. serviceCréons une interface dans le paquet 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);
}
Et sa mise en œuvre :
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);
    }
}
La structure du projet ressemble maintenant à ceci :
Introduction à Maven, Spring, MySQL, Hibernate et à la première application CRUD (partie 2) - 1

Contrôleur et vues

Travaillons maintenant sur les méthodes du contrôleur et le remplissage des pages. Pour remplir les pages, nous aurons besoin de quelques techniques. Par exemple, pour afficher une liste de films, nous avons besoin d'une boucle, si, par exemple, nous voulons modifier une inscription, en fonction des paramètres, nous avons besoin de conditions, etc. Le format JSP (JavaServer Pages) permet d'utiliser des inserts de code Java avec lesquels tout cela peut être implémenté. Mais je ne veux pas utiliser de code Java mélangé à du code HTML sur la page. Ce serait, au minimum, très moche. Heureusement, pour résoudre ce problème, il existe une chose aussi merveilleuse que JSTL (JavaServer Pages Standard Tag Library) ou la JSP Standard Tag Library. Cela nous permet d'utiliser tout un tas de balises supplémentaires dans nos pages JSP pour une variété de besoins. Connectons-le àpom.xml :
<dependency>
      <groupId>jstl</groupId>
      <artifactId>jstl</artifactId>
      <version>1.2</version>
</dependency>
Jetons maintenant un œil au contrôleur. Tout d’abord, supprimons la création de l’objet à partir de là Film, cela a été fait à des fins de test et nous n’avons besoin de rien d’autre. Ajoutons-y un service et appelons ses méthodes.
public class FilmController {
    private FilmService filmService = new FilmServiceImpl();
Eh bien, en conséquence, nous allons créer des méthodes pour chaque cas, ajouter, supprimer, etc. Tout d'abord une méthode pour afficher la page principale avec une liste de films :
@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;
    }
Il n'y a rien de nouveau ici. Nous obtenons une liste de films du service et l'ajoutons au modèle. Créons maintenant la page principale films.jsprenvoyée par cette méthode :
<%@ 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>
Regardons de plus près cette page pour voir de quoi il s'agit. <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> - ici le noyau JSTL est connecté, qui comprend les principales balises pour créer des cycles, des conditions, etc. .
  • <table>— balise pour créer un tableau.
  • <tr>— ligne du tableau
  • <th>- en-tête de colonne
  • <td>— cellule du tableau
Tout d’abord, nous créons une ligne d’en-tête de tableau avec les noms des colonnes. Ensuite <c:forEach var="film" items="${filmsList}">, dans une boucle (que nous avons tirée du noyau JSTL), nous parcourons tous les éléments de la liste passée ( filmsList), pour chaque élément ( film) nous créons une nouvelle ligne et écrivons la valeur correspondante dans chaque cellule. Il y a un point ici, l'enregistrement semble film.iddevoir être compris comme film.getId(), c'est-à-dire Le champ n'est pas accessible directement, mais le getter est appelé. Dans la dernière colonne ( action), nous créons des liens pour supprimer et éditer (nous allons maintenant créer les méthodes correspondantes). Eh bien, vous trouverez ci-dessous un lien vers la méthode pour ajouter un nouveau film. Voici à quoi cela ressemble : Examinons ensuite la méthode qui renverra la page d'édition pour un film spécifique :
@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;
    }
Quelque chose de nouveau est apparu ici - c'est une annotation @PathVariable. Il indique que ce paramètre ( int id) est obtenu depuis la barre d'adresse. Pour indiquer l'emplacement de ce paramètre dans la barre d'adresse, la construction est utilisée {id}(d'ailleurs, si le nom de la variable est le même, comme dans ce cas, alors vous n'êtes pas obligé de l'indiquer entre parenthèses, mais écrivez-le simplement @PathVariable int id). Ainsi, sur la page principale nous avons fait des liens pour chaque film indiquant id:
<a href="/edit/${film.id}">edit</a>
Ensuite, cette valeur est attribuée au paramètre de méthode, puis nous l'utilisons pour obtenir un film spécifique du référentiel via le service et l'ajouter au modèle. C'était la méthode pour obtenir la page d'édition, maintenant nous avons besoin d'une méthode pour l'éditer elle-même :
@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;
    }
Dans la méthode, editPagenous avons ajouté un attribut au modèle :
modelAndView.addObject("film", filmService.getById(id));
Et maintenant, avec l'aide de l'annotation, @ModelAttributenous obtenons cet attribut et nous pouvons le modifier. Méthode de requête POSTcar ici nous transmettrons les données. " redirect:/" signifie qu'après avoir exécuté cette méthode, nous serons redirigés vers l'adresse " /", c'est-à-dire la méthode s'exécutera allFilmset nous reviendrons à la page principale. Créons maintenant la page elle-mêmeeditPage.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>— un formulaire de collecte et d'envoi des données, indiquant qui les traitera ( /edit)
  • <input>— éléments d'interface pour l'interaction de l'utilisateur (boutons, champs de saisie, etc.)
  • <label>- étiquette de texte
Ainsi, lorsque vous cliquez sur le bouton, <input type="submit" value="Edit film">les données du formulaire seront envoyées au serveur (un champ invisible avec la valeur a été spécialement ajouté idpour que le serveur sache quel enregistrement de la base de données doit être mis à jour). Dans la méthode, editFilmils seront affectés aux champs d'attributs correspondants film. Nous reviendrons ensuite à la page principale avec une liste mise à jour. La page d'édition ressemble à ceci : Commençons maintenant à ajouter de nouveaux films à la liste. Pour ce faire, vous aurez également besoin d'un formulaire de saisie et de soumission des données. Vous pouvez créer un formulaire sur la page principale ou créer une page séparée, comme editPage.jsp. Mais, d'un autre côté, la forme pour l'ajout sera exactement la même que pour l'édition, c'est-à-dire 4 champs de saisie et un bouton de soumission. Alors pourquoi créer une nouvelle page alors, utilisons editPage.jsp. Méthode pour obtenir la page :
@RequestMapping(value = "/add", method = RequestMethod.GET)
    public ModelAndView addPage() {
        ModelAndView modelAndView = new ModelAndView();
        modelAndView.setViewName("editPage");
        return modelAndView;
    }
Dans la méthode, editPagenous avons en plus transmis l'attribut afin de le modifier ultérieurement, mais ici nous recevons simplement la page. Et la méthode à ajouter :
@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;
    }
Puisque nous n'avons pas transmis l'attribut ici, un nouvel objet sera créé ici Film. Eh bien, il n’y a fondamentalement rien de nouveau ici. Il convient également de noter que les deux méthodes sont disponibles sur " /add". Cela est possible grâce au fait qu’ils répondent à différents types de demandes. En suivant le lien sur la page principale, nous faisons une requête GET, qui nous amène au addPage. Et lorsque sur la page d'ajout nous cliquons sur le bouton pour envoyer des données, une requête POST est effectuée et le fichier addFilm. Pour ajouter un nouveau film, nous avons décidé d'utiliser la même page que pour le montage. Mais là les données sont envoyées à l'adresse " /edit" :
<c:url value="/edit" var="var"/>
<form action="${var}" method="POST">
    <input type="submit" value="Edit film">
</form>
Nous devons modifier un peu la page pour qu'elle se comporte différemment lors de l'ajout et de la modification. Pour résoudre ce problème, nous utiliserons les conditions de la même bibliothèque principale JSTL :
<%@ 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>
Ceux. nous vérifions simplement le terrain film.title. S'il est vide, alors c'est un nouveau film, nous devons remplir toutes les données le concernant et l'ajouter à la liste. Si ce champ n'est pas vide, alors il s'agit d'un film de la liste et il vous suffit de le modifier. Que. nous obtenons deux versions de notre page : Eh bien, la dernière méthode du contrôleur pour supprimer un film de la 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;
    }
Je pense qu'il n'est pas nécessaire de commenter quoi que ce soit ici, tout cela a déjà été envisagé. Nous avons déjà fait des liens vers cette adresse sur la page principale. Eh bien, tout semble être prêt ici, vous pouvez le relancer et voir comment tout fonctionne.

Référentiel et service en tant que composants Spring

Faisons encore une petite correction. Le fait est que désormais notre stockage et notre service ne sont que des classes, et pour les utiliser, nous devons créer nous-mêmes un objet de classe ( new FilmServiceImpl()). Mais nous avons Spring connecté pour une raison , alors laissez-le contrôler lui-même cette affaire. Pour mettre nos classes sous le contrôle de Spring, nous devons indiquer qu'elles sont des composants. Pour ce faire, nous les marquons avec des annotations spéciales :
@Repository
public class FilmDAOImpl implements FilmDAO {
@Service
public class FilmServiceImpl implements FilmService {
Les annotations @Repositoryet @Service, ainsi que @Controllersont dérivées de @Component. Quelles sont les caractéristiques spécifiques et les différences de ces trois annotations et en quoi elles diffèrent d'un simple composant doivent être lues séparément dans la documentation ou les guides. Pour l’instant, il suffit de savoir que ces annotations indiquent à Spring que ces classes sont respectivement un référentiel et un service. Et maintenant, nous n'avons plus besoin de créer nous-mêmes des objets concrets de ces classes :
private FilmService filmService = new FilmServiceImpl();
Au lieu de cela, vous pouvez marquer le champ avec une annotation spéciale et Spring sélectionnera l'implémentation appropriée :
@Autowired
private FilmService filmService;
L'annotation @Autowired(liaison automatique) indique à Spring qu'il doit fouiller dans son contexte et remplacer ici un bean approprié. Très confortablement. Si avant nous utilisions des interfaces pour ne pas nous soucier de l'implémentation spécifique des méthodes, désormais nous n'avons même plus besoin de nous soucier de l'implémentation de l'interface elle-même ni même de connaître son nom. L'idée est qu'il n'est pas recommandé d'utiliser l'auto-binding sur un champ, il est préférable d'utiliser un constructeur ou un setter. En savoir plus à ce sujet dans la documentation. Pour nous, en principe, ce n'est pas important, nous pouvons le laisser ainsi en toute sécurité. Mais, puisque l'idée le demande, nous respecterons que tout soit beau et sans aucune signalisation jaune. Dans la classe contrôleur, créons un setter et annotons-le :
@Controller
public class FilmController {

    private FilmService filmService;

    @Autowired
    public void setFilmService(FilmService filmService) {
        this.filmService = filmService;
    }
Et de même, nous faisons un passeur pour FilmDAOla classe FilmServiceImpl. A suivre... Présentation de Maven, Spring, MySQL, Hibernate et de la première application CRUD (partie 1) Présentation de Maven, Spring, MySQL, Hibernate et de la première application CRUD (partie 2) Présentation de Maven, Spring, MySQL, Hibernate et de la première application CRUD (partie 3) Introduction à Maven, Spring, MySQL, Hibernate et la première application CRUD (partie 4)
Commentaires
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION