JavaRush /وبلاگ جاوا /Random-FA /مقدمه ای بر Maven، Spring، MySQL، Hibernate و اولین برنام...
Макс
مرحله

مقدمه ای بر Maven، Spring، MySQL، Hibernate و اولین برنامه CRUD (قسمت 2)

در گروه منتشر شد
عصر بخیر. در این مقاله می‌خواهم اولین برخورد خود را با مواردی مانند Maven، Spring، Hibernate، MySQL و Tomcat در فرآیند ایجاد یک برنامه ساده CRUD به اشتراک بگذارم. این قسمت دوم از 4 است. این مقاله در درجه اول برای کسانی در نظر گرفته شده است که قبلاً 30-40 سطح را در اینجا تکمیل کرده اند، اما هنوز از جاوای خالص فراتر نرفته اند و تازه شروع کرده اند (یا می خواهند شروع کنند) برای ورود به دنیای باز با همه این فن آوری ها، چارچوب ها و دیگر کلمات ناآشنا. این قسمت دوم مقاله «معرفی Maven، Spring، MySQL، Hibernate و اولین برنامه CRUD» است. قسمت اول را می توانید از طریق این لینک مشاهده کنید: مقدمه ای بر Maven، Spring، MySQL، Hibernate و اولین برنامه CRUD (قسمت 1)

محتوا:

خوب، بیایید ادامه دهیم، بیایید اکنون سعی کنیم یک مخزن کامل از فیلم ها را تداعی کنیم. در برنامه کوچک و ساده ما، البته، می توانید به سادگی تمام منطق را در کنترلر قرار دهید، اما، همانطور که قبلا ذکر شد، بهتر است بلافاصله یاد بگیرید که چگونه همه چیز را به درستی انجام دهید. بنابراین، اجازه دهید چندین لایه ایجاد کنیم. ما یک DAO داریم که مسئول کار با داده ها است، یک سرویس ، که در آن انواع منطق های دیگر وجود خواهد داشت، و کنترل کننده فقط درخواست ها را پردازش می کند و روش های خدمات لازم را فراخوانی می کند.

شیء دسترسی به داده

شیء دسترسی به داده (DAO) چنین الگوی طراحی است. نکته این است که یک لایه خاص ایجاد کنید که تنها مسئول دسترسی به داده ها (کار با پایگاه داده یا مکانیسم ذخیره سازی دیگر) باشد. در بسته daoما یک رابط ایجاد خواهیم کرد FilmDAOکه در آن روش هایی مانند افزودن، حذف و غیره وجود خواهد داشت. من آنها را کمی متفاوت نامیدم، اما آنها با عملیات اصلی CRUD ( C reate، Read ، U pdate، D elete) مطابقت دارند.

در اینجا شایان ذکر است که علاوه بر DAO، رویکردی مانند Repository نیز وجود دارد، به نظر می رسد که آنها بسیار مشابه هستند، هر دو برای کار با داده ها استفاده می شوند. من هنوز متوجه نشده ام که این رویکردها چه ویژگی هایی دارند و چه تفاوتی بین آنها وجود دارد. بنابراین، من ممکن است در اینجا اشتباه کنم و این را باید یک مخزن نامید، نه یک تائو، یا شاید چیزی در این بین باشد. اما در اکثر نمونه هایی که من دیده ام و مطالعه کرده ام، این DAO نامیده می شود، بنابراین احتمالاً آن را به همین شکل می نامم. در عین حال، شاید در جایی بیشتر از متن از کلمه مخزن استفاده کنم. در هر صورت اگر جایی در این مورد اشتباه می کنم، مرا ببخشید.

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);
}
اکنون به اجرای آن نیاز داریم. ما هنوز پایگاه داده را وصل نمی کنیم، هنوز کمی ترسناک است. برای تمرین و عادت کردن به آن، اجازه دهید ابتدا فضای ذخیره سازی را در حافظه شبیه سازی کنیم و یک لیست با چندین فیلم ایجاد کنیم. برای ذخیره‌سازی فهرست، از نه List، بلکه استفاده می‌کنیم Mapتا بازیابی یک فیلم خاص توسط آن id، بدون مرور کل فهرست، راحت باشد. برای نسل ما از AtomicIntegerid استفاده می کنیم . بیایید یک کلاس ایجاد کنیم ، همه متدها را پیاده سازی کنیم و نقشه را پر کنیم. یه چیزی شبیه اون. FilmDAOImpl
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);
    }
}

سرویس

حالا بیایید یک لایه سرویس اضافه کنیم. در اصل، در این مثال کاملاً امکان پذیر است که بدون آن کار کنیم و خود را به DAO محدود کنیم؛ برنامه بسیار ساده خواهد بود و هیچ برنامه ای برای هیچ منطق پیچیده ای در سرویس وجود ندارد. اما ناگهان در آینده می خواهید انواع پیچیدگی ها و چیزهای جالب را به پروژه اضافه کنید، بنابراین برای کامل بودن، اجازه دهید. در حال حاضر، به سادگی متدها را از DAO فراخوانی می کند. serviceبیایید یک رابط در بسته ایجاد کنیم 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);
}
و اجرای آن:
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);
    }
}
ساختار پروژه اکنون به شکل زیر است:
مقدمه ای بر Maven، Spring، MySQL، Hibernate و اولین برنامه CRUD (قسمت 2) - 1

کنترلر و نماها

حالا بیایید روی روش های کنترلر و پر کردن صفحات کار کنیم. هنگام پر کردن صفحات، به چند تکنیک نیاز داریم. به عنوان مثال، برای نمایش لیست فیلم ها، به یک حلقه نیاز داریم، اگر مثلاً بخواهیم مقداری نوشته را تغییر دهیم، بسته به پارامترها، به شرایط و غیره نیاز داریم. فرمت JSP (صفحات جاوا سرور) به شما امکان می دهد از درج کدهای جاوا استفاده کنید که همه اینها را می توان پیاده سازی کرد. اما من نمی خواهم از کد جاوا مخلوط با کد HTML در صفحه استفاده کنم. این حداقل می تواند بسیار زشت باشد. خوشبختانه، برای حل این مشکل چیز شگفت انگیزی مانند JSTL (کتابخانه برچسب استاندارد صفحات جاوا سرور) یا کتابخانه برچسب استاندارد JSP وجود دارد. این به ما این امکان را می دهد که از یک دسته کامل برچسب اضافی در صفحات JSP خود برای نیازهای مختلف استفاده کنیم. بیایید آن را به pom.xml:
<dependency>
      <groupId>jstl</groupId>
      <artifactId>jstl</artifactId>
      <version>1.2</version>
</dependency>
حالا بیایید نگاهی به کنترلر بیاندازیم. اول از همه، بیایید ایجاد شی را از آنجا حذف کنیم Film، این کار برای آزمایش انجام شد و به چیز دیگری نیاز نداریم. بیایید یک سرویس را در آنجا اضافه کنیم و متدهای آن را فراخوانی کنیم.
public class FilmController {
    private FilmService filmService = new FilmServiceImpl();
خوب، بر این اساس ما برای هر مورد متدهایی ایجاد می کنیم، اضافه، حذف و غیره. ابتدا روشی برای نمایش صفحه اصلی با لیستی از فیلم ها:
@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;
    }
اینجا چیز جدیدی نیست ما لیستی از فیلم ها را از سرویس دریافت می کنیم و آن را به مدل اضافه می کنیم. حالا بیایید صفحه اصلی films.jspرا که این روش برمی گرداند ایجاد کنیم:
<%@ 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>
بیایید نگاهی دقیق تر به این صفحه بیندازیم تا ببینیم چه چیزی چیست. <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> - در اینجا هسته JSTL متصل است که شامل تگ های اصلی برای ایجاد چرخه ها، شرایط و غیره است. .
  • <table>- برچسب برای ایجاد یک جدول.
  • <tr>- ردیف جدول
  • <th>- سربرگ ستون
  • <td>- سلول جدول
ابتدا یک ردیف سرصفحه جدول با نام ستون ها ایجاد می کنیم. سپس <c:forEach var="film" items="${filmsList}">در یک حلقه (که از هسته JSTL گرفته ایم)، تمام عناصر لیست ارسال شده ( ) را مرور می کنیم filmsList، برای هر عنصر ( film) یک ردیف جدید ایجاد می کنیم و مقدار مربوطه را در هر سلول می نویسیم. در اینجا یک نکته وجود دارد، به نظر می رسد ضبط film.idباید به این صورت درک شود film.getId()، یعنی. فیلد مستقیماً قابل دسترسی نیست، اما گیرنده فراخوانی می شود. در ستون آخر ( action) پیوندهایی برای حذف و ویرایش ایجاد می کنیم (اکنون روش های مربوطه را ایجاد می کنیم). خب، در زیر لینک روش افزودن فیلم جدید است. در اینجا به نظر می رسد: در مرحله بعد، بیایید نگاهی به روشی بیندازیم که صفحه ویرایش یک فیلم خاص را برمی گرداند:
@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;
    }
