Java web MVC – Admin-CRUD sản phẩm

 

1. Phân tích chức năng

Xây dựng chức năng:

  • Hiển thị
  • Thêm
  • Sửa
  • Xoá

dữ liệu bảng sản phẩm (products)

2. Thực thi

Đối với mối chức năng chúng ta sẽ có 1 controller riêng để đảm nhiệm

2.1. Chức năng hiển thị

B1: Tạo controller IndexProductServlet kế thừa lớp BaseAdminServlet thực hiện chức năng quản lý trang hiển thị dữ liệu các sản phẩm

package binh.dev.admin.product;
import java.io.IOException;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import java.util.List;
import binh.dev.BaseServlet;
import binh.dev.data.dao.DatabaseDao;
import binh.dev.data.model.Product;
/**
*
* @author binhdev
*/
public class IndexProductServlet extends BaseServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
List<Product> productList = DatabaseDao.getInstance().getProductDao().findAll();
request.setAttribute("productList", productList);
request.getRequestDispatcher("admin/product/index.jsp").include(request, response);
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
}
}

B2: Tạo giao diện index.jsp trong thư mục web/admin/products làm chức năng view

<%@page contentType="text/html" pageEncoding="UTF-8"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<%@ taglib uri="http://java.sun.com/jsp/jstl/fmt" prefix="fmt" %>
<%@ taglib prefix = "fmt" uri = "http://java.sun.com/jsp/jstl/fmt" %>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<meta name="description" content="">
<meta name="author" content="">
<title>SB Admin 2 - Dashboard</title>
<!-- Custom fonts for this template-->
<link href="./assets/admin/vendor/fontawesome-free/css/all.min.css" rel="stylesheet" type="text/css">
<link
href="https://fonts.googleapis.com/css?family=Nunito:200,200i,300,300i,400,400i,600,600i,700,700i,800,800i,900,900i"
rel="stylesheet">
<!-- Custom styles for this template-->
<link href="./assets/admin/css/sb-admin-2.min.css" rel="stylesheet">
</head>
<body id="page-top">
<!-- Page Wrapper -->
<div id="wrapper">
<!-- Sidebar -->
<%@include file="../inc/sidebar.jsp" %>
<!-- End of Sidebar -->
<!-- Content Wrapper -->
<div id="content-wrapper" class="d-flex flex-column">
<%@include file="../inc/header.jsp" %>
<!-- Main Content -->
<!-- Begin Page Content -->
<div class="container-fluid">
<!-- Page Heading -->
<h1 class="h3 mb-2 text-gray-800">PRODUCT</h1>
<p class="mb-4">Danh sách tất cả mặt hàng có trong bảng product</p>
<!-- DataTales Example -->
<div class="card shadow mb-4">
<div class="card-header py-3">
<h6 class="m-0 font-weight-bold text-primary">DataTables Example</h6>
</div>
<div class="card-body">
<div class="table-responsive">
<table class="table table-bordered" id="dataTable" width="100%" cellspacing="0">
<thead>
<tr>
<th>STT</th>
<th>Picture</th>
<th>Name</th>
<th>Description</th>
<th>Price</th>
<th>Quantity</th>
<th>Category</th>
<th>#</th>
<th>#</th>
</tr>
</thead>
<tbody>
<c:set var="index" value="0"/>
<c:forEach items="${productList}" var="product">
<c:set var="index" value="${index + 1}"/>
<tr>
<td>${index}</td>
<td>
<img src="${product.thumbnail}" width="50" height="50" alt="alt"/>
</td>
<td>${product.name}</td>
<td>${product.description}</td>
<td>
<fmt:setLocale value = "en_US"/>
<fmt:formatNumber type="currency" value = "${product.price}" />
</td>
<td>${product.quantity}</td>
<td>${product.category.name}</td>
<td>
<a href="EditProductServlet?productId=${product.id}">Edit</a>
</td>
<td>
<a href="DeleteProductServlet?productId=${product.id}">Delete</a>
</td>
</tr>
</c:forEach>
</tbody>
</table>
</div>
</div>
</div>
</div>
<!-- /.container-fluid -->
<!-- End of Main Content -->
<!-- Footer -->
<%@include file="../inc/footer.jsp" %>
<!-- End of Footer -->
</div>
<!-- End of Content Wrapper -->
</div>
<!-- End of Page Wrapper -->
<!-- Scroll to Top Button-->
<a class="scroll-to-top rounded" href="#page-top">
<i class="fas fa-angle-up"></i>
</a>
<!-- Bootstrap core JavaScript-->
<script src="./assets/admin/vendor/jquery/jquery.min.js"></script>
<script src="./assets/admin/vendor/bootstrap/js/bootstrap.bundle.min.js"></script>
<!-- Core plugin JavaScript-->
<script src="./assets/admin/vendor/jquery-easing/jquery.easing.min.js"></script>
<!-- Custom scripts for all pages-->
<script src="./assets/admin/js/sb-admin-2.min.js"></script>
<!-- Page level plugins -->
<script src="./assets/admin/vendor/chart.js/Chart.min.js"></script>
<!-- Page level custom scripts -->
<script src="./assets/admin/js/demo/chart-area-demo.js"></script>
<script src="./assets/admin/js/demo/chart-pie-demo.js"></script>
</body>
</html>

