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 - 409Trong 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!
Các bài cũ hơn
- Validation Form-Upload File Image-Nhúng CKEditor trong SpringBoot (10:28 AM - 19/03/2025)
- Tìm hiểu về Form trong Thymeleaf (10:30 PM - 18/03/2025)
- Giới thiệu và cài đặt Thymeleaf trong Eclipse (09:58 PM - 16/03/2025)
- Tìm hiểu về Spring Boot MVC (10:01 AM - 15/03/2025)
- Hướng dẫn cài đặt môi trường phát triển ứng dụng web với Spring Boot 3 sử dụng Eclipse trên Windows (11:27 AM - 13/03/2025)