چیزی جدید در اینجا ظاهر شده است - این یک حاشیه نویسی است @PathVariable. نشان می دهد که این پارامتر ( int id) از نوار آدرس به دست می آید. برای نشان دادن محل این پارامتر در نوار آدرس، از ساختار استفاده می شود {id}(به هر حال، اگر نام متغیر یکسان است، مانند این مورد، لازم نیست آن را در پرانتز نشان دهید، بلکه فقط آن را بنویسید. @PathVariable int id). بنابراین، در صفحه اصلی ما پیوندهایی برای هر فیلم ایجاد کرده ایم که نشان می دهد id:
<a href="/edit/${film.id}">edit</a>
سپس این مقدار به پارامتر متد اختصاص داده می شود و سپس با استفاده از آن فیلم خاصی را از مخزن از طریق سرویس دریافت کرده و به مدل اضافه می کنیم. این روش برای دریافت صفحه ویرایش بود، اکنون به یک روش برای ویرایش خود نیاز داریم:
@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;
    }
در متد editPageیک ویژگی به مدل اضافه کردیم:
modelAndView.addObject("film", filmService.getById(id));
و اکنون با کمک annotation @ModelAttributeاین ویژگی را به دست می آوریم و می توانیم آن را تغییر دهیم. روش درخواست POSTزیرا در اینجا داده ها را ارسال می کنیم. " redirect:/" به این معنی است که پس از اجرای این روش به آدرس " " هدایت می شویم /، i.e. متد اجرا می شود allFilmsو به صفحه اصلی باز می گردیم. حالا بیایید خود صفحه را بسازیم 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>- فرمی برای جمع آوری و ارسال داده ها که نشان می دهد چه کسی آن را پردازش می کند ( /edit)
  • <input>- عناصر رابط برای تعامل با کاربر (دکمه ها، فیلدهای ورودی و غیره)
  • <label>- برچسب متن
بنابراین، هنگامی که روی دکمه کلیک می کنید، <input type="submit" value="Edit film">داده های فرم به سرور ارسال می شود (یک فیلد نامرئی با مقدار به طور ویژه اضافه شده است idتا سرور بداند کدام رکورد در پایگاه داده باید به روز شود). در متد editFilmآنها به فیلدهای ویژگی مربوطه اختصاص داده می شوند film. سپس با یک لیست به روز شده به صفحه اصلی باز خواهیم گشت. صفحه ویرایش به این صورت است: حالا بیایید شروع کنیم به اضافه کردن فیلم های جدید به لیست. برای این کار به فرمی برای وارد کردن و ارسال اطلاعات نیز نیاز دارید. می توانید یک فرم در صفحه اصلی ایجاد کنید یا می توانید یک صفحه جداگانه مانند editPage.jsp. اما، از طرف دیگر، فرم اضافه کردن دقیقاً مانند ویرایش خواهد بود، یعنی. 4 فیلد ورودی و یک دکمه ارسال. پس چرا یک صفحه جدید ایجاد کنید، بیایید استفاده کنیم editPage.jsp. روش دریافت صفحه:
@RequestMapping(value = "/add", method = RequestMethod.GET)
    public ModelAndView addPage() {
        ModelAndView modelAndView = new ModelAndView();
        modelAndView.setViewName("editPage");
        return modelAndView;
    }
در متد، editPageویژگی را به منظور تغییر بعداً ارسال کردیم، اما در اینجا به سادگی صفحه را دریافت می کنیم. و روش اضافه کردن:
@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;
    }
از آنجایی که ما ویژگی را در اینجا ارسال نکردیم، یک شی جدید در اینجا ایجاد می شود Film. خب، اساساً هیچ چیز جدیدی در اینجا وجود ندارد. همچنین شایان ذکر است که ما هر دو روش را در " /add" در دسترس داریم. این امر به دلیل پاسخگویی آنها به انواع درخواست ها امکان پذیر است. با دنبال کردن پیوند موجود در صفحه اصلی، یک درخواست GET ارائه می کنیم که ما را به addPage. و هنگامی که در صفحه افزودن روی دکمه ارسال داده کلیک می کنیم، درخواست POST ایجاد می شود و addFilm. برای افزودن یک فیلم جدید، تصمیم گرفتیم از همان صفحه برای ویرایش استفاده کنیم. اما در آنجا داده ها به آدرس " /edit" ارسال می شود:
<c:url value="/edit" var="var"/>
<form action="${var}" method="POST">
    <input type="submit" value="Edit film">
</form>
باید صفحه را کمی تغییر دهیم تا برای افزودن و ویرایش رفتار متفاوتی داشته باشد. برای حل این مشکل، از شرایط همان کتابخانه هسته 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>
آن ها ما فقط میدان را بررسی می کنیم film.title. اگر خالی است، پس فیلم جدیدی است، باید تمام داده های آن را پر کرده و به لیست اضافه کنیم. اگر این قسمت خالی نیست، پس یک فیلم از لیست است و فقط باید آن را تغییر دهید. که ما دو نسخه از صفحه خود را دریافت می کنیم: خوب، آخرین روش کنترل کننده برای حذف یک فیلم از لیست:
@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;
    }
من فکر می کنم نیازی به اظهار نظر در اینجا نیست، همه اینها قبلاً در نظر گرفته شده است. ما قبلاً پیوندهایی به این آدرس در صفحه اصلی ایجاد کرده ایم. خب، به نظر می رسد همه چیز در اینجا آماده است، می توانید دوباره آن را اجرا کنید و ببینید که چگونه همه چیز کار می کند.

مخزن و سرویس به عنوان اجزای فنری

بیایید یک اصلاح کوچک دیگر انجام دهیم. واقعیت این است که اکنون ذخیره سازی و سرویس ما فقط کلاس هستند و برای استفاده از آنها باید خود یک شی کلاس ایجاد کنیم ( new FilmServiceImpl()). اما ما اسپرینگ را به یک دلیل وصل کرده ایم ، پس بگذار خودش این موضوع را کنترل کند. برای اینکه کلاس های خود را تحت کنترل Spring قرار دهیم، باید مشخص کنیم که آنها جزء هستند. برای انجام این کار، آنها را با حاشیه نویسی خاص علامت گذاری می کنیم:
@Repository
public class FilmDAOImpl implements FilmDAO {
@Service
public class FilmServiceImpl implements FilmService {
حاشیه نویسی @Repositoryو @Service, و همچنین @Controllerمشتق شده از @Component. ویژگی‌ها و تفاوت‌های این سه حاشیه‌نویسی چیست و تفاوت آن‌ها با یک جزء ساده چیست، باید به طور جداگانه در مستندات یا راهنماها مطالعه شود. در حال حاضر کافی است بدانید که این حاشیه نویسی به Spring می گوید که این کلاس ها به ترتیب یک مخزن و یک سرویس هستند. و اکنون دیگر نیازی نیست که خودمان اشیاء عینی این کلاس ها را ایجاد کنیم:
private FilmService filmService = new FilmServiceImpl();
در عوض، می توانید فیلد را با یک حاشیه نویسی خاص علامت گذاری کنید و Spring پیاده سازی مناسب را انتخاب می کند:
@Autowired
private FilmService filmService;
حاشیه‌نویسی @Autowired(صحافی خودکار) به Spring می‌گوید که باید در زمینه‌اش حفاری کند و یک لوبیا مناسب را در اینجا جایگزین کند. خیلی راحت اگر قبلاً از رابط ها استفاده می کردیم تا نگران اجرای خاص متدها نباشیم، اکنون حتی نیازی به نگرانی در مورد پیاده سازی خود اینترفیس نداریم و حتی نام آن را می دانیم. ایده این است که استفاده از اتصال خودکار در یک فیلد توصیه نمی شود، بهتر است از سازنده یا تنظیم کننده استفاده کنید. در مورد این در مستندات بیشتر بخوانید. برای ما، در اصل، این مهم نیست، ما می توانیم با خیال راحت آن را به همین شکل رها کنیم. اما، از آنجایی که ایده آن را درخواست می کند، ما احترام می گذاریم که همه چیز زیبا و بدون هیچ گونه هشدار زرد است. در کلاس کنترلر، بیایید یک setter ایجاد کنیم و آن را حاشیه نویسی کنیم:
@Controller
public class FilmController {

    private FilmService filmService;

    @Autowired
    public void setFilmService(FilmService filmService) {
        this.filmService = filmService;
    }
و به همین ترتیب یک ستتر برای FilmDAOکلاس درست می کنیم FilmServiceImpl. ادامه دارد... معرفی Maven، Spring، MySQL، Hibernate و اولین برنامه CRUD (قسمت 1) معرفی Maven، Spring، MySQL، Hibernate و اولین برنامه CRUD (قسمت 2) معرفی Maven، Spring، MySQL، Hibernate و اولین برنامه CRUD (قسمت 3) مقدمه ای بر Maven، Spring، MySQL، Hibernate و اولین برنامه CRUD (قسمت 4)
نظرات
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION