Lập trình Spring Boot: Xây dựng Dự án BookStore bằng Spring JDBC, Thymeleaf - P3

Trong bài viết tiếp theo này, các bạn học java web sẽ lập trình chức năng quản lý sách trong dự án BookStore sử dụng spring jdbc, thymeleaf trong lập trình Spring Boot bằng công cụ Intellij IDEA.

Ở phần 2 của seri bài viết này, các bạn đã xây dựng được chức năng quản lý thông tin chủ đề sách sử dụng Spring Data JDBC và Thymeleaf trong lập trình Spring Boot. Trong bài viết này Stanford sẽ tiếp tục hướng dẫn các bạn học lập trình java web xây dựng các chức năng quản lý thông tin sách, hiển thị ảnh và xử lý tìm kiếm, upload ảnh sách trong Spring Boot.


Lập trình các lớp xử lý dữ liệu sách với MySQL

Đầu tiên bạn cần tạo ra một lớp giao diện có tên SachDao kế thừa từ lớp IHanhDong như sau:

package vn.com.stanford.stanford_workingjdbcspringboot.model;
 
import vn.com.stanford.stanford_workingjdbcspringboot.entities.Sach;
import java.util.List;
public interface SachDao extends IHanhDong<Sach, String>{
    List<Sach> timKiemSach(String tuKhoa, String maCD);
}
Tiếp theo xây dựng các hàm xử lý với bảng thông tin sách trong lớp có tên SachImpl được triển khai từ lớp giao diện SachDao như sau:

 

package vn.com.stanford.stanford_workingjdbcspringboot.model;
 
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.EmptyResultDataAccessException;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Repository;
import vn.com.stanford.stanford_workingjdbcspringboot.entities.Sach;
import vn.com.stanford.stanford_workingjdbcspringboot.entities.SachMapper;
 
import java.util.List;
 
@Repository("sachDao")
public class SachImpl implements SachDao{
    @Autowired
    private JdbcTemplate jdbcTemplate;
 
    @Override
    public List<Sach> timKiemSach(String tuKhoa, String maCD)
    {
        String sql = "SELECT MaSach, TenSach, MoTa, AnhSach, GiaSach, TacGia, NgayTao, NgayCapNhat, MaChuDe FROM Sach where 1=1";
 
        if(tuKhoa!= null && !tuKhoa.isEmpty())
        {
            sql += " AND (MaSach = '" + tuKhoa + "' OR TenSach like '%" + tuKhoa + "%' OR TacGia like '%" + tuKhoa + "%')";
        }
 
        if(maCD!= null && !maCD.isEmpty())
        {
            sql += " AND MaChuDe = '" + maCD + "'";
        }
 
        return jdbcTemplate.query(sql, new SachMapper());
    }
 
    @Override
    public List<Sach> getList() {
        String sql = "SELECT MaSach, TenSach, MoTa, AnhSach, GiaSach, TacGia, NgayTao, NgayCapNhat, MaChuDe FROM Sach";
        return jdbcTemplate.query(sql, new SachMapper());
    }
 
    @Override
    public Sach getById(String maSach) {
        try {
            String sql = "SELECT * FROM Sach WHERE MaSach = ?";
            return jdbcTemplate.queryForObject(sql, new SachMapper(), maSach);
        } catch (EmptyResultDataAccessException e) {
            System.err.println("Không tìm thấy thông tin chủ đề. Chi tiết: " + e.getMessage());
            return null;
        }
    }
 
    @Override
    public boolean add(Sach obj) {
        String sql = "INSERT INTO Sach (MaSach, TenSach, MoTa, AnhSach, GiaSach, TacGia, NgayTao, NgayCapNhat, MaChuDe) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)";
        jdbcTemplate.update(sql, obj.getMaSach(), obj.getTenSach(), obj.getMoTa(), obj.getAnhSach(), obj.getGiaSach(), obj.getTacGia(), obj.getNgayTao(), obj.getNgayCapNhat(), obj.getMaChuDe());
 
        return true;
    }
 
    @Override
    public boolean update(Sach obj) {
        String sql = "UPDATE Sach SET TenSach= ?, MoTa= ?, AnhSach= ?, GiaSach= ?, TacGia= ?, NgayTao= ?, NgayCapNhat= ?, MaChuDe= ? WHERE MaSach = ? ";
        jdbcTemplate.update(sql, obj.getTenSach(), obj.getMoTa(), obj.getAnhSach(), obj.getGiaSach(), obj.getTacGia(), obj.getNgayTao(), obj.getNgayCapNhat(), obj.getMaChuDe(), obj.getMaSach());
 
        return true;
    }
 
    @Override
    public boolean delete(String id) {
 
        String sql = "DELETE FROM Sach WHERE MaSach = '" + id + "'";
        jdbcTemplate.update(sql);
 
        return true;
    }
}

Lập trình lớp xử lý nghiệp vụ với sách

Trong packgage vn.com.stanford.stanford_workingjdbcspringboot.controller, bạn cần tạo một lớp SachController trong đó có các hàm xử lý bao gồm như sau:

- Hàm hiển thị tìm kiếm và danh sách thông tin sách:

      @Autowired
    SachDao sachDao;
    @Autowired
    ChuDeDao chuDeDao;
 
    @RequestMapping(value="/admin/sach/danhsach")
    public String hienThiDanhSachSach(Model model, SachModel objSach)
    {
        //Lấy danh sách từ db
        List<Sach> lstSach = sachDao.timKiemSach(objSach.getTuKhoa(), objSach.getMaChuDe());
 
        //Đưa để hiển thị ra view
        model.addAttribute("lstSach", lstSach);
 
        model.addAttribute("sach", objSach);
 
       //model.addAttribute("fileUpload", fileUploadPath);
        return "admin/QuanLySach";
    }
- Hàm hiển thị giao diện thêm mới, thông tin chi tiết trước khi sửa thông tin sách:

 

@RequestMapping(value="/admin/sach/them")
    public String hienThiThemMoiSach(Model model)
    {
        model.addAttribute("sach", new Sach());
        return "admin/SachAdd";
    }
 
    @RequestMapping(value="/admin/sach/sua/{id}")
    public String suaThongTinSach(@PathVariable("id") String id, Model model)
    {
        Sach objSach = sachDao.getById(id);
 
        model.addAttribute("sach", objSach);
        return "admin/SachAdd";
    }
- Hàm xử lý thêm mới hoặc cập nhật thông tin sách:
@RequestMapping(value="/admin/sach/themMoiSach", method = RequestMethod.POST)
    public String thucHienThemSach(@ModelAttribute("sach") Sach objSach, @RequestParam("fUpload") MultipartFile fUpload, HttpServletRequest request, Model model)
    {
 
            System.out.println("Mã sách: " + objSach.getMaSach());
            System.out.println("Tên sách: " + objSach.getTenSach());
            System.out.println("Mã chủ đề: " + objSach.getMaChuDe());
 
            boolean isInsert = true;
 
            //Nếu đã sách đã có thì là TH sửa
            Sach objSachOld = sachDao.getById(objSach.getMaSach());
            if (objSachOld != null) {
                isInsert = false;
 
                objSach.setAnhSach(objSachOld.getAnhSach());
            }
 
            //Xử lý upload file trong Spring MVC
            String fileName = "";
            if(fUpload != null)
            {
                //Lấy tên file
                fileName = fUpload.getOriginalFilename();
 
                try {
                    //Tạo file
                    File file = new File(fileUploadPath, fileName);
 
                    //Ghi ra file
                    fUpload.transferTo(file);
 
                    //Gán ảnh mới vào thuộc tính
                    objSach.setAnhSach(fileName);
                    model.addAttribute("fileName",fileName);
                }
                catch (IOException ex)
                {
                    System.err.println("Có lỗi xảy ra trong quá trình upload file. Chi tiết: " + ex.getMessage());
                }
            }
 
            //Thực hiện thêm mới sách vào db
            boolean ketQua = false;
            if (isInsert) {
                objSach.setNgayTao(new Date());
                objSach.setNgayCapNhat(new Date());
                objSach.setDaDuyet(false);
                ketQua = sachDao.add(objSach);
            } else {
                objSach.setNgayCapNhat(new Date());
 
                ketQua = sachDao.update(objSach);
            }
 
            if (ketQua) {
                return "redirect:/admin/sach/danhsach";
            }
             
        return "admin/SachAdd";
    }
- Hàm xử lý xóa thông tin sách và hiển thị chủ đề sách cho phép người dùng có thể chọn chủ đề theo dạng dropdownlist khi tìm kiếm hoặc thêm mới, sửa thông tin sách như sau:
@RequestMapping(value="/admin/sach/xoa/{id}")
    public String xoaThongTinSach(@PathVariable("id") String id, Model model)
    {
        Sach objSach = sachDao.getById(id);
        if(objSach != null)
        {
            sachDao.delete(id);
            return "redirect:/admin/sach/danhsach";
        }
        return "admin/QuanLySach";
    }
 
    @ModelAttribute("chuDeList")
    public List<ChuDe> danhSachChuDe()
    {
        //Lấy danh sách chủ đề
        List<ChuDe> lstChuDe = chuDeDao.getList();
        return lstChuDe;
    }

Thiết kế giao diện tìm kiếm và hiển thị danh sách thông tin sách


Trong phần này, các bạn tiếp tục sử dụng kiến thức về thymeleaf để thiết kế giao diện bằng việc tạo ra một trang web có tên QuanLySach.html với trình tự như sau:

- Khai báo sử dụng thymeleaf và thư viện css, js của bootstrap trên trang QuanLySach như sau:


- Xử lý phần giao diện tìm kiếm thông tin sách:
<c:url value="/admin/sach/danhsach" var="timSach"/>
<div style="width:100%; text-align:center;margin-bottom:5px;">
<h1>Quản lý thông tin sách</h1>
</div>
<form method="post" th:action="@{/admin/sach/danhsach}" th:object="${sach}">
    <fieldset>
        <legend>Nhập thông tin tìm kiếm</legend>
        <div class="row">
            <div class="col-md-1">Từ khóa:</div>
            <div class="col-md-4">
                <input th:field="*{tuKhoa}" th:class="form-control"/>
            </div>
            <div class="col-md-1">
                Chủ đề:
            </div>
            <div class="col-md-3">
                <select th:field="*{maChuDe}" th:class="form-control">
                    <option value="" label="Chọn chủ đề"/>
                    <th:block th:each="c : ${chuDeList}">
                        <option th:value="${c.maChuDe}">[[${c.tenChuDe}]]</option>
                    </th:block>
                </select>
            </div>
            <div class="col-md-2">
                <button type="submit" class="btn btn-primary">Tìm kiếm</button>
                [[${fileUpload}]]
            </div>
        </div>
    </fieldset>
</form>
- Xử lý giao diện hiển thị danh sách thông tin sách như sau:
<div class="row">
    <div class="col-md-12">
        <div style="width:100%; text-align:right;margin-bottom:5px;">
            <a th:href="@{/admin/sach/them}" class="btn btn-primary">Thêm mới</a>
        </div>
        <div class="tile">
            <div class="tile-body">
                <table id="sampleTable" class="table table-bordered table-striped"
                       style="width: 100%; border-collapse: collapse;">
                    <thead>
                    <tr>
                        <th>Ảnh sách</th>
                        <th>Mã sách</th>
                        <th>Tên sách</th>
                        <th>Mô tả</th>
                        <th>Tác giả</th>
                        <th>Giá sách</th>
                        <th>Chủ đề</th>
                        <th style="width:150px;"></th>
                    </tr>
                    </thead>
                    <tbody>
                    <tr th:each="s : ${lstSach}">
 
                        <td><img th:src="@{'/images/' + ${s.anhSach}}" width="100" height="120"></td>
                        <td>[[${s.maSach}]]</td>
                        <td>[[${s.tenSach}]]</td>
                        <td>[[${s.moTa}]]</td>
                        <td>[[${s.tacGia}]]</td>
                        <td>[[${s.giaSach}]]</td>
                        <td>[[${s.maChuDe}]]</td>
                        <td>
                            <a class="btn btn-xs btn-info" th:href="@{'/admin/sach/sua/' + ${s.maSach}}">Sửa</a>
                              
                            <a onclick="return confirm('Bạn có chắc chắn muốn xóa thông tin này ?');" class="btn btn-xs btn-danger" th:href="@{'/admin/sach/xoa/' + ${s.maSach}}">Xóa</a>
                        </td>
                    </tr>
                    </tbody>
                </table>
            </div>
        </div>
    </div>
</div>
Sau đó khi chạy chương trình sẽ hiển thị giao diện như hình sau đây là thành công:

Thiết kế giao diện thêm mới, sửa thông tin sách

Trong giao diện này ngoài việc khai báo sử dụng thư viện css, js của bootstrap giống như trên trang danh sách, các bạn học lập trình java web chú ý cần khai báo đầy đủ các thuộc tính của thẻ form, trong đó thuộc tính enctype="multipart/form-data" cho phép gửi đính kèm file lên hệ thống. Bạn tạo ra một trang web có tên SachAdd.html với nội dung chi tiết như sau:

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>Thêm mới thông tin sách</title>
    <link rel="stylesheet" type="text/css" th:href="@{/css/style.css}"/>
    <link rel="stylesheet" type="text/css" th:href="@{/css/bootstrap.min.css}"/>
    <script type="text/javascript" th:src="@{/js/jquery-3.4.1.min.js}"></script>
    <script type="text/javascript" th:src="@{/js/bootstrap.min.js}"></script>
