读书笔记《developing-java-applications-with-spring-and-spring-boot-ebook》从春天开始-CMS应用程序
现在,我们将创建我们的第一个应用程序;至此,我们已经了解了 Spring 的概念,并准备将它们付诸实践。在本章的开头,我们将介绍创建 Web 应用程序的 Spring 依赖项,同时我们也知道 Spring Initializr 是一个很棒的项目,它使开发人员能够创建 Spring 框架项目,并且可以根据需要添加任意数量的依赖项。在本章中,我们将学习如何在 IDE 和命令行上构建我们的第一个 Spring 应用程序,公开我们的第一个端点,了解它是如何工作的,并了解 Spring REST 支持的主要注释。我们将弄清楚如何为 CMS (内容管理系统< /strong>) 应用程序并了解依赖注入如何在 Spring 容器中工作。我们将满足 Spring 的原型并实现我们的第一个 Spring bean。在本章的最后,我们将解释如何创建一个视图层并将其与 AngularJS 集成。
在本章中,将涉及以下主题:
- Creating the project structure
- Running the first Spring application
- Introducing the REST support
- Understanding the Dependency Injection in Spring
现在我们将使用 Spring 框架创建我们的第一个 application;我们将为 CMS 应用程序创建一个基本结构 with Spring Initializr。这个页面有助于引导我们的应用程序,它是一种指南,允许我们配置对 Maven 或 Gradle 的依赖项。我们还可以选择 Spring Boot 的语言和版本。
页面如下所示:
在 Project Metadata
部分,我们可以放置 Maven 项目的坐标;有一个 group 字段引用 groupId
标记, 我们有引用 artifactId
的工件。这都是针对 Maven 坐标的。
dependencies 部分启用 Spring 依赖项的配置,该字段具有自动完成功能并帮助开发人员放入正确的依赖项。
在开始写代码和学习amazing的东西之前,我们先来了解一下CMS项目,这个项目的主要目的是帮助企业管理不同主题的CMS内容。该项目有三个主要实体:
- The
News
class is the most important, it will store the content of the news. - It has a category which makes the search easier, and we can also group news by category, and of course, we can group by the user who has created the news. The news should be approved by other users to make sure it follows the company rules.
- The news has some tags as well, as we can see the application is pretty standard, the business rules are easy as well; this is intentional because we keep the focus on the new things we will learn.
现在我们知道 Spring Initializr (https://start.spring.io) 的工作原理和business 规则我们需要遵循,我们准备创建项目。让我们现在就做。
在 Search for Dependencies
字段中键入 MVC
词。 Web module 将作为一个选项出现,Web 模块包含嵌入式 Tomcat 和 Spring 的全栈 web 开发MVC,选择它。另外,我们需要在这个模块中加入 Thymeleaf
依赖。它是一个模板引擎,对本章末尾的视图功能很有用。输入Thymeleaf
,它包含了 Thymeleaf 模板引擎,并包含与Spring 的集成。该模块将出现,然后也将其选中。现在我们可以看到 Web
和 Thymeleaf
在 < strong class="userinput">Selected Dependencies
窗格:
在我们完成项目definition 并选择项目依赖项后,我们就可以下载项目了。可以使用 Generate Project
按钮完成,点击它。该项目将被下载。在这个阶段,项目已经准备好开始我们的工作了:
Note
>在打开项目之前,我们必须将Spring Initializr生成的工件解压到想要的位置。命令应该是: unzip -d <target_destination> /<path_to_file>/cms.zip
。按照示例进行操作: unzip -d /home/john /home/john/Downloads/cms.zip.
现在,我们可以在 IDE 中打开项目。我们打开它,看看项目的基本结构。
使用 Import
Project
在 IntelliJ IDEA 上打开项目或 Open
选项(两者类似),会显示如下页面:
然后我们可以打开或导入 pom.xml
文件。
应显示以下项目结构:
打开pom.xml,
我们有三个依赖, spring-boot-starter-thymeleaf
, < code class="literal">spring-boot-starter-web, spring-boot-starter-test
,还有一个有趣的插件, spring-boot-maven-plugin
.
这些 starter
依赖是开发人员的捷径,因为它们为模块提供了完整的依赖。比如spring-boot-starter-web,
有 web-mvc
,jackson-databind
、hibernate-validator-web
等;这些依赖项必须在类路径上才能运行 Web 应用程序,并且启动器使这项任务变得相当容易。
此外,我们还有一个 spring-boot-maven-plugin
,这个很棒的插件为 Maven 提供 Spring Boot 支持。它使您能够将应用程序打包在 Fat-JAR 中,并且插件 支持 运行、启动和停止目标,以及与我们的应用程序交互。
现在,这对 Maven 配置来说已经足够了;让我们看一下Java文件。
Spring Initializr 为我们创建了一个类,一般来说,这个类的名称是工件名称加上 Application
, 在我们的例子中是 CmsApplication< /code>,这个类应该是这样的:
我们这里有一些有趣的东西,让我们了解它们。 @SpringBootApplication
是 Spring Boot 应用的必备注解;它是@Configuration
、@EnableAutoConfiguration
和@Component
注解。让我们深入研究:
- The first annotation,
@Configuration
indicates that the class can produce a beans definitions for the Spring container. This is an interesting annotation to work with external dependencies such asDataSources
; this is the most common use case for this annotation. - The second annotation,
@EnableAutoConfiguration
means that with the SpringApplicationContext
container, it will try to help us configure the default beans for the specific context. For instance, when we create the web MVC application with Spring Boot, we will probably need a web server container to run it. In a default configuration, the Spring container, together with@EnableAutoConfiguration
, will configure a bean Tomcat-embedded container for us. This annotation is very helpful for developers. - The
@Component
is a stereotype, the container understands which class is considered for auto-detection and needs to instantiate it.
SpringApplication
类负责从 main 方法引导 Spring 应用程序,它会创建一个 ApplicationContext
实例,照顾configuration 文件提供的配置,最后,它将加载由注释定义的单例bean。
我们将在 IntelliJ IDEA 和 command 行中运行应用程序。学习是一项重要的任务,因为我们在不同的开发环境中工作;有时应用程序的配置有点复杂,我们无法使用 IDE 运行它,或者有时公司有不同的 IDE 作为标准,因此我们将学习两种不同的方式。
command 行是一个更generic 工具来运行项目。此外,由于 Spring Boot Maven 插件,这项任务很容易。有两种运行方式,我们将同时介绍这两种方式。
第一个是Spring Boot Maven插件的一个goal,简单明了;打开终端然后转到根项目文件夹,注意这是我们有 pom.xml,
和 execute 如下命令:
Maven 现在将编译项目并运行主类 CmsApplication
,我们应该会看到以下输出:
通过Java文件运行,我们需要编译并打包,然后我们就可以运行项目了 使用 Java 命令行。要编译和打包它,我们可以使用非常标准的 Maven 命令,如下所示:
项目编译打包成Fat-JAR后,我们可以执行JAR文件,进入目标文件夹,查看该文件夹下的文件,大概结果如下:
我们的目标文件夹中有两个主要文件,cms-0.0.1-SNAPSHOT.jar
和 cms-0.0.1-SNAPSHOT .jar.original
, .original
扩展名的文件不可执行。它是编译产生的原始工件,另一个是我们的可执行文件。就是我们要找的,我们执行一下,输入如下命令:
结果应如显示。应用程序已启动并正在运行:
这部分就是这样,在下一节中,我们将创建第一个 REST (Representational State Transfer) 资源并了解 REST 端点的工作方式。
现在,我们在本节中启动并运行了一个应用程序,我们将添加一些 REST 端点并为 CMS 应用程序建模一些初始类,即 REST endpoints 将对 AngularJS 集成很有用。
API 的必需特性之一是文档,而 Swagger 是帮助我们完成这些任务 的流行工具。 Spring 框架支持 Swagger,我们可以通过几个注解来实现。项目的Spring Fox是正确的工具来做这件事,本章我们就来看看这个工具。
我们开工吧。
在我们开始创建我们的类之前,我们将添加Lombok
依赖在我们的项目中。这是一个很棒的库,它在编译时提供了一些有趣的东西,例如 GET
/SET
, Val
关键字使变量成为最终变量,@Data
使类具有一些默认方法,例如 getter/setters,等于
和hashCode
。
将以下依赖项放入 pom.xml
文件中:
provided
范围指示 Maven 不要在 JAR 文件中include 这个依赖项因为我们在编译时需要它。我们在运行时不需要它。等待 Maven 下载依赖项,现在就是这样。
另外,我们可以使用 Reimport All Maven Project
s
由 IntelliJ IDEA 提供,位于 Maven 项目选项卡中,如下所示:
现在,我们将创建我们的模型,这些模型是用@Data< /代码>。
这个类代表我们域中的新闻,目前它没有任何行为。只有属性和 getter/setter 被暴露;未来,我们会添加一些行为:
Review
类可以在 GitHub 上找到:(https://github.com/PacktPublishing/Spring-5.0-By-Example/tree/master/Chapter02/ src/main/java/springfive/cms/domain/models)。
正如我们所见,它们是代表我们的 CMS 应用程序域的简单 Java 类。它是我们应用程序的核心,所有领域逻辑都将驻留在这些类中。这是一个重要的特征。
我们已经创建了模型,我们可以开始思考我们的 REST 资源。我们将创建三个主要资源:
CategoryResource
which will be responsible for theCategory
class.- The second one is
UserResource
. It will manage the interactions between theUser
class and the REST APIs. - The last one, and more important as well, will be the
NewsResource
which will be responsible for managing news entities, such as reviews.
我们将创建我们的第一个 REST 资源,让我们开始 使用 CategoryResource
负责管理我们的 Category
类的类。该实体的实现将很简单,我们 将创建CRUD 端点,例如创建、检索、更新和删除。在创建 API 时,我们必须牢记两件重要的事情。第一个是正确的 HTTP 动词,例如 POST
、GET
、PUT
和
DELETE
。 REST API 必须有正确的 HTTP 动词,因为它为我们提供了有关 API 的内在知识。它是任何与我们的 API 交互的模式。另一件事是状态码,它与我们必须遵循的第一个相同,这是开发人员很容易识别的模式。 Richardson 成熟度模型 可以帮助我们创建令人惊叹的 REST API,并且该模型引入了一些级别来衡量 REST API,它是一种温度计。
首先,我们将为我们的 API 创建骨架。想想关于您的应用程序需要哪些功能。 在下一节中,我们< id="id326249813" class="indexterm"> 将解释如何在我们的 REST API 中添加服务层。现在,让我们构建一个 CategoryResource
类,我们的实现可能如下所示:
CategoryRequest
可以在 GitHub (https://github.com/PacktPublishing/Spring-5.0-By-Example/tree/master/Chapter02/src/主/java/springfive/cms/domain/vo)。
我们这里有一些重要的概念。第一个是 @RestController
。它指示 Spring 框架 CategoryResource
类将通过 Web-MVC 模块公开 REST 端点。这个注解会在框架中配置一些东西,比如 HttpMessageConverters
来处理HTTP请求和响应,比如XML或者JSON。当然,我们需要类路径上的正确库来处理 JSON 和 XML。另外,在请求中添加一些标头,例如 Accept
和Content-Type
。 这个注解是在4.0版本中引入的.它是一种语法糖注解,因为它使用 @Controller
和 @ResponseBody
进行注解。
第二个是@RequestMapping
注解,这个重要的注解负责我们类中的HTTP请求和响应。当我们在类级别使用它时,这段代码的用法非常简单,它将传播给所有方法,并且方法使用它作为相对。 @RequestMapping
注解有不同的用例。它允许我们配置 HTTP 动词、参数和标头。
最后,我们有@GetMapping
、@PostMapping
、@DeleteMapping
、和 @PutMapping
, 这些注解是用正确的 HTTP 动词配置 @RequestMapping
的一种快捷方式;一个优点是这些注释使代码更具可读性。
除了 removeCategory
之外,所有方法都返回 ResponseEntity
类,它使我们能够在接下来处理正确的 HTTP 状态码部分。
UserResource
class 是 same 作为 CategoryResource
,但它使用 User
类。我们可以在 GitHub (https://github.com/PacktPublishing/Spring-5.0-By-Example/tree/master/Chapter02)。
NewsResource
class 是必不可少的,这个 endpoint 使用户能够查看news 之前注册过,它还提供了一个端点来返回更新的新闻。这是一个重要特征,因为我们只对相关新闻感兴趣。不相关的新闻不能在门户上显示。资源类应如下所示:
NewsRequest
类可以在 GitHub。
注意 HTTP 动词和 HTTP 状态码,因为我们需要遵循正确的语义。
现在,我们已经为 REST 层准备好了 skeleton,在本节中,我们将开始为我们的应用程序。我们将展示依赖注入如何在底层工作,学习 Spring Framework 上的原型注解,并开始考虑我们的持久性存储,这将在下一节中介绍。
我们需要对我们的模型进行一些更改,特别是在 News
类。在我们的业务规则中,我们需要保证我们的信息安全,然后我们需要查看所有新闻。我们将添加一些方法来添加用户完成的新评论,并且我们还将添加一个方法来检查新闻是否已被所有强制评论者评论。
我们的应用程序需要有一个 persistence 存储,即使应用程序出现故障,我们的记录也可以在其中加载。我们将为我们的存储库创建假实现。 在 第 3 章,使用 Spring Data 和 Reactive 的持久性 时尚 ,我们将介绍 Spring Data 项目,这些项目可帮助开发人员使用出色的 DSL 创建令人惊叹的存储库。现在,我们将创建一些 Spring bean 来将我们的元素存储在内存中,让我们这样做。
让我们从我们最简单的服务开始, CategoryService
类,这个类的预期行为是 CRUD 操作。然后,我们需要一个表示我们的 persistence 存储或存储库实现,目前,我们正在使用临时存储和 < code class="literal">ArrayList 与我们的类别。在下一章中,我们将为我们的 CMS 应用程序添加真正的持久性。
让我们创建我们的第一个 Spring 服务。实现在以下代码段中:
这里有一些新东西。这个类将被 Spring 容器检测并实例化,因为它有一个 @Service
注解。正如我们所见,该类没有什么特别之处。它不一定扩展任何类或实现接口。我们在构造函数上收到了 CategoryRepository
这个类将由 Spring 容器提供,因为我们指示容器生成它,但在 Spring 5 中不需要在构造函数中使用 @Autowired
。它之所以有效,是因为我们在该类中只有一个构造函数,而 Spring 会检测到它。此外,我们有几个表示 CRUD 行为的方法,而且很容易理解。
UserService
类与 CategoryService
非常相似, 但是rules 是关于 User
实体,对于这个实体我们没有什么特别的。我们有 @Service
注解,我们也收到了 UserRepository
构造函数。它非常简单易懂。我们将展示 UserService
实现,它必须是这样的:
注意带有 @Service
注解的类声明。这是 Spring 生态系统中非常常见的实现。此外,我们还可以找到 @Component
、@Repository
注释。 @Service
和 @Component
是服务层通用的,行为上没有区别。 @Repository
稍微改变了一些行为,因为框架将转换数据访问层上的一些异常。
Swagger 是 document 网络 API 的事实上的工具,该工具允许开发人员对 API 进行建模,创建一种交互式的播放方式使用 API,还提供了一种简单的方法来生成 多种语言的客户端实现。
API 文档是吸引开发人员使用我们的 API 的绝佳方式。
在开始配置之前,我们需要添加 required 依赖项。这些依赖项包括我们项目中的 Spring Fox,并提供了许多注释来正确配置 Swagger。让我们添加这些依赖项。
新的依赖项位于 pom.xml
文件中:
第一个依赖是 Swagger 的核心,带有注释和相关的东西。 Spring Fox Swagger UI 依赖项在 HTML 中提供了丰富的接口,允许开发人员与 API 进行交互。
dependencies 已添加,现在我们可以为 Swagger 配置基础架构了。配置非常简单。我们将使用 @Configuration
创建一个类来为 Spring 容器生成 Swagger 配置。我们开始做吧。
@Configuration
指示 Spring 为 Swagger 生成 bean 定义。注释@EnableSwagger2
添加了对 Swagger 的支持。 @EnableSwagger2
应该伴随 @Configuration
, 它是强制性的。
Docket
类是创建 API 定义的构建器,它为 Spring Swagger MVC 框架的配置提供了合理的默认值和便捷的方法。
方法 .apis(RequestHandlerSelectors.withClassAnnotation(RestController.class))
的调用指示框架处理使用 @RestController
注释的类.
自定义 API 文档的方法有很多,例如,有一种方法可以添加身份验证标头。
这就是 Swagger 配置,在下一节中,我们将创建第一个文档化 API。
我们将从 CategoryResource
类开始,因为它是 simple 来理解的,我们需要把重点放在技术上。我们将添加几个注释,神奇的事情就会发生,让我们来做个魔术吧。
CategoryResource
类应该是这样的:
有很多新的注释 需要理解。 @Api
是将此类配置为 Swagger 资源的根注释。有很多配置,但我们将使用标签和描述,因为它们就足够了。
@ApiOperation
描述了我们 API 中的操作,通常针对请求的路径。 value
属性作为 Swagger 上的汇总字段,是操作的简要说明,notes
是对操作的描述一个操作(更详细的内容)。
最后一个是 @ApiResponse
,它使开发人员能够描述操作的响应。通常,他们希望配置状态码和消息来描述操作的结果。
现在,我们已经配置了 Swagger 集成,我们可以在 Web 浏览器上查看 API 文档。为此,我们需要导航到 http://localhost:8080/swagger-ui.html
这个页面应该会显示出来:
我们可以看到在我们的 CMS 应用程序中配置的 API 端点。现在,我们来看看我们之前配置的category
,点击 显示/隐藏
链接。输出应该是:
如我们所见,我们的Category API
中有五个操作,操作有一个路径和一个摘要来帮助理解目的。我们可以单击请求的操作并查看有关操作的详细信息。动手吧,点击List categories
查看详细文档。页面如下所示:
出色的工作。现在我们有了一个 amazing API 和优秀的文档。做得好。
让我们继续创建我们的 CMS 应用程序。
AngularJS 框架已经成为几年来的趋势,社区 非常活跃,该项目是由 Google 创建的。
该框架的主要思想是帮助开发人员处理前端层的复杂性,尤其是在 HTML 部分。 HTML 标记语言是静态的。它是创建静态文档的绝佳工具,但如今它已不再是现代 Web 应用程序的必需品。这些应用程序需要是动态的。世界各地的 UX 团队,努力创造令人惊叹的应用程序,具有不同的效果,这些人试图让应用程序对用户更舒适。
AngularJS 增加了用一些额外的属性和标签来扩展 HTML 的可能性。在本节中,我们将在前端应用程序上添加一些有趣的行为。我们开始做吧。
在我们的 CMS 应用程序中,我们将使用一些 Angular 组件工作。我们将使用 控制器
它将与我们的 HTML 交互并处理某些页面的行为,例如显示错误消息的页面。 Services
负责处理基础设施代码,例如与我们的 CMS API 交互。本书不打算成为 AngularJS 指南。但是,我们将看一些有趣的概念来开发我们的应用程序。
AngularJS 的常用标签有:
ng-app
ng-controller
ng-click
ng-hide
ng-show
这些标签包含在 AngularJS 框架中。社区创建和维护了更多标签。例如,有一个用于处理 HTML 表单的库,我们将使用它在我们的 CMS 门户中添加动态行为。
控制器是 framework 到 handle 应用程序的业务逻辑。它们应该用于控制应用程序中的数据流。控制器通过 ng-controller
指令附加到 DOM。
要向我们的视图添加一些动作,我们需要在控制器上创建函数,方法是创建函数并将它们添加到 $scope
对象中。
控制器不能用于执行 DOM 操作、格式化数据和过滤数据,它被认为是 AngularJS 世界中的最佳实践。
通常,控制器注入服务对象以委托处理业务逻辑。我们将在下一节中了解服务。
服务是在我们的应用程序中处理业务逻辑的对象。在一些 情况下,它们可以用于 处理状态。服务对象是一个单例,这意味着我们在整个应用程序中只有一个实例。
在我们的应用程序中,服务负责与我们基于 Spring Boot 构建的 CMS API 进行交互。让我们这样做。
Spring Boot 框架允许我们服务 静态文件。这些文件应位于以下文件夹之一的类路径中, /static
、/public
、/resources
, 或 /META-INF/resources
。
我们将使用 /static
文件夹,在这个文件夹中,我们将放置我们的 AngularJS 应用程序。 有一些标准可以模块化 AngularJS 应用程序文件夹结构,这取决于应用程序大小和要求。我们将使用最简单的风格来保持对 Spring 集成的关注。看项目结构:
有一些资产可以启动和运行 AngularJS 应用程序。我们将使用内容交付网络 (CDN) 加载 AngularJS 框架,Angular UI-Router 有助于处理我们的 Web 应用程序上的路由,以及帮助开发我们的页面的 Bootstrap 框架。
Note
内容交付网络是分布在世界各地的代理服务器。它使内容具有更高的可用性并提高了性能,因为它将托管在更靠近最终用户的地方。详细说明可以在 CloudFare 页面 (https ://www.cloudflare.com/learning/cdn/what-is-a-cdn/)。
然后我们可以开始配置 我们的AngularJS 应用程序。让我们从开始我们的入口点, index.html
:
这里有一些重要的事情。让我们了解他们。
ng-app
标签是一个用于引导 AngularJS 应用程序的指令。这个标签是应用程序的根元素,通常放在 <body>
或 <html>
标签上。
ui-view
标签指示 Angular UI-Router HTML 文档的哪一部分 将由应用程序状态处理,换句话说,指定的部分具有动态行为和变化取决于路由系统。看下面的代码片段:
这部分代码可以在 index.hml
文件中找到。
在 ui-view
之后,我们有我们的 JavaScript 文件,第一个是 AngularJS 框架,在这个版本中文件被缩小了。查看我们的 JavaScript 文件,这些文件是在 /static/app/components
文件夹中创建的。看看这里的图片:
第二个是 UI-Router 帮助我们管理路由。最后,我们的 JavaScript 文件配置了 AngularJS 应用程序、我们的控制器以及与我们的 CMS API 交互的服务。
此外,我们还有一些 Bootstrap 类来对齐字段并使设计更容易。
现在,我们需要创建我们的控制器。我们将从 simplest 开始,以使示例更易于理解。 CategoryController
负责控制Category
实体的数据。有两个控制器,一个使我们能够创建一个类别,另一个列出存储在数据库中的所有类别。
category-controller.js
应该是这样的:
我们创建了一个 AngularJS 模块。它帮助我们保持功能的组织。它对我们来说是一种命名空间。 .controller
函数是创建控制器实例的构造函数。我们收到了一些参数,AngularJS 框架会为我们注入这些对象。
CategoryService
对象是一个 singleton 对象,因为它是一个 AngularJS 服务。该服务将与我们由 Spring Boot 应用程序提供支持的 CMS API 进行交互。
我们将使用 $http
服务。它使 HTTP 通信更容易。
让我们编写 CategoryService
:
干得好,现在我们已经实现了 CategoryService
。
.service
函数是创建服务实例的构造函数,angular
在幕后起作用。在构造函数上有一个注入,对于服务,我们需要一个 $http
服务来对我们的 API 进行 HTTP 调用。这里有几个 HTTP 方法。注意保持HTTP语义的正确方法。