JavaRush /Blog Java /Random-MS /Pengenalan kepada Maven, Spring, MySQL, Hibernate dan apl...
Макс
Tahap

Pengenalan kepada Maven, Spring, MySQL, Hibernate dan aplikasi CRUD pertama (bahagian 2)

Diterbitkan dalam kumpulan
Selamat petang. Dalam artikel ini saya ingin berkongsi pertemuan pertama saya dengan perkara seperti Maven, Spring, Hibernate, MySQL dan Tomcat dalam proses mencipta aplikasi CRUD yang mudah. Ini adalah bahagian kedua daripada 4. Artikel ini ditujukan terutamanya untuk mereka yang telah menyelesaikan 30-40 tahap di sini, tetapi belum menerokai Java tulen dan baru bermula (atau akan bermula) untuk memasuki dunia terbuka dengan semua teknologi, rangka kerja dan perkataan asing yang lain ini. Ini adalah bahagian kedua artikel "Pengenalan kepada Maven, Spring, MySQL, Hibernate dan aplikasi CRUD yang pertama." Bahagian pertama boleh dilihat dengan mengikuti pautan ini: Pengenalan kepada Maven, Spring, MySQL, Hibernate dan aplikasi CRUD pertama (bahagian 1)

Kandungan:

Baiklah, mari kita teruskan, mari kita cuba mencipta keseluruhan repositori filem. Dalam aplikasi kami yang kecil dan mudah, sudah tentu, anda boleh dengan mudah meletakkan semua logik dengan betul dalam pengawal, tetapi, seperti yang telah dinyatakan, lebih baik untuk segera belajar cara melakukan semuanya dengan betul. Oleh itu, mari kita buat beberapa lapisan. Kami akan mempunyai DAO yang bertanggungjawab untuk bekerja dengan data, Perkhidmatan , di mana akan terdapat pelbagai jenis logik lain, dan Pengawal hanya akan memproses permintaan dan memanggil kaedah perkhidmatan yang diperlukan.

Objek Capaian Data

Objek Akses Data (DAO) ialah corak reka bentuk sedemikian. Intinya adalah untuk mencipta lapisan khas yang akan bertanggungjawab sepenuhnya untuk mengakses data (bekerja dengan pangkalan data atau mekanisme storan lain). Dalam pakej daokami akan membuat antara muka FilmDAOdi mana terdapat kaedah seperti tambah, padam, dll. Saya memanggilnya sedikit berbeza, tetapi ia sepadan dengan operasi CRUD asas ( C reate, Read , U pdate, D elete).

Perlu diperhatikan di sini bahawa sebagai tambahan kepada DAO, terdapat juga pendekatan seperti Repositori, mereka kelihatan sangat serupa, kedua-duanya digunakan untuk bekerja dengan data. Saya masih belum mengetahui ciri-ciri pendekatan ini dan apakah perbezaan di antara mereka. Oleh itu, saya mungkin tersilap di sini dan ini harus dipanggil repositori, dan bukan Tao, atau mungkin ia adalah sesuatu di antaranya. Tetapi dalam kebanyakan contoh yang saya lihat dan pelajari, ini dipanggil DAO, jadi saya mungkin akan memanggilnya sama. Pada masa yang sama, mungkin di tempat yang lebih jauh dalam teks saya akan menggunakan repositori perkataan. Walau apa pun, jika saya tersilap dalam hal ini, harap maafkan saya.

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);
}
Sekarang kita memerlukan pelaksanaannya. Kami tidak akan menyambungkan pangkalan data lagi, ia masih agak menakutkan. Untuk berlatih dan membiasakannya, mari kita simulasi storan dalam ingatan dan buat senarai dengan beberapa filem. Untuk menyimpan senarai, kami akan menggunakan bukan List, tetapi Map, untuk memudahkan anda mendapatkan semula filem tertentu mengikut id, tanpa melalui keseluruhan senarai. Untuk penjanaan idkami menggunakan AtomicInteger . Mari buat kelas FilmDAOImpl, laksanakan semua kaedah dan isi peta. Sesuatu seperti itu.
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);
    }
}

Perkhidmatan

Sekarang mari tambah lapisan perkhidmatan. Pada dasarnya, dalam contoh ini adalah sangat mungkin untuk dilakukan tanpa itu, mengehadkan diri kita kepada DAO; aplikasi akan menjadi sangat mudah dan tidak ada rancangan untuk sebarang logik kompleks dalam perkhidmatan. Tetapi tiba-tiba, pada masa hadapan, anda ingin menambah pelbagai komplikasi dan perkara yang menarik pada projek itu, jadi demi kesempurnaan, biarkan saja. Buat masa ini, ia hanya akan memanggil kaedah daripada DAO. serviceMari buat antara muka dalam pakej 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);
}
Dan pelaksanaannya:
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);
    }
}
Struktur projek kini kelihatan seperti ini:
Pengenalan kepada Maven, Spring, MySQL, Hibernate dan aplikasi CRUD pertama (bahagian 2) - 1

Pengawal dan Pandangan

Sekarang mari kita bekerja pada kaedah pengawal dan mengisi halaman. Semasa mengisi halaman, kami memerlukan beberapa teknik. Sebagai contoh, untuk memaparkan senarai filem, kita memerlukan kitaran, jika, sebagai contoh, kita ingin menukar beberapa inskripsi, bergantung pada parameter, kita memerlukan syarat, dsb. Format JSP (JavaServer Pages) membolehkan anda menggunakan sisipan kod java yang dengannya semua ini boleh dilaksanakan. Tetapi saya tidak mahu menggunakan kod java bercampur dengan kod HTML pada halaman. Ia akan menjadi, sekurang-kurangnya, sangat hodoh. Nasib baik, untuk menyelesaikan masalah ini terdapat perkara yang menarik seperti JSTL (JavaServer Pages Standard Tag Library) atau JSP Standard Tag Library. Ia membolehkan kami menggunakan sejumlah besar teg tambahan dalam halaman JSP kami untuk pelbagai keperluan. Mari sambungkannya ke pom.xml:
<dependency>
      <groupId>jstl</groupId>
      <artifactId>jstl</artifactId>
      <version>1.2</version>
</dependency>
Sekarang mari kita lihat pada pengawal. Pertama sekali, mari kita keluarkan penciptaan objek dari sana Film, ini dilakukan untuk ujian dan kita tidak memerlukan apa-apa lagi. Mari tambahkan perkhidmatan di sana dan panggil kaedahnya.
public class FilmController {
    private FilmService filmService = new FilmServiceImpl();
Oleh itu, kami akan membuat kaedah untuk setiap kes, tambah, padam, dll. Pertama kaedah untuk memaparkan halaman utama dengan senarai filem:
@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;
    }
Tiada yang baru di sini. Kami mendapat senarai filem daripada perkhidmatan dan menambahkannya pada model. Sekarang mari kita buat halaman utama films.jspyang kaedah ini kembalikan:
<%@ 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>
Mari lihat halaman ini dengan lebih dekat untuk melihat apa itu. <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> - di sini teras JSTL disambungkan, yang termasuk teg utama untuk mencipta kitaran, keadaan, dsb. .
  • <table>— tag untuk membuat jadual.
  • <tr>- baris meja
  • <th>- pengepala lajur
  • <td>- sel meja
Mula-mula, kami membuat baris pengepala jadual dengan nama lajur. Kemudian <c:forEach var="film" items="${filmsList}">, dalam gelung (yang kami ambil daripada teras JSTL), kami pergi melalui semua elemen senarai yang diluluskan ( filmsList), untuk setiap elemen ( film) kami mencipta baris baharu dan menulis nilai yang sepadan ke dalam setiap sel. Terdapat satu perkara di sini, rakaman itu nampaknya film.idperlu difahami sebagai film.getId(), i.e. Medan tidak diakses secara langsung, tetapi pengambil dipanggil. Dalam lajur terakhir ( action) kami membuat pautan untuk memadam dan mengedit (kami akan mencipta kaedah yang sepadan sekarang). Nah, di bawah ialah pautan kepada kaedah untuk menambah filem baharu. Begini rupanya: Seterusnya, mari kita lihat kaedah yang akan mengembalikan halaman edit untuk filem tertentu:
@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;
    }
