1.前言
Spring Boot将Spring框架提升到了一个新的水平。它极大地缩短了Spring项目所需的配置和设置时间。
您可以设置几乎为零配置的项目,并开始构建对您的应用程序而言非常重要的事物。
如果你是Spring的新手,想快速入门,那么这篇博文就是为你准备的。
在这篇文章中,我们将为简单的笔记应用程序构建一个Restful CRUD API。注释可以有标题和一些内容。我们将首先构建apis来创建,检索,更新和删除一个Note,然后使用POSTMAN测试它们。
2.创建项目
Spring Boot提供了一个名为Spring Initializer的Web工具来快速引导应用程序。只需访问http://start.spring.io并按照以下步骤生成一个新项目。
第2步:输入详细信息如下 -
Group : com.example
Artifact : easy-notes
Name : easy-notes
Description : Rest API for a Simple Note Taking Application
Package Name : com.example.easynotes
Packaging : jar (This is the default value)
Java Version : 1.8 (Default)
Dependencies : Web, JPA, MySQL, DevTools
输入完所有细节后,单击生成项目以生成并下载项目。Spring初始化程序将生成具有您输入的详细信息的项目并下载包含所有项目文件夹的zip文件。
接下来,解压下载的zip文件并将其导入到您最喜欢的IDE中。
3.查看目录结构
以下是我们的笔记记录应用程序的目录结构 -
让我们了解一些重要文件和目录的细节 -
1. EasyNotesApplication
这是我们的Spring Boot应用程序的主要入口点。
package com.example.easynotes;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class EasyNotesApplication {
public static void main(String[] args) {
SpringApplication.run(EasyNotesApplication.class, args);
}
}
它包含一个简单的注释@SpringBootApplication,它是以下更具体的Spring注释的组合 -
@Configuration:用@ConfigurationAnnotation注解的任何类由Spring引导,并且也被认为是其他bean定义的来源。
@EnableAutoConfiguration:这个注解告诉Spring根据你添加到pom.xml文件中的依赖来自动配置你的应用程序。
例如,如果spring-data-jpa在类路径中,则它会自动尝试DataSource通过从application.properties文件中读取数据库属性来配置一个。
@ComponentScan:它告诉Spring扫描并引导当前包(com.example.easynotes)和所有子包中定义的其他组件。
该main()方法调用Spring Boot的SpringApplication.run()方法来启动应用程序。
2.资源/
顾名思义,该目录专用于所有静态资源,模板和属性文件。
资源/静态 - 包含静态资源,如css,js和图像。
资源/模板 - 包含由Spring呈现的服务器端模板。
resources / application.properties - 这个文件非常重要。它包含应用程序范围内的属性。Spring读取这个文件中定义的属性来配置你的应用程序。您可以在此文件中定义服务器的默认端口,服务器的上下文路径,数据库URL等。
您可以参考此页面来了解Spring Boot中使用的常见应用程序属性。
3. EasyNotesApplicationTests - 在这里定义单元和集成测试。
4. pom.xml - 包含所有的项目依赖关系
4.配置MySQL数据库
正如我前面指出的那样,Spring Boot 通过从文件中读取数据库配置,尝试在类路径中自动配置DataSourceif 。spring-data-jpaapplication.properties
所以,我们只需要添加配置,而Spring Boot将负责其余部分。
打开application.properties文件并向其中添加以下属性。
## Spring DATASOURCE (DataSourceAutoConfiguration & DataSourceProperties)
spring.datasource.url = jdbc:mysql://localhost:3306/notes_app?useSSL=false
spring.datasource.username = root
spring.datasource.password = root
## Hibernate Properties
# The SQL dialect makes Hibernate generate better SQL for the chosen database
spring.jpa.properties.hibernate.dialect = org.hibernate.dialect.MySQL5InnoDBDialect
# Hibernate ddl auto (create, create-drop, validate, update)
spring.jpa.hibernate.ddl-auto = update
您需要在MySQL中创建一个名为notes_app的数据库,并根据您的MySQL安装更改spring.datasource.username&spring.datasource.password属性。
在上面的属性文件中,最后两个属性用于休眠。Spring Boot使用Hibernate作为默认的JPA实现。
该属性spring.jpa.hibernate.ddl-auto用于数据库初始化。我已经使用这个属性的值“update”。
它做了两件事 -
定义域模型时,将自动在数据库中创建一个表,并将域模型的字段映射到表中的相应列。
对域模型的任何更改也会触发表的更新。例如,如果您更改字段的名称或类型,或将其他字段添加到模型中,则所有这些更改也会反映在映射表中。
使用更新的spring.jpa.hibernate.ddl-auto财产是好的发展。但是,对于生产,您应该保留此属性的值以“验证”,并使用像Flyway这样的数据库迁移工具来管理数据库模式中的更改。
6.创建Note模型
好吧!现在让我们来创建Note模型。我们的Note模型有以下领域 -
id:带自动递增的主键。
title:备注的标题。(NOT NULL字段)
content:笔记的内容。(NOT NULL字段)
createdAt:Note创建时间。
updatedAt:Note更新时间。
现在,让我们看看我们如何在Spring中对它进行建模。创建一个名为modelinside 的新包,com.example.easynotes并添加一个名为Note.java以下内容的类-
package com.example.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", "updatedAt"},
allowGetters = true)
public class Note implements Serializable {
@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 updatedAt;
// Getters and Setters ... (Omitted for brevity)
}
您的所有域模型必须使用注释进行@Entity注释。它用于将该类标记为持久的Java类。
@Table 注释用于提供此实体将映射到的表的详细信息。
@Id 注释用于定义主键。
@GeneratedValue注释用于定义主键生成策略。在上述情况下,我们宣布主键是一个Auto Increment字段。
@NotBlank注释用于验证注释字段是否为not null空。
@Column注释用于定义将映射到注释字段的列的属性。您可以定义多个属性,如名称,长度,可为空,可更新等。
默认情况下,名为的字段将createdAt映射到created_at数据库表中指定的列。即所有的骆驼案件都被下划线取代。
如果您想将字段映射到不同的列,可以使用以下命令指定它 -
@Column(name = "created_on")
private String createdAt;
@Temporal注释java.util.Date和java.util.Calendar类一起使用。它将Java Object中的日期和时间值转换为兼容的数据库类型,反之亦然。
@JsonIgnoreProperties注释是杰克逊的注释。Spring Boot使用Jackson将JSON序列化和反序列化Java对象。
使用这个注解是因为我们不希望剩下的api的客户端提供createdAt和updatedAt值。如果他们提供这些值,那么我们会简单地忽略它们。但是,我们将在JSON响应中包含这些值。
7.启用JPA审核
在我们的Note模型中,我们已经注解createdAt,并updatedAt与领域@CreatedDate,并@LastModifiedDate分别标注。
现在,我们想要的是,只要我们创建或更新实体,这些字段就会自动填充。
要做到这一点,我们需要做两件事 -
1.将Spring Data JPA添加AuditingEntityListener到域模型中。
我们已经在我们的Note模型中使用了注释@EntityListeners(AuditingEntityListener.class)。
2.在主应用程序中启用JPA审核。
打开EasyNotesApplication.java并添加@EnableJpaAuditing注释。
@SpringBootApplication
@EnableJpaAuditing
public class EasyNotesApplication {
public static void main(String[] args) {
SpringApplication.run(EasyNotesApplication.class, args);
}
}
8.创建NoteRepository以访问数据库中的数据
接下来我们要做的是创建一个存储库来访问数据库中的Note数据。
那么,Spring Data JPA已经在这里介绍了我们。它带有一个JpaRepository接口,该接口定义实体上所有CRUD操作的方法,以及一个默认的JpaRepository调用实现SimpleJpaRepository。
现在创建存储库。首先,创建一个repository在基础包内调用的新包com.example.easynotes。然后,创建一个接口NoteRepository并将其从JpaRepository-
package com.example.easynotes.repository;
import com.example.easynotes.model.Note;
import org.springframework.data.jpa.repository.JpaRepository;
@Repository
public interface NoteRepository extends JpaRepository {
}
请注意,我们使用注释标注了界面@Repository。这告诉Spring在组件扫描期间引导存储库。
大!这就是您在存储库层中必须做的所有事情。现在,您将能够使用JpaRepository的方法,如save(),findOne(),findAll(),count(),delete()等。
你不需要实现这些方法。Spring Data JPA已经实现了它们SimpleJpaRepository。这个实现在运行时被Spring自动插入。
9.创建自定义业务例外
我们将Note在下一节中定义用于创建,检索,更新和删除a的Rest API 。
ResourceNotFoundException只要在数据库中找不到Note给定的API,API就会抛出id。
以下是定义ResourceNotFoundException。(我创建了一个名为exceptioninside 的包com.example.easynotes来存储这个异常类) -
package com.example.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;
}
}
注意@ResponseStatus在上述异常类中使用注释。这将导致Spring引导以指定的HTTP状态码进行响应,无论何时从您的控制器抛出此异常。
10.创建NoteController
最后一步 - 我们现在将创建REST API来创建,检索,更新和删除注释。
首先,controller在里面创建一个新的包com.example.easynotes。然后,创建一个NoteController.java包含以下内容的新课程-
package com.example.easynotes.controller;
import com.example.easynotes.exception.ResourceNotFoundException;
import com.example.easynotes.model.Note;
import com.example.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;
// Get All Notes
// Create a new Note
// Get a Single Note
// Update a Note
// Delete a Note
}
@RestController注释是Spring @Controller和@ResponseBody注释的组合。
该@Controller注释被用来定义一个控制器和所述@ResponseBody注释被用于指示一个方法的返回值应作为所述请求的响应主体。
@RequestMapping("/api")声明此控制器中所有apis的url将以/api。
现在我们来看看所有apis的执行情况。
1.获取所有Notes(GET / api / notes)
// Get All Notes
@GetMapping("/notes")
public List getAllNotes() {
return noteRepository.findAll();
}
上述方法非常简单。它调用JpaRepository的findAll()方法从数据库中检索所有注释并返回整个列表。
此外,@GetMapping("/notes")注释是一种简短形式@RequestMapping(value="/notes", method=RequestMethod.GET)。
2.创建一个新的Note(POST / api / notes)
// Create a new Note
@PostMapping("/notes")
public Note createNote(@Valid @RequestBody Note note) {
return noteRepository.save(note);
}
该@RequestBody注释用于将请求主体与方法参数绑定。
该@Valid注释可以确保请求主体是有效的。请记住,我们在模型中标注了注释的标题和@NotBlank注释内容Note?
如果请求主体没有标题或内容,那么spring会400 BadRequest向客户端返回错误。
3.获取单个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));
}
的@PathVariable注释,顾名思义,是用来与方法参数路径变量绑定。
在上面的方法中,我们抛出一个没有找到给定id的ResourceNotFoundExceptiona Note。
这将导致Spring Boot向客户端返回一个404 Not Found错误(请记住,我们已经@ResponseStatus(value = HttpStatus.NOT_FOUND)为ResourceNotFoundException该类添加了注释)。
4.更新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.删除一个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();
}
运行应用程序
我们已经成功为我们的应用程序构建了所有apis。现在运行该应用并测试apis。
只需转到应用程序的根目录并输入以下命令即可运行它 -
$ mvn spring-boot:run
该应用程序将从Spring Boot的默认tomcat端口8080开始。
大!现在,是时候用邮差测试我们的apis了。
测试API
使用POST /api/notesAPI 创建新的note
使用GET /api/notesAPI 检索所有Notes
使用GET /api/notes/{noteId}API 检索单个Note
使用PUT /api/notes/{noteId}API 更新note
使用DELETE /api/notes/{noteId}API 删除note