介绍
Spring是Java Web开发最流行的框架之一。
它的扩展,即用于IntelliJ的SpringBoot和Spring Initializr插件,已成为使用Spring开发Web应用程序的行业标准之一。
在Web应用程序中,一种非常普遍和现代的趋势是开发REST API。 这些仅使用HTTP作为前端和后端之间的通信方式。 通常,前端发送一个http请求以获取资源端点返回一个响应。 这些响应通常包含资源和响应代码。
我们将看到如何编写一个使用并生成JSON的基本端点,以及如何为该端点编写集成测试。
设置
对于我们的设置,我们将使用IntelliJ的Spring Initializr(但是您可以使用IDE中可用的任何东西,甚至可以手动设置一些东西)。
出于此简单文章的目的,我们假设我们要在POST请求的正文中发送具有以下结构的JSON:
{"name":"John", "age":12}
作为响应,我们想返回以下JSON:
{"迎接":"Hi, John", "date":<return date of request>}
使用REST API时,通常需要做好一些准备工作:
DTO(数据传输对象):对于请求和响应,我们都需要能够放置代表我们的请求和响应的对象,以便我们可以在Java端构建它。 这些对象将用于对请求进行进一步的数据处理并建立响应。
使用ObjectMapper(例如Jackson)在JSON中反序列化/从JSON序列化。
REST API应该接受JSON作为请求有效负载,并向JSON发送响应。 JSON是用于传输数据的标准。 几乎每种联网技术都可以使用它:JavaScript具有内置方法,可以通过Fetch API或其他HTTP客户端对JSON进行编码和解码。 服务器端技术具有无需大量工作即可解码JSON的库。
- 最好有一个“服务类”,我们将实际的业务逻辑委托给该“服务类”,作为唯一的
有了这些之后,我们就可以准备端点了。 让我们设置它们。
准备数据传输类
对于请求,假设我们有一个人DTO
类:
public class 人DTO {
private String name;
private int age;
//Needed for Jackson
public PersonDTO() {
}
public PersonDTO(String name, int age) {
this。name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
并且,为了得到答复,我们将有一个打招呼
:
public class GreetDTO {
private String greet;
private Date date;
//Needed for Jackson
public GreetDTO() {
}
public GreetDTO(String greet, Date date) {
this.greet = greet;
this.date = date;
}
public String getGreet() {
return greet;
}
public void setGreet(String greet) {
this.greet = greet;
}
public Date getDate() {
return date;
}
public void setDate(Date date) {
this.date = date;
}
}
请注意,如果我们想在测试上下文中使用这些类,或者由于某种原因需要从外部源中加载它们,则需要Jackson对其进行反序列化或从JSON序列化,为此,我们需要默认的构造函数. To learn more about Jackson you can read my post about it.
Spring功能介绍-@RestController
注解
在Spring中,控制器用于提供应用程序功能并协调其内部代码流。
当Spring中的某个类获得此特定注释时:@RestController
,该框架将知道在类的方法和成员中可以支持某些附加注释,以使用作为端点的必要功能来增强它。
这意味着我们可以使用@RequestMapping
将方法“绑定”到某个HTTP动词(用于执行请求)的注释。
使用时@RequestMapping
我们需要指定所使用的实际“动词”,因此可以进行PUT,GET,POST,DELETE等操作,也可以为某个动词使用特定的映射,例如@PostMapping
这指示端点将仅接受发布请求。
让我们看一下端点的外观,然后将其分解为重要的部分:
@RestController
public class GreetingsResource {
private static final Log LOG = LogFactory.getLog(GreetingsResource.class);
// 1
@PostMapping(value = "/迎接", consumes = MediaType.APPLICATION_JSON_VALUE)
// 2
public 响应实体<GreetDTO> greet(@RequestBody PersonDTO person) {
if(person==null) {
LOG.error("Request Body can not be null");
return new ResponseEntity<>(HttpStatus.NO_CONTENT);
}
GreetingService greetingService = new GreetingService(person);
GreetDTO response = greetingService.getGreeting();
if(response==null){
return new ResponseEntity<>(HttpStatus.EXPECTATION_FAILED);
}
return new ResponseEntity<>(response, HttpStatus.OK);
}
}
我们已经讨论过@RestController
因此,让我们集中讨论以数字为注释的区域:
//1
-分析@PostMapping
注解
注释用于确保greet
方法将映射到/greet
端点,此外,它仅接受POST请求。
我们也看到了消耗= MediaType.APPLICATION_JSON_VALUE
参数,指出该端点只能接收JSON格式的请求。 这既有利于与编写REST API的良好实践保持一致,也可以用作API将来使用的“文档”。
//2
-深入了解ResponseEntity<>
和@RequestBody
结构体
我们看到在方法的标题下有很多关于REST控制器工作方式的有用信息。
的@RequestBody
批注用于定义将方法参数发送到http请求正文中的端点。
当我们发送JSON时,将存在从JSON到Java DTO的隐式映射,并且JSON的值将在Java对象上设置,因此有效地,我们的requestBody对象将是JSON请求数据的Java表示。
然后,我们可以使用Java处理数据。 通常,此处理步骤在服务类内部进行,该服务类是通常用于封装业务逻辑的类。 因此,如果业务逻辑发生变化,我们无需更改端点,而只需修改服务类即可。
服务类还可以构建响应,该响应通常由ResponseEntity<T>
class,这是Spring中包含响应DTO的类,在本例中为T类型:ResponseEntity<GreetDTO>
.
我们将讨论的最后一件事是服务类的实现,该类将封装端点的业务逻辑。
服务等级
要将我们已完成的所有工作链接在一起,我们需要做的最后一件事是查看服务类的实际实现,该类将包含端点的逻辑并生成一个ResponseEntity
JSON和成功代码。 让我们看一下实现:
public class GreetingService {
private final PersonDTO person;
public GreetingService(PersonDTO person) {
this.person = person;
}
public GreetDTO getGreeting() {
return new GreetDTO("Hi, "+person.getName(), new Date());
}
}
在此示例中,服务类的所有逻辑都是微不足道的,并且着重于从服务对象构建新的响应对象。PersonDTO
对象是在我们的请求正文中发送的对象。
至此,我们简单的端点的所有工作结束了。
结论
希望您对如何使用Spring的功能编写简单的终结点有一个更好的主意! 在下一篇文章中,我们将看到如何使用Postman实际查看它的工作,并且我们将看到我们可以在Spring的生态系统中利用哪些功能为其编写集成测试。