Sesuatu yang baharu telah muncul di sini - ini adalah anotasi @PathVariable. Ia menunjukkan bahawa parameter ini ( int id) diperoleh daripada bar alamat. Untuk menunjukkan lokasi parameter ini dalam bar alamat, pembinaan digunakan {id}(dengan cara ini, jika nama pembolehubah adalah sama, seperti dalam kes ini, maka anda tidak perlu menunjukkannya dalam kurungan, tetapi tulis sahaja @PathVariable int id). Jadi, pada halaman utama kami telah membuat pautan untuk setiap filem yang menunjukkan id:
<a href="/edit/${film.id}">edit</a>
Kemudian nilai ini diberikan kepada parameter kaedah dan kemudian kami menggunakannya untuk mendapatkan filem tertentu daripada repositori melalui perkhidmatan dan menambahnya pada model. Ini adalah kaedah untuk mendapatkan halaman pengeditan, sekarang kita memerlukan kaedah untuk mengedit sendiri:
@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;
    }
Dalam kaedah editPagekami menambah atribut kepada model:
modelAndView.addObject("film", filmService.getById(id));
Dan sekarang dengan bantuan anotasi @ModelAttributekami mendapat atribut ini dan kami boleh mengubahnya. Kaedah permintaan POSTkerana di sini kami akan menghantar data. " redirect:/" bermakna selepas melaksanakan kaedah ini kita akan dialihkan ke alamat " /", i.e. kaedah akan berjalan allFilmsdan kami akan kembali ke halaman utama. Sekarang mari kita buat halaman itu sendiri 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>— borang untuk mengumpul dan menghantar data, menunjukkan siapa yang akan memprosesnya ( /edit)
  • <input>— elemen antara muka untuk interaksi pengguna (butang, medan input, dsb.)
  • <label>- label teks
Jadi, apabila anda mengklik butang, <input type="submit" value="Edit film">data dari borang akan dihantar ke pelayan (medan halimunan dengan nilai telah ditambah khas idsupaya pelayan mengetahui rekod dalam pangkalan data yang perlu dikemas kini). Dalam kaedah editFilmmereka akan diberikan kepada medan atribut yang sepadan film. Kami kemudiannya akan kembali ke halaman utama dengan senarai yang dikemas kini. Halaman penyuntingan kelihatan seperti ini: Sekarang mari kita mula menambahkan filem baharu pada senarai. Untuk melakukan ini, anda juga memerlukan borang untuk memasukkan dan menyerahkan data. Anda boleh membuat borang di halaman utama atau anda boleh membuat halaman yang berasingan, seperti editPage.jsp. Tetapi, sebaliknya, borang untuk menambah akan sama seperti untuk mengedit, i.e. 4 medan input dan butang hantar. Jadi mengapa buat halaman baharu, mari gunakan editPage.jsp. Kaedah untuk mendapatkan halaman:
@RequestMapping(value = "/add", method = RequestMethod.GET)
    public ModelAndView addPage() {
        ModelAndView modelAndView = new ModelAndView();
        modelAndView.setViewName("editPage");
        return modelAndView;
    }
Dalam kaedah ini, editPagekami juga meluluskan atribut untuk mengubahnya kemudian, tetapi di sini kami hanya menerima halaman tersebut. Dan kaedah untuk menambah:
@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;
    }
Memandangkan kami tidak melepasi atribut di sini, objek baharu akan dibuat di sini Film. Nah, pada dasarnya tidak ada yang baru di sini. Perlu diingat juga bahawa kami mempunyai kedua-dua kaedah yang tersedia di " /add". Ini mungkin disebabkan oleh fakta bahawa mereka bertindak balas terhadap pelbagai jenis permintaan. Dengan mengikuti pautan pada halaman utama kami membuat permintaan GET, yang membawa kami ke addPage. Dan apabila pada halaman penambahan kami mengklik butang untuk menghantar data, permintaan POST dibuat, dan addFilm. Untuk menambah filem baharu, kami memutuskan untuk menggunakan halaman yang sama seperti untuk menyunting. Tetapi di sana data dihantar ke alamat " /edit":
<c:url value="/edit" var="var"/>
<form action="${var}" method="POST">
    <input type="submit" value="Edit film">