2.2. Chức năng thêm mới

B1: Tạo controller CreateProductServlet kế thừa lớp BaseAdminServlet thực hiện chức năng quản lý trang hiển thị dữ liệu các sản phẩm

package binh.dev.admin.product;
import java.io.IOException;
import jakarta.servlet.ServletException;
import jakarta.servlet.annotation.MultipartConfig;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.servlet.http.HttpSession;
import binh.dev.BaseServlet;
import binh.dev.data.dao.DatabaseDao;
import binh.dev.data.model.Product;
import java.util.List;
import binh.dev.data.model.Category;
import binh.dev.data.model.Gallery;
import binh.dev.util.Constants;
import binh.dev.util.UploadFileHelper;
/**
*
* @author binhdev
*/
@MultipartConfig(
fileSizeThreshold = 1024 * 1024 * 10, // 10 MB
maxFileSize = 1024 * 1024 * 50, // 50 MB
maxRequestSize = 1024 * 1024 * 100 // 100 MB
)
public class CreateProductServlet extends BaseServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
List<Category> categoryList = DatabaseDao.getInstance().getCategoryDao().findAll();
request.setAttribute("categoryList", categoryList);
request.getRequestDispatcher("admin/product/create.jsp").include(request, response);
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
HttpSession session = request.getSession();
String name = request.getParameter("name");
String description = request.getParameter("description");
double price = Double.parseDouble(request.getParameter("price"));
int quantity = 0;
if(request.getParameter("quantity") == null)
{
session.setAttribute("errorMessage", "Vui lòng điền đầy đủ thông tin");
request.getRequestDispatcher("admin/product/create.jsp").forward(request, response);
}else
{
quantity = Integer.parseInt(request.getParameter("quantity"));
}
int categoryId = Integer.parseInt(request.getParameter("categoryId"));
Product product = new Product(name, description, price, quantity, categoryId);
if (name.isEmpty() || description.isEmpty() ) {
session.setAttribute("errorMessage", "Vui lòng điền đầy đủ thông tin");
request.getRequestDispatcher("admin/product/edit.jsp").forward(request, response);
}
int productId = DatabaseDao.getInstance().getProductDao().insert(product);
createGallery(productId, request);
response.sendRedirect("IndexProductServlet");
}
private void createGallery(int productId, HttpServletRequest request) {
List<String> photos = UploadFileHelper.uploadFile(Constants.UPLOAD_DIR, request);
for (int i = 0; i < photos.size(); i++) {
Gallery g = new Gallery(Constants.UPLOAD_DIR + "/" + photos.get(i), productId);
DatabaseDao.getInstance().getGalleryDao().insert(g);
}
}
}

B2: Tạo tập tin create.jsp trong thư mục web/admin/products làm chức năng view

<%@page contentType="text/html" pageEncoding="UTF-8"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<%@ taglib uri="http://java.sun.com/jsp/jstl/fmt" prefix="fmt" %>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<meta name="description" content="">
<meta name="author" content="">
<title>CornSalad Admin - Dashboard</title>
<!-- Custom fonts for this template-->
<link href="./assets/admin/vendor/fontawesome-free/css/all.min.css" rel="stylesheet" type="text/css">
<link
href="https://fonts.googleapis.com/css?family=Nunito:200,200i,300,300i,400,400i,600,600i,700,700i,800,800i,900,900i"
rel="stylesheet">
<!-- Custom styles for this template-->
<link href="./assets/admin/css/sb-admin-2.min.css" rel="stylesheet">
<link href="./assets/admin/css/style.css" rel="stylesheet">
</head>
<body id="page-top">
<!-- Page Wrapper -->
<div id="wrapper">
<!-- Sidebar -->
<%@include file="../inc/sidebar.jsp" %>
<!-- End of Sidebar -->
<!-- Content Wrapper -->
<div id="content-wrapper" class="d-flex flex-column">
<!-- Topbar -->
<%@include file="../inc/header.jsp" %>
<!-- End of Topbar -->
<!-- Main Content -->
<div class="container-fluid">
<form action="CreateProductServlet" method="post" enctype="multipart/form-data">
<div class="form-group">
<label for="exampleInputEmail1">Picture</label>
<input type="file" name="photos" multiple="multiple" />
</div>
<div class="form-group">
<label for="exampleInputEmail1">Name</label>
<input type="text" name="name" class="form-control" placeholder="Enter name">
</div>
<div class="form-group">
<label for="exampleInputEmail1">Description</label>
<input type="text" name="description" class="form-control" placeholder="Enter Description">
</div>
<div class="form-group">
<label for="exampleInputEmail1">Category</label>
<select name="categoryId" class="form-control">
<c:forEach items="${categoryList}" var="category">
<option value="${category.id}">${category.name}</option>
</c:forEach>
</select>
</div>
<div class="form-group">
<label for="exampleInputEmail1">Price</label>
<input type="number" name="price" class="form-control" placeholder="Enter Price">
</div>
<div class="form-group">
<label for="exampleInputEmail1">Quantity</label>
<input type="number" name="quantity" class="form-control" placeholder="Enter Quantity">
</div>
<button type="submit" class="btn btn-primary">Submit</button>
</form>
</div>
<!-- End of Main Content -->
<!-- Footer -->
<%@include file="../inc/footer.jsp" %>
<!-- End of Footer -->
</div>
<!-- End of Content Wrapper -->
</div>
<!-- End of Page Wrapper -->
<!-- Scroll to Top Button-->
<a class="scroll-to-top rounded" href="#page-top">
<i class="fas fa-angle-up"></i>
</a>
<!-- Bootstrap core JavaScript-->
<script src="./assets/admin/vendor/jquery/jquery.min.js"></script>
<script src="./assets/admin/vendor/bootstrap/js/bootstrap.bundle.min.js"></script>
<!-- Core plugin JavaScript-->
<script src="./assets/admin/vendor/jquery-easing/jquery.easing.min.js"></script>
<!-- Custom scripts for all pages-->
<script src="./assets/admin/js/sb-admin-2.min.js"></script>
<!-- Page level plugins -->
<script src="./assets/admin/vendor/chart.js/Chart.min.js"></script>
<!-- Page level custom scripts -->
<script src="./assets/admin/js/demo/chart-area-demo.js"></script>
<script src="./assets/admin/js/demo/chart-pie-demo.js"></script>
</body>
</html>

2.3. Chức năng cập nhật

B1: Tạo controller EditProductServlet kế thừa lớp BaseAdminServlet thực hiện chức năng cập nhật sản phẩm

package binh.dev.admin.product;
import java.io.IOException;
import jakarta.servlet.ServletException;
import jakarta.servlet.annotation.MultipartConfig;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.servlet.http.HttpSession;
import java.util.List;
import binh.dev.BaseServlet;
import binh.dev.data.dao.Database;
import binh.dev.data.dao.DatabaseDao;
import binh.dev.data.dao.GalleryDao;
import binh.dev.data.dao.ProductDao;
import binh.dev.data.model.Category;
import binh.dev.data.model.Gallery;
import binh.dev.data.model.Product;
import binh.dev.util.Constants;
import binh.dev.util.UploadFileHelper;
/**
*
* @author binhdev
*/
@MultipartConfig(
fileSizeThreshold = 1024 * 1024 * 10, // 10 MB
maxFileSize = 1024 * 1024 * 50, // 50 MB
maxRequestSize = 1024 * 1024 * 100 // 100 MB
)
public class EditProductServlet extends BaseServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
HttpSession session = request.getSession();
int productId = Integer.parseInt(request.getParameter("productId"));
Product product = DatabaseDao.getInstance().getProductDao().find(productId);
List<Category> categoryList = DatabaseDao.getInstance().getCategoryDao().findAll();
session.setAttribute("product", product);
session.setAttribute("categoryList", categoryList);
request.getRequestDispatcher("admin/product/edit.jsp").include(request, response);
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
HttpSession session = request.getSession();
ProductDao productDao = Database.getInstance().getProductDao();
int productId = Integer.parseInt(request.getParameter("productId"));
Product product = productDao.find(productId);
String name = request.getParameter("name");
String description = request.getParameter("description");
double price = Double.parseDouble(request.getParameter("price"));
int quantity = Integer.parseInt(request.getParameter("quantity"));
int categoryId = Integer.parseInt(request.getParameter("categoryId"));
product.setName(name);
product.setDescription(description);
product.setPrice(price);
product.setQuantity(quantity);
product.setCategoryId(categoryId);
// if (name.isEmpty() || description.isEmpty() ) {
// session.setAttribute("errorMessage", "Vui lòng điền đầy đủ thông tin");
// request.getRequestDispatcher("admin/product/edit.jsp").forward(request, response);
// }
productDao.update(product);
updateGallery(product.getId(), request);
response.sendRedirect("IndexProductServlet");
}
private void updateGallery(int productId, HttpServletRequest request) {
GalleryDao galleryDao = DatabaseDao.getInstance().getGalleryDao();
galleryDao.deleteByProduct(productId);
List<String> photos = UploadFileHelper.uploadFile(Constants.UPLOAD_DIR, request);
for (int i = 0; i < photos.size(); i++) {
Gallery g = new Gallery(Constants.UPLOAD_DIR + "/" + photos.get(i), productId);
galleryDao.insert(g);
}
}
}

B2: Tạo tập tin update.jsp trong thư mục web/admin/products làm chức năng view

