读书笔记《building-restful-web-services-with-spring-5-second-edition》Plain REST(无反应)和文件上载中的CRUD操作
在上一章中,我们探索了一个支持 Reactive 的 CRUD 操作。由于 Spring 开发团队仍在更新更多的 Reactive 实体,因此 Reactive 支持还没有达到他们的水平。尽管 Spring 5 Reactive 支持运行良好,但他们仍需要对其进行改进以使其稳定。在考虑了这些指示之后,我们计划避免响应式支持,以使您更简单。
在本章中,我们将介绍 Spring 5(无 Reactive)REST 中的基本 CRUD(创建、读取、更新和删除)API。在本章之后,您将能够在没有 Reactive 支持的情况下在 Spring 5 中进行简单的 CRUD 操作。另外,我们将讨论 Spring 5 中的文件上传选项。
在本章中,我们将介绍以下方法:
- Mapping CRUD operations to HTTP methods
- Creating a user
- Updating a user
- Deleting a user
- Reading (selecting) a user
- File uploads in Spring
要创建基本的 Spring project 资源,您可以使用 Spring Initializr (https://start.spring.io/ )。在 Spring Initializr 中,提供必要的详细信息:
使用 Java 和 Spring Boot Maven 项目 ="userinput">1.5.9。
组:com.packtpub.restapp
Artifact:票务管理
搜索依赖项: 选择 Web(使用 Tomcat 和 Web MVC 进行全栈 Web 开发)  依赖关系 
填写详细信息后,点击Generate Project;然后它将以 ZIP 格式创建 Spring 基本资源。我们可以通过将它们导入 Eclipse 来开始使用该项目。 
Spring 5 POM 文件将如下所示:
让我们删除父级以简化 POM:
当我们删除父级时,我们可能需要在所有依赖项中添加版本。让我们在依赖项中添加版本:
由于依赖神器spring-boot-starter-web version 1.5.9 是基于Spring 4.3.11 ,我们将不得不升级到 Spring 5。让我们清理并升级我们的 POM 文件以引入 Spring 5 更新:
您可以在前面的 POM 文件中看到 Spring 5 相关的依赖项。让我们使用 REST 端点来测试它们。首先,创建一个 Spring Boot 主文件来初始化 Spring Boot:
您可以通过右键单击项目并选择 Run As | 开始在 Eclipse 上运行 Spring Boot Spring Boot 应用。如果这样做,您将在 Eclipse 控制台中看到日志。
以下是示例日志。您可能看不到完全匹配;但是,您将了解服务器运行日志的外观:
您应该在日志的最后几行中看到 Tomcat 在端口(s):8080 上启动。
当您检查 URI http://localhost:8080 时,您将看到以下错误:
上面的错误是说应用程序中没有配置相应的URI。让我们通过在 com.packtpub.restapp 包下创建一个名为 HomeController 的控制器来解决这个问题:
在前面的代码中,我们使用 simpleHomeController 的虚拟控制器>map 结果。此外,我们添加了新的控制器,我们需要让这些类被我们的主应用程序自动扫描,在我们的例子中是 TicketManagementApplication 类。我们将通过在主类中添加 @ComponentScan("com.packtpub") 来告诉他们。最后,我们的主类将如下所示:
当您重新启动 Spring Boot 应用程序时,您将看到 REST 端点工作(localhost:8080):
让我们执行用户 CRUD 操作。正如我们之前讨论过 CRUD 概念一样,这里我们将只讨论 Spring 5 上的用户管理(没有 Reactive 支持)。让我们为 CRUD 端点填写所有虚拟方法。在这里,我们可以创建 UserContoller 并填写所有用于 CRUD 用户操作的方法:
我们已经为所有 CRUD 操作填充了基本端点。如果您在 Postman 上使用适当的方法调用它们,例如 GET、POST、PUT< /code> 和 DELETE, 您将看到提及相应消息的结果。
例如,对于 getAllUsers API (localhost:8080/user),您将获得:
让我们实现 getAllUsers API。对于这个 API,我们可能需要创建一个名为User的模型类 在包com.packtpub.model下:
现在,我们将为 getAllUsers 实现添加代码。由于这是业务逻辑,我们将创建一个单独的 UserService 和 UserServiceImpl 类。通过这样做,我们可以将业务逻辑保留在不同的位置,以避免代码复杂性。 
UserService 界面如下所示:
UserServiceImpl 类的实现如下:
在前面的实现中,我们在构造函数中创建了虚拟用户。当类由 Spring 配置初始化时,这些用户将被添加到列表中。
UserController类调用 getAllUsers 方法如下:
在前面的代码中,我们通过在控制器文件中自动装配来调用 getAllUsers 方法。 @Autowired 将在幕后完成所有的实例化魔法。 
如果您现在运行该应用程序,您可能会遇到以下错误:
此错误背后的原因是您的应用程序无法识别 UserService,因为它位于不同的包中。我们可以通过在 TicketManagementApplication 类中添加 @ComponentScan("com.packtpub") 来解决这个问题。这将识别不同子包中的所有 @service 和其他 bean:
现在您可以在调用 API 时看到结果(http://localhost:8080/user):
就像我们之前在 第 4 章中所做的,Spring REST 中的 CRUD 操作 我们要去在这个实现getUser业务逻辑部分。让我们使用 Java 8 Streams 在此处添加 getUser 方法。
UserService 界面如下所示:
 UserServiceImpl class 实现如下:
在之前的 getUser 方法实现中,我们使用 Java 8 Streams 和 lambda 表达式通过 userid 获取用户。与使用传统的 for 循环不同,lambda 表达式更容易获取详细信息。在前面的代码中,我们通过过滤条件检查用户。如果用户匹配,则返回具体用户;否则,它将创建一个带有 "Not available" 消息的虚拟用户。 
 getUser方法的UserController类如下:
您可以通过在客户端访问 http://localhost:8080/user/100 来验证 API(使用 Postman 或 SoapUI 进行测试):
 UserService 界面如下所示:
 UserServiceImpl class 实现如下:
 createUser方法的UserController类如下:
前面的代码会将用户添加到我们的地图中。在这里,我们使用了 userid和username作为方法参数。 您可以在以下 API 调用中查看 userid 和 username:
 
 
       当您使用 SoapUI/Postman 调用此方法时,您将得到以下结果。在这种情况下,我们使用参数(userid, username)而不是 JSON 输入。这只是为了简化过程:
 UserService 界面如下所示:
 UserServiceImpl class 实现如下:
在前面的方法中,我们使用了基于 Java Streams 的实现来更新用户。我们只需应用过滤器并检查用户是否可用。如果 userid 不匹配,则会抛出 RuntimeException。如果用户可用,我们会得到对应的用户,然后我们更新username。
 updateUser方法的UserController类如下:
我们将尝试将 username 从 David 更新为 Sammy on < code class="literal">userid 值为 100。我们可以从以下屏幕截图中查看 API 详细信息:
 
 
       当我们使用 SoapUI/Postman 扩展 (http://localhost:8080/userUPDATE 方法) >),我们将得到以下结果:
您可以通过检查 Postman 扩展 (http://localhost:8080/user);你会得到以下结果:
在 NIO libraries 和 Spring 的 MultipartFile 选项的支持下,文件上传变得非常容易。在这里,我们将添加文件上传代码。 
FileUploadService 界面如下所示:
在前面的代码中,我们只是定义了让具体类(实现类)覆盖我们的方法的方法。我们使用了 MultipartFile 这里转发一个文件,比如一个媒体文件来完成我们的业务逻辑。
FileUploadServerImpl类实现 如下: 
前面的代码中,我们在构造函数中自己设置了位置,所以在Spring Boot App初始化的时候,会设置正确的路径;如果需要,它将在上述位置创建一个特定文件夹。
在 uploadFile 方法中,我们首先获取文件并清理它们。我们使用名为 StringUtils 的 Spring 实用程序类来清理文件路径。您可以在此处查看清洁过程:
如果文件为空,我们只需抛出一个异常。您可以在此处检查异常:
然后是真正的文件上传逻辑!我们只需使用 Files.copy 方法将文件从客户端复制到服务器位置。如果发生任何错误,我们会抛出 RuntimeException:
由于主要实现由具体类完成,控制器只需将 MultipartFile 传递给服务。我们在这里使用了 POST 方法,因为它将是上传文件的完美方法。此外,您可以看到我们使用 @Autowired 选项来使用 service 方法。
 uploadFile方法的FileController类如下:
