CÔNG NGHỆ THÔNG TIN >> SINH VIÊN BKAP

Truy xuất database sử dụng Spring Data JPA Phần 1

Đăng lúc: 02:14 PM - 20/03/2025 bởi Charles Chung - 409

Trong bài này tôi sẽ hướng dẫn các bạn truy xuất cơ sở dữ liệu SQL thực hiện các hành động CRUD trên một bảng sử dụng Spring Data JPA

1. Giới thiệu Spring Data JPA

Spring Data JPA là một phần của Spring Framework, cung cấp cách tiếp cận đơn giản và nhanh chóng để làm việc với các cơ sở dữ liệu quan hệ thông qua JPA (Java Persistence API). Các tính năng chính:

  • Tự động hóa các thao tác CRUD: Tạo, đọc, cập nhật và xóa dữ liệu.
  • Hỗ trợ viết truy vấn tùy chỉnh.
  • Tích hợp dễ dàng với Spring Boot.
  • Quản lý giao dịch dễ dàng.
  •  

2. Ví dụ demo

Bước 1: Tạo project Springboot session6example1 (xem bài 1), nhớ chọn thêm dependency spring data jpa

Bước 2: Tạo các package, class, view theo cấu trúc bên dưới

Bước 3: Cấu hình kết nối database SQL Server(nhớ tạo tên DB là springboot01 trong SQL Server trước khi chạy nhé) trong file application.properties như sau

spring.application.name=session6example1

spring.datasource.url= jdbc:sqlserver://localhost:1433;encrypt=true;trustServerCertificate=true;databaseName=springboot01
spring.datasource.username= sa
spring.datasource.password= 123465

spring.jpa.properties.hibernate.dialect= org.hibernate.dialect.SQLServerDialect
spring.jpa.hibernate.ddl-auto= update

Bước 4: Code lớp Product theo gợi ý sau:

package com.bkap.entities;

import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import jakarta.persistence.Table;
import jakarta.validation.constraints.Min;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.Size;

@Entity
@Table(name="Products")
public class Product {
	@Id
	@GeneratedValue(strategy = GenerationType.IDENTITY)
	@Column(name="productid")
	private long productId;
	
	@Column(name="productname", columnDefinition = "nvarchar(200)")
	@NotBlank(message = "Không để trống")
	@Size(min = 5,max = 200,message = "Độ dài từ 5-200 ký tự")
	private String productName;
	
	@Column(name="brand", columnDefinition = "nvarchar(100)")
	@NotBlank(message = "Không để trống")
	private String brand;
	
	@Column(name="price")
	@Min(value = 0,message = "Giá phải >=0")
	private int price;
	
	@Column(name="description", columnDefinition = "nvarchar(max)")
	private String description;
	
	@Column(name="active")
	private boolean active;
	
	public Product() {
		// TODO Auto-generated constructor stub
	}

	public Product(long productId, String productName,String brand, int price, String description, boolean active) {
		super();
		this.productId = productId;
		this.productName = productName;
		this.brand=brand;
		this.price = price;
		this.description = description;
		this.active = active;
	}

	public String getBrand() {
		return brand;
	}

	public void setBrand(String brand) {
		this.brand = brand;
	}

	public long getProductId() {
		return productId;
	}

	public void setProductId(long productId) {
		this.productId = productId;
	}

	public String getProductName() {
		return productName;
	}

	public void setProductName(String productName) {
		this.productName = productName;
	}

	public int getPrice() {
		return price;
	}

	public void setPrice(int price) {
		this.price = price;
	}

	public String getDescription() {
		return description;
	}

	public void setDescription(String description) {
		this.description = description;
	}

	public boolean isActive() {
		return active;
	}

	public void setActive(boolean active) {
		this.active = active;
	}
	
}

Bước 5: Code lớp ProductRepository

public interface ProductRepository extends JpaRepository<Product, Long> {
	@Query("SELECT p FROM Product p WHERE productName LIKE %:name%")
	List<Product> findByNameContain(@Param("name") String name);
	List<Product> findByActive(boolean active);
}

Bước 6: Code lớp ProductService

package com.bkap.services;

import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.bkap.entities.Product;
import com.bkap.repositories.ProductRepository;

@Service
public class ProductService {
	@Autowired
	private ProductRepository repo;
	
	public List<Product> getAll(){
		return repo.findAll();
	}
	public void save(Product product) {
		repo.save(product);
	}
	public Product getById(long id) {
		return repo.findById(id).get();
	}
	public void delete(long id) {
		repo.deleteById(id);
	}
	public List<Product> searchName(String name){
		return repo.findByNameContain(name);
	}
	public List<Product> getByActive(boolean active){
		return repo.findByActive(active);
	}
}

Bước 7: Code lớp ProductController

package com.bkap.controllers;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;

import com.bkap.entities.Product;
import com.bkap.services.ProductService;

import jakarta.validation.Valid;

@Controller
public class ProductController {
	@Autowired
	ProductService productService;
	
	@GetMapping({"/","/san-pham"})
	public String index(Model model) {
		model.addAttribute("products",productService.getAll());
		return "index";
	}
	@GetMapping("/san-pham/tim-kiem")
	public String search(String searchname, int active, Model model) {
		model.addAttribute("active",active);
		if(searchname.isEmpty())
		{
			model.addAttribute("products",productService.getByActive(active==1?true:false));
			return "index";
		}else
		{
			model.addAttribute("products",productService.searchName(searchname));
			return "index";
		}
	}
	@GetMapping("/san-pham/them-moi")
	public String create(Model model) {
		model.addAttribute("product",new Product());
		return "create";
	}
	
	@PostMapping("/san-pham/ghi")
	public String create(@Valid Product product, BindingResult result, Model model) {
		if(result.hasErrors()) {
			model.addAttribute("product",product);
			return "create";
		}
		productService.save(product);
		return "redirect:/san-pham";
	}
	
	@GetMapping("/san-pham/xoa/{id}")
	public String delete(@PathVariable int id) {
		productService.delete(id);
		return "redirect:/san-pham";
	}

	@GetMapping("/san-pham/chi-tiet/{id}")
	public String detail(@PathVariable int id,Model model) {
		model.addAttribute("product",productService.getById(id));
		return "detail";
	}
	
	@GetMapping("/san-pham/sua/{id}")
	public String edit(@PathVariable int id, Model model) {
		model.addAttribute("product",productService.getById(id));
		return "edit";
	}
	
	@PostMapping("/san-pham/cap-nhat")
	public String edit(@Valid Product product, BindingResult result, Model model) {
		if(result.hasErrors()) {
			model.addAttribute("product",product);
			return "edit";
		}
		productService.save(product);
		return "redirect:/san-pham";
	}
}

Bước 8: Code cho view index.html

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Danh sách sản phẩm</title>
<link rel="stylesheet"
	href="https://cdn.jsdelivr.net/npm/bootstrap@4.6.2/dist/css/bootstrap.min.css" />
</head>
<body>
	<div class="container">
		<h2 class="mt-2">DANH SÁCH SẢN PHẨM</h2>
		<p><a th:href="@{/san-pham/them-moi}" class="btn btn-primary">Thêm mới</a></p>
		<div>
			<form th:action="@{/san-pham/tim-kiem}" method="get">
				<span>Nhập tên </span><input type="text" name="searchname"/> 
				<input th:if="${active}" type="radio" name="active" checked value="1"/> 
				<input th:unless="${active}" type="radio" name="active" value="1"/> Còn hàng 
				<input th:if="${active}" type="radio" name="active" value="0"/> 
				<input th:unless="${active}" type="radio" checked name="active" value="0"/> Hết hàng 
				<button>Tìm</button>
			</form>
		</div>
		<table class="table table-bordered mt-2">
			<tr>
				<th>Mã số</th>
				<th>Tên</th>
				<th>Giá</th>
				<th>Hãng</th>
				<th>Mô tả</th>
				<th>Tình trạng</th>
				<th></th>
			</tr>
			<tr th:each="p:${products}" th:object="${p}">
				<td th:text="*{productId}"></td>
				<td th:text="*{productName}"></td>
				<td th:text="*{price}"></td>
				<td th:text="*{brand}"></td>
				<td th:text="*{description}"></td>
				<td th:text="*{active?'Còn hàng':'Hết hàng'}"></td>
				<td>
					<a th:href="@{/san-pham/xoa/{id}(id=*{productId})}" onclick="return confirm('Bán có muốn xóa không?')" class="btn btn-danger">Xóa</a>
					<a th:href="@{/san-pham/sua/{id}(id=*{productId})}" class="btn btn-info">Sửa</a>
					<a th:href="@{/san-pham/chi-tiet/{id}(id=*{productId})}" class="btn btn-success">Chi tiết</a>
				</td>
			</tr>
		</table>
	</div>
</body>
</html>

Bước 9: Code cho view create.html

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>Thêm mới sản phẩm</title>
    <link href="https://maxcdn.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css" rel="stylesheet">
