RestTemplate如何使用JSON发送Post请求
作者:梦想画家
我们说下如何使用Spring的 RestTemplate调用post请求,发送json内容。
1. 定义服务端web接口
1.1. 定义业务接口
先定义Person实体类表示post请求的数据:
public class Person { private Integer id; private String name; // standard constructor, getters, setters }
再定义PersonService接口并实现两个方法,关联使用Person类:
public interface PersonService { public Person saveUpdatePerson(Person person); public Person findPersonById(Integer id); }
这些方法的实现仅返回对象,不再具体讨论,让我们聚焦web层。
1.2. 定义业务REST API
下面我们为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); }
我们需要发送json格式post请求数据,为此,在两个方法的@PostMapping中增加consumes属性并设置值为“application/json”。
类似的,设置produces属性值为“application/json”,为了告诉Spring我们希望响应数据也是json格式。
person参数前的注解@RequestBody,表明person对象和http请求体绑定。
最后两个方法返回Person对象会绑定至http响应体。
如果给api类增加@RestController注解,则所有api方法都带有@ResponseBody注解。
2. 使用RestTemplate
现在写几个单元测试,测试Person rest api。
我们尝试使用RestTemplate发送post请求给Person api,
共三个方法:
postForObject
postForEntity
and postForLocation
开始实现单元测试之前,先定义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); ObjectNode personJsonObject = objectMapper.createObjectNode(); personJsonObject.put("id", 1); personJsonObject.put("name", "John"); }
除了setup方法,还要引入ObjectMapper对象转换JSON字符串为JSONNode对象:
private final ObjectMapper objectMapper = new ObjectMapper();
我们前面提到,post请求数据使用json格式。
因此,在请求头中增加 Content-Type属性,值为APPLICATION_JSON 。
Spring的 HttpHeaders提供不同的方法访问请求头信息。
这里需要通过setContentType方法设置Content-Type 属性值为 application/json。然后给请求对象附加头信息。
2.1. 使用postForObject方法发送json
RestTemplate的postForObject 方法post对象给uri并返回新的对象。返回值自动被转换为responseType参数指定的类型,这里是字符串。
我们的需求是发送post请求至person api,创建新的Person对象并响应中包括新创建的对象。
首先,基于personJsonObject构建HttpEntity 类型的请求对象,并在请求头中指定Content-Type。
然后调用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()); }
该示例中 postForObject() 方法返回字符串响应体。
我们也可以通过设置responseType参数使其返回Person类型:
Person person = restTemplate.postForObject(createPersonUrl, request, Person.class); assertNotNull(person); assertNotNull(person.getName());
实际上我们的请求处理方法(createPersonUrl 参数匹配的)产生json格式的响应体,但对postForObject 方法没有限制,通过设置responseType参数可以自动转换为响应的java类型。
2.2. 使用postForEntity发送json
相比于postForObject()方法, postForEntity() 返回响应体为 ResponseEntity 类型,其他两个方法功能一致。
我们的需求是发送post请求至person api,创建新的Person对象并返回ResponseEntity类型响应体。
可以使用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()); }
类似的,也可以设置responseType 参数转换响应体为Java类型。
这里我们能够返回响应体为ResponseEntity,也能返回响应为 ResponseEntity 对象,只要设置responseType参数为 Person.class:
ResponseEntity<Person> responseEntityPerson = restTemplate. postForEntity(createPersonUrl, request, Person.class); assertNotNull(responseEntityPerson.getBody()); assertNotNull(responseEntityPerson.getBody().getName());
2.3. 使用postForLocation发送json
与postForObject 和 postForEntity 方法类型, postForLocation 也发送post请求至特定uri并创建新的对象。
唯一的差异是返回值为Location头信息。
前面updatePerson rest api在响应中设置Location 头信息:
response.setHeader("Location", ServletUriComponentsBuilder.fromCurrentContextPath() .path("/findPerson/" + person.getId()).toUriString());
现在我们需要实现更新person对象后接收返回带有Location头信息的响应,使用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); }
3. 总结
本文讲解了RestTemplate 如何发送json类型的post请求,共三种方法应用与不同场景。
以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。