第一個 Spring boot API 開發範例。使用的元件有以下,開發使用 vscode 建立專案時透過工具進行建立非常的容易。這一個專案使用了 Mysql 進行 DB 連線,使用 JPA 的框架進行簡易的 API 實現。
...
<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-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</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>
...
主要的資料夾結構
/springboot-crud/src/main/java/com/example/cch/crud$ tree
.
├── CrudApplication.java
├── controller # 靠近 UI 層
│ └── ProductController.java
├── model # 實體層,宣告一個領域
│ └── Product.java
├── repository # 有關 DB 的操作
│ └── ProductRepository.java
└── service # 業務邏輯
├── ProductService.java
└── ProductServiceImp.java
我們在 resource 資料夾下的 application.properties 檔案進行關於 DB 連線的設置
# Mysql
# demo DB name
spring.datasource.url=jdbc:mysql://192.168.134.146:3306/crudb
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.username=springcrud
spring.datasource.password=123456
# Hibernate
# spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MYSQL
spring.jpa.database-platform=org.hibernate.dialect.MySQL8Dialect
spring.jpa.properties.hibernate.dialect.storage_engine=innodb
spring.jpa.hibernate.ddl-auto=none
spring.jpa.show-sql=true
logging.level.org.hibernate.SQL=DEBUG
logging.level.org.hibernate.type=TRACE
我們假設設計一個有關於產品的領域的實體,有個簡單的主鍵 ID 和商品名稱以及價格。
@Entity
public class Product {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column()
private String name;
@Column()
private float price;
// ... get、set and constructor
}
建立實體後,需要操作 DB 以獲得 DB 中的資料或是存儲資料,簡單的透過繼層 JpaRepository
即可實現簡易的 CRUD 操作。JpaRepository<Product, Long>
中 Product 是實體類它會對應 DB 中的欄位,Long
則是主鍵。
public interface ProductRepository extends JpaRepository<Product, Long>{
}
接這我們撰寫業務邏輯,首先我們定義一個 Interface,分別是以下
public interface ProductService {
List<Product> getAllProduct(); //獲取所有
void saveProduct(Product product); // 儲存
Product getProductById(Long id); // 透過主鍵獲取資料
void deleteProductById(Long id); // 刪除資料
}
實現介面,也就是實現業務邏輯,簡單來說就是把 DB 的操作邏輯寫在這
@Service
public class ProductServiceImp implements ProductService {
@Autowired // 將 DB 的操作注入,這可以將其想像成是建構方法
private ProductRepository productRepository;
@Override
public List<Product> getAllProduct() {
// TODO Auto-generated method stub
return this.productRepository.findAll();
}
@Override
public void saveProduct(Product product) {
// TODO Auto-generated method stub
productRepository.save(product);
}
@Override
public Product getProductById(Long id) {
// TODO Auto-generated method stub
Optional<Product> optional = productRepository.findById(id);
Product product = null;
if (optional.isPresent()){
product = optional.get();
}
return product;
}
@Override
public void deleteProductById(Long id) {
// TODO Auto-generated method stub
this.productRepository.deleteById(id);
}
}
接著把靠近 UI 層部分就是 controller 進行實現,這邊會使用 HTTP 的 Method 進行 CRUD 實現。
@RestController
public class ProductController {
@Autowired
private ProductService productService;
@GetMapping("/products")
public List<Product> list() {
return productService.getAllProduct();
}
@GetMapping("/products/{id}")
public ResponseEntity<Product> get(@PathVariable(value = "id") Long id) {
// 這邊的防呆其實可以拉到 Service 層進行
try {
Product product = productService.getProductById(id);
if (product == null){
return new ResponseEntity<Product>(HttpStatus.NOT_FOUND);
}
return new ResponseEntity<Product>(product, HttpStatus.OK);
} catch (Exception e) {
// TODO: handle exception
return new ResponseEntity<Product>(HttpStatus.NOT_FOUND);
}
}
@PostMapping("/products")
public void add(@RequestBody Product product) {
productService.saveProduct(product);
}
@PutMapping("/products/{id}")
public ResponseEntity<?> update(@RequestBody Product product, @PathVariable(value = "id") Long id){
try {
Product existProduct = productService.getProductById(id);
if (existProduct == null){
return new ResponseEntity<Product>(HttpStatus.NOT_FOUND);
}
productService.saveProduct(product);
return new ResponseEntity<Product>(HttpStatus.OK);
} catch (Exception e) {
// TODO: handle exception
return new ResponseEntity<Product>(HttpStatus.NOT_FOUND);
}
}
@DeleteMapping("/products/{id}")
public void delete(@PathVariable(value = "id") Long id) {
productService.deleteProductById(id);
}
}
建立資料庫和使用者
mysql> create user 'springcrud'@'%' identified by '123456';
Query OK, 0 rows affected (0.02 sec)
mysql> create database crudb;
Query OK, 1 row affected (0.00 sec)
mysql> grant all on crudb.* to 'springcrud'@'%';
Query OK, 0 rows affected (0.00 sec)
mysql> CREATE TABLE product ( id INT NOT NULL AUTO_INCREMENT PRIMARY KEY, name VARCHAR(45) NOT NULL, price FLOAT NOT NULL );
Query OK, 0 rows affected (0.04 sec)
mysql> show tables;
+-----------------+
| Tables_in_crudb |
+-----------------+
| product |
+-----------------+
1 row in set (0.01 sec)
mysql> SHOW COLUMNS FROM product;
+-------+-------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-------+-------------+------+-----+---------+----------------+
| id | int | NO | PRI | NULL | auto_increment |
| name | varchar(45) | NO | | NULL | |
| price | float | NO | | NULL | |
+-------+-------------+------+-----+---------+----------------+
3 rows in set (0.01 sec)
對映 controller 中 add 方法
$ curl -X POST -H "Content-Type: application/json" -d '{"name": "apple", "price": 189.8}' http://localhost:8080/products
mysql> use crudb;
Reading table information for completion of table and column names
You can turn off this feature to get a quicker startup with -A
Database changed
mysql> SELECT * FROM product;
+----+-------+-------+
| id | name | price |
+----+-------+-------+
| 1 | apple | 189.8 |
+----+-------+-------+
1 row in set (0.00 sec)
對映 controller 中 list 方法
$ curl http://localhost:8080/products
[{"id":1,"name":"apple","price":189.8}]
$ curl -X POST -H "Content-Type: application/json" -d '{"name": "sony", "price": 120.86}' http://localhost:8080/products
$ curl -X POST -H "Content-Type: application/json" -d '{"name": "samsung", "price": 170.7}' http://localhost:8080/products
$ curl http://localhost:8080/products
[{"id":1,"name":"apple","price":189.8},{"id":2,"name":"sony","price":120.86},{"id":3,"name":"samsung","price":170.7}]
對映 controller 中 update 方法
$ curl -X PUT -H "Content-Type: application/json" -d '{"id": 1, "name": "iphone 12", "price": 999.7}' http://localhost:8080/products/1 -v
* Trying 127.0.0.1...
* TCP_NODELAY set
* Connected to localhost (127.0.0.1) port 8080 (#0)
> PUT /products/1 HTTP/1.1
> Host: localhost:8080
> User-Agent: curl/7.58.0
> Accept: */*
> Content-Type: application/json
> Content-Length: 46
>
* upload completely sent off: 46 out of 46 bytes
< HTTP/1.1 200
< Content-Length: 0
< Date: Sun, 06 Dec 2020 13:28:07 GMT
<
* Connection #0 to host localhost left intact
$ curl http://localhost:8080/products
[{"id":1,"name":"iphone 12","price":999.7},{"id":2,"name":"sony","price":120.86},{"id":3,"name":"samsung","price":170.7}]
mysql> SELECT * FROM product;
+----+-----------+--------+
| id | name | price |
+----+-----------+--------+
| 1 | iphone 12 | 999.7 |
| 2 | sony | 120.86 |
| 3 | samsung | 170.7 |
+----+-----------+--------+
3 rows in set (0.01 sec)
當 id 不正確時回應 404
$ curl -X PUT -H "Content-Type: application/json" -d '{"id": 10, "name": "iphone 12", "price": 999.7}' http://localhost:8080/products/10 -v
* Trying 127.0.0.1...
* TCP_NODELAY set
* Connected to localhost (127.0.0.1) port 8080 (#0)
> PUT /products/10 HTTP/1.1
> Host: localhost:8080
> User-Agent: curl/7.58.0
> Accept: */*
> Content-Type: application/json
> Content-Length: 47
>
* upload completely sent off: 47 out of 47 bytes
< HTTP/1.1 404
< Content-Length: 0
< Date: Sun, 06 Dec 2020 13:58:54 GMT
<
* Connection #0 to host localhost left intact
對映 controller 中 deleteProductById 方法
$ curl -X DELETE http://localhost:8080/products/1
mysql> SELECT * FROM product;
+----+---------+--------+
| id | name | price |
+----+---------+--------+
| 2 | sony | 120.86 |
| 3 | samsung | 170.7 |
+----+---------+--------+
2 rows in set (0.00 sec)
$ curl http://localhost:8080/products/
[{"id":2,"name":"sony","price":120.86},{"id":3,"name":"samsung","price":170.7}]
真的有點忙,文章內容都不是很完整,在麻煩見諒~~
這範例都在我github上