JavaRush /Java Blogu /Random-AZ /Maven, Spring, MySQL, Hibernate və ilk CRUD tətbiqinə gir...
Макс
Səviyyə

Maven, Spring, MySQL, Hibernate və ilk CRUD tətbiqinə giriş (2-ci hissə)

Qrupda dərc edilmişdir
Günortanız Xeyir. Bu yazıda sadə CRUD tətbiqi yaratma prosesində Maven, Spring, Hibernate, MySQL və Tomcat kimi şeylərlə ilk tanışlığımı bölüşmək istərdim. Bu, 4-cü hissənin ikinci hissəsidir. Məqalə ilk növbədə burada 30-40 səviyyəni tamamlamış, lakin hələ təmiz Java-dan kənara çıxmamış və açıq dünyaya yeni başlayanlar (və ya başlamaq üzrə olanlar) üçün nəzərdə tutulub. bütün bu texnologiyalar, çərçivələr və digər tanış olmayan sözlər. Bu, "Maven, Spring, MySQL, Hibernate və ilk CRUD tətbiqinə giriş" məqaləsinin ikinci hissəsidir. Birinci hissəyə bu linkdən baxmaq olar: Maven, Spring, MySQL, Hibernate və ilk CRUD tətbiqinə giriş (1-ci hissə)

Məzmun:

Yaxşı, davam edək, indi filmlərin bütöv bir anbarını təsəvvür etməyə çalışaq. Kiçik və sadə tətbiqimizdə, əlbəttə ki, bütün məntiqi axmaqcasına nəzarətçiyə yerləşdirə bilərsiniz, lakin artıq qeyd edildiyi kimi, hər şeyi necə düzgün edəcəyinizi dərhal öyrənmək daha yaxşıdır. Buna görə də bir neçə təbəqə yaradaq. Bizdə verilənlərlə işləmək üçün məsul DAO , hər cür digər məntiqin olacağı bir Xidmət olacaq və Nəzarətçi yalnız sorğuları emal edəcək və lazımi xidmət üsullarını çağıracaq.

Məlumata giriş obyekti

Data Access Object (DAO) belə bir dizayn nümunəsidir. Məsələ yalnız məlumatların əldə edilməsinə cavabdeh olacaq (verilənlər bazası və ya digər saxlama mexanizmi ilə işləmək) xüsusi bir təbəqə yaratmaqdır. Paketdə əlavə etmək, silmək və s kimi üsulların olacağı daobir interfeys yaradacağıq. FilmDAOMən onları bir az fərqli adlandırdım, lakin onlar əsas CRUD əməliyyatlarına uyğundur ( C reate, Read , U pdate, D elete).

Burada qeyd etmək lazımdır ki, DAO ilə yanaşı, Repository kimi bir yanaşma da var, onlar çox oxşar görünür, hər ikisi məlumatlarla işləmək üçün istifadə olunur. Bu yanaşmaların hansı xüsusiyyətlərə malik olduğunu və aralarındakı fərqin nə olduğunu hələ anlamamışam. Buna görə də, mən burada səhv edə bilərəm və bunu Tao deyil, depo adlandırmaq lazımdır və ya bəlkə də bu, aralarında bir şeydir. Ancaq gördüyüm və öyrəndiyim nümunələrin əksəriyyətində bu DAO adlanır, ona görə də yəqin ki, eyni adlandıracağam. Eyni zamanda, bəlkə də mətnin daha bir yerində mən anbar sözündən istifadə edəcəyəm. Hər halda, bununla bağlı bir yerdə səhv etmişəmsə, məni bağışlayın.

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);
}
İndi onun həyata keçirilməsinə ehtiyacımız var. Verilənlər bazasını hələ bağlamayacağıq, hələ bir az qorxuludur. Məşq etmək və buna öyrəşmək üçün əvvəlcə yaddaşda saxlama simulyasiyasını edək və bir neçə filmdən ibarət siyahı yaradaq. Siyahını saxlamaq üçün bütün siyahıdan keçmədən konkret filmi onun vasitəsilə əldə etməyi rahat etmək üçün deyil, Listlakin istifadə edəcəyik. Nəsil üçün biz AtomicInteger istifadə edirik . Gəlin bir sinif yaradaq , bütün üsulları tətbiq edək və xəritəni dolduraq. Belə bir şey. MapididFilmDAOImpl
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);
    }
}

Xidmət

İndi bir xidmət qatını əlavə edək. Prinsipcə, bu nümunədə özümüzü DAO ilə məhdudlaşdıraraq, onsuz etmək olduqca mümkündür; tətbiq çox sadə olacaq və xidmətdə hər hansı bir mürəkkəb məntiq üçün planlar yoxdur. Ancaq birdən-birə gələcəkdə layihəyə hər cür fəsadlar və maraqlı şeylər əlavə etmək istəyəcəksiniz, ona görə də tamlıq naminə, olsun. Hələlik o, sadəcə olaraq DAO-dan metodları çağıracaq. Paketdə servicebir interfeys yaradaq 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);
}
Və onun həyata keçirilməsi:
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);
    }
}
Layihə strukturu indi belə görünür:
Maven, Spring, MySQL, Hibernate və ilk CRUD tətbiqinə giriş (2-ci hissə) - 1

Nəzarətçi və Baxışlar

İndi nəzarətçi üsulları və səhifələrin doldurulması üzərində işləyək. Səhifələri doldurarkən bəzi texnikalara ehtiyacımız olacaq. Məsələn, filmlərin siyahısını göstərmək üçün bizə bir döngə lazımdır, məsələn, bəzi yazıları dəyişdirmək istəyiriksə, parametrlərdən asılı olaraq şərtlərə ehtiyacımız var və s. JSP (JavaServer Səhifələri) formatı bütün bunların həyata keçirilə biləcəyi java kodu əlavələrindən istifadə etməyə imkan verir. Ancaq səhifədə HTML kodu ilə qarışdırılmış java kodundan istifadə etmək istəmirəm. Bu, ən azı, çox çirkin olardı. Xoşbəxtlikdən, bu problemi həll etmək üçün JSTL (JavaServer Pages Standard Tag Library) və ya JSP Standard Tag Library kimi gözəl bir şey var . Bu, bizə müxtəlif ehtiyaclar üçün JSP səhifələrimizdə bir çox əlavə teqlərdən istifadə etməyə imkan verir. Onu bağlayaq pom.xml:
<dependency>
      <groupId>jstl</groupId>
      <artifactId>jstl</artifactId>
      <version>1.2</version>
</dependency>
İndi nəzarətçiyə nəzər salaq. Əvvəlcə obyektin yaradılmasını oradan çıxaraq Film, bu sınaq üçün edilib və bizə başqa heç nə lazım deyil. Oraya bir xidmət əlavə edək və onun üsullarını çağıraq.
public class FilmController {
    private FilmService filmService = new FilmServiceImpl();
Yaxşı, buna uyğun olaraq hər bir hal üçün üsullar yaradacağıq, əlavə edəcəyik, siləcəyik və s. Əvvəlcə filmlərin siyahısı ilə əsas səhifəni göstərmək üçün bir üsul:
@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;
    }
Burada yeni heç nə yoxdur. Xidmətdən filmlərin siyahısını alırıq və modelə əlavə edirik. films.jspİndi bu metodun qaytardığı əsas səhifəni yaradaq :
<%@ 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>
Nə olduğunu görmək üçün bu səhifəyə daha yaxından nəzər salaq. <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> - burada dövrlər, şərtlər və s. yaratmaq üçün əsas teqləri ehtiva edən JSTL nüvəsi birləşdirilir. .
  • <table>— cədvəl yaratmaq üçün etiket.
  • <tr>- masa sırası
  • <th>- sütun başlığı
  • <td>- masa hüceyrəsi
Əvvəlcə sütunların adları ilə cədvəl başlığı sətirini düzəldirik. Sonra <c:forEach var="film" items="${filmsList}">, bir döngədə (JSTL nüvəsindən götürdük) keçən siyahının bütün elementlərini ( filmsList) keçirik, hər bir element üçün ( film) yeni sətir yaradırıq və hər bir xanaya müvafiq dəyəri yazırıq. Burada bir məqam var, qeydi, deyəsən, film.idbaşa düşmək lazımdır film.getId(), yəni. Sahəyə birbaşa daxil olunmur, lakin alıcı çağırılır. Son sütunda ( action) biz silmək və redaktə etmək üçün keçidlər edirik (indi müvafiq üsulları yaradacağıq). Yaxşı, aşağıda yeni film əlavə etmək üsuluna keçid var. Bu belə görünür: Sonra, konkret film üçün redaktə səhifəsini qaytaracaq üsula nəzər salaq:
@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;
    }
