Spring Boot是一个自以为是的框架,可简化Spring应用程序的开发。 它使我们摆脱了复杂配置文件的束缚,并帮助我们创建了不需要外部servlet容器的独立Spring应用程序。
这听起来实在令人难以置信,但Spring Boot确实可以完成所有这一切 。
这篇博客文章演示了实现REST API多么容易,该API为保存到MongoDB数据库中的待办事项提供CRUD操作。
让我们开始创建我们的Maven项目。
注意:这篇博客文章假定您已经安装了MongoDB数据库。 如果尚未执行此操作,则可以按照博客文章中的说明进行操作: 使用MongoDB访问数据 。
创建我们的Maven项目
我们可以按照以下步骤创建Maven项目:
- 使用spring-boot-starter-parent POM作为我们的Maven项目的父POM。 这可以确保我们的项目从Spring Boot继承合理的默认设置。
- 将Spring Boot Maven插件添加到我们的项目中。 这个插件使我们可以将应用程序打包到可执行的jar文件中,将其打包到war存档中,然后运行该应用程序。
- 配置我们项目的依赖项。 我们需要配置以下依赖项:
- spring-boot-starter-web依赖关系提供了Web应用程序的依赖关系。
- spring-data-mongodb依赖项提供了与MongoDB文档数据库的集成。
- 启用Spring Boot的Java 8支持。
- 配置我们的应用程序的主类。 此类负责配置和启动我们的应用程序。
pom.xml文件的相关部分如下所示:
<properties><!-- Enable Java 8 --><java.version>1.8</java.version><project.build.sourceEncoding>UTF-8</project.build.sourceEncoding><!-- Configure the main class of our Spring Boot application --><start-class>com.javaadvent.bootrest.TodoAppConfig</start-class>
</properties><!-- Inherit defaults from Spring Boot -->
<parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>1.1.9.RELEASE</version>
</parent><dependencies><!-- Get the dependencies of a web application --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><!-- Spring Data MongoDB--><dependency><groupId>org.springframework.data</groupId><artifactId>spring-data-mongodb</artifactId></dependency>
</dependencies><build><plugins><!-- Spring Boot Maven Support --><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId></plugin></plugins>
</build>
补充阅读:
- Spring Boot参考手册:9.1.1 Maven安装
- Spring Boot参考手册:12.1 Maven
- Spring Boot Maven插件–用法
让我们继续前进,了解如何配置应用程序。
配置我们的应用
我们可以按照以下步骤配置Spring Boot应用程序:
- 创建一个com.javaadvent.bootrest包的TodoAppConfig类。
- 启用Spring Boot自动配置。
- 配置Spring容器以扫描从com.javaadvent.bootrest包的子包中找到的组件。
- 将main()方法添加到TodoAppConfig类,并通过运行我们的应用程序来实现。
TodoAppConfig类的源代码如下所示:
package com.javaadvent.bootrest;import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;@Configuration
@EnableAutoConfiguration
@ComponentScan
public class TodoAppConfig {public static void main(String[] args) {SpringApplication.run(TodoAppConfig.class, args);}
}
现在,我们已经创建了配置类,用于配置和运行我们的Spring Boot应用程序。 由于从类路径中找到了MongoDB jar,因此Spring Boot使用其默认设置来配置MongoDB连接。
补充阅读:
- Spring Boot参考手册:13.2定位主应用程序类
- Spring Boot参考手册:14.配置类
- @EnableAutoConfiguration批注的Javadoc
- Spring Boot参考手册:15.自动配置
- SpringApplication类的Javadoc
- Spring Boot参考手册:27.2.1连接到MongoDB数据库
让我们继续并实现我们的REST API。
实施我们的REST API
我们需要实现一个REST API,为待办事项提供CRUD操作。 我们的REST API的要求是:
- 发送到URL'/ api / todo'的POST请求必须使用从请求正文中找到的信息来创建新的todo条目,并返回创建的todo条目的信息。
- 发送到网址“ / api / todo / {id}”的DELETE请求必须删除从网址中找到ID的待办事项,并返回已删除的待办事项的信息。
- 发送到URL'/ api / todo'的GET请求必须返回从数据库中找到的所有todo条目。
- 发送到URL'/ api / todo / {id}'的GET请求必须返回其id从URL中找到的todo条目的信息。
- 发送到url'/ api / todo / {id}'的PUT请求必须使用从请求正文中找到的信息来更新现有待办事项的信息,并返回更新后的待办事项的信息。
我们可以通过执行以下步骤来满足这些要求:
- 创建包含单个待办事项条目信息的实体。
- 创建用于将待办事项保存到MongoDB数据库并从中查找待办事项的存储库。
- 创建负责将DTO映射到域对象,反之亦然的服务层。 服务层的目的是将域模型与Web层隔离。
- 创建用于处理HTTP请求并将正确的响应返回给客户端的控制器类。
注意:此示例非常简单,我们可以将存储库注入到控制器中。 但是,由于在实现实际应用程序时这不是可行的策略,因此我们将在Web层和存储库层之间添加一个服务层。
让我们开始吧。
创建实体
我们需要创建包含单个待办事项条目信息的实体类。 我们可以按照以下步骤进行操作:
- 将id , description和title字段添加到创建的实体类中。 通过使用@Id注释对id字段进行注释来配置实体的id字段。
- 指定常量( MAX_LENGTH_DESCRIPTION和MAX_LENGTH_TITLE ),这些常量指定描述和标题字段的最大长度。
- 将静态生成器类添加到实体类。 此类用于创建新的Todo对象。
- 向实体类添加一个update()方法。 如果给定有效值作为方法参数,则此方法仅更新实体的标题和说明 。
Todo类的源代码如下所示:
import org.springframework.data.annotation.Id;import static com.javaadvent.bootrest.util.PreCondition.isTrue;
import static com.javaadvent.bootrest.util.PreCondition.notEmpty;
import static com.javaadvent.bootrest.util.PreCondition.notNull;final class Todo {static final int MAX_LENGTH_DESCRIPTION = 500;static final int MAX_LENGTH_TITLE = 100;@Idprivate String id;private String description;private String title;public Todo() {}private Todo(Builder builder) {this.description = builder.description;this.title = builder.title;}static Builder getBuilder() {return new Builder();}//Other getters are omittedpublic void update(String title, String description) {checkTitleAndDescription(title, description);this.title = title;this.description = description;}/*** We don't have to use the builder pattern here because the constructed * class has only two String fields. However, I use the builder pattern * in this example because it makes the code a bit easier to read.*/static class Builder {private String description;private String title;private Builder() {}Builder description(String description) {this.description = description;return this;}Builder title(String title) {this.title = title;return this;}Todo build() {Todo build = new Todo(this);build.checkTitleAndDescription(build.getTitle(), build.getDescription());return build;}}private void checkTitleAndDescription(String title, String description) {notNull(title, "Title cannot be null");notEmpty(title, "Title cannot be empty");isTrue(title.length() <= MAX_LENGTH_TITLE,"Title cannot be longer than %d characters",MAX_LENGTH_TITLE);if (description != null) {isTrue(description.length() <= MAX_LENGTH_DESCRIPTION,"Description cannot be longer than %d characters",MAX_LENGTH_DESCRIPTION);}}
}
补充阅读:
- 第2项:面对许多构造函数参数时,请考虑构造器
让我们继续并创建与MongoDB数据库通信的存储库。
创建存储库
我们必须创建存储库接口,该接口用于将Todo对象保存到MondoDB数据库并从中检索Todo对象。
如果我们不想使用Java 8对Spring Data的支持,则可以通过创建扩展CrudRepository <T,ID>接口的接口来创建存储库。 但是,由于我们要使用Java 8支持,因此必须遵循以下步骤:
- 创建一个扩展Repository <T,ID>接口的接口。
- 将以下存储库方法添加到创建的接口:
- void delete(删除Todo的方法)删除作为方法参数给出的todo条目。
- List <Todo> findAll()方法返回从数据库中找到的所有待办事项条目。
- Optional <Todo> findOne(String id)方法返回单个待办事项的信息。 如果未找到待办事项,则此方法返回一个空的Optional 。
- Todo save(保存Todo的方法)将新的todo项保存到数据库中,并返回保存的todo项。
TodoRepository接口的源代码如下所示:
import org.springframework.data.repository.Repository;import java.util.List;
import java.util.Optional;interface TodoRepository extends Repository<Todo, String> {void delete(Todo deleted);List<Todo> findAll();Optional<Todo> findOne(String id);Todo save(Todo saved);
}
补充阅读:
- CrudRepository <T,ID>接口的Javadoc
- Repository <T,ID>接口的Javadoc
- Spring Data MongoDB参考手册:5.使用Spring Data存储库
- Spring Data MongoDB参考手册:5.3.1对存储库定义进行微调
让我们继续并创建示例应用程序的服务层。
创建服务层
首先 ,我们必须创建一个服务接口,为待办事项提供CRUD操作。 TodoService接口的源代码如下所示:
import java.util.List;interface TodoService {TodoDTO create(TodoDTO todo);TodoDTO delete(String id);List<TodoDTO> findAll();TodoDTO findById(String id);TodoDTO update(TodoDTO todo);
}
TodoDTO类是DTO,其中包含单个todo条目的信息。 在创建示例应用程序的Web层时,我们将详细讨论它。
其次 ,我们必须实现TodoService接口。 我们可以按照以下步骤进行操作:
- 通过使用构造函数注入将我们的存储库注入服务类。
- 将私有Todo findTodoById(String id)方法添加到服务类,并通过返回找到的Todo对象或抛出TodoNotFoundException来实现它。
- 在服务类中添加一个私有TodoDTO convertToDTO(Todo model)方法,并通过将Todo对象转换为TodoDTO对象并返回创建的对象来实现该方法。
- 添加一个私有List <TodoDTO> convertToDTOs(List <Todo>模型)并通过将Todo对象的列表转换成TodoDTO对象的列表并返回创建的列表来实现它。
- 实现TodoDTO create(TodoDTO todo)方法。 此方法创建一个新的Todo对象,将创建的对象保存到MongoDB数据库,并返回创建的todo条目的信息。
- 实现TodoDTO delete(String id)方法。 此方法找到删除的Todo对象,将其删除,然后返回删除的Todo条目的信息。 如果未找到具有给定id的Todo对象,则此方法将抛出TodoNotFoundException 。
- 实现List <TodoDTO> findAll()方法。 此方法从数据库检索所有Todo对象,将它们转换为TodoDTO对象列表,然后返回创建的列表。
- 实现TodoDTO findById(String id)方法。 此方法从数据库中查找Todo对象,将其转换为TodoDTO对象,然后返回创建的TodoDTO对象。 如果未找到待办事项条目,则此方法将抛出TodoNotFoundException 。
- 实现TodoDTO update(TodoDTO todo)方法。 此方法从数据库中查找更新的Todo对象,更新其标题和说明 ,保存并返回更新的信息。 如果未找到更新的Todo对象,则此方法将抛出TodoNotFoundException 。
MongoDBTodoService的源代码如下所示:
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;import java.util.List;
import java.util.Optional;import static java.util.stream.Collectors.toList;@Service
final class MongoDBTodoService implements TodoService {private final TodoRepository repository;@AutowiredMongoDBTodoService(TodoRepository repository) {this.repository = repository;}@Overridepublic TodoDTO create(TodoDTO todo) {Todo persisted = Todo.getBuilder().title(todo.getTitle()).description(todo.getDescription()).build();persisted = repository.save(persisted);return convertToDTO(persisted);}@Overridepublic TodoDTO delete(String id) {Todo deleted = findTodoById(id);repository.delete(deleted);return convertToDTO(deleted);}@Overridepublic List findAll() {List todoEntries = repository.findAll();return convertToDTOs(todoEntries);}private List convertToDTOs(List models) {return models.stream().map(this::convertToDTO).collect(toList());}@Overridepublic TodoDTO findById(String id) {Todo found = findTodoById(id);return convertToDTO(found);}@Overridepublic TodoDTO update(TodoDTO todo) {Todo updated = findTodoById(todo.getId());updated.update(todo.getTitle(), todo.getDescription());updated = repository.save(updated);return convertToDTO(updated);}private Todo findTodoById(String id) {Optional result = repository.findOne(id);return result.orElseThrow(() -> new TodoNotFoundException(id));}private TodoDTO convertToDTO(Todo model) {TodoDTO dto = new TodoDTO();dto.setId(model.getId());dto.setTitle(model.getTitle());dto.setDescription(model.getDescription());return dto;}
}
现在,我们已经创建了示例应用程序的服务层。 让我们继续创建控制器类。
创建控制器类
首先 ,我们需要创建DTO类,其中包含单个待办事项的信息,并指定用于确保仅将有效信息保存到数据库的验证规则。 TodoDTO类的源代码如下所示:
import org.hibernate.validator.constraints.NotEmpty;import javax.validation.constraints.Size;public final class TodoDTO {private String id;@Size(max = Todo.MAX_LENGTH_DESCRIPTION)private String description;@NotEmpty@Size(max = Todo.MAX_LENGTH_TITLE)private String title;//Constructor, getters, and setters are omitted
}
补充阅读:
- Hibernate Validator 5.0.3参考手册
其次 ,我们必须创建控制器类来处理发送到我们的REST API的HTTP请求,并将正确的响应发送回客户端。 我们可以按照以下步骤进行操作:
- 使用构造函数注入将服务注入控制器。
- 将create()方法添加到我们的控制器并通过以下步骤实现它:
- 从请求正文中读取创建的待办事项条目的信息。
- 验证创建的待办事项条目的信息。
- 创建一个新的待办事项条目并返回创建的待办事项条目。 将响应状态设置为201。
- 通过将已删除的待办事项条目的ID委托给我们的服务来实现delete()方法,并返回已删除的待办事项条目。
- 通过从数据库中找到待办事项并返回找到的待办事项来实现findAll()方法。
- 通过从数据库中找到待办事项并返回找到的待办事项来实现findById()方法。
- 通过执行以下步骤来实现update()方法:
- 从请求正文中读取更新的待办事项条目的信息。
- 验证更新的待办事项条目的信息。
- 更新待办事项的信息,并返回更新后的待办事项。
- 创建一个@ExceptionHandler方法,如果未找到todo条目(抛出TodoNotFoundException ),则将响应状态设置为404。
TodoController类的源代码如下所示:
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestController;import javax.validation.Valid;
import java.util.List;@RestController
@RequestMapping("/api/todo")
final class TodoController {private final TodoService service;@AutowiredTodoController(TodoService service) {this.service = service;}@RequestMapping(method = RequestMethod.POST)@ResponseStatus(HttpStatus.CREATED)TodoDTO create(@RequestBody @Valid TodoDTO todoEntry) {return service.create(todoEntry);}@RequestMapping(value = "{id}", method = RequestMethod.DELETE)TodoDTO delete(@PathVariable("id") String id) {return service.delete(id);}@RequestMapping(method = RequestMethod.GET)List<TodoDTO> findAll() {return service.findAll();}@RequestMapping(value = "{id}", method = RequestMethod.GET)TodoDTO findById(@PathVariable("id") String id) {return service.findById(id);}@RequestMapping(value = "{id}", method = RequestMethod.PUT)TodoDTO update(@RequestBody @Valid TodoDTO todoEntry) {return service.update(todoEntry);}@ExceptionHandler@ResponseStatus(HttpStatus.NOT_FOUND)public void handleTodoNotFound(TodoNotFoundException ex) {}
}
注意:如果验证失败,我们的REST API将验证错误作为JSON返回,并将响应状态设置为400。如果您想了解更多有关此信息,请阅读标题为: Spring从Trenches:将验证添加到REST API的博客文章。 。
这就对了。 现在,我们已经创建了一个REST API,它为待办事项提供CRUD操作并将其保存到MongoDB数据库中。 让我们总结一下我们从此博客文章中学到的知识。
摘要
这篇博客文章教会了我们三件事:
- 我们可以通过仅声明两个依赖项来获得Maven所需的依赖项: spring-boot-starter-web和spring-data-mongodb 。
- 如果我们对Spring Boot的默认配置感到满意,则可以使用其自动配置支持并将新的jar“丢弃”到类路径中来配置Web应用程序。
- 我们学习了如何创建一个简单的REST API,该API将信息保存到MongoDB数据库并从中查找信息。
您可以从Github获得此博客文章的示例应用程序 。
翻译自: https://www.javacodegeeks.com/2014/12/creating-a-rest-api-with-spring-boot-and-mongodb-2.html