</form>
Kita perlu mengubah sedikit halaman supaya ia berkelakuan berbeza untuk menambah dan mengedit. Untuk menyelesaikan isu ini, kami akan menggunakan syarat daripada pustaka teras JSTL yang sama:
<%@ 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>
Itu. kami hanya menyemak padang film.title. Jika ia kosong, maka ia adalah filem baru, kita mesti mengisi semua data untuknya dan menambahnya ke senarai. Jika medan ini tidak kosong, maka ia adalah filem daripada senarai dan anda hanya perlu menukarnya. Itu. kami mendapat dua versi halaman kami: Nah, kaedah pengawal terakhir untuk mengalih keluar filem daripada senarai:
@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;
    }
Saya rasa tidak perlu mengulas apa-apa di sini, semua ini sudah dipertimbangkan. Kami telah membuat pautan ke alamat ini di halaman utama. Nah, semuanya nampaknya sudah siap di sini, anda boleh menjalankannya semula dan melihat bagaimana semuanya berfungsi.

Repositori dan Perkhidmatan sebagai Komponen Spring

Mari kita buat satu lagi pembetulan kecil. Hakikatnya kini storan dan perkhidmatan kami hanyalah kelas, dan untuk menggunakannya, kami perlu mencipta objek kelas sendiri ( new FilmServiceImpl()). Tetapi kami mempunyai Spring berhubung atas sebab tertentu , jadi biarkan dia mengawal perkara ini sendiri. Untuk meletakkan kelas kami di bawah kawalan Spring, kami perlu menunjukkan bahawa ia adalah komponen. Untuk melakukan ini, kami menandakannya dengan anotasi khas:
@Repository
public class FilmDAOImpl implements FilmDAO {
@Service
public class FilmServiceImpl implements FilmService {
Anotasi @Repositorydan @Service, serta @Controllerberasal daripada @Component. Apakah ciri khusus dan perbezaan ketiga-tiga anotasi ini dan bagaimana ia berbeza daripada komponen mudah harus dibaca secara berasingan dalam dokumentasi atau panduan. Buat masa ini, cukup untuk mengetahui bahawa anotasi ini memberitahu Spring bahawa kelas ini masing-masing ialah repositori dan perkhidmatan. Dan sekarang kita tidak perlu lagi mencipta objek konkrit kelas ini sendiri:
private FilmService filmService = new FilmServiceImpl();
Sebaliknya, anda boleh menandakan medan dengan anotasi khas dan Spring akan memilih pelaksanaan yang sesuai:
@Autowired
private FilmService filmService;
Anotasi @Autowired(autobinding) memberitahu Spring bahawa ia harus menggali konteksnya dan menggantikan kacang yang sesuai di sini. Sangat selesa. Jika sebelum ini kita menggunakan antara muka supaya tidak bimbang tentang pelaksanaan kaedah tertentu, kini kita tidak perlu risau tentang pelaksanaan antara muka itu sendiri malah tahu namanya. Ideanya ialah tidak disyorkan untuk menggunakan auto-binding pada medan; lebih baik menggunakan pembina atau setter. Baca lebih lanjut mengenai ini dalam dokumentasi. Bagi kami, pada dasarnya, ini tidak penting, kami boleh meninggalkannya dengan selamat seperti itu. Tetapi, kerana idea itu memintanya, kami akan menghormati bahawa semuanya indah dan tanpa sebarang amaran kuning. Dalam kelas pengawal, mari buat penetap dan anotasinya:
@Controller
public class FilmController {

    private FilmService filmService;

    @Autowired
    public void setFilmService(FilmService filmService) {
        this.filmService = filmService;
    }
Dan begitu juga kita membuat setter untuk FilmDAOdalam kelas FilmServiceImpl. Bersambung... Memperkenalkan Maven, Spring, MySQL, Hibernate dan aplikasi CRUD pertama (bahagian 1) Memperkenalkan Maven, Spring, MySQL, Hibernate dan aplikasi CRUD pertama (bahagian 2) Memperkenalkan Maven, Spring, MySQL, Hibernate dan aplikasi CRUD pertama (bahagian 3) Pengenalan kepada Maven, Spring, MySQL, Hibernate dan aplikasi CRUD pertama (bahagian 4)
Komen
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION