Làm quen và xây dựng Restfull API CRUD đơn giản với Spring Boot
Spring Boot là gì?
Spring boot là một dự án nổi bật trong hệ sinh thái Spring Framework, là cách nhanh nhất để tạo ra một REST service độc lập. Spring boot đơn giản hóa việc cấu hình, cụ thể ở đây là Spring Boot tự cấu hình tất cả bằng cách cung cấp các hành vi cụ thể. Nó đơn giản hóa việc deploy, bằng cách đóng gói app của chúng ta thành gói jar, để có thể dễ dàng tích hợp vào các web container. Nếu như trước đây, công đoạn khởi tạo một dự án Spring khá vất vả từ việc khai báo các dependency trong file pom.xml cho đến cấu hình bằng XML hoặc các annotation phức tạp, thì giờ đây với Spring Boot chúng ta có thể tạo ứng dụng Spring một cách nhanh chóng và cấu hình cũng đơn giản hơn.
Các lợi ích của Spring Boot:
· Dễ dàng để phát triển các ứng dụng dựa trên Spring với Java hoặc Groovy
· Giảm thiểu thời gian phát triển và tăng năng xuất
· Nó tránh việc phải viết nhiều mã nguyên mẫu (boilerplate Code), Annotations và các cấu hình XML.
· Nó dễ dàng để bạn tương tác các ứng dụng Spring Boot với các hệ sinh thái của Spring như Spring JDBC, Spring ORM, Spring Data, Spring Security etc.
· Nó đi theo cách tiếp cận “Nguyên tắc cấu hình mặc định” để giảm thiểu thời gian và nỗ lực cần thiết để phát triển ứng dụng.
· Nó cung cấp các Server nhúng (Embedded HTTP servers) như là Tomcat, Jetty …. để phát triển và test các ứng dụng web nhanh chóng và dễ dàng.
· Nó cung cấp công cụ CLI (Command Line Interface) dể phát triển và test các ứng dụng Spring Boot(Java hoặc Groovy) từ các dòng lệnh (command prompt) rất dễ dàng và nhanh chóng.
· Nó cung cấp rất nhiều các plugin để phát triển và test các ứng dụng Spring Boot nhanh chóng sử dụng các công cụ Buildnhư Maven và Gradle
· Nó cung cấp nhiều plugin để làm việc với các cơ sở dữ liệu nhúng (embedded database) và các cơ sở dữ liệu lưu trữ trên bộ nhớ (in-memory Databases) một cách dễ dàng.
Restfull API là gì?
REST (REpresenttational State Transfer) lần đầu tiên được giới thiệu vào năm 2000 trong luận văn tiến sĩ của Roy Thomas Fielding (đồng sáng lập giao thức HTTP). Trong luận văn ông giới thiệu khá chi tiết về các ràng buộc, quy ước cũng như cách thức thực hiện với hệ thống để có được một hệ thống REST. Hiểu một cách đơn giản, REST là một hệ thống các ràng buộc (constraints), chỉ cần đảm bảo những điều đó hệ thống của bạn có thể được gọi là RESTfull.
REST định nghĩa các quy tắc kiến trúc để bạn thiết kế Web services, chú trọng vào tài nguyên hệ thống, bao gồm các trạng thái tài nguyên được định dạng như thế nào và được truyền tải qua HTTP, và được viết bởi nhiều ngôn ngữ khác nhau.
REST có kiến trúc đơn giản, định rõ các ràng buộc nhằm tạo ra ứng dụng Web service đạt được những tính chất mong muốn về hiệu suất, khả năng mở rộng, khả năng điều chỉnh v.v..
REST hướng tới việc xây dựng ứng dụng Web service có khả năng làm việc tốt nhất trên môi trường WWW.
Dữ liệu và các tính năng được coi như tài nguyên và được truy suất thông qua các URI (Uniform Resource Identifier)
REST sử dụng 4 phương thức chính của HTTP là POST, GET, PUT và DELETE để thực hiện các hành động CRUD đối với các tài nguyên
Restfull API là một tiêu chuẩn dùng trong việc thiết kế các thiết kế API. Các web service thường được áp dụng các cấu trúc REST vào để xây dựng.
Các cấu trúc cơ bản của cấu trúc REST:
· Sử dụng các phương thức HTTP một cách rõ ràng
· Phi trạng thái
· Hiển thị cấu trúc thư mục như các URLs
· Truyền tải JavaScript Object Notation(JSON), XML hoặc cả hai
Tạo dự án Spring Boot như thế nào?
Các bước để tạo một dự án Spring Boot với Maven:
Bước 1: Ta chọn Create New Project -> Spring Initializr -> Next
Bước 2: Nhập các thông tin cơ bản như Group, Artifact, Name, Package -> Type -> Next
Name ở đây sẽ là tên của lớp chứa hàm main của dự án(HelloSpringBootApplication). ở đây mình chọn Type là Maven và Java là Version 8.
Bước 3: Chọn Dependency -> Next
Ở đây Spring Boot sẽ yêu cầu chọn các dependency cho dự án. Do chưa có nhiều nhu cầu nên mình chỉ lựa chọn dependency Web.
Cuối cùng: Nhập tên project -> chọn thư mục lưu trữ dữ án -> Finish
Đây chính là file để chạy application, từ đây chúng ta sẽ có root của application, Spring Boot sẽ tự động scan các component từ package khai báo với Annotation @SpringBootApplication trở xuống.
Annotation @SpringBootApplication là cách viết ngắn gọn của việc khai báo bằng các annotation sau.
· @Configuration
· @EnableAutoConfiguration
· @ComponentScan
package com.velacorp.hellospringbot;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class HelloSpringBotApplication {
public static void main(String[] args) {
SpringApplication.run(HelloSpringBotApplication.class, args);
}
}
Cấu trúc thư mục quản lý product RestFull API sử dụng Spring Boot:
Để tạo bắt đầu chúng ta cần cấu hình trong file pom.xml, xác định những thư viện cần thiết cho dự án và add add các dependency để spring boot tự động downloads các thư việc cần thiết.
Để xây dựng dự án Restfull API với các chức năng CRUD đơn giản với Spring Boot chúng ta sẽ cần cấu hình trong file pom.xml như sau:
· Các thư viện để chuyển đổi dự liệu từ Json sang Java và ngược lại:
<!--json-->
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>2.8.4</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
<version>2.9.2</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
<version>2.9.2</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.dataformat</groupId>
<artifactId>jackson-dataformat-xml</artifactId>
</dependency>
· Các thư viện kết nối và thao tác với CSDL (Hibernate, JPA):
<!--hibernate-->
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-core</artifactId>
<version>5.2.6.Final</version>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-entitymanager</artifactId>
<version>5.2.3.Final</version>
</dependency>
<dependency>
<groupId>org.hibernate.javax.persistence</groupId>
<artifactId>hibernate-jpa-2.1-api</artifactId>
<version>1.0.0.Final</version>
</dependency>
· Các thư viện cần thiết cho Spring Boot (services, repository):
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<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-web-services</artifactId>
</dependency>
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
Sau khi thêm các dependency vào file pom.xml chúng ta nên chạy thử để xem dự án của mình có gặp vấn đề nào không. Nếu không, chúng ta sẽ bắt đầu tạo các Package và các lớp cũng như các Interface cần thiết cho dự án.
Đầu tiên, chúng ta cần xây dựng hệ thống database gồm các bảng và các cột:
create database productmanager;
use productmanager;
create table products (
id int auto_increment primary key ,
name varchar(255) not null ,
price double not null ,
description varchar(255) not null
);
Sau đó, chúng ta sẽ tạo các model tương ứng với các bảng trong CSDL:
package com.velacorp.hellospringbot.model;
import javax.persistence.*;
import java.io.Serializable;
@Entity
@Table(name = "products")
public class Product implements Serializable {
private static final long serialVersionUID = 1L;
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Integer id;
private String name;
private double price;
private String description;
public Product() {
}
// Get and Set
}
Để Mapping giữa các đối tượng và các bảng chúng ta sẽ cần phải khai báo trong file application.properties link dẫn datasource và hibernate cần thiết để Spring Boot hiểu:
spring.datasource.url=jdbc:mysql://localhost:3306/productmanager?useSSL=false
spring.datasource.username=root
spring.datasource.password=
spring.jpa.hibernate.ddl-auto=update
spring.jpa.properties.hibernate.dialect = org.hibernate.dialect.MySQL5Dialect
Nhớ kiểm tra đường dẫn Url, username và password tương ứng.
Tiếp theo, tạo Interface repository để Spring tự động tạo ra các câu truy vấn động tương ứng:
package com.velacorp.hellospringbot.repository;
import com.velacorp.hellospringbot.model.Product;
import org.springframework.data.repository.CrudRepository;
import org.springframework.stereotype.Repository;
@Repository
public interface ProductRepository extends CrudRepository<Product, Integer> {
}
Nếu chỉ muốn sử dụng các câu truy vấn động CRUD đơn giản bạn chỉ cần để Interface repository Extends Interface CrudRepository (nếu cần phân trang bạn có thể extends Interface PagingAndSortingRepository). Bạn cũng có thể tạo ra các các câu truy vấn động bằng cơ chế duyệt qua tên của phương thức với các tiền tố như find…By, read…By, query…By, count…By và get…By của Spring Data repository. Có thể sử dụng thêm một số từ khóa khác, chẳng hạn như Distinct, Or, And… Spring Data repository sẽ tự động nhận diện và chuyển thành câu truy vấn phù hợp.
Không giống như trong Spring MVC bạn phải tạo ra các file xml hoặc các file Java rườm và các Annotation để cấu hình cho Spring hiểu rằng Interface nào là repository, Trong Spring Boot bạn chỉ cần chỉ cần thêm Annotation @repository vào Interface và khi đó Spring sẽ tự động tìm, dò và tạo thể hiện của bean.
Tiếp theo, chúng ta cần tạo ra các service(các Interface và các lớp implements triển khai các interface đó) để xử lý với dự liệu trong database.
Trong Interface service chúng ta sẽ nêu ra các phương thức trừu tượng để cho lớp implements triển khai nó. Và khi dự án hoạt động, lớp controller sẽ chỉ cần quan tâm tới Interface Service mà không cần quan tâm đến các lớp Implements.
package com.velacorp.hellospringbot.service;
import com.velacorp.hellospringbot.model.Product;
import java.util.List;
import java.util.Optional;
public interface ProductService {
List<Product> findAllProduct(); Optional<Product> findById(Integer id); void save(Product product); void remove(Product product);
}
Trong lớp implement service tương tự như Interface repository, chúng ta sẽ cần đến Annotation @service để tự động tìm, dò và tạo thể hiện của bean.
package com.velacorp.hellospringbot.service.impl;
import com.velacorp.hellospringbot.model.Product;
import com.velacorp.hellospringbot.repository.ProductRepository;
import com.velacorp.hellospringbot.service.ProductService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
import java.util.Optional;
@Service
public class ProductServiceImpl implements ProductService {
private ProductRepository productRepository;
@Autowired
public ProductServiceImpl (ProductRepository productRepository){
this.productRepository = productRepository;
}
@Override
public List<Product> findAllProduct() {
return (List<Product>) productRepository.findAll();
}
@Override
public Optional<Product> findById(Integer id) {
return productRepository.findById(id);
}
@Override
public void save(Product product) {
productRepository.save(product);
}
@Override
public void remove(Product product) {
productRepository.delete(product);
}
}
Cuối cùng, Tạo ra lớp controller và thêm Annotation @RestController để chú thích cho Spring hiểu rằng nó là một Spring Restfull Controller. Chúng ta triển khai dự án theo cấu trúc RESTfull sử dụng các method GET, POST, PUT và DELETE.
package com.velacorp.hellospringbot.controller;
import com.velacorp.hellospringbot.model.Product;
import com.velacorp.hellospringbot.service.ProductService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.util.UriComponentsBuilder;
import java.util.List;
import java.util.Optional;
@RestController
public class ProductManagerController {
private ProductService productService;
@Autowired
public ProductManagerController(ProductService productService) {
this.productService = productService;
}
@RequestMapping(value = "/products", method = RequestMethod.GET)
public ResponseEntity<List<Product>> findAllProduct() { List<Product> products = productService.findAllProduct();
if (products.isEmpty()) {
return new ResponseEntity<>(HttpStatus.NO_CONTENT);
}
return new ResponseEntity<>(products, HttpStatus.OK);
}
@RequestMapping(value = "/products/{id}",
method = RequestMethod.GET,
produces = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<Product> getProductById(
@PathVariable("id") Integer id) { Optional<Product> product = productService.findById(id);
if (!product.isPresent()) {
return new ResponseEntity<>(product.get(),
HttpStatus.NO_CONTENT);
}
return new ResponseEntity<>(product.get(), HttpStatus.OK);
}
@RequestMapping(value = "/products",
method = RequestMethod.POST)
public ResponseEntity<Product> createProduct(
@RequestBody Product product,
UriComponentsBuilder builder) { productService.save(product);
HttpHeaders headers = new HttpHeaders();
headers.setLocation(builder.path("/products/{id}")
.buildAndExpand(product.getId()).toUri());
return new ResponseEntity<>(product, HttpStatus.CREATED);
}
@RequestMapping(value = "/products/{id}",
method = RequestMethod.PUT)
public ResponseEntity<Product> updateProduct(
@PathVariable("id") Integer id,
@RequestBody Product product) { Optional<Product> currentProduct = productService
.findById(id);
if (!currentProduct.isPresent()) {
return new ResponseEntity<>(HttpStatus.NO_CONTENT);
}
currentProduct.get().setName(product.getName());
currentProduct.get().setPrice(product.getPrice());
currentProduct.get().setDescription(product.getDescription());
productService.save(currentProduct.get());
return new ResponseEntity<>(currentProduct.get(), HttpStatus.OK);
}
@RequestMapping(value = "/products/{id}",
method = RequestMethod.DELETE)
public ResponseEntity<Product> deleteProduct(
@PathVariable("id") Integer id) { Optional<Product> product = productService.findById(id);
if (!product.isPresent()) {
return new ResponseEntity<>(HttpStatus.NOT_FOUND);
}
productService.remove(product.get());
return new ResponseEntity<>(HttpStatus.NO_CONTENT);
}
}
Sau khi viết xong chúng ta sẽ dùng ứng dụng POSTMAN để test thử ứng dụng của mình
Giới thiệu POSTMAN
· POSTMAN là một App Extensions, cho phép làm việc với các API, điển hình là REST.
· Hỗ trợ tất cả các phương thức HTTP (GET, POST, PUT, DELETE, OPTIONS, HEAD …)
Cài đặt POSTMAN
· POSTMAN được cung cấp miễn phí qua web site https://www.getpostman.com/
Sử dụng POSTMAN
· Bước 1: Nhập URL của web service vào thanh địa chỉ của POSTMAN.
· Bước 2: Chọn phương thức của web service.
· Bước 3: Sửa, thêm các thông tin params phụ thuộc vào web service.
· Bước 4: Nhấn SEND và theo dõi kết quả web service trả ra.
Đây là giao diện chính của POSTMAN:
Nếu bạn nào chưa biết xử dụng POSTMAN có thể tham khảo thêm bài viết này: https://viblo.asia/p/postman-goi-api-chua-bao-gio-de-dang-nhu-vay-AoDGYNDQRvg
Test method POST (create) :
Test method GET:
Như vậy, chúng ta đã xây dựng được Restfull API CRUD đơn giản với Spring Boot.
Lời kết
Như vậy, Spring Boot chỉ đơn giản là được xây dựng trên nền tảng của Spring Framwork, Spring Boot được xây dựng ra để khác phục những nhược điểm của Spring Framwork (quá nhiều cấu hình, để chạy được Spring Framwork cần cài đặt các ứng dụng server), đồng thời cung cấp một số hướng phát triển phần mềm mới trong tương lai. Với việc triển khai đơn giản, nhưng mạnh mẽ, Spring Boot là một lựa chọn tốt để phát triển các Spring project.
Các bạn có thể tìm đọc cuốn Spring Boot in Action hiểu sâu hơn về Spring Boot.