owned this note
owned this note
Published
Linked with GitHub
---
title: 'SpringBoot crud restful api (使用資料庫還有postman)'
disqus: hackmd
---
###### tags: `SpringBoot`
SpringBoot crud restful api (使用資料庫還有postman)
===
[TOC]
## 筆記目的
> 讓你了解怎麼樣使用mysql還有spring boot 實現restful api 讓你可以前後端分離,本筆記只有後端部分,所以使用postman來當作客戶端來測試
本筆記的架構大概如下:
![123](https://i.imgur.com/QqjIjPr.png)
> 介面層(Controller) 接收前端請求(處理網址)
業務邏輯層(Service):根據請求做資料處理或是處理從DAO回來的資料。
資料訪問層(Dao):對資料庫做增修查改等操作。
開發的順序很簡單:
1. 先完成applications的設定
2. 完成model
3. 完成dao也就是repository
4. 完成service
5. 完成controller
6. 完成exception
[引用自Day 17 - Spring Boot Todo List RESTful API 實作](https://ithelp.ithome.com.tw/articles/10244715)
具體請參考:
* [Spring Boot Hibernate MySQL CRUD REST API Tutorial | Full Course](https://www.youtube.com/watch?v=4Ico2HjRTCE)
* [application.properties (ithome)](https://ithelp.ithome.com.tw/articles/10217667)
* [完整的設定application(ithome)](https://ithelp.ithome.com.tw/articles/10223745)
## 先備條件
1. 請安裝mysql 並設定好root的密碼
2. 請在spring boot 啟用時對以下的東西打勾
Spring Web
Spring data jpa
mysql driver
lombok
![](https://i.imgur.com/c7L6YGq.png)
## 程式碼部分
### 專案架構
![](https://i.imgur.com/xxdm2KO.png)
### application.properties
```xml=
spring.jpa.hibernate.ddl-auto=update
spring.datasource.url=jdbc:mysql://localhost:3306/helloworld?useUnicode=true&characterEncoding=UTF-8&serverTimezone=UTC
###helloworld is database name資料庫名稱,不是資料表名稱喔
spring.datasource.username=root
spring.datasource.password=yourpassword
###下面的都照抄,不懂去翻ithome的連結
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.jpa.database-platform=org.hibernate.dialect.MySQL8Dialect
spring.jpa.properties.hibernate.dialect.storage_engine=innodb
```
### pom.xml
在此省略,因為只要你有在先備條件裡面打勾,便會自動生成
### Model
```java=
package com.example.demo.model;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;
@Entity
@Table(name="employees")
public class Employee {
public Employee() {
super();
// TODO Auto-generated constructor stub
}
public Employee(long id, String firstName, String lastName, String email) {
super();
this.id = id;
this.firstName = firstName;
this.lastName = lastName;
this.email = email;
}
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private long id;
@Column(name = "first_name", nullable = false)
private String firstName;
@Column(name = "last_name")
private String lastName;
@Column(name = "email")
private String email;
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
public String getFirstName() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
}
```
### Dao
```
package com.example.demo.dao;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
import com.example.demo.model.Employee;
@Repository
public interface EmployeeRepository extends JpaRepository<Employee, Long>{
}
```
> 繼承JpaRepository讓我不需要去實作方法,只是要記住他的語法,所以重點都會擺在
> service impl
### Service
```java==
package com.example.demo.service;
import java.util.List;
import org.springframework.stereotype.Service;
import com.example.demo.model.Employee;
@Service
public interface EmployeeService {
Employee saveEmployee(Employee employee);
List<Employee> getAllEmployees();
Employee getEmployeeById(long id);
Employee updateEmployee(Employee employee, long id);
void deleteEmployee(long id);
}
```
> service的介面,重點是回傳的資料型態,還有方法名稱要取的好,參數當然也是
### Service impl
```java=
package com.example.demo.service.impl;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.example.demo.dao.EmployeeRepository;
import com.example.demo.model.Employee;
import com.example.demo.service.EmployeeService;
import exception.ResourceNotFoundException;
@Service
public class EmployeeServiceImpl implements EmployeeService {
@Autowired
EmployeeRepository employeeRepository;
public EmployeeServiceImpl(EmployeeRepository employeeRepository) {
super();
this.employeeRepository = employeeRepository;
}
@Override
public Employee saveEmployee(Employee employee) {
return employeeRepository.save(employee);
}
@Override
public List<Employee> getAllEmployees() {
return employeeRepository.findAll();
}
@Override
public Employee getEmployeeById(long id) {
// Optional<Employee> employee = employeeRepository.findById(id);
// if(employee.isPresent()) {
// return employee.get();
// }else {
// throw new ResourceNotFoundException("Employee", "Id", id);
// }
return employeeRepository.findById(id).orElseThrow(() -> new ResourceNotFoundException("Employee", "Id", id));
}
@Override
public Employee updateEmployee(Employee employee, long id) {
// we need to check whether employee with given id is exist in DB or not
Employee existingEmployee = employeeRepository.findById(id)
.orElseThrow(() -> new ResourceNotFoundException("Employee", "Id", id));
existingEmployee.setFirstName(employee.getFirstName());
existingEmployee.setLastName(employee.getLastName());
existingEmployee.setEmail(employee.getEmail());
// save existing employee to DB
employeeRepository.save(existingEmployee);
return existingEmployee;
}
@Override
public void deleteEmployee(long id) {
// check whether a employee exist in a DB or not
employeeRepository.findById(id).orElseThrow(() -> new ResourceNotFoundException("Employee", "Id", id));
employeeRepository.deleteById(id);
}
}
```
> 千萬要記住要`Autowired EmployeeRepository employeeRepository`
> 基本上就是宣告一個類別型態為EmployeeRepository的實體,而employeeRepository是變數名稱,所以都要使用employeeRepository來call 內建的方法
put的邏輯比較難,務必要看懂她的巧妙思考方式
### Controller
```java=
package com.example.demo.controller;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.example.demo.model.Employee;
import com.example.demo.service.EmployeeService;
@RestController
@RequestMapping("/api/employees")
public class EmployeeController {
@Autowired
EmployeeService employeeService;
// public EmployeeController(EmployeeService employeeService) {
// super();
// this.employeeService = employeeService;
// }
// build create employee REST API
@PostMapping()
public ResponseEntity<Employee> saveEmployee(@RequestBody Employee employee) {
return new ResponseEntity<Employee>(employeeService.saveEmployee(employee), HttpStatus.CREATED);
}
// build get all employees REST API
@GetMapping
public List<Employee> getAllEmployees() {
return employeeService.getAllEmployees();
}
// build get employee by id REST API
// http://localhost:8080/api/employees/1
@GetMapping("{id}")
public ResponseEntity<Employee> getEmployeeById(@PathVariable("id") long employeeId) {
return new ResponseEntity<Employee>(employeeService.getEmployeeById(employeeId), HttpStatus.OK);
}
// build update employee REST API
// http://localhost:8080/api/employees/1
@PutMapping("{id}")
public ResponseEntity<Employee> updateEmployee(@PathVariable("id") long id, @RequestBody Employee employee) {
return new ResponseEntity<Employee>(employeeService.updateEmployee(employee, id), HttpStatus.OK);
}
// build delete employee REST API
// http://localhost:8080/api/employees/1
@DeleteMapping("{id}")
public ResponseEntity<String> deleteEmployee(@PathVariable("id") long id) {
// delete employee from DB
employeeService.deleteEmployee(id);
return new ResponseEntity<String>("Employee deleted successfully!.", HttpStatus.OK);
}
}
```
### Exception
```
package exception;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.http.HttpStatus;
@ResponseStatus(value = HttpStatus.NOT_FOUND)
public class ResourceNotFoundException extends RuntimeException{
/**
*
*/
private static final long serialVersionUID = 1L;
private String resourceName;
private String fieldName;
private Object fieldValue;
public ResourceNotFoundException(String resourceName, String fieldName, Object fieldValue) {
super(String.format("%s not found with %s : '%s'", resourceName, fieldName, fieldValue));
this.resourceName = resourceName;
this.fieldName = fieldName;
this.fieldValue = fieldValue;
}
public String getResourceName() {
return resourceName;
}
public String getFieldName() {
return fieldName;
}
public Object getFieldValue() {
return fieldValue;
}
}
```
## 測試
基本上這裡測試的邏輯都是使用postman,基本的操作是所謂的crud
就是大家說的增刪改查就對了
| 資料庫操作 | 對應的postman request |
| ---------- | --------------------- |
| create | Post |
| read | Get |
| update | Put |
| delete | Delete |
所以我的測試邏輯很簡單,你想要新增員工就使用Post請求,然會去看看我們的controller是
怎麼寫url的
```java=21
@RequestMapping("/api/employees")
```
所以你可以知道你要適用的url就會是`http://localhost:8080`+`/api/employees`
=`http://localhost:8080/api/employees`
然後再加上一些變化。以下會詳細給出例子
### 新增員工
![](https://i.imgur.com/Owbip6Z.png)
```
http://localhost:8080/api/employees
```
put the block code into body
```
{
"firstName":"mike",
"lastName":"sandy",
"email":"hotmail@gmail.com"
}
```
> 因為我這裡是新增員工,所以我不需要給定員工id,這個程式碼會自動幫我加上
### 查詢員工
```
http://localhost:8080/api/employees/5
```
![](https://i.imgur.com/00BhPUN.png)
### 更改員工
```
http://localhost:8080/api/employees/5
```
```
{
"id": 5,
"firstName": "Terry",
"lastName": "sandy",
"email": "a57249683012@gmail.com"
}
```
> 更改員工便需要在body的地方加上id,不然你不知道你是要更改誰而且要傳回完整的你想要更改的,不然他會變成null,舉例而言,如果你把lastname刪掉,他就會變成
![](https://i.imgur.com/qSEFkHP.png)
### 刪除員工
```
http://localhost:8080/api/employees/5
```
![](https://i.imgur.com/EZAypUo.png)
打開資料庫後會發現5號員工確實被刪除了
![](https://i.imgur.com/FaoTLnf.png)