</head>
<body>
    <div class="container mt-5">
        <h1>Thêm mới sản phẩm</h1>
        
        <form th:action="@{/san-pham/ghi}" th:object="${product}" method="post">
            
            <!-- Product Name -->
            <div class="form-group">
                <label for="productName">Tên sản phẩm</label>
                <input type="text" class="form-control" id="productName" th:field="*{productName}" />
                <div th:if="${#fields.hasErrors('productName')}" class="text-danger">
                    <ul th:errors="*{productName}"></ul>
                </div>
            </div>
            
            <!-- Price -->
            <div class="form-group">
                <label for="price">Giá</label>
                <input type="number" class="form-control" id="price" th:field="*{price}" step="0.01" />
                <div th:if="${#fields.hasErrors('price')}" class="text-danger">
                    <ul th:errors="*{price}"></ul>
                </div>
            </div>
            
            <!-- Brand -->
            <div class="form-group">
                <label for="brand">Thương hiệu</label>
                <input type="text" class="form-control" id="brand" th:field="*{brand}" />
                <div th:if="${#fields.hasErrors('brand')}" class="text-danger">
                    <ul th:errors="*{brand}"></ul>
                </div>
            </div>
            
            <!-- Description -->
            <div class="form-group">
                <label for="description">Mô tả</label>
                <textarea class="form-control" id="description" th:field="*{description}"></textarea>
                <div th:if="${#fields.hasErrors('description')}" class="text-danger">
                    <ul th:errors="*{description}"></ul>
                </div>
            </div>
            
            <!-- Active -->
            <div class="form-group form-check">
                <input type="checkbox" class="form-check-input" id="active" th:field="*{active}" />
                <label class="form-check-label" for="active">Còn hàng</label>
            </div>
            
            <button type="submit" class="btn btn-primary"> Lưu </button>
        </form>
    </div>

</body>
</html>

Bước 10: Code cho view edit.html

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>Sửa mới sản phẩm</title>
    <link href="https://maxcdn.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css" rel="stylesheet">
</head>
<body>
    <div class="container mt-5">
        <h1>Sửa mới sản phẩm</h1>
        
        <form th:action="@{/san-pham/cap-nhat}" th:object="${product}" method="post">
            <input type="hidden" th:field="*{productId}"/>
            <!-- Product Name -->
            <div class="form-group">
                <label for="productName">Tên sản phẩm</label>
                <input type="text" class="form-control" id="productName" th:field="*{productName}" />
                <div th:if="${#fields.hasErrors('productName')}" class="text-danger">
                    <ul th:errors="*{productName}"></ul>
                </div>
            </div>
            
            <!-- Price -->
            <div class="form-group">
                <label for="price">Giá</label>
                <input type="number" class="form-control" id="price" th:field="*{price}" step="0.01" />
                <div th:if="${#fields.hasErrors('price')}" class="text-danger">
                    <ul th:errors="*{price}"></ul>
                </div>
            </div>
            
            <!-- Brand -->
            <div class="form-group">
                <label for="brand">Thương hiệu</label>
                <input type="text" class="form-control" id="brand" th:field="*{brand}" />
                <div th:if="${#fields.hasErrors('brand')}" class="text-danger">
                    <ul th:errors="*{brand}"></ul>
                </div>
            </div>
            
            <!-- Description -->
            <div class="form-group">
                <label for="description">Mô tả</label>
                <textarea class="form-control" id="description" th:field="*{description}"></textarea>
                <div th:if="${#fields.hasErrors('description')}" class="text-danger">
                    <ul th:errors="*{description}"></ul>
                </div>
            </div>
            
            <!-- Active -->
            <div class="form-group form-check">
                <input type="checkbox" class="form-check-input" id="active" th:field="*{active}" />
                <label class="form-check-label" for="active">Còn hàng</label>
            </div>
            
            <button type="submit" class="btn btn-primary"> Cập nhật </button>
        </form>
    </div>

</body>
</html>

Bước 11: Code cho view detail.html

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Chi tiết sản phẩm</title>
<link rel="stylesheet"
	href="https://cdn.jsdelivr.net/npm/bootstrap@4.6.2/dist/css/bootstrap.min.css" />
</head>
<body>
	<div class="container">
		<h2 class="mt-2">Chi tiết sản phẩm</h2>
		<div th:object="${product}">
			<p>
				Tên sản phẩm: <span th:text="*{productName}"></span>
			</p>
		</div>
	</div>

</body>
</html>

Bước 12: Chạy và xem kết quả

Source code tải tại đây

3. Video Demo (Quay trong buổi dạy lớp C2308G)

 

thay lời cảm ơn!

QUẢNG CÁO - TIẾP THỊ