<%@page contentType="text/html" pageEncoding="UTF-8"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<%@ taglib uri="http://java.sun.com/jsp/jstl/fmt" prefix="fmt" %>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<meta name="description" content="">
<meta name="author" content="">
<title>CornSalad Admin - Dashboard</title>
<!-- Custom fonts for this template-->
<link href="./assets/admin/vendor/fontawesome-free/css/all.min.css" rel="stylesheet" type="text/css">
<link
href="https://fonts.googleapis.com/css?family=Nunito:200,200i,300,300i,400,400i,600,600i,700,700i,800,800i,900,900i"
rel="stylesheet">
<!-- Custom styles for this template-->
<link href="./assets/admin/css/sb-admin-2.min.css" rel="stylesheet">
<link href="./assets/admin/css/style.css" rel="stylesheet">
</head>
<body id="page-top">
<!-- Page Wrapper -->
<div id="wrapper">
<!-- Sidebar -->
<%@include file="../inc/sidebar.jsp" %>
<!-- End of Sidebar -->
<!-- Content Wrapper -->
<div id="content-wrapper" class="d-flex flex-column">
<!-- Topbar -->
<%@include file="../inc/header.jsp" %>
<!-- End of Topbar -->
<!-- Main Content -->
<div class="container-fluid">
<form action="EditProductServlet" method="post" enctype="multipart/form-data">
<input type="hidden" name="productId" value="${product.id}">
<div class="form-group">
<div class="row">
<c:forEach items="${product.galleries}" var="photo">
<div class="col-md-3">
<img class="p-thumbnail" src="${photo.url}" alt="alt"/>
</div>
</c:forEach>
</div>
</div>
<div class="form-group">
<label for="exampleInputEmail1">Picture</label>
<input type="file" name="photos" multiple="multiple" />
</div>
<div class="form-group">
<label for="exampleInputEmail1">Name</label>
<input type="text" name="name" class="form-control" placeholder="Enter name" value="${product.name}">
</div>
<div class="form-group">
<label for="exampleInputEmail1">Description</label>
<input type="text" name="description" class="form-control" placeholder="Enter Description" value="${product.description}">
</div>
<div class="form-group">
<label for="exampleInputEmail1">Category</label>
<select name="categoryId" class="form-control">
<c:forEach items="${categoryList}" var="cat">
<option <c:if test="${cat.id == category.id}">selected</c:if> value="${cat.id}">${cat.name}</option>
</c:forEach>
</select>
</div>
<div class="form-group">
<label for="exampleInputEmail1">Price</label>
<input type="number" name="price" min="0" class="form-control" placeholder="Enter Price" value="${product.price}">
</div>
<div class="form-group">
<label for="exampleInputEmail1">Quantity</label>
<input type="number" name="quantity" class="form-control" placeholder="Enter Quantity" value="${product.quantity}">
</div>
<div class="form-text text-muted" >
${errorMessage}
<c:remove var="errorMessage" scope="session" />
</div>
<button type="submit" class="btn btn-primary">Submit</button>
</form>
</div>
<!-- End of Main Content -->
<!-- Footer -->
<%@include file="../inc/footer.jsp" %>
<!-- End of Footer -->
</div>
<!-- End of Content Wrapper -->
</div>
<!-- End of Page Wrapper -->
<!-- Scroll to Top Button-->
<a class="scroll-to-top rounded" href="#page-top">
<i class="fas fa-angle-up"></i>
</a>
<!-- Bootstrap core JavaScript-->
<script src="./assets/admin/vendor/jquery/jquery.min.js"></script>
<script src="./assets/admin/vendor/bootstrap/js/bootstrap.bundle.min.js"></script>
<!-- Core plugin JavaScript-->
<script src="./assets/admin/vendor/jquery-easing/jquery.easing.min.js"></script>
<!-- Custom scripts for all pages-->
<script src="./assets/admin/js/sb-admin-2.min.js"></script>
<!-- Page level plugins -->
<script src="./assets/admin/vendor/chart.js/Chart.min.js"></script>
<!-- Page level custom scripts -->
<script src="./assets/admin/js/demo/chart-area-demo.js"></script>
<script src="./assets/admin/js/demo/chart-pie-demo.js"></script>
</body>
</html>

2.3. Chức năng xoá

B1: Tạo controller DeleteProductServlet kế thừa lớp BaseAdminServlet thực hiện chức năng xoá sản phẩm

package loi.dev.admin.product;
import java.io.IOException;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import binh.dev.BaseServlet;
import binh.dev.data.dao.DatabaseDao;
/**
*
* @author binhdev
*/
public class DeleteProductServlet extends BaseServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
int productId = Integer.parseInt(request.getParameter("productId"));
DatabaseDao.getInstance().getProductDao().delete(productId);
response.sendRedirect("IndexProductServlet");
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
}
}

B2: Với chức năng xoá thì chúng ta không cần giao diện chỉ sử lý việc xoá dữ liệu xong chuyển hướng trang lại trang index

Đăng nhận xét

0 Nhận xét