</head>
<body>
<div class="row">
    <div class="col-md-12">
        <div class="tile">
            <div class="tile-body">
                <form action="#" method="post" th:action="@{/admin/sach/themMoiSach}" th:object="${sach}" enctype="multipart/form-data">
                    <fieldset>
                        <legend>Nhập thông tin sách</legend>
                        <div class="container-fluid">
                            <div class="row">
                                <label class="col-md-2">
                                    Mã sách:
                                </label>
                                <div class="col-md-4">
                                    <input type="text" class="form-control" th:field="*{maSach}"/>
                                    <td th:if="${#fields.hasErrors('maSach')}" th:errors="*{maSach}">Bạn phải nhập mã sách</td>
                                </div>
                            </div>
                            <div class="row">
                                <label class="col-md-2">
                                    Tên sách:
                                </label>
                                <div class="col-md-10">
                                    <input type="text" class="form-control" th:field="*{tenSach}"/>
                                    <td th:if="${#fields.hasErrors('tenSach')}" th:errors="*{tenSach}">Bạn phải nhập tên sách</td>
                                </div>
                            </div>
                            <div class="row">
                                <label class="col-md-2">
                                    Mô tả:
                                </label>
                                <div class="col-md-10">
                                    <input type="text" class="form-control" th:field="*{moTa}"/>
                                </div>
                            </div>
                            <div class="row">
                                <label class="col-md-2">
                                    Ảnh sách:
                                </label>
                                <div class="col-md-10">
                                    <input type="file" name="fUpload" class="form-control"/>
                                </div>
                            </div>
                            <div class="row">
                                <label class="col-md-2">
                                    Tác giả:
                                </label>
                                <div class="col-md-10">
                                    <input type="text" class="form-control" th:field="*{tacGia}"/>
                                </div>
                            </div>
                            <div class="row">
                                <label class="col-md-2">
                                    Giá sách:
                                </label>
                                <div class="col-md-10">
                                    <input type="text" class="form-control" th:field="*{giaSach}"/>
                                </div>
                            </div>
                            <div th:class="row">
                                <div class="col-md-2">
                                    Chủ đề:
                                </div>
                                <div class="col-md-10">
                                    <select th:field="*{maChuDe}" th:class="form-control">
                                        <option value="" label="Chọn chủ đề"/>
                                        <th:block th:each="c : ${chuDeList}">
                                            <option th:value="${c.maChuDe}">[[${c.tenChuDe}]]</option>
                                        </th:block>
                                    </select>
                                </div>
                            </div>
                            <div class="row">
                                <div class="col-md-2"></div>
                                <div class="col-md-4">
                                    <input type="submit" class="btn btn-primary" name="btnCapNhat" value="Cập nhật"/>
                                      
                                    <a th:href="@{/admin/sach/danhsach}" class="btn btn-primary">Trở về</a>
                                </div>
                            </div>
                            <div class="row">
                                <div class="col-md-2"></div>
                                <div class="col-md-10">
                                    <span class="text-warning">[[${message}]]</span><br>
 
                                </div>
                            </div>
                        </div>
                    </fieldset>
                </form>
            </div>
        </div>
    </div>
</div>
</body>
</html>
Sau đó chạy chương trình giao diện thêm mới, sửa thông tin sách sẽ hiển thị như hình dưới đây:

 


Hình 1: Giao diện thêm mới thông tin sách


Hình 2: Giao diện sửa thông tin sách

Như vậy qua bài viết này các bạn học lập trình java web đã được hướng dẫn lập trình chi tiết các chức năng bao gồm tìm kiếm và hiển thị danh sách thông tin sách, chức năng thêm mới, sửa thông tin sách với tính năng upload ảnh và xóa thông tin sách,...bằng lập trình Spring Boot trên công cụ Intellij IDEA. Hy vọng các bạn sẽ áp dụng thành công theo hướng dẫn này nếu có khó khăn hãy liên lạc với Stanford để được hỗ trợ. Chúc các bạn thành công !

Bên cạnh đó nếu bạn đang muốn được đào tạo bài bản từ cơ bản đến nâng cao có thể tham gia ngay khóa học lập trình java fullstack cùng chuyên gia giàu kinh nghiệm Stanford tại đây: http://bit.ly/2SLPYFF và nhận ưu đãi hấp dẫn của Stanford trong thời gian này. Bạn có thể gọi theo hotline: 0963 723 236 - 0866 586 366 để được gọi lại tư vấn trực tiếp nhé.

=============================
☎ STANFORD – ĐÀO TẠO VÀ PHÁT TRIỂN CÔNG NGHỆ
Hotline: 0963 723 236 - 0866 586 366
Website: https://stanford.com.vn
Facebook: http://bit.ly/2FN0TYb
Youtube: http://bit.ly/2TkKT7I

Tags: spring data jdbc, thymeleaf, lập trình spring boot