Spring Boot MySQL JPA Hibernate Restful CRUD API Tutorial
Spring Boot has taken Spring framework to the next level. It has drastically reduced the configuration and setup time required for spring projects.
Spring Boot將Spring框架提升到了一個新的高度。它大大減少了Spring專案所需的配置和設定時間
You can setup a project with almost zero configuration and start building the things that actually matter to your application.
您可以使用幾乎為零的配置設定專案,然後開始構建對您的應用程式真正重要的內容
If you are new to Spring boot and want to get started with it quickly, then this blog post is for you.
In this post, we’ll build a Restful CRUD API for a simple note-taking application. A Note can have a title and some content. We’ll first build the apis to create, retrieve, update and delete a Note, and then test them using postman.
在本文中,我們將為一個簡單的筆記應用程式構建一個Restful CRUD API。筆記可以包含標題和一些內容。我們將首先構建用於建立,檢索,更新和刪除記事的api,然後使用postman對其進行測試
So, Let’s get started!
Creating the Project
Spring Boot provides a web tool called Spring Initializer to bootstrap an application quickly. Just go to http://start.spring.io and follow the steps below to generate a new project.
Spring Boot提供了一個稱為Spring Initializer的Web工具,可以快速引導應用程式。只需轉到http://start.spring.io並按照以下步驟生成一個新專案
Step 1 : Click Switch to full version on http://start.spring.io page.
Step 2 : Enter the details as follows -
- Group : com.zetcode
- Artifact : easy-notes
- Dependencies : Web, JPA, MySQL, DevTools
Once all the details are entered, click Generate Project to generate and download your project. Spring Initializer will generate the project with the details you have entered and download a zip file with all the project folders.
輸入所有詳細資訊後,單擊“生成專案”以生成並下載您的專案。Spring Initializer將使用您輸入的詳細資訊生成專案,並下載包含所有專案資料夾的zip檔案
Next, Unzip the downloaded zip file and import it into your favorite IDE.
接下來,解壓縮下載的zip檔案並將其匯入您喜歡的IDE
Exploring the Directory Structure
探索目錄結構
Following is the directory structure of our Note taking application -
以下是應用程式的目錄結構
Let’s understand the details of some of the important files and directories -
讓我們瞭解一些重要檔案和目錄的詳細資訊
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>com.zetcode</groupId>
<artifactId>easy-notes</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>jar</packaging>
<name>easy-notes</name>
<description>Rest API for a Simple Note Taking Application</description>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.3.1.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-devtools</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.20</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.hibernate.validator</groupId>
<artifactId>hibernate-validator</artifactId>
<version>6.0.18.Final</version>
</dependency>
</dependencies>
<build>
<pluginManagement>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</pluginManagement>
</build>
</project>
1. EasyNotesApplication
This is the main entry point of our Spring Boot application.
這是Spring Boot應用程式的主要入口點
package com.zetcode.easynotes;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.data.jpa.repository.config.EnableJpaAuditing;
@SpringBootApplication
@EnableJpaAuditing
public class EasyNotesApplication {
public static void main(String[] args) {
SpringApplication.run(EasyNotesApplication.class, args);
}
}
It contains a simple annotation called @SpringBootApplication
which is a combination of the following more specific spring annotations -
它包含一個名為@SpringBootApplication的簡單註解,該註解是以下更具體的spring註解的組合-
-
@Configuration : Any class annotated with
@Configuration
annotation is bootstrapped by Spring and is also considered as a source of other bean definitions.任何用@Configuration註解的類都由Spring引導,也被視為其他bean定義的源
-
@EnableAutoConfiguration : This annotation tells Spring to automatically configure your application based on the dependencies that you have added in the
pom.xml
file.這個註解告訴Spring根據在pom.xml檔案中新增的依賴項自動配置您的應用程式
For example, If
spring-data-jpa
orspring-jdbc
is in the classpath, then it automatically tries to configure aDataSource
by reading the database properties fromapplication.properties
file.例如,如果spring-data-jpa或spring-jdbc在類路徑中,則它將通過從application.properties檔案讀取資料庫屬性來自動嘗試配置DataSource
-
@ComponentScan : It tells Spring to scan and bootstrap other components defined in the current package (com.zetcode.easynotes) and all the sub-packages.
它告訴Spring掃描並引導當前程式包(com.zetcode.easynotes)和所有子程式包中定義的其它元件
The main()
method calls Spring Boot’s SpringApplication.run()
method to launch the application.
main()方法呼叫Spring Boot的SpringApplication.run()方法來啟動應用程式
2. resources/
This directory, as the name suggests, is dedicated to all the static resources, templates and property files.
顧名思義,該目錄專用於所有靜態資源,模板和屬性檔案
-
resources/static - contains static resources such as css, js and images.
包含靜態資源,例如CSS,JS和圖片
-
resources/templates - contains server-side templates which are rendered by Spring.
包含由Spring呈現的伺服器端模板
-
resources/application.properties - This file is very important. It contains application-wide properties. Spring reads the properties defined in this file to configure your application. You can define server’s default port, server’s context path, database URLs etc, in this file.
這個檔案非常重要。它包含應用程式範圍的屬性。Spring讀取此檔案中定義的屬性以配置您的應用程式。您可以在此檔案中定義伺服器的預設埠,伺服器的上下文路徑,資料庫URL等
You can refer this page for common application properties used in Spring Boot.
您可以參考此頁面以瞭解Spring Boot中使用的常見應用程式屬性
3. EasyNotesApplicationTests - Define unit and integration tests here.
在此處定義單元和整合測試
4. pom.xml - contains all the project dependencies
包含所有專案依賴項
Configuring MySQL Database
配置MySQL資料庫
As I pointed out earlier, Spring Boot tries to auto-configure a DataSource
if spring-data-jpa
is in the classpath by reading the database configuration from application.properties
file.
正如我之前指出的,如果spring-data-jpa在類路徑中,則Spring Boot會通過從application.properties檔案中讀取資料庫配置來嘗試自動配置資料來源
So, we just have to add the configuration and Spring Boot will take care of the rest.
因此,我們只需要新增配置,Spring Boot將負責其餘的工作
Open application.properties
file and add the following properties to it.
開啟application.properties檔案,並向其中新增以下屬性
## Spring DATASOURCE (DataSourceAutoConfiguration & DataSourceProperties)
spring.datasource.url = jdbc:mysql://localhost:3306/notes_app?useSSL=false&serverTimezone=UTC&useLegacyDatetimeCode=false
spring.datasource.username = root
spring.datasource.password = MyNewPass4!
## Hibernate Properties
# The SQL dialect makes Hibernate generate better SQL for the chosen database
spring.jpa.properties.hibernate.dialect = org.hibernate.dialect.MySQL8Dialect
# Hibernate ddl auto (create, create-drop, validate, update)
spring.jpa.hibernate.ddl-auto = update
You will need to create a database named notes_app in MySQL, and change the spring.datasource.username
& spring.datasource.password
properties as per your MySQL installation.
您需要在MySQL中建立一個名為notes_app的資料庫,並根據您的MySQL安裝更改spring.datasource.username和spring.datasource.password屬性
In the above properties file, the last two properties are for hibernate. Spring Boot uses Hibernate as the default JPA implementation.
在上面的屬性檔案中,最後兩個屬性用於hibernate。Spring Boot使用Hibernate作為預設的JPA實現
The property spring.jpa.hibernate.ddl-auto
is used for database initialization. I’ve used the value “update” for this property.
spring.jpa.hibernate.ddl-auto屬性用於資料庫初始化。我已經為此屬性使用了“更新”值
It does two things -
-
When you define a domain model, a table will automatically be created in the database and the fields of the domain model will be mapped to the corresponding columns in the table.
定義域模型時,將在資料庫中自動建立一個表,並且該域模型的欄位將對映到表中的相應列
-
Any change to the domain model will also trigger an update to the table. For example, If you change the name or type of a field, or add another field to the model, then all these changes will be reflected in the mapped table as well.
域模型的任何更改也將觸發對該表的更新。例如,如果您更改欄位的名稱或型別,或向模型新增另一個欄位,則所有這些更改也將反映在對映表中
Using update for spring.jpa.hibernate.ddl-auto
property is fine for development. But, For production, You should keep the value of this property to “validate”, and use a database migration tool like Flyway for managing changes in the database schema.
對spring.jpa.hibernate.ddl-auto屬性使用update可以進行開發。但是,對於生產而言,您應將此屬性的值保留為“ validate”,並使用Flyway之類的資料庫遷移工具來管理資料庫架構中的更改
Creating the Note model
建立筆記模型
All right! Let’s now create the Note
model. Our Note
model has following fields -
現在建立一個Note模型。Note模型具有以下欄位
-
id
: Primary Key with Auto Increment.具有自動增量的主鍵
-
title
: The title of the Note. (NOT NULL field)筆記的標題(非空欄位)
-
content
: Note’s content. (NOT NULL field)筆記的內容(非空欄位)
-
createdAt
: Time at which theNote
was created.筆記建立的時間
-
updatedAt
: Time at which theNote
was updated.筆記更新的時間
Now, let’s see how we can model this in Spring. Create a new package called model
inside com.zetcode.easynotes
and add a class named Note.java
with following contents -
現在,讓我們看看如何在Spring中對此建模。在com.zetcode.easynotes內部建立一個名為model的包,並新增一個名為Note.java的類,其內容如下:
package com.zetcode.easynotes.model;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import org.springframework.data.annotation.CreatedDate;
import org.springframework.data.annotation.LastModifiedDate;
import org.springframework.data.jpa.domain.support.AuditingEntityListener;
import javax.persistence.*;
import javax.validation.constraints.NotBlank;
import java.util.Date;
@Entity
@Table(name = "notes")
@EntityListeners(AuditingEntityListener.class)
@JsonIgnoreProperties(value = {"createdAt", "updateAt"}, allowGetters = true)
public class Note {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@NotBlank
private String title;
@NotBlank
private String content;
@Column(nullable = false, updatable = false)
@Temporal(TemporalType.TIMESTAMP)
@CreatedDate
private Date createdAt;
@Column(nullable = false)
@Temporal(TemporalType.TIMESTAMP)
@LastModifiedDate
private Date updateAt;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public String getContent() {
return content;
}
public void setContent(String content) {
this.content = content;
}
public Date getCreatedAt() {
return createdAt;
}
public void setCreatedAt(Date createdAt) {
this.createdAt = createdAt;
}
public Date getUpdateAt() {
return updateAt;
}
public void setUpdateAt(Date updateAt) {
this.updateAt = updateAt;
}
}
-
All your domain models must be annotated with
@Entity
annotation. It is used to mark the class as a persistent Java class.所有域模型都必須使用@Entity註解進行註釋。它用於將類標記為永續性Java類
-
@Table
annotation is used to provide the details of the table that this entity will be mapped to.註解被用於提供此實體對映到的表的詳細資訊
-
@Id
annotation is used to define the primary key.註解用於定義主鍵
-
@GeneratedValue
annotation is used to define the primary key generation strategy. In the above case, we have declared the primary key to be anAuto Increment
field.註解用於定義主鍵生成策略。在上述情況下,我們已將主鍵宣告為“自動增量”欄位
-
@NotBlank
annotation is used to validate that the annotated field isnot null
or empty.註解用於驗證帶註釋的欄位不為null或為空
-
@Column
annotation is used to define the properties of the column that will be mapped to the annotated field. You can define several properties like name, length, nullable, updateable etc.註解用於定義將被對映到帶註釋欄位的列的屬性。您可以定義幾個屬性,例如名稱,長度,可為空,可更新等
By default, a field named
createdAt
is mapped to a column namedcreated_at
in the database table. i.e. all camel cases are replaced with underscores.預設情況下,名為createdAt的欄位對映到資料庫表中名為created_at的列。也就是說,所有駝峰案例都用下劃線代替
If you want to map the field to a different column, you can specify it using -
如果要將欄位對映到其他列,則可以使用-
@Column(name = "created_on") private String createdAt;
-
@Temporal
annotation is used withjava.util.Date
andjava.util.Calendar
classes. It converts the date and time values from Java Object to compatible database type and vice versa.註解與java.util.Date和java.util.Calendar類一起使用。它將日期和時間值從Java物件轉換為相容的資料庫型別,反之亦然
-
@JsonIgnoreProperties
annotation is a Jackson annotation. Spring Boot uses Jackson for Serializing and Deserializing Java objects to and from JSON.註解是Jackson註解。Spring Boot使用Jackson將Java物件與JSON進行序列化和反序列化
This annotation is used because we don’t want the clients of the rest api to supply the
createdAt
andupdatedAt
values. If they supply these values then we’ll simply ignore them. However, we’ll include these values in the JSON response.使用此註解的原因是,我們不希望其餘api的客戶端提供createdAt和updatedAt值。如果它們提供了這些值,那麼我們將忽略它們。但是,我們會將這些值包括在JSON響應中
Enable JPA Auditing
啟用JPA稽核
In our Note
model we have annotated createdAt
and updatedAt
fields with @CreatedDate
and @LastModifiedDate
annotations respectively.
在Note模型中,分別用@CreatedDate和@LastModifiedDate註釋了createdAt和updatedAt欄位
Now, what we want is that these fields should automatically get populated whenever we create or update an entity.
現在,想要的是每當我們建立或更新實體時都應自動填充這些欄位
To achieve this, we need to do two things -
為此,我們需要做兩件事-
1. Add Spring Data JPA’s AuditingEntityListener
to the domain model.
將Spring Data JPA的AuditingEntityListener新增到域模型
We have already done this in our Note
model with the annotation @EntityListeners(AuditingEntityListener.class)
.
我們已經在Note模型中使用@EntityListeners(AuditingEntityListener.class)註解進行了此操作
2. Enable JPA Auditing in the main application.
在主應用程式中啟用JPA稽核
Open EasyNotesApplication.java
and add @EnableJpaAuditing
annotation.
開啟EasyNotesApplication.java並新增@EnableJpaAuditing註解
package com.zetcode.easynotes;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.data.jpa.repository.config.EnableJpaAuditing;
@SpringBootApplication
@EnableJpaAuditing
public class EasyNotesApplication {
public static void main(String[] args) {
SpringApplication.run(EasyNotesApplication.class, args);
}
}
Creating NoteRepository to access data from the database
建立NoteRepository以訪問資料庫中的資料
The next thing we’re gonna do is create a repository to access Note’s data from the database.
我們要做的下一件事是建立一個儲存庫,以從資料庫訪問Note的資料
Well, Spring Data JPA has got us covered here. It comes with a JpaRepository
interface which defines methods for all the CRUD operations on the entity, and a default implementation of JpaRepository
called SimpleJpaRepository
.
Spring Data JPA在這裡為我們提供了覆蓋。它帶有JpaRepository介面,該介面定義了實體上所有CRUD操作的方法,以及JpaRepository的預設實現,稱為SimpleJpaRepository
Cool! Let’s create the repository now. First, Create a new package called repository
inside the base package com.zetcode.easynotes
. Then, create an interface called NoteRepository
and extend it from JpaRepository
-
現在建立儲存庫。首先,在基本軟體包com.example.easynotes內建立一個名為“ repository”的新軟體包。然後,建立一個名為NoteRepository的介面,並從JpaRepository擴充套件它
package com.zetcode.easynotes.repository;
import com.zetcode.easynotes.model.Note;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
@Repository
public interface NoteRepository extends JpaRepository<Note, Long> {
}
Note that, we have annotated the interface with @Repository
annotation. This tells Spring to bootstrap the repository during component scan.
請注意,我們已經使用@Repository註解對介面進行了註釋。這告訴Spring在元件掃描期間引導儲存庫
Great! That is all you have to do in the repository layer. You will now be able to use JpaRepository’s methods like save()
, findOne()
, findAll()
, count()
, delete()
etc.
這就是您在儲存庫層中要做的所有事情。現在,您將能夠使用JpaRepository方法,例如save(),findOne(),findAll(),count(),delete()等
You don’t need to implement these methods. They are already implemented by Spring Data JPA’s SimpleJpaRepository
. This implementation is plugged in by Spring automatically at runtime.
您無需實現這些方法。它們已經由Spring Data JPA的SimpleJpaRepository實現。Spring會在執行時自動插入該實現
Checkout all the methods available from SimpleJpaRepository’s documentation.
檢出SimpleJpaRepository文件中可用的所有方法
Spring Data JPA has a bunch of other interesting features like Query methods (dynamically creating queries based on method names), Criteria API, Specifications, QueryDsl etc.
Spring Data JPA還有許多其它有趣的功能,例如查詢方法(基於方法名稱動態建立查詢),標準API,規範,QueryDsl等
I strongly recommend you to checkout the Spring Data JPA’s documentation to learn more.
我強烈建議您檢視Spring Data JPA文件以瞭解更多資訊
Creating Custom Business Exception
建立自定義業務異常
We’ll define the Rest APIs for creating, retrieving, updating, and deleting a Note
in the next section.
在下一部分中,將定義用於建立,檢索,更新和刪除的Rest API
The APIs will throw a ResourceNotFoundException
whenever a Note
with a given id
is not found in the database.
每當在資料庫中找不到具有給定id的Note時,API都會引發ResourceNotFoundException
Following is the definition of ResourceNotFoundException
. (I’ve created a package named exception
inside com.example.easynotes
to store this exception class) -
以下是ResourceNotFoundException的定義。(我在com.zetcode.easynotes內建立了一個名為exception的程式包來儲存此異常類)
package com.zetcode.easynotes.exception;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.ResponseStatus;
@ResponseStatus(value = HttpStatus.NOT_FOUND)
public class ResourceNotFoundException extends RuntimeException {
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;
}
}
Notice the use of @ResponseStatus
annotation in the above exception class. This will cause Spring boot to respond with the specified HTTP status code whenever this exception is thrown from your controller.
注意上面的異常類中@ResponseStatus註解的使用。每當從控制器丟擲此異常時,這將導致Spring Boot以指定的HTTP狀態程式碼響應
package com.zetcode.easynotes.controller;
import com.zetcode.easynotes.exception.ResourceNotFoundException;
import com.zetcode.easynotes.model.Note;
import com.zetcode.easynotes.repository.NoteRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import javax.validation.Valid;
import java.util.List;
@RestController
@RequestMapping("api")
public class NoteController {
@Autowired
NoteRepository noteRepository;
@GetMapping("/notes")
public List<Note> getAllNotes() {
return noteRepository.findAll();
}
@PostMapping("/notes")
public Note createNote(@Valid @RequestBody Note note) {
return noteRepository.save(note);
}
@GetMapping("/notes/{id}")
public Note getNoteById(@PathVariable(value = "id") Long noteId) {
return noteRepository.findById(noteId)
.orElseThrow(() -> new ResourceNotFoundException("Note", "id", noteId));
}
@PutMapping("/notes/{id}")
public Note updateNote(@PathVariable(value = "id") Long noteId, @Valid @RequestBody Note noteDetails) {
Note note = noteRepository.findById(noteId)
.orElseThrow(() -> new ResourceNotFoundException("Note", "id", noteId));
note.setTitle(noteDetails.getTitle());
note.setContent(noteDetails.getContent());
Note updateNote = noteRepository.save(note);
return updateNote;
}
@DeleteMapping("/notes/{id}")
public ResponseEntity<?> deleteNote(@PathVariable(value = "id") Long noteId) {
Note note = noteRepository.findById(noteId)
.orElseThrow(() -> new ResourceNotFoundException("Note", "id", noteId));
noteRepository.delete(note);
return ResponseEntity.ok().build();
}
}
@RestController
annotation is a combination of Spring’s @Controller
and @ResponseBody
annotations.
@RestController註解是Spring的@Controller和@ResponseBody註解的組合
The @Controller
annotation is used to define a controller and the @ResponseBody
annotation is used to indicate that the return value of a method should be used as the response body of the request.
@Controller註解用於定義控制器,而@ResponseBody註解用於指示應將方法的返回值用作請求的響應主體
@RequestMapping("/api")
declares that the url for all the apis in this controller will start with /api
.
@RequestMapping(“/api”)宣告此控制器中所有api的URL將以/api開頭
Let’s now look at the implementation of all the apis one by one.
現在,讓我們一一看一下所有api的實現
1. Get All Notes (GET /api/notes)
// Get All Notes
@GetMapping("/notes")
public List<Note> getAllNotes() {
return noteRepository.findAll();
}
The above method is pretty straightforward. It calls JpaRepository’s findAll()
method to retrieve all the notes from the database and returns the entire list.
上面的方法非常簡單。它呼叫JpaRepository的findAll()方法從資料庫中檢索所有筆記,並返回整個列表
Also, The @GetMapping("/notes")
annotation is a short form of @RequestMapping(value="/notes", method=RequestMethod.GET)
.
另外,@GetMapping(“/notes”)註解是@RequestMapping(value =“/notes”,method = RequestMethod.GET)的縮寫
2. Create a new Note (POST /api/notes)
// Create a new Note
@PostMapping("/notes")
public Note createNote(@Valid @RequestBody Note note) {
return noteRepository.save(note);
}
The @RequestBody
annotation is used to bind the request body with a method parameter.
@RequestBody註解用於將請求主體與方法引數繫結
The @Valid
annotation makes sure that the request body is valid. Remember, we had marked Note’s title and content with @NotBlank
annotation in the Note
model?
@Valid註解確保請求正文有效。還記得我們在Note模型中用@NotBlank批註標記Note的標題和內容嗎?
If the request body doesn’t have a title or a content, then spring will return a 400 BadRequest
error to the client.
如果請求正文沒有標題或內容,那麼spring將向客戶端返回400 BadRequest錯誤
3. Get a Single Note (Get /api/notes/{noteId})
// Get a Single Note
@GetMapping("/notes/{id}")
public Note getNoteById(@PathVariable(value = "id") Long noteId) {
return noteRepository.findById(noteId)
.orElseThrow(() -> new ResourceNotFoundException("Note", "id", noteId));
}
The @PathVariable
annotation, as the name suggests, is used to bind a path variable with a method parameter.
顧名思義,@PathVariable註解用於將路徑變數與方法引數繫結
In the above method, we are throwing a ResourceNotFoundException
whenever a Note
with the given id is not found.
在上述方法中,每當找不到具有給定id的Note時,都將引發ResourceNotFoundException
This will cause Spring Boot to return a 404 Not Found error to the client (Remember, we had added a @ResponseStatus(value = HttpStatus.NOT_FOUND)
annotation to the ResourceNotFoundException
class).
這將導致Spring Boot向客戶端返回404 Not Found錯誤(請記住,我們已經在ResourceNotFoundException類中添加了@ResponseStatus(value = HttpStatus.NOT_FOUND)註解)
4. Update a Note (PUT /api/notes/{noteId})
// Update a Note
@PutMapping("/notes/{id}")
public Note updateNote(@PathVariable(value = "id") Long noteId,
@Valid @RequestBody Note noteDetails) {
Note note = noteRepository.findById(noteId)
.orElseThrow(() -> new ResourceNotFoundException("Note", "id", noteId));
note.setTitle(noteDetails.getTitle());
note.setContent(noteDetails.getContent());
Note updatedNote = noteRepository.save(note);
return updatedNote;
}
5. Delete a Note (DELETE /api/notes/{noteId})
// Delete a Note
@DeleteMapping("/notes/{id}")
public ResponseEntity<?> deleteNote(@PathVariable(value = "id") Long noteId) {
Note note = noteRepository.findById(noteId)
.orElseThrow(() -> new ResourceNotFoundException("Note", "id", noteId));
noteRepository.delete(note);
return ResponseEntity.ok().build();
}
Running the Application
We’ve successfully built all the apis for our application. Let’s now run the app and test the apis.
我們已經為我們的應用程式成功構建了所有API。現在執行應用程式並測試api
Just go to the root directory of the application and type the following command to run it -
只需轉到應用程式的根目錄並鍵入以下命令即可執行它-
$ mvn spring-boot:run
The application will start at Spring Boot’s default tomcat port 8080.
該應用程式將從Spring Boot的預設tomcat埠8080啟動
Great! Now, It’s time to test our apis using postman.
現在,該使用postman測試我們的api了
Testing the APIs
Creating a new Note using POST /api/notes
API
Retrieving all Notes using GET /api/notes
API
Retrieving a single Note using GET /api/notes/{noteId}
API
Updating a Note using PUT /api/notes/{noteId}
API
Deleting a Note using DELETE /api/notes/{noteId}
API
More Resources
The application that we built in this article had only one domain model. If you want to learn how to build REST APIs in an application with more than one domain models exhibiting a one-to-many relationship between each other, then I highly recommend you to check out the following article -
在本文中構建的應用程式只有一個域模型。如果想學習如何在一個以上具有相互之間一對多關係的域模型的應用程式中構建REST API,那麼我強烈建議您檢視以下文章-
Spring Boot, JPA, Hibernate One-To-Many mapping example
Also, Go through the following article to learn how to build a full stack application with authentication and authorization using Spring Boot, Spring Security and React -
另外,閱讀以下文章,瞭解如何使用Spring Boot,Spring Security和React構建具有身份驗證和授權的完整全棧應用程式-
Spring Boot + Spring Security + JWT + MySQL + React Full Stack Polling App - Part 1
Conclusion
Congratulations folks! We successfully built a Restful CRUD API using Spring Boot, Mysql, Jpa and Hibernate.
You can find the source code for this tutorial on my github repository. Feel free to clone the repository and build upon it.
Thank you for reading. Please ask any questions in the comment section below.