JavaRush /Java Blog /Random-ID /Pengenalan Maven, Spring, MySQL, Hibernate dan aplikasi C...
Макс
Level 41

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

Dipublikasikan di grup Random-ID
Selamat siang. Pada artikel ini saya ingin berbagi pengalaman pertama saya dengan hal-hal seperti Maven, Spring, Hibernate, MySQL dan Tomcat dalam proses pembuatan aplikasi CRUD sederhana. Ini adalah bagian kedua dari 4. Artikel ini ditujukan terutama bagi mereka yang telah menyelesaikan 30-40 level di sini, tetapi belum berani melampaui Java murni dan baru mulai (atau akan memulai) memasuki dunia terbuka dengan semua teknologi, kerangka kerja, dan kata-kata asing lainnya. Ini adalah bagian kedua dari artikel "Pengantar Maven, Spring, MySQL, Hibernate dan aplikasi CRUD pertama". Bagian pertama dapat dilihat dengan mengikuti link ini: Pengenalan Maven, Spring, MySQL, Hibernate dan Aplikasi CRUD pertama (part 1)

Isi:

Baiklah, mari kita lanjutkan, sekarang mari kita coba menyulap seluruh gudang film. Dalam aplikasi kami yang kecil dan sederhana, tentu saja, Anda dapat dengan bodohnya memasukkan semua logika ke dalam pengontrol, tetapi, seperti yang telah disebutkan, lebih baik segera mempelajari cara melakukan semuanya dengan benar. Oleh karena itu, mari buat beberapa layer. Kami akan memiliki DAO yang bertanggung jawab untuk bekerja dengan data, Layanan , di mana akan ada segala macam logika lainnya, dan Pengontrol hanya akan memproses permintaan dan memanggil metode layanan yang diperlukan.

Objek Akses Data

Objek Akses Data (DAO) adalah pola desain seperti itu. Intinya adalah membuat layer khusus yang bertanggung jawab penuh untuk mengakses data (bekerja dengan database atau mekanisme penyimpanan lainnya). Dalam paket tersebut daokita akan membuat antarmuka FilmDAOyang di dalamnya akan terdapat metode seperti menambah, menghapus, dll. Saya menyebutnya sedikit berbeda, tetapi mereka sesuai dengan operasi dasar CRUD ( C reate, Read , U pdate, D elete).

Perlu dicatat di sini bahwa selain DAO, ada juga pendekatan seperti Repositori, keduanya tampaknya sangat mirip, keduanya digunakan untuk bekerja dengan data. Saya belum mengetahui fitur apa saja yang dimiliki pendekatan ini dan apa perbedaan di antara keduanya. Oleh karena itu, saya mungkin salah di sini dan ini seharusnya disebut gudang, dan bukan Tao, atau mungkin ada di antara keduanya. Namun di sebagian besar contoh yang pernah saya lihat dan pelajari, ini disebut DAO, jadi saya mungkin akan menyebutnya sama. Pada saat yang sama, mungkin di bagian selanjutnya dalam teks ini saya akan menggunakan kata repositori. Bagaimanapun, jika saya salah dalam hal ini, mohon 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 membutuhkan implementasinya. Kami belum akan menghubungkan database, ini masih sedikit menakutkan. Untuk berlatih dan membiasakannya, mari kita simulasikan dulu penyimpanan di memori dan buat daftar dengan beberapa film. Untuk menyimpan daftar, kita akan menggunakan bukan List, tetapi Map, untuk memudahkan mengambil film tertentu berdasarkan id, tanpa menelusuri seluruh daftar. Untuk generasi idkami menggunakan AtomicInteger . Mari buat kelas FilmDAOImpl, terapkan semua metode, dan isi petanya. 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);
    }
}

Melayani

Sekarang mari tambahkan lapisan layanan. Pada prinsipnya, dalam contoh ini sangat mungkin dilakukan tanpanya, membatasi diri pada DAO; aplikasinya akan sangat sederhana dan tidak ada rencana untuk logika rumit apa pun dalam layanan. Namun tiba-tiba di kemudian hari Anda ingin menambahkan segala macam komplikasi dan hal menarik ke dalam proyek tersebut, jadi demi kelengkapan, biarkan saja. Untuk saat ini, ia hanya akan memanggil metode dari DAO. serviceMari buat antarmuka dalam paket 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 implementasinya:
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 proyek sekarang terlihat seperti ini:
Pengenalan Maven, Spring, MySQL, Hibernate dan aplikasi CRUD pertama (bagian 2) - 1

Pengontrol dan Tampilan

Sekarang mari kita bekerja pada metode pengontrol dan pengisian halaman. Saat mengisi halaman, kita memerlukan beberapa teknik. Misalnya, untuk menampilkan daftar film, kita memerlukan loop, jika, katakanlah, kita ingin mengubah beberapa prasasti, tergantung pada parameternya, kita memerlukan kondisi, dll. Format JSP (JavaServer Pages) memungkinkan Anda menggunakan sisipan kode Java yang dapat digunakan untuk mengimplementasikan semua ini. Tapi saya tidak ingin menggunakan kode java yang dicampur dengan kode HTML pada halaman tersebut. Minimal, itu akan menjadi sangat jelek. Untungnya, untuk mengatasi masalah ini ada hal yang luar biasa seperti JSTL (JavaServer Pages Standard Tag Library) atau JSP Standard Tag Library. Hal ini memungkinkan kita untuk menggunakan sejumlah tag tambahan di halaman JSP kita untuk berbagai kebutuhan. Mari kita sambungkan ke pom.xml:
<dependency>
      <groupId>jstl</groupId>
      <artifactId>jstl</artifactId>
      <version>1.2</version>
</dependency>
Sekarang mari kita lihat pengontrolnya. Pertama-tama, mari kita hapus pembuatan objek dari sana Film, ini dilakukan untuk pengujian dan kita tidak memerlukan yang lain. Mari tambahkan layanan di sana dan panggil metodenya.
public class FilmController {
    private FilmService filmService = new FilmServiceImpl();
Oleh karena itu, kami akan membuat metode untuk setiap kasus, menambah, menghapus, dll. Pertama metode untuk menampilkan halaman utama dengan daftar film:
@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;
    }
Tidak ada yang baru di sini. Kami mendapatkan daftar film dari layanan dan menambahkannya ke model. Sekarang mari kita buat halaman utama films.jspyang dikembalikan metode ini:
<%@ 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 kita lihat lebih dekat halaman ini untuk mengetahui apa itu. <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> - di sini inti JSTL terhubung, yang mencakup tag utama untuk membuat siklus, kondisi, dll .
  • <table>— tag untuk membuat tabel.
  • <tr>— baris tabel
  • <th>- tajuk kolom
  • <td>— sel tabel
Pertama, kita membuat baris header tabel dengan nama kolomnya. Kemudian <c:forEach var="film" items="${filmsList}">, dalam satu lingkaran (yang kita ambil dari inti JSTL), kita menelusuri semua elemen daftar yang diteruskan ( filmsList), untuk setiap elemen ( film) kita membuat baris baru dan menulis nilai yang sesuai ke dalam setiap sel. Ada satu hal di sini, rekaman itu sepertinya film.idperlu dipahami sebagai film.getId(), yaitu. Bidang ini tidak diakses secara langsung, tetapi pengambilnya dipanggil. Di kolom terakhir ( action) kami membuat tautan untuk menghapus dan mengedit (kami akan membuat metode yang sesuai sekarang). Nah dibawah ini link cara menambahkan film baru. Berikut tampilannya: Selanjutnya, mari kita lihat metode yang akan mengembalikan halaman edit untuk film 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 baru telah muncul di sini - ini adalah anotasi @PathVariable. Ini menunjukkan bahwa parameter ini ( int id) diperoleh dari bilah alamat. Untuk menunjukkan lokasi parameter ini di bilah alamat, konstruksi digunakan {id}(omong-omong, jika nama variabelnya sama, seperti dalam kasus ini, maka Anda tidak perlu menunjukkannya dalam tanda kurung, tetapi tulis saja @PathVariable int id). Jadi, di halaman utama kami telah membuat link untuk setiap film yang menunjukkan id:
<a href="/edit/${film.id}">edit</a>
Kemudian nilai ini ditetapkan ke parameter metode dan kemudian kita menggunakannya untuk mendapatkan film tertentu dari repositori melalui layanan dan menambahkannya ke model. Ini tadi cara untuk mendapatkan halaman editnya, sekarang kita membutuhkan cara untuk mengeditnya 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 metode ini editPagekami menambahkan atribut ke model:
modelAndView.addObject("film", filmService.getById(id));
Dan sekarang dengan bantuan anotasi @ModelAttributekita mendapatkan atribut ini dan kita dapat mengubahnya. Minta metode POSTkarena disini kami akan meneruskan datanya. " redirect:/" artinya setelah menjalankan cara ini kita akan diarahkan ke alamat " /", yaitu. caranya akan berjalan allFilmsdan kita akan kembali ke halaman utama. Sekarang mari kita membuat halamannya 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>— formulir untuk mengumpulkan dan mengirimkan data, yang menunjukkan siapa yang akan memprosesnya ( /edit)
  • <input>— elemen antarmuka untuk interaksi pengguna (tombol, kolom input, dll.)
  • <label>- label teks
Jadi, ketika Anda mengklik tombol tersebut, <input type="submit" value="Edit film">data dari formulir akan dikirim ke server (bidang tak terlihat dengan nilai telah ditambahkan secara khusus idsehingga server mengetahui catatan mana dalam database yang perlu diperbarui). Dalam metode ini editFilmmereka akan ditugaskan ke bidang atribut yang sesuai film. Kami kemudian akan kembali ke halaman utama dengan daftar yang diperbarui. Halaman pengeditan terlihat seperti ini: Sekarang mari mulai menambahkan film baru ke dalam daftar. Untuk melakukan ini, Anda juga memerlukan formulir untuk memasukkan dan mengirimkan data. Anda bisa membuat formulir di halaman utama atau Anda bisa membuat halaman tersendiri, seperti editPage.jsp. Namun sebaliknya, bentuk penambahannya akan sama persis dengan bentuk pengeditannya, yaitu. 4 kolom input dan tombol kirim. Jadi mengapa membuat halaman baru, mari gunakan editPage.jsp. Metode untuk mendapatkan halaman:
@RequestMapping(value = "/add", method = RequestMethod.GET)
    public ModelAndView addPage() {
        ModelAndView modelAndView = new ModelAndView();
        modelAndView.setViewName("editPage");
        return modelAndView;
    }
Dalam metode ini, editPagekami juga meneruskan atribut untuk mengubahnya nanti, tetapi di sini kami hanya menerima halamannya. Dan cara menambahkannya:
@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;
    }
Karena kita tidak meneruskan atribut di sini, objek baru akan dibuat di sini Film. Sebenarnya tidak ada hal baru di sini. Perlu juga dicatat bahwa kami memiliki kedua metode yang tersedia di " /add". Hal ini dimungkinkan karena mereka menanggapi berbagai jenis permintaan. Dengan mengikuti link di halaman utama kita membuat permintaan GET, yang membawa kita ke file addPage. Dan ketika pada halaman penambahan kita mengklik tombol untuk mengirim data, permintaan POST dibuat, dan file addFilm. Untuk menambahkan film baru, kami memutuskan untuk menggunakan halaman yang sama seperti untuk mengedit. Namun disana datanya dikirim ke alamat " /edit":
<c:url value="/edit" var="var"/>
<form action="${var}" method="POST">
    <input type="submit" value="Edit film">
</form>
Kita perlu sedikit mengubah halaman agar berperilaku berbeda saat menambahkan dan mengedit. Untuk mengatasi masalah ini, kami akan menggunakan ketentuan dari pustaka inti 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 memeriksa lapangan film.title. Jika kosong berarti itu film baru, kita harus mengisi semua datanya dan menambahkannya ke daftar. Jika kolom ini tidak kosong, maka itu adalah film dari daftar dan Anda hanya perlu mengubahnya. Itu. kami mendapatkan dua versi halaman kami: Nah, metode pengontrol terakhir untuk menghapus film dari daftar:
@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 kira tidak perlu berkomentar apa-apa di sini, semua sudah dipertimbangkan. Kami telah membuat tautan ke alamat ini di halaman utama. Nah, semuanya sepertinya sudah siap di sini, Anda dapat menjalankannya lagi dan melihat bagaimana semuanya bekerja.

Repositori dan Layanan sebagai Komponen Pegas

Mari kita lakukan satu koreksi kecil lagi. Faktanya adalah sekarang penyimpanan dan layanan kita hanyalah kelas, dan untuk menggunakannya kita harus membuat objek kelas sendiri ( new FilmServiceImpl()). Tapi kami menghubungkan Spring karena suatu alasan , jadi biarkan dia mengendalikan masalah ini sendiri. Untuk menempatkan kelas kita di bawah kendali Spring, kita perlu menunjukkan bahwa mereka adalah komponen. Untuk melakukan ini, kami menandainya dengan anotasi khusus:
@Repository
public class FilmDAOImpl implements FilmDAO {
@Service
public class FilmServiceImpl implements FilmService {
Anotasi @Repositorydan @Service, serta @Controllerberasal dari @Component. Apa saja fitur dan perbedaan spesifik dari ketiga anotasi ini dan perbedaannya dengan komponen sederhana sebaiknya dibaca secara terpisah di dokumentasi atau panduan. Untuk saat ini, cukup mengetahui bahwa anotasi ini memberi tahu Spring bahwa kelas-kelas ini masing-masing adalah repositori dan layanan. Dan sekarang kita tidak perlu lagi membuat objek konkrit dari kelas-kelas ini sendiri:
private FilmService filmService = new FilmServiceImpl();
Sebagai gantinya, Anda dapat menandai bidang tersebut dengan anotasi khusus dan Spring akan memilih implementasi yang sesuai:
@Autowired
private FilmService filmService;
Anotasi @Autowired(pengikatan otomatis) memberi tahu Spring bahwa ia harus menggali konteksnya dan mengganti kacang yang sesuai di sini. Sangat nyaman. Jika sebelumnya kita menggunakan antarmuka agar tidak khawatir tentang implementasi metode secara spesifik, sekarang kita bahkan tidak perlu khawatir tentang implementasi antarmuka itu sendiri dan bahkan mengetahui namanya. Idenya adalah tidak disarankan menggunakan pengikatan otomatis pada suatu bidang; lebih baik menggunakan konstruktor atau penyetel. Baca selengkapnya tentang ini di dokumentasi. Bagi kami, pada prinsipnya, ini tidak penting, kami bisa membiarkannya begitu saja. Tapi, karena idenya memintanya, kami akan menghargai bahwa semuanya indah dan tanpa peringatan kuning. Di kelas pengontrol, mari buat penyetel dan beri anotasi:
@Controller
public class FilmController {

    private FilmService filmService;

    @Autowired
    public void setFilmService(FilmService filmService) {
        this.filmService = filmService;
    }
Demikian pula kami membuat setter FilmDAOdi kelas FilmServiceImpl. Bersambung... Memperkenalkan Maven, Spring, MySQL, Hibernate dan aplikasi CRUD pertama (bagian 1) Memperkenalkan Maven, Spring, MySQL, Hibernate dan aplikasi CRUD pertama (bagian 2) Memperkenalkan Maven, Spring, MySQL, Hibernate dan aplikasi CRUD pertama (part 3) Pengenalan Maven, Spring, MySQL, Hibernate dan aplikasi CRUD pertama (part 4)
Komentar
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION