RestTemplate Post Request with JSON – 带有JSON的RestTemplate帖子请求

最后修改: 2019年 5月 4日

中文/混合/英文(键盘快捷键:t)

1. Introduction

1.绪论

In this quick tutorial, we illustrate how to use Spring’s RestTemplate to make POST requests sending JSON content.

在这个快速教程中,我们说明了如何使用Spring的RestTemplate来进行发送JSON内容的POST请求。

2. Setting Up the Example

2.设置实例

Let’s start by adding a simple Person model class to represent the data to be posted:

让我们首先添加一个简单的Person模型类来表示要发布的数据。

public class Person {
    private Integer id;
    private String name;

    // standard constructor, getters, setters
}

To work with Person objects, we’ll add a PersonService interface and implementation with two methods:

为了处理Person对象,我们将添加一个PersonService接口和具有两个方法的实现。

public interface PersonService {

    public Person saveUpdatePerson(Person person);
    public Person findPersonById(Integer id);
}

The implementation of these methods will simply return an object. We’re using a dummy implementation of this layer here so we can focus on the web layer.

这些方法的实现将简单地返回一个对象。我们在这里使用这个层的虚拟实现,所以我们可以把注意力放在网络层上。

3. REST API Setup

3.REST API设置

Let’s define a simple REST API for our Person class:

让我们为我们的Person类定义一个简单的REST API。

@PostMapping(
  value = "/createPerson", consumes = "application/json", produces = "application/json")
public Person createPerson(@RequestBody Person person) {
    return personService.saveUpdatePerson(person);
}

@PostMapping(
  value = "/updatePerson", consumes = "application/json", produces = "application/json")
public Person updatePerson(@RequestBody Person person, HttpServletResponse response) {
    response.setHeader("Location", ServletUriComponentsBuilder.fromCurrentContextPath()
      .path("/findPerson/" + person.getId()).toUriString());
    
    return personService.saveUpdatePerson(person);
}

Remember, we want to post the data in JSON format. In order to that, we added the consumes attribute in the @PostMapping annotation with the value of “application/json” for both methods.

请记住,我们希望以JSON格式发布数据。为此,我们在@PostMapping注解中添加了consumes属性,其值为 “application/json”,用于两个方法。

Similarly, we set the produces attribute to “application/json” to tell Spring that we want the response body in JSON format.

同样,我们将produces属性设置为 “application/json”,以告诉Spring我们希望响应体为JSON格式。

We annotated the person parameter with the @RequestBody annotation for both methods. This will tell Spring that the person object will be bound to the body of the HTTP request.

我们用@RequestBody注解为这两个方法的person参数做了注解。这将告诉Spring,person对象将被绑定到HTTP请求的主体。

Lastly, both methods return a Person object that will be bound to the response body. Let’s note that we’ll annotate our API class with @RestController to annotate all API methods with a hidden @ResponseBody annotation.

最后,这两个方法都返回一个Person对象,该对象将被绑定到响应体中。让我们注意到,我们将用@RestController注解我们的API类,用隐藏的@ResponseBody注解来注解所有API方法。

4. Using RestTemplate

4.使用RestTemplate

Now we can write a few unit tests to test our Person REST API. Here, we’ll try to send POST requests to the Person API by using the POST methods provided by the RestTemplate: postForObject, postForEntity, and postForLocation.

现在我们可以写一些单元测试来测试我们的Person REST API。在这里,我们将尝试通过使用RestTemplate提供的POST方法向Person API发送POST请求。postForObjectpostForEntitypostForLocation

Before we start to implement our unit tests, let’s define a setup method to initialize the objects that we’ll use in all our unit test methods:

在我们开始实施单元测试之前,让我们定义一个setup方法来初始化我们将在所有单元测试方法中使用的对象。

@BeforeClass
public static void runBeforeAllTestMethods() {
    createPersonUrl = "http://localhost:8082/spring-rest/createPerson";
    updatePersonUrl = "http://localhost:8082/spring-rest/updatePerson";

    restTemplate = new RestTemplate();
    headers = new HttpHeaders();
    headers.setContentType(MediaType.APPLICATION_JSON);
    personJsonObject = new JSONObject();
    personJsonObject.put("id", 1);
    personJsonObject.put("name", "John");
}

Besides this setup method, note that we’ll refer to the following mapper to convert the JSON String to a JSONNode object in our unit tests:

除了这个设置方法,注意我们将参考下面的映射器,在单元测试中把JSON字符串转换为JSONNode对象。

private final ObjectMapper objectMapper = new ObjectMapper();

As previously mentioned, we want to post the data in JSON format. To achieve this, we’ll add a Content-Type header to our request with the APPLICATION_JSON media type.

如前所述,我们希望以JSON格式发布数据。为了实现这一目标,我们将在请求中添加一个Content-Type头,其中包括APPLICATION_JSON媒体类型。

Spring’s HttpHeaders class provides different methods to access the headers. Here, we set the Content-Type header to application/json by calling the setContentType method. We’ll attach the headers object to our requests.

Spring的HttpHeaders类提供了不同的方法来访问头信息。在这里,我们通过调用setContentType方法将Content-Type头设置为application/json。我们将把headers对象附加到我们的请求。

4.1. Posting JSON With postForObject

4.1.使用postForObject发布JSON信息

RestTemplate‘s postForObject method creates a new resource by posting an object to the given URI template. It returns the result as automatically converted to the type specified in the responseType parameter.

RestTemplatepostForObject方法通过向给定的URI模板发布一个对象来创建一个新资源。它返回自动转换为responseType参数中指定类型的结果。

Let’s say that we want to make a POST request to our Person API to create a new Person object and return this newly created object in the response.

假设我们想向我们的Person API发出一个POST请求,创建一个新的Person对象,并在响应中返回这个新创建的对象。

First, we’ll build the request object of type HttpEntity based on the personJsonObject and the headers containing the Content-Type. This allows the postForObject method to send a JSON request body:

首先,我们将基于personJsonObject和包含Content-Type的头文件,建立request类型的HttpEntity对象。这使得postForObject方法可以发送一个JSON请求体。

@Test
public void givenDataIsJson_whenDataIsPostedByPostForObject_thenResponseBodyIsNotNull()
  throws IOException {
    HttpEntity<String> request = 
      new HttpEntity<String>(personJsonObject.toString(), headers);
    
    String personResultAsJsonStr = 
      restTemplate.postForObject(createPersonUrl, request, String.class);
    JsonNode root = objectMapper.readTree(personResultAsJsonStr);
    
    assertNotNull(personResultAsJsonStr);
    assertNotNull(root);
    assertNotNull(root.path("name").asText());
}

The postForObject() method returns the response body as a String type.

postForObject()方法将响应体返回为String类型。

We can also return the response as a Person object by setting the responseType parameter:

我们还可以通过设置responseType参数将响应作为Person对象返回。

Person person = restTemplate.postForObject(createPersonUrl, request, Person.class);

assertNotNull(person);
assertNotNull(person.getName());

Actually, our request handler method matching with the createPersonUrl URI produces the response body in JSON format.

实际上,我们的请求处理方法与createPersonUrl URI匹配,产生JSON格式的响应体。

But this is not a limitation for us — postForObject is able to automatically convert the response body into the requested Java type (e.g. String, Person) specified in the responseType parameter.

但这对我们来说不是一个限制–postForObject能够自动将响应体转换为请求的Java类型(例如String, Person),这些类型在responseType参数中指定。

4.2. Posting JSON With postForEntity

4.2.使用 postForEntity 发布 JSON

Compared to postForObject(), postForEntity() returns the response as a ResponseEntity object. Other than that, both methods do the same job.

postForObject()相比,postForEntity()将响应作为ResponseEntity对象返回。除此之外,两个方法的工作是一样的。

Let’s say that we want to make a POST request to our Person API to create a new Person object and return the response as a ResponseEntity.

假设我们想向我们的Person API发出POST请求,创建一个新的Person对象,并将响应作为ResponseEntity返回。

We can make use of the postForEntity method to implement this:

我们可以利用postForEntity方法来实现这一点。

@Test
public void givenDataIsJson_whenDataIsPostedByPostForEntity_thenResponseBodyIsNotNull()
  throws IOException {
    HttpEntity<String> request = 
      new HttpEntity<String>(personJsonObject.toString(), headers);
    
    ResponseEntity<String> responseEntityStr = restTemplate.
      postForEntity(createPersonUrl, request, String.class);
    JsonNode root = objectMapper.readTree(responseEntityStr.getBody());
 
    assertNotNull(responseEntityStr.getBody());
    assertNotNull(root.path("name").asText());
}

Similar to the postForObject, postForEntity has the responseType parameter to convert the response body to the requested Java type.

postForObject类似,postForEntity也有responseType参数,以将响应体转换为请求的Java类型。

Here, we were able to return the response body as a ResponseEntity<String>.

在这里,我们能够将响应体作为ResponseEntity<String>返回。

We can also return the response as a ResponseEntity<Person> object by setting the responseType parameter to Person.class:

我们还可以通过将ResponseEntity<Person>参数设置为Person.class,将响应作为ResponseEntity<Person>对象返回。

ResponseEntity<Person> responseEntityPerson = restTemplate.
  postForEntity(createPersonUrl, request, Person.class);
 
assertNotNull(responseEntityPerson.getBody());
assertNotNull(responseEntityPerson.getBody().getName());

4.3. Posting JSON With postForLocation

4.3.使用postForLocation发布JSON信息

Similar to the postForObject and postForEntity methods, postForLocation also creates a new resource by posting the given object to the given URI. The only difference is that it returns the value of the Location header.

postForObjectpostForEntity方法类似,postForLocation也通过将给定的对象发布到给定的URI来创建一个新资源。唯一的区别是,它返回Location头的值。

Remember, we already saw how to set the Location header of a response in our updatePerson REST API method above:

请记住,我们已经看到如何在上面的updatePerson REST API方法中设置响应的Location头。

response.setHeader("Location", ServletUriComponentsBuilder.fromCurrentContextPath()
  .path("/findPerson/" + person.getId()).toUriString());

Now let’s imagine that we want to return the Location header of the response after updating the person object we posted.

现在让我们设想一下,我们想在更新我们发布的person对象之后,返回响应的Location标题。

We can implement this by using the postForLocation method:

我们可以通过使用postForLocation方法实现这一点。

@Test
public void givenDataIsJson_whenDataIsPostedByPostForLocation_thenResponseBodyIsTheLocationHeader() 
  throws JsonProcessingException {
    HttpEntity<String> request = new HttpEntity<String>(personJsonObject.toString(), headers);
    URI locationHeader = restTemplate.postForLocation(updatePersonUrl, request);
    
    assertNotNull(locationHeader);
}

5. Conclusion

5.总结

In this article, we explored how to use RestTemplate to make a POST request with JSON.

在这篇文章中,我们探讨了如何使用RestTemplate来进行JSON的POST请求。

As always, all the examples and code snippets can be found over on GitHub.

一如既往,所有的例子和代码片段都可以在GitHub上找到