Burada yeni bir şey ortaya çıxdı - bu annotasiyadır @PathVariable. int idBu parametrin ( ) ünvan çubuğundan alındığını göstərir . Bu parametrin ünvan çubuğunda yerini göstərmək üçün konstruksiyadan istifadə olunur {id}(yeri gəlmişkən, əgər dəyişən adı bu vəziyyətdə olduğu kimi eynidirsə, onu mötərizədə göstərmək lazım deyil, sadəcə yazın. @PathVariable int id). Beləliklə, əsas səhifədə hər bir film üçün aşağıdakıları göstərən keçidlər etdik id:
<a href="/edit/${film.id}">edit</a>
Sonra bu dəyər metod parametrinə təyin edilir və sonra xidmət vasitəsilə anbardan konkret filmi əldə edib modelə əlavə etmək üçün istifadə edirik. Bu, redaktə səhifəsini əldə etmək üsulu idi, indi bizə özünü redaktə etmək üçün bir üsul lazımdır:
@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;
    }
Metodda editPagemodelə bir atribut əlavə etdik:
modelAndView.addObject("film", filmService.getById(id));
İndi annotasiyanın köməyi ilə @ModelAttributebiz bu atributu əldə edirik və onu dəyişə bilərik. Sorğu metodu POST, çünki burada məlumatları ötürəcəyik. " redirect:/" o deməkdir ki, bu metodu icra etdikdən sonra biz " " ünvanına yönləndiriləcəyik /, yəni. üsul işləyəcək allFilmsvə biz əsas səhifəyə qayıdacağıq. İndi səhifənin özünü düzəldək 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>— məlumatı kimin emal edəcəyini göstərən məlumatların toplanması və göndərilməsi forması ( /edit)
  • <input>— istifadəçinin qarşılıqlı əlaqəsi üçün interfeys elementləri (düymələr, giriş sahələri və s.)
  • <label>- mətn etiketi
Beləliklə, düyməni basdığınız zaman <input type="submit" value="Edit film">formadan verilənlər serverə göndəriləcək ( idverilənlər bazasında hansı qeydin yenilənməsi lazım olduğunu serverin bilməsi üçün dəyəri olan görünməz sahə xüsusi olaraq əlavə edilmişdir). Metodda editFilmonlar müvafiq atribut sahələrinə təyin ediləcəklər film. Daha sonra yenilənmiş siyahı ilə əsas səhifəyə qayıdacağıq. Redaktə səhifəsi belə görünür: İndi siyahıya yeni filmlər əlavə etməyə başlayaq. Bunun üçün sizə məlumatların daxil edilməsi və təqdim edilməsi üçün bir forma da lazımdır. Siz əsas səhifədə forma yarada bilərsiniz və ya kimi ayrıca səhifə yarada bilərsiniz editPage.jsp. Lakin, digər tərəfdən, əlavə etmək forması redaktə ilə eyni olacaq, yəni. 4 giriş sahəsi və göndərmə düyməsi. Bəs onda niyə yeni səhifə yaradaq, istifadə edək editPage.jsp. Səhifəni əldə etmək üsulu:
@RequestMapping(value = "/add", method = RequestMethod.GET)
    public ModelAndView addPage() {
        ModelAndView modelAndView = new ModelAndView();
        modelAndView.setViewName("editPage");
        return modelAndView;
    }
Metodda editPagebiz atributu daha sonra dəyişdirmək üçün əlavə olaraq keçdik, lakin burada sadəcə səhifəni alırıq. Və əlavə etmək üsulu:
@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;
    }
Burada atribut keçmədiyimiz üçün burada yeni obyekt yaradılacaq Film. Yaxşı, burada əsasən yeni heç nə yoxdur. Həm də qeyd etmək lazımdır ki, bizdə hər iki üsul var " /add". Bu, onların müxtəlif növ sorğulara cavab verməsi səbəbindən mümkündür. Əsas səhifədəki linkə daxil olaraq biz GET sorğusu veririk ki, bu da bizi addPage. Və əlavə səhifəsində məlumat göndərmək üçün düyməni sıxdıqda POST sorğusu edilir və addFilm. Yeni film əlavə etmək üçün redaktə üçün eyni səhifədən istifadə etmək qərarına gəldik. Ancaq orada məlumatlar " " ünvanına göndərilir /edit:
<c:url value="/edit" var="var"/>
<form action="${var}" method="POST">
    <input type="submit" value="Edit film">
