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 or spring-jdbc is in the classpath, then it automatically tries to configure a DataSource by reading the database properties from application.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 the Note was created.

    笔记创建的时间

  • updatedAt: Time at which the Note 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 an Auto Increment field.

    注解用于定义主键生成策略。在上述情况下,我们已将主键声明为“自动增量”字段

  • @NotBlank annotation is used to validate that the annotated field is not 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 named created_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 with java.util.Date and java.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 and updatedAt 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.

posted @ 2020-07-01 18:27  PrimerPlus  阅读(351)  评论(0编辑  收藏  举报