Hướng dẫn sử dụng Spring Boot, JPA và Spring Transaction
1. Mục tiêu của bài viết
Tài liệu được viết dựa trên:
- Spring Boot 2.x
- Eclipse 4.7 (Oxygen)
Trong bài viết này tôi sẽ hướng dẫn bạn tạo một dự án Spring Boot và làm việc với một cơ sở dữ liệu (Oracle, MySQL, SQL Server, Postgres,..) sử dụng JPA & Spring Transaction. Các vấn đề sẽ được thảo luận trong bài viết này bao gồm:
- Khai báo các thư viện cần thiết để có thể làm việc với cơ sở dữ liệu.
- Cấu hình Spring Boot để có thể kết nối tới cơ sở dữ liệu.
- Thao tác với cơ sở dữ liệu sử dụng EntityManager của JPA.
- Sử dụng Spring Transaction và giải thích nguyên tắc hoạt động của Spring Transaction.
Một ví dụ mô phỏng việc chuyển tiền từ tài khoản A tới tài khoản B.
2. Chuẩn bị database
MySQL
-- Create table
create table BANK_ACCOUNT
(
ID BIGINT not null,
FULL_NAME VARCHAR(128) not null,
BALANCE DOUBLE not null
) ;
--
alter table BANK_ACCOUNT
add constraint BANK_ACCOUNT_PK primary key (ID);
Insert into Bank_Account(ID, Full_Name, Balance) values (1, 'Tom', 1000);
Insert into Bank_Account(ID, Full_Name, Balance) values (2, 'Jerry', 2000);
Insert into Bank_Account(ID, Full_Name, Balance) values (3, 'Donald', 3000);
commit;
SQL Server
-- Create table
create table BANK_ACCOUNT
(
ID BIGINT not null,
FULL_NAME VARCHAR(128) not null,
BALANCE DOUBLE PRECISION not null
) ;
--
alter table BANK_ACCOUNT
add constraint BANK_ACCOUNT_PK primary key (ID);
Insert into Bank_Account(ID, Full_Name, Balance) values (1, 'Tom', 1000);
Insert into Bank_Account(ID, Full_Name, Balance) values (2, 'Jerry', 2000);
Insert into Bank_Account(ID, Full_Name, Balance) values (3, 'Donald', 3000);
Oracle
-- Create table
create table BANK_ACCOUNT
(
ID NUMBER(19) not null,
FULL_NAME VARCHAR2(128) not null,
BALANCE NUMBER not null
) ;
--
alter table BANK_ACCOUNT
add constraint BANK_ACCOUNT_PK primary key (ID);
Insert into Bank_Account(ID, Full_Name, Balance) values (1, 'Tom', 1000);
Insert into Bank_Account(ID, Full_Name, Balance) values (2, 'Jerry', 2000);
Insert into Bank_Account(ID, Full_Name, Balance) values (3, 'Donald', 3000);
commit;
PostGres
Create table Bank_Account (
ID Bigint not null,
Full_Name Varchar(128) not null,
Balance real not null,
CONSTRAINT Bank_Account_pk PRIMARY KEY (ID)
);
Insert into Bank_Account(ID, Full_Name, Balance) values (1, 'Tom', 1000);
Insert into Bank_Account(ID, Full_Name, Balance) values (2, 'Jerry', 2000);
Insert into Bank_Account(ID, Full_Name, Balance) values (3, 'Donald', 3000);
3. Tạo dự án Spring Boot
Trên Eclipse tạo một dự án Spring Boot.
Nhập vào:
- Name: SpringBootJPA
- Group: org.o7planning
- Artifact: SpringBootJPA
- Description: Spring Boot + JPA + Spring Transaction
- Package: org.o7planning.springbootjpa
Lựa chọn các công nghệ, và thư viện sẽ sử dụng:
- JPA
- MySQL
- PostgrsSQL
- SQL Server
- Web
- Thymeleaf
4. Cấu hình pom.xml
Nếu bạn làm việc với cơ sở dữ liệu Oracle, bạn cần khai báo các thư viện sau trên pom.xml:
* Oracle *
<dependencies>
.....
<dependency>
<groupId>com.oracle</groupId>
<artifactId>ojdbc6</artifactId>
<version>11.2.0.3</version>
</dependency>
.....
</dependencies>
<repositories>
....
<!-- Repository for ORACLE JDBC Driver -->
<repository>
<id>codelds</id>
<url>https://code.lds.org/nexus/content/groups/main-repo</url>
</repository>
.....
</repositories>
Nếu bạn kết nối vào cơ sở dữ liệu SQL Service, bạn có thể sử dụng một trong 2 thư viện JTDS hoặc Mssql-Jdbc:
* SQL Server *
<dependencies>
.....
<dependency>
<groupId>com.microsoft.sqlserver</groupId>
<artifactId>mssql-jdbc</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>net.sourceforge.jtds</groupId>
<artifactId>jtds</artifactId>
<scope>runtime</scope>
</dependency>
.....
</dependencies>
Nội dung đầy đủ của tập tin pom.xml:
pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.o7planning</groupId>
<artifactId>SpringBootJPA</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>
<name>SpringBootJPA</name>
<description>Spring Boot + JPA + Spring Transaction</description>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.0.0.RELEASE</version>
<relativePath /> <!-- lookup parent from repository -->
</parent>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
<scope>42.1.4</scope>
</dependency>
<dependency>
<groupId>com.microsoft.sqlserver</groupId>
<artifactId>mssql-jdbc</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>net.sourceforge.jtds</groupId>
<artifactId>jtds</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>com.oracle</groupId>
<artifactId>ojdbc6</artifactId>
<version>11.2.0.3</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.threeten/threetenbp -->
<dependency>
<groupId>org.threeten</groupId>
<artifactId>threetenbp</artifactId>
<version>1.3.6</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<repositories>
<!-- Repository for ORACLE JDBC Driver -->
<repository>
<id>codelds</id>
<url>https://code.lds.org/nexus/content/groups/main-repo</url>
</repository>
</repositories>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
5. Cấu hình Datasource
Để Spring có thể kết nối vào Database bạn cần cấu hình các thông số cần thiết trong tập tin application.properties.
application.properties (MySQL)
# ===============================
# DATABASE
# ===============================
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/mydatabase
spring.datasource.username=root
spring.datasource.password=12345
# ===============================
# JPA / HIBERNATE
# ===============================
spring.jpa.show-sql=true
spring.jpa.hibernate.ddl-auto=none
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQL5Dialect
application.properites (Sql Server + Mssql-Jdbc)
# ===============================
# DATABASE
# ===============================
spring.datasource.driver-class-name=com.microsoft.sqlserver.jdbc.SQLServerDriver
spring.datasource.url=jdbc:sqlserver://tran-vmware-pc\\SQLEXPRESS:1433;databaseName=bank
spring.datasource.username=sa
spring.datasource.password=12345
# ===============================
# JPA / HIBERNATE
# ===============================
spring.jpa.show-sql=true
spring.jpa.hibernate.ddl-auto=none
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.SQLServer2012Dialect
application.properites (Sql Server + JTDS)
# ===============================
# DATABASE
# ===============================
spring.datasource.driver-class-name=net.sourceforge.jtds.jdbc.Driver
spring.datasource.url=jdbc:jtds:sqlserver://tran-vmware-pc:1433/bank;instance=SQLEXPRESS
spring.datasource.username=sa
spring.datasource.password=12345
# ===============================
# JPA / HIBERNATE
# ===============================
spring.jpa.show-sql=true
spring.jpa.hibernate.ddl-auto=none
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.SQLServer2012Dialect
application.properties (Oracle)
# ===============================
# DATABASE
# ===============================
spring.datasource.driver-class-name=oracle.jdbc.driver.OracleDriver
spring.datasource.url=jdbc:oracle:thin:@localhost:1521:db12c
spring.datasource.username=Test
spring.datasource.password=test001
# ===============================
# JPA / HIBERNATE
# ===============================
spring.jpa.show-sql=true
spring.jpa.hibernate.ddl-auto=none
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.Oracle10gDialect
application.properties (PostGres)
# ===============================
# DATABASE CONNECTION
# ===============================
spring.datasource.driver-class-name=org.postgresql.Driver
spring.datasource.url=jdbc:postgresql://tran-vmware-pc:5432/bank
spring.datasource.username=postgres
spring.datasource.password=12345
# ===============================
# JPA / HIBERNATE
# ===============================
spring.jpa.show-sql=true
spring.jpa.hibernate.ddl-auto=none
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.PostgreSQLDialect
# Fix Postgres JPA Error:
# Method org.postgresql.jdbc.PgConnection.createClob() is not yet implemented.
spring.jpa.properties.hibernate.temp.use_jdbc_metadata_defaults= false
6. Entity, Model, Form, DAO
Trong JPA (Hoặc Hibernate), Entity là một class đại diện (tương ứng) cho một bảng trong cơ sở dữ liệu. Các trường (field) trong lớp này sẽ tương ứng với các cột trong bảng.
Chúng ta sẽ tạo lớp BankAccount để đại diện cho bảng BANK_ACCOUNT trong database. Các JPA Annotation sẽ được sử dụng để chú thích trên các trường (field) để mô tả cách ánh xạ (mapping) giữa các trường và các cột của bảng. Các ánh xạ này là 1-1, mỗi trường tương ứng với 1 cột trong bảng.
Chúng ta sẽ tạo lớp BankAccount để đại diện cho bảng BANK_ACCOUNT trong database. Các JPA Annotation sẽ được sử dụng để chú thích trên các trường (field) để mô tả cách ánh xạ (mapping) giữa các trường và các cột của bảng. Các ánh xạ này là 1-1, mỗi trường tương ứng với 1 cột trong bảng.
BankAccount.java
package org.o7planning.springbootjpa.entity;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.Table;
@Entity
@Table(name = "Bank_Account" )
public class BankAccount {
@Id
@GeneratedValue
@Column(name = "id", nullable = false)
private Long id;
@Column(name = "Full_Name", length = 128, nullable = false)
private String fullName;
@Column(name = "Balance", nullable = false)
private double balance;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getFullName() {
return fullName;
}
public void setFullName(String fullName) {
this.fullName = fullName;
}
public double getBalance() {
return balance;
}
public void setBalance(double balance) {
this.balance = balance;
}
}
Trong khi một lớp Entity đại diện cho dữ liệu của một bản ghi (record) của một bảng, thì một lớp Model đại diện cho dữ liệu của 1 bản ghi của một câu lệnh truy vấn (Join từ một hoặc nhiều bảng). Bạn sử dụng lớp Model khi bạn quan tâm tới một vài cột của một hoặc nhiều bảng.
BankAccountInfo.java
package org.o7planning.springbootjpa.model;
public class BankAccountInfo {
private Long id;
private String fullName;
private double balance;
public BankAccountInfo() {
}
// Sử dụng trong câu truy vấn của JPA
public BankAccountInfo(Long id, String fullName, double balance) {
this.id = id;
this.fullName = fullName;
this.balance = balance;
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getFullName() {
return fullName;
}
public void setFullName(String fullName) {
this.fullName = fullName;
}
public double getBalance() {
return balance;
}
public void setBalance(double balance) {
this.balance = balance;
}
}
Để làm việc với JPA truyền thống, việc đầu tiên bạn cần phải làm là tạo ra đối tượng EntityManager. Với Spring Boot mọi thứ thực sự dễ dàng, nó đã tự động cấu hình vào và tạo ra EntityManager và quản lý nó như một Spring BEAN. Và trong ứng dụng bạn có thể sử dụng đối tượng EntityManager bất kỳ đâu mà bạn muốn.
BankAccountDAO.java
package org.o7planning.springbootjpa.dao;
import java.util.List;
import javax.persistence.EntityManager;
import javax.persistence.Query;
import org.o7planning.springbootjpa.entity.BankAccount;
import org.o7planning.springbootjpa.exception.BankTransactionException;
import org.o7planning.springbootjpa.model.BankAccountInfo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
@Repository
public class BankAccountDAO {
@Autowired
private EntityManager entityManager;
public BankAccountDAO() {
}
public BankAccount findById(Long id) {
return this.entityManager.find(BankAccount.class, id);
}
public List<BankAccountInfo> listBankAccountInfo() {
String sql = "Select new " + BankAccountInfo.class.getName() //
+ "(e.id,e.fullName,e.balance) " //
+ " from " + BankAccount.class.getName() + " e ";
Query query = entityManager.createQuery(sql, BankAccountInfo.class);
return query.getResultList();
}
// MANDATORY: Bắt buộc phải có Transaction đã được tạo trước đó.
@Transactional(propagation = Propagation.MANDATORY )
public void addAmount(Long id, double amount) throws BankTransactionException {
BankAccount account = this.findById(id);
if (account == null) {
throw new BankTransactionException("Account not found " + id);
}
double newBalance = account.getBalance() + amount;
if (account.getBalance() + amount < 0) {
throw new BankTransactionException(
"The money in the account '" + id + "' is not enough (" + account.getBalance() + ")");
}
account.setBalance(newBalance);
}
// Không bắt ngoại lệ BankTransactionException trong phương thức này.
@Transactional(propagation = Propagation.REQUIRES_NEW,
rollbackFor = BankTransactionException.class)
public void sendMoney(Long fromAccountId, Long toAccountId, double amount) throws BankTransactionException {
addAmount(toAccountId, amount);
addAmount(fromAccountId, -amount);
}
}
BankTransactionException.java
package org.o7planning.springbootjpa.exception;
public class BankTransactionException extends Exception {
private static final long serialVersionUID = -3128681006635769411L;
public BankTransactionException(String message) {
super(message);
}
}
SendMoneyForm.java
package org.o7planning.springbootjpa.form;
public class SendMoneyForm {
private Long fromAccountId;
private Long toAccountId;
private Double amount;
public SendMoneyForm() {
}
public SendMoneyForm(Long fromAccountId, Long toAccountId, Double amount) {
this.fromAccountId = fromAccountId;
this.toAccountId = toAccountId;
this.amount = amount;
}
public Long getFromAccountId() {
return fromAccountId;
}
public void setFromAccountId(Long fromAccountId) {
this.fromAccountId = fromAccountId;
}
public Long getToAccountId() {
return toAccountId;
}
public void setToAccountId(Long toAccountId) {
this.toAccountId = toAccountId;
}
public Double getAmount() {
return amount;
}
public void setAmount(Double amount) {
this.amount = amount;
}
}
Giải thích về cơ chế hoạt động của Spring Transaction:
Trong ví dụ này tôi mô phỏng một giao dịch ngân hàng, tài khoản A gửi cho tài khoản B một số tiền 700$. Như vậy sẽ có 2 hành động được tạo ra trong database:
- Cộng 700$ vào tài khoản B.
- Trừ 700$ khỏi tài khoản của A.
Nếu hành động thứ nhất thành công (Cộng 700$ vào tài khoản B), nhưng hành động 2 không thành công vì một nguyên nhân nào đó. Trường hợp này ngân hàng sẽ bị thiệt hại.
Vì vậy chúng cần phải quản lý giao dịch (Transaction) để đảm bảo rằng nếu có một hành động không thành công, dữ liệu sẽ được đưa trở lại trạng thái ban đầu (Trước khi giao dịch). Giao dịch được coi là thành công khi tất cả các hành động thành công.
Vì vậy chúng cần phải quản lý giao dịch (Transaction) để đảm bảo rằng nếu có một hành động không thành công, dữ liệu sẽ được đưa trở lại trạng thái ban đầu (Trước khi giao dịch). Giao dịch được coi là thành công khi tất cả các hành động thành công.
Sử dụng @Transactional(rollbackFor = BankTransactionException.class) chú thích (annotate) trên một phương thức để nói với "Spring Transaction" rằng hãy áp dụng AOP cho phương thức này.
@Transactional(propagation = Propagation.REQUIRES_NEW,
rollbackFor = BankTransactionException.class)
public void sendMoney(Long fromAccountId, Long toAccountId,
double amount) throws BankTransactionException {
addAmount(toAccountId, amount);
addAmount(fromAccountId, -amount);
}
Spring Transaction áp dụng Spring AOP cho phương thức của bạn, nó giống như hành động thay đổi code của phương thức, thêm vào đoạn code bắt ngoại lệ và gọi Rollback giao dịch khi ngoại lệ xẩy ra, sau đó nó ném tiếp (rethrow) ngoại lệ ra ngoài phương thức. Tất cả giống như hình minh họa dưới đây:
7. Controller
MainController.java
package org.o7planning.springbootjpa.controller;
import java.util.List;
import org.o7planning.springbootjpa.dao.BankAccountDAO;
import org.o7planning.springbootjpa.exception.BankTransactionException;
import org.o7planning.springbootjpa.form.SendMoneyForm;
import org.o7planning.springbootjpa.model.BankAccountInfo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
@Controller
public class MainController {
@Autowired
private BankAccountDAO bankAccountDAO;
@RequestMapping(value = "/", method = RequestMethod.GET)
public String showBankAccounts(Model model) {
List<BankAccountInfo> list = bankAccountDAO.listBankAccountInfo();
model.addAttribute("accountInfos", list);
return "accountsPage";
}
@RequestMapping(value = "/sendMoney", method = RequestMethod.GET)
public String viewSendMoneyPage(Model model) {
SendMoneyForm form = new SendMoneyForm(1L, 2L, 700d);
model.addAttribute("sendMoneyForm", form);
return "sendMoneyPage";
}
@RequestMapping(value = "/sendMoney", method = RequestMethod.POST)
public String processSendMoney(Model model, SendMoneyForm sendMoneyForm) {
System.out.println("Send Money: " + sendMoneyForm.getAmount());
try {
bankAccountDAO.sendMoney(sendMoneyForm.getFromAccountId(), //
sendMoneyForm.getToAccountId(), //
sendMoneyForm.getAmount());
} catch (BankTransactionException e) {
model.addAttribute("errorMessage", "Error: " + e.getMessage());
return "/sendMoneyPage";
}
return "redirect:/";
}
}
8. Thymeleaf Template
_menu.html
<div xmlns:th="http://www.thymeleaf.org"
style="border: 1px solid #ccc;padding:5px;margin-bottom:20px;">
<a th:href="@{/}">Accounts</a>
|
<a th:href="@{/sendMoney}">Send Money</a>
</div>
accountsPage.html
<!DOCTYPE HTML>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<title>Bank</title>
<style>
th, td {
padding: 5px;
}
</style>
</head>
<body>
<!-- Include _menu.html -->
<th:block th:include="/_menu"></th:block>
<h2>Accounts</h2>
<table border="1">
<tr>
<th>ID</th>
<th>Full Name</th>
<th>Balance</th>
</tr>
<tr th:each="accountInfo : ${accountInfos}">
<td th:utext="${accountInfo.id}">..</td>
<td th:utext="${accountInfo.fullName}">..</td>
<td th:utext="${accountInfo.balance}">..</td>
</tr>
</table>
</body>
</html>
sendMoneyPage.html
<!DOCTYPE HTML>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<title>Bank</title>
</head>
<body>
<!-- Include _menu.html -->
<th:block th:include="/_menu"></th:block>
<h2>Send Money</h2>
<ul>
<li>1 - Tom</li>
<li>2 - Jerry</li>
<li>3 - Donald</li>
</ul>
<div th:if="${errorMessage!=null}"
style="color:red;font-style:italic" th:utext="${errorMessage}">..</div>
<form th:action="@{/sendMoney}" th:object="${sendMoneyForm}" method="POST">
<table>
<tr>
<td>From Bank Account Id</td>
<td><input type="text" th:field="*{fromAccountId}"/></td>
</tr>
<tr>
<td>To Bank Account Id</td>
<td><input type="text" th:field="*{toAccountId}"/></td>
</tr>
<tr>
<td>Amount</td>
<td><input type="text" th:field="*{amount}" /></td>
</tr>
<tr>
<td> </td>
<td><input type="submit" value="Send"/></td>
</tr>
</table>
</form>
</body>
</html>
Các hướng dẫn Spring Boot
- Cài đặt Spring Tool Suite cho Eclipse
- Hướng dẫn lập trình Spring cho người mới bắt đầu
- Hướng dẫn lập trình Spring Boot cho người mới bắt đầu
- Các thuộc tính thông dụng của Spring Boot
- Hướng dẫn sử dụng Spring Boot và Thymeleaf
- Hướng dẫn sử dụng Spring Boot và FreeMarker
- Hướng dẫn sử dụng Spring Boot và Groovy
- Hướng dẫn sử dụng Spring Boot và Mustache
- Hướng dẫn sử dụng Spring Boot và JSP
- Hướng dẫn sử dụng Spring Boot, Apache Tiles, JSP
- Sử dụng Logging trong Spring Boot
- Giám sát ứng dụng với Spring Boot Actuator
- Tạo ứng dụng web đa ngôn ngữ với Spring Boot
- Sử dụng nhiều ViewResolver trong Spring Boot
- Sử dụng Twitter Bootstrap trong Spring Boot
- Hướng dẫn và ví dụ Spring Boot Interceptor
- Hướng dẫn sử dụng Spring Boot, Spring JDBC và Spring Transaction
- Hướng dẫn và ví dụ Spring JDBC
- Hướng dẫn sử dụng Spring Boot, JPA và Spring Transaction
- Hướng dẫn sử dụng Spring Boot và Spring Data JPA
- Hướng dẫn sử dụng Spring Boot, Hibernate và Spring Transaction
- Tương tác Spring Boot, JPA và cơ sở dữ liệu H2
- Hướng dẫn sử dụng Spring Boot và MongoDB
- Sử dụng nhiều DataSource với Spring Boot và JPA
- Sử dụng nhiều DataSource với Spring Boot và RoutingDataSource
- Tạo ứng dụng Login với Spring Boot, Spring Security, Spring JDBC
- Tạo ứng dụng Login với Spring Boot, Spring Security, JPA
- Tạo ứng dụng đăng ký tài khoản với Spring Boot, Spring Form Validation
- Ví dụ OAuth2 Social Login trong Spring Boot
- Chạy các nhiệm vụ nền theo lịch trình trong Spring
- Ví dụ CRUD Restful Web Service với Spring Boot
- Ví dụ Spring Boot Restful Client với RestTemplate
- Ví dụ CRUD với Spring Boot, REST và AngularJS
- Bảo mật Spring Boot RESTful Service sử dụng Basic Authentication
- Bảo mật Spring Boot RESTful Service sử dụng Auth0 JWT
- Ví dụ Upload file với Spring Boot
- Ví dụ Download file với Spring Boot
- Ví dụ Upload file với Spring Boot và jQuery Ajax
- Ví dụ Upload file với Spring Boot và AngularJS
- Tạo ứng dụng Web bán hàng với Spring Boot, Hibernate
- Hướng dẫn và ví dụ Spring Email
- Tạo ứng dụng Chat đơn giản với Spring Boot và Websocket
- Triển khai ứng dụng Spring Boot trên Tomcat Server
- Triển khai ứng dụng Spring Boot trên Oracle WebLogic Server
- Cài đặt chứng chỉ SSL miễn phí Let's Encrypt cho Spring Boot
- Cấu hình Spring Boot chuyển hướng HTTP sang HTTPS
- Tìm nạp dữ liệu với Spring Data JPA DTO Projections
Show More