vlambda博客
学习文章列表

读书笔记《building-a-restful-web-service-with-spring》用Maven和Gradle构建REST风格的Web服务

Chapter 2. Building RESTful Web Services with Maven and Gradle

如前一章所述,我们将构建一个示例物业管理系统作为 RESTful Web 服务。在深入研究实现之前,让我们先看一下服务将如何组合在一起。在本章中,我们将讨论以下主题:

  • 使用 Apache Maven 构建 RESTful Web 服务

  • 使用 Gradle 构建 RESTful Web 服务

  • 构建我们的物业管理网络服务

  • 运行和调试基于 Spring 的 Web 服务

Apache Maven


Maven 是一个 开源软件项目管理工具。它诞生于简化基于 Ant 的构建的需要,它更倾向于约定而不是配置。更具体而言,它为典型的工作流提供开箱即用的支持,例如构建 Java Web 应用程序,只要遵循其约定即可。然而,自定义构建过程可能具有挑战性,许多批评者指出这种 设计选择是不使用 Maven 的主要动机。

Note

有关 Maven 的更多信息,请访问 https://maven.apache.org

虽然 Maven 提供了许多特性,但它们超出了本章的范围。我们将专注于它对构建 Java Web 应用程序的支持。

以下 POM (Project Object Model)文件说明了如何使用 Maven 声明项目(在名为 pom.xml 的文件中):

<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.packtpub.rest-with-spring</groupId>
    <artifactId>rest-with-spring</artifactId>
    <version>1.0.0-SNAPSHOT</version>
    <packaging>war</packaging>

</project>

这个 pom.xml 文件定义了一个带有组标识符、工件标识符和版本的项目。它还描述了如何打包生成的应用程序(在本例中为 WAR 文件)。

Tip

Maven 工件属于一个组(通常是 com.company.application),并且必须具有唯一标识符(通常是应用程序的名称)。

开发人员可以自由选择他们的版本控制方案。但是,Maven 最适合使用 x.y 形式的版本,其中 x 是主要版本号,y 次要版本号。

Note

SNAPSHOT 版本后缀告诉 Maven 这个项目目前正在开发中。它对依赖解析处理工件的方式有影响,如下节所述。

Dependency management in Apache Maven

一个使开发更容易的构建特性 是依赖管理。它减少了手动下载第三方库并将它们与应用程序打包的需要。 Maven 具有基于工件存储库的强大依赖管理。

Tip

Maven 的主要 存储库称为中央存储库,可以在 http://maven.org

要声明依赖关系,可以按以下方式修改上一节中提供的示例 POM 文件:

// content omitted for readability purposes
    <version>1.0.0-SNAPSHOT</version>
    <packaging>war</packaging>
    <dependencies>
        <dependency>
            <groupId>org.hibernate</groupId>
            <artifactId>hibernate-core</artifactId>
            <version>4.1.9.Final</version>
        </dependency>
        <!-- Test Dependencies -->
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.11</version>
            <scope>test</scope>
        </dependency>
    </dependencies>
</project>

修改后的 POM 文件中的 <dependencies> 元素声明了两个依赖项:

  • Hibernate:这是一个标准的依赖,Maven会在编译前自动获取该项目

  • JUnit:有了这个 依赖,Maven 将改变用于编译的类路径并执行单元测试

另一个广受欢迎的构建工具是 Gradle,将在下一节中讨论

Gradle


Gradle 是一个 项目自动化工具,它借鉴了 Maven 的很多概念。它与 Maven 的不同之处在于使用基于 Groovy 的声明性语法,而不是XML

Note

https:// 阅读有关 Gradle 的更多信息gradle.org。并且,前往 http://www.groovy-lang.org 获取Groovy 简介。

Gradle 因其灵活性和更简洁的声明式语法已成为 Maven 的流行替代品,同时仍提供强大的依赖管理。我们将在下一节快速了解依赖管理。

Dependency management in Gradle

Gradle 提供 依赖解析。它可以设置为使用 Maven 的中央存储库。让我们考虑一个示例 Gradle 构建(在一个名为 build.gradle 的文件中):

apply plugin: 'java'

repositories {
    mavenCentral()
}

我们指示 Gradle 我们要构建一个 Java 项目,并且应该从 Maven 的中央存储库中获取依赖项。现在,我们可以简单地声明我们需要的依赖项,如下所示:

dependencies {
  runtime group: 'org.hibernate', name: 'hibernate-core', version: '4.1.9.Final'
  testCompile group: 'junit', name: 'junit', version: '4.+'
}

以下 Gradle 构建文件声明了两个依赖项:

  • Hibernate:这是一个运行时依赖,在项目编译的时候会用到,会和应用一起打包

  • JUnit:此依赖项添加到运行测试时使用的类路径中。这种类型的依赖不会包含在最终的应用程序中

Tip

下载示例代码

您可以从您的帐户下载示例代码文件,网址为 http://www.packtpub.com对于您购买的所有 Packt Publishing 书籍。如果您在其他地方购买了这本书,您可以访问 http://www.packtpub.com/support< /a> 并注册以将文件直接通过电子邮件发送给您。

Tip

可以通过将以下内容添加到构建文件来使用远程 Maven 存储库:

repositories {
    maven {
        url "http://repo.mycompany.com"
    }
}

Maven 和 Gradle 都为构建我们的示例 RESTful 服务提供了出色的支持,并且可以下载完整的构建脚本以及本书的所有源代码。现在,让我们关注我们的物业管理系统的结构。

The structure of our sample web service


第 1 章一些基础知识,我们将此应用程序分解为 为四个组件:

  • 库存服务

  • 可用性服务

  • 预订服务

  • 计费服务

一种方法是将我们的项目构建为单个模块,并将这四个服务的代码放在一起。

虽然它使设置变得非常简单,但它可能会阻碍我们单独部署这些组件的能力,如果出于可伸缩性目的需要它(请参阅第 10 章< /a>,扩展 RESTful Web 服务,讨论可扩展性)。相反,我们会将每个服务组织到其自己的单独模块中。

出于本节的目的,我们将重点关注 Maven。我们的项目将由六个独立的 Maven 模块组成:

  • common:这个模块包含通用代码和要使用的Hibernate设置

  • inventory:这是 库存服务实现

  • availability:这是可用性服务实现

  • booking:这是 booking 服务实现

  • 计费:这是计费服务实现

  • all:这是一个模块,它使用四个服务来构建单个Web应用程序进行开发和单个部署目的

Note

请参阅 文档-modules.html" target="_blank">https://maven.apache.org/guides/mini/guide-multiple-modules.html 了解更多关于使用 Maven 模块的信息。

因此,我们的父 POM 文件将如下所示:

<project ... // omitted for readability
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.packtpub.rest-with-spring</groupId>
    <artifactId>rest-with-spring</artifactId>
    <version>1.0.0-SNAPSHOT</version>
    <packaging>pom</packaging>

    <modules>
        <module>common</module>
        <module>inventory</module>
        <module>availability</module>
        <module>booking</module>
        <module>billing</module>
        <module>all</module>
    </modules>

</project>

如前所述,我们的模块在顶级 pom.xml 中声明。 common 模块是一个 简单的 JAR 模块,而 inventory availabilitybookingbillingall 被声明为 WAR 模块。

Tip

可以下载完整的 Maven 设置TODO

The anatomy of a Service Module

定义了 整体项目结构后,我们现在可以专注于每个模块(例如,booking)被宣布。

一些服务 模块在运行时依赖于其他服务模块。例如,billing 依赖于 booking 中定义的预订服务。

开箱即用,Maven 支持将模块打包为 WAR (Web Application Archive< /strong>)。但是,它不会将 Java 代码公开为工件。为此,我们的服务模块必须包含以下配置:

<project>
    <modelVersion>4.0.0</modelVersion>

    <parent>
        <groupId>com.packtpub.rest-with-spring</groupId>
        <artifactId>rest-with-spring</artifactId>
        <version>1.0.0-SNAPSHOT</version>
    </parent>

    <artifactId>rest-with-spring-billing</artifactId>
    <packaging>war</packaging>

    <build>
        <plugins>
            <plugin>
                <artifactId>maven-war-plugin</artifactId>
                <version>2.6</version>
                <configuration>
                    <attachClasses>true</attachClasses>
                </configuration>
            </plugin>
        </plugins>
    </build>
</project>

指示负责构建 WAR 文件的插件将 Java 代码附加为单独的 工件,然后可以在其他地方引用。下面的代码片段说明了如何引用这个工件:

<dependency>
  <groupId>com.packtpub.rest-with-spring</groupId>
  <artifactId>rest-with-spring-billing</artifactId>
  <version>1.0.0-SNAPSHOT</version>
  <classifier>classes</classifier>
</dependency>

这是一个相当 标准的依赖声明,除了 classifier 元素,它指的是 Java 代码服务。

Local versus Remote Service Invocations

此时,您可能想知道,如果每个服务单独部署,它们将如何相互调用。

在单个部署的上下文中,这些调用将是简单的 Java 调用。但是,在分布式系统中,将利用 RESTful API。

为了使代码与操作模式无关,我们将我们的服务声明为接口,并且使用 Spring,可以在单一部署模式中注入实际实现,或者注入客户端实现 (第 9 章构建 REST 客户端,讨论如何在分布式模式下构建服务客户端的操作。

Developing RESTful web services


在本节中,我们 将提供一些技巧来有效地开发基于 Spring 的 RESTful Web 服务。

Working with your favorite IDE

Maven 和 Gradle 是 得到良好支持的工具和集成度最高的 开发环境,或者 span class="strong">IDEs,提供导入此类项目的方法。例如,使用 IntelliJ IDEA,我们的示例 Web 服务项目可以是通过选择菜单选项 File | 导入打开。导入后,项目将显示如下:

读书笔记《building-a-restful-web-service-with-spring》用Maven和Gradle构建REST风格的Web服务

导入项目后,我们可以开始实施我们的物业管理系统 Web 服务。然而,在我们这样做之前,让我们讨论一下如何执行我们的服务。

Note

Eclipse 和 NetBeans 还提供对 Maven 和 Gradle 的支持(通过插件)。

Making services executable

使用 Maven 或 Gradle,可以将服务打包成 WAR 格式。但是,为了在开发过程中快速启动和调试应用程序,我们将实现一个可执行的 Java 类。使用 Spring Boot 可以通过以下类轻松实现:

package com.packtpub.restspring.app;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class WebApplication {

    public static void main(String[] args) {
        SpringApplication.run(WebApplication.class, args);
    }
}

此类通过发现所有 Web 组件并加载它们来引导我们的应用程序。

Tip

添加以下 Maven 依赖项以访问 org.springframework.boot.SpringApplication

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
    <version>1.2.3.RELEASE</version>
</dependency>

Spring Boot 的好处是它不需要设置或配置。一旦执行了这个类,服务将通过嵌入式 Tomcat 服务器在端口 8080 上可用。

Note

关于 Spring Boot 的信息可以在 http://projects.spring.io/spring-boot/

Starting services with Maven

在开发期间启动 Web 服务(没有 IDE)的另一种 方法是使用 Jetty Maven 插件。以下 POM 摘录说明了必要的配置:

<build>
  <plugins>
    ...
    <plugin>
      <groupId>org.mortbay.jetty</groupId>
      <artifactId>jetty-maven-plugin</artifactId>
      <configuration>
        <useTestScope>true</useTestScope>
        <stopPort>8005</stopPort>
        <stopKey>DIE!</stopKey>
        <systemProperties>
          <systemProperty>
            <name>jetty.port</name>
            <value>8080</value>
          </systemProperty>
        </systemProperties>
      </configuration>
    </plugin>
  </plugins>
</build>

将此插件元素添加到 POM 文件后,现在可以通过运行以下命令来启动服务:

mvn jetty:start

然后,该服务将在 http://localhost:8080 上可用。

请注意,在服务运行时,应用程序不会公开任何端点。下一章将介绍如何创建 RESTful 端点,但目前,开发人员可以创建以下控制器来快速测试服务:

import org.springframework.web.bind.annotation.*;

@RestController
public class HelloWorldResource {

    @RequestMapping(method = RequestMethod.GET)
    public String helloWorld() {
        return "Hello, world!";
    }
}

有了这个 控制器,调用 http://localhost:8080 将显示以下内容:

Hello, world!

Summary


我们了解了如何设置 Maven 或 Gradle 构建以支持 RESTful Web 服务的实现。现在是时候开始实现我们的示例 Web 服务了。下一章将介绍第一个 REST 端点。