Java 企业 101:使用 Spring Boot 构建 REST 服务器
设置项目
开始工作!
我们的第一个 Spring REST 端点
启动
测试
结束语
继Java Enterprise 101 的第一部分之后,这一次我们将亲自动手,在Spring的帮助下实现 JEE 堆栈。
您需要遵循以下说明:
- JDK 10(或更高版本)的有效安装
- 有效的互联网连接
- 可选,您最喜欢的编辑器或 IDE
设置项目
我们从……嗯,从 start 开始。准确地说,是从start.spring.io开始。这个 URL 会引导你到Spring Initializr——一个方便的小网站,你可以在这里根据项目需求混合搭配库和包。在我们的例子中,我们需要Web、JPA和H2包:
我还将项目名称从“com.example”更改为“org.example”,并将项目类型从Maven更改为Gradle。您也可以使用 Maven,但在本指南中,我将使用 Gradle。点击“生成项目”按钮后,您将得到一个 *.zip 文件。将其解压到您选择的目录中;这将成为我们的项目目录。在里面,您将找到:
- build.gradle:此文件包含您的构建配置。
- gradlew / gradlew.bat:Gradle 包装器。务必使用这些,切勿使用“gradle”本身。
- settings.gradle:基本上是你的 Gradle 模块结构。我们暂时不会触及它。
- .gitignore:一个非常基本的配置,用于排除二进制文件和生成的文件。
- src:代码的源目录。遵循 Maven 项目结构。
让我们看看生成的build.gradle脚本,好吗?
buildscript {
ext {
springBootVersion = '2.0.2.RELEASE'
}
repositories {
mavenCentral()
}
dependencies {
classpath("org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}")
}
}
apply plugin: 'java'
apply plugin: 'eclipse'
apply plugin: 'org.springframework.boot'
apply plugin: 'io.spring.dependency-management'
group = 'org.example'
version = '0.0.1-SNAPSHOT'
sourceCompatibility = 1.8
repositories {
mavenCentral()
}
dependencies {
compile('org.springframework.boot:spring-boot-starter-data-jpa')
compile('org.springframework.boot:spring-boot-starter-web')
runtime('com.h2database:h2')
testCompile('org.springframework.boot:spring-boot-starter-test')
}
就构建脚本而言,这实际上相当易读。它首先声明它使用spring-boot-gradle-plugin
Maven Central仓库来获取依赖项。这并不奇怪,不是吗?
下一节中,我们将列出应用于我们项目的 Gradle 插件。您可以随意将eclipse
插件替换为您的 IDE 的插件(例如idea
IntelliJ 用户)。如果您坚持使用编辑器和命令行,则完全不需要这些。
在我的版本中,我将 改为 ,sourceCompatibility
以便1.10
可以使用var
Java 10 中的关键字。构建脚本还提到了我们项目的 Maven 坐标。做一个好公民,始终坚持使用语义版本控制(SemVer)!在最后一部分,我们可以看到依赖项列表,用于编译和测试项目。
/!\ 重要提示:
为了使此构建脚本能够与 Java 9 及更高版本(模块化 Java 平台库)正常工作,您还需要添加以下依赖项:
compile('javax.xml.bind:jaxb-api')
我们实际上不会使用 JAXB,但
NoClassDefFoundError
如果您缺少此依赖项,则会收到一个。希望 Spring Boot 团队在不久的将来将其添加到他们的入门包中。
Spring Boot Starter软件包是“元软件包”,其中包含一些针对常见任务的库。例如:
spring-boot-starter-web
包含(嵌入式)Tomcat
作为应用程序容器并Jackson
用于 JSON 处理spring-bot-stater-data-jpa
包含Hibernate
作为 JPA 提供程序spring-boot-starter-test
包含JUnit
这很好,但如果您不同意Spring Boot 团队的选择怎么办?别担心,他们会帮您解决的。如果 Spring Boot 检测到其他库(例如 TestNG),该库将自动优先于默认库。很多情况下,您甚至无需手动配置即可实现这一点;只需在 gradle 中添加依赖项并重新构建项目即可。如果您想要一些 Spring 无法识别的更奇特的替代方案,则需要做更多工作,但那是另一篇文章的内容。现在,让我们利用现有的资源。
开始工作!
首先,您应该验证您的设置是否按预期运行。最好的方法是打开命令提示符(是的,Windows 也cmd
可以……),然后导航到您的项目文件夹(build.gradle
位于)。运行以下命令:
gradlew build
在 Windows 下cmd
,你可能需要使用gradlew.bat
。无论如何,这将:
- 从 Maven Central 下载所有必需的依赖项
- 编译源文件
- 执行所有测试
你可能会说:“但我们没有测试!” 其实,Spring Initializr 总是会包含一个特定的测试用例,乍一看可能有点奇怪,但实际上却很有道理。打开该文件DemoApplicationTests.java
(如果你的应用程序名称不是Demo
,请相应地替换它)。
@RunWith(SpringRunner.class)
@SpringBootTest
public class DemoApplicationTests {
@Test
public void contextLoads() {
}
}
顾名思义,此测试的作用是断言 Spring 上下文是否已正确加载。如果此基本测试失败,则意味着您的 Spring / Spring Boot 设置存在严重问题,需要先解决这些问题才能继续下一步。现在我们的设置应该已经完成了。
Spring Initializr 为您生成的另一个类是DemoApplication.java
:
@SpringBootApplication
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
}
这是您的主类,是服务器端应用程序的入口点。
/!\ 重要提示:此类所在的包会被 Spring Boot 视为
根包。请确保您的所有源代码都位于根包或其(直接或间接)子包中,否则 Spring Boot 将无法找到您的类。
我们的第一个 Spring REST 端点
准备好写一些实际的代码了吗?创建一个 Java 文件并将其放在你的根包(或子包)中。我将我的文件放在了org.example.demo.rest中:
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class HelloWorldRestController {
@RequestMapping(method = RequestMethod.GET, path = "/api/hello-world")
@ResponseBody
public String sayHello(){
return "Hello World!";
}
}
就是这样。这就是使用 Spring Boot 构建 REST 端点所需的全部内容@RestController
。注解告诉 Spring Boot 如何处理此类(在本系列教程的后面,我们还会看到其他示例)。方法sayHello
(名称无关紧要,只要它是一个有效的 Java 标识符,您可以随意命名)实现了一个 REST 端点。方法@RequestMapping
向 Spring 提供信息,告知哪些传入的请求需要路由到此端点。在本例中,我们将其绑定到资源路径/api/hello-world
和请求方法GET
。通过@ResponseBody
,我们告诉 Spring 此方法将生成一个结果,该结果应作为 HTML 响应的主体返回给客户端。
启动
现在到了真正精彩的部分。再次打开命令行界面,并导航到项目文件夹(如果您还没有这样做的话)。gradlew build
再次运行该命令。成功后,导航到build/libs子目录。在那里,您会找到一个.jarjava
文件。像平常一样运行此文件:
java -jar demo-0.0.1-SNAPSHOT.jar
这将启动您的应用服务器。等等,什么?但我们甚至还没有安装 Tomcat!有趣的是:您不需要安装。虽然您现在可以以“传统”的方式将 Java 企业应用程序部署为war文件,但您也可以将其作为常规 Java 应用程序运行,因为应用程序容器已经嵌入到您的应用程序中。启动完成后,打开 Web 浏览器并导航至:
http://localhost:8080/api/hello-world
您应该会看到我们的“Hello World!”消息出现。
测试
如果到了 2018 年,我们连合适的测试都写不出来,那我们就算不上开发者了,不是吗?幸运的是,Spring 让我们测试 REST 端点变得相对容易。但是,需要进行一些设置。为了简单起见,我将扩展现有的测试类(并在以下清单中省略现有的测试用例)。以下是我们需要的设置代码:
package org.example.demo;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
import org.springframework.web.context.WebApplicationContext;
import static org.junit.Assert.assertEquals;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
@RunWith(SpringRunner.class)
@SpringBootTest
public class DemoApplicationTests {
@Autowired
private WebApplicationContext context;
private MockMvc mvc;
@Before
public void setup(){
this.mvc = MockMvcBuilders
.webAppContextSetup(context)
.build();
}
}
这帮助我们设置了MockMVC辅助类。这个类的功能比乍一看要丰富得多;我们将在另一篇教程中探讨为什么这个类在测试 Spring REST 端点方面如此出色。目前,我们只需将其视为一个用于构建 REST 请求的便捷辅助类即可。请注意,上面的设置代码可以移至测试基类;它永远不会改变,也无需在每个测试类中重复。让我们更详细地看一下代码。
@Autowired
是Spring 使用的依赖注入注解,与JSR 330实现(例如Google Guice@Inject
)使用的注解非常相似。通过它,我们基本上告诉 Spring 将单个实例传递给我们的测试。然后,我们使用 JUnit 的方法,通过我们的 Web 上下文来设置实例。这就是实例“找到”你的端点的方式。WebApplicationContext
@Before
MockMvc
MockMvc
现在,让我们为 REST 端点编写一个实际测试:
@Test
public void testHelloWorldEndpoint() throws Exception {
var response = this.mvc.perform(
get("/api/hello-world")
).andExpect(status().isOk()).andReturn().getResponse().getContentAsString();
assertEquals("Hello World!", response);
}
这种内部 DSL允许我们将perform
请求get
和expect
HTTPstatus
代码转换为字符串。这读起来就像散文一样ok
。return
经过编译器检查的散文,将几十行带有断言的代码精简为一行。如果这还不够优美,我真不知道还有什么才算优美。response
content
运行这个测试,看看它是否通过!你可以在命令行中使用以下命令:
gradlew test
...(这将运行所有测试)或直接在您的 IDE 中运行。
结束语
这篇文章已经很长了——比我预想的要长得多。但是,考虑到我们实际编写的代码行数(大概10行?),考虑到我们在功能方面取得的成就,很难说 Java 是“一种冗长的语言”。我们还打下了基础,将在下一篇文章中为服务器扩展数据模型和数据库连接。实际上,我们只是触及了皮毛。撇开简洁不谈,Spring Boot 和 JEE 架构的真正优势目前还不明显。请耐心等待 ;)
文章来源:https://dev.to/martinhaeusler/java-enterprise-101-building-a-rest-server-with-spring-boot-m7k