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.