</form>
Səhifəni bir az dəyişdirməliyik ki, əlavə və redaktə üçün fərqli davransın. Bu problemi həll etmək üçün eyni JSTL əsas kitabxanasının şərtlərindən istifadə edəcəyik:
<%@ 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>
Bunlar. biz sadəcə sahəni yoxlayırıq film.title. Boşdursa, o, yeni bir filmdir, onun üçün bütün məlumatları doldurmalı və siyahıya əlavə etməliyik. Bu sahə boş deyilsə, o, siyahıdan bir filmdir və sadəcə onu dəyişdirməlisiniz. Bu. səhifəmizin iki versiyasını alırıq: Yaxşı, siyahıdan bir filmi silmək üçün son nəzarətçi metodu:
@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;
    }
Hesab edirəm ki, burada nəyisə şərh etməyə ehtiyac yoxdur, bütün bunlar artıq nəzərdən keçirilib. Biz artıq əsas səhifədə bu ünvana keçidlər etmişik. Yaxşı, burada hər şey hazır görünür, yenidən işə salıb hər şeyin necə işlədiyini görə bilərsiniz.

Yay Komponentləri kimi Repozitoriya və Xidmət

Gəlin daha bir kiçik düzəliş edək. Fakt budur ki, indi bizim saxlama və xidmətimiz sadəcə siniflərdir və onlardan istifadə etmək üçün özümüz bir sinif obyekti yaratmalıyıq ( new FilmServiceImpl()). Amma bizim Baharın bir səbəbi var , qoy bu işə özü nəzarət etsin. Dərslərimizi Baharın nəzarəti altına almaq üçün onların komponentlər olduğunu göstərməliyik. Bunun üçün onları xüsusi qeydlərlə qeyd edirik:
@Repository
public class FilmDAOImpl implements FilmDAO {
@Service
public class FilmServiceImpl implements FilmService {
Annotasiyalar @Repositoryvə , @Servicehəmçinin @Controller. @ComponentBu üç annotasiyanın spesifik xüsusiyyətləri və fərqləri nələrdir və onların sadə komponentdən necə fərqləndiyi sənədlərdə və ya təlimatlarda ayrıca oxunmalıdır. Hələlik bu annotasiyaların Bahara bu siniflərin müvafiq olaraq bir depo və bir xidmət olduğunu bildirdiyini bilmək kifayətdir. İndi bu siniflərin konkret obyektlərini özümüz yaratmağa ehtiyacımız yoxdur:
private FilmService filmService = new FilmServiceImpl();
Bunun əvəzinə sahəni xüsusi annotasiya ilə qeyd edə bilərsiniz və Bahar müvafiq icranı seçəcək:
@Autowired
private FilmService filmService;
Annotasiya @Autowired(avtomatik bağlama) Bahara deyir ki, o, öz kontekstinə daxil olmalı və burada uyğun lobya ilə əvəz etməlidir. Çox rahat. Əgər əvvəllər metodların konkret tətbiqi ilə bağlı narahat olmamaq üçün interfeyslərdən istifadə edirdiksə, indi interfeysin özünün həyata keçirilməsindən narahat olmağa belə ehtiyac yoxdur və hətta onun adını da bilirik. İdeya ondan ibarətdir ki, bir sahədə avtomatik bağlamadan istifadə etmək tövsiyə edilmir, konstruktor və ya tənzimləyicidən istifadə etmək daha yaxşıdır. Bu barədə sənədlərdə daha çox oxuyun. Bizim üçün, prinsipcə, bu vacib deyil, biz bunu təhlükəsiz şəkildə belə tərk edə bilərik. Ancaq fikir bunu tələb etdiyinə görə, hər şeyin gözəl və heç bir sarı xəbərdarlıq olmadan olmasına hörmət edəcəyik. Nəzarətçi sinfində tənzimləyici yaradaq və ona annotasiya edək:
@Controller
public class FilmController {

    private FilmService filmService;

    @Autowired
    public void setFilmService(FilmService filmService) {
        this.filmService = filmService;
    }
FilmDAOVə eynilə biz sinifdə təyinedici düzəldirik FilmServiceImpl. Davamı olacaq... Maven, Spring, MySQL, Hibernate və ilk CRUD tətbiqinin təqdimatı (1-ci hissə) Maven, Spring, MySQL, Hibernate və ilk CRUD tətbiqinin təqdimatı (2-ci hissə) Maven, Spring, MySQL, Hibernate və ilk CRUD tətbiqi (3-cü hissə) Maven, Spring, MySQL, Hibernate-ə giriş və ilk CRUD tətbiqi (4-cü hissə)
Şərhlər
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION