4.1.2 消费Web服务
当我们创建Controller之后,接下来要做的事情就是对它暴露的HTTP端点进行消费。这就是本小节要介绍的内容,我们将引入Spring Boot提供的RestTemplate模板工具类。
1. 创建RestTemplate
要想创建一个RestTemplate对象,最简单也最常见的方法就是直接new一个该类的实例,如代码清单4-6所示。
代码清单4-6 创建RestTemplate实例示例
@Bean public RestTemplate restTemplate(){ return new RestTemplate(); }
这里创建了一个RestTemplate实例,并通过@Bean注解将其注入到Spring容器中。在Spring Boot应用程序中,通常我们会把上述代码放在Bootstrap类中,这样在代码工程的其他地方都可以引用这个实例。
2. 使用RestTemplate
我们明确,通过RestTemplate发送的请求和获取的响应都是以JSON作为序列化方式。当创建完RestTemplate之后,我们就可以使用它内置的工具方法来向远程Web服务发起请求。RestTemplate为开发人员提供了一大批发送HTTP请求的工具方法,如表4-1所示。
表4-1 RestTemplate发送HTTP请求方法列表
在一个Web请求中,请求路径可以携带参数,在使用RestTemplate时也可以在它的URL中嵌入路径变量。例如,针对前面介绍的UserController中的HTTP端点,我们可以发起如代码清单4-7所示的Web请求。
代码清单4-7 URL中带1个参数的Web请求示例
("http://localhost:8080/users/{id}", 100)
这里我们定义了一个拥有路径变量名为id的URL,然后在实际访问时将该变量值设置为100。
URL中也可以包含多个路径变量,因为Java支持不定长参数语法,所以多个路径变量的赋值将按参数依次设置。在代码清单4-8所示的代码中,我们就在URL中定义了username和password这两个路径变量,实际访问时它们将被替换为tianyalan和123456。
代码清单4-8 URL中带2个参数的Web请求示例
("http://localhost:8080/users/{username}/{password}", "tianyalan", 123456)
一旦准备好了请求URL,就可以使用RestTemplate所提供的一系列工具方法完成远程服务的访问。
我们先来介绍get方法组,包括getForObject()和getForEntity()这两组方法,每组各有参数完全对应的三个方法。例如,getForObject()方法组中的三个方法如代码清单4-9所示。从方法定义上不难看出它们之间的区别只是在对所传入参数的处理上有所不同。
代码清单4-9 getForObject()方法组代码
public <T> T getForObject(URI url, Class<T> responseType) public <T> T getForObject(String url, Class<T> responseType, Object... uriVariables) public <T> T getForObject(String url, Class<T> responseType, Map<String, ?> uriVariables)
对于UserController暴露的HTTP端点,我们就可以通过getForObject()方法构建一个HTTP请求来获取目标User对象,实现代码如代码清单4-10所示。
代码清单4-10 getForObject()方法调用的示例代码
User result = restTemplate.getForObject("http://localhost:8080/users/{id}", User.class, 100);
可以使用getForEntity()方法实现同样的效果,但写法上有所区别,如代码清单4-11所示。
代码清单4-11 getForEntity()方法调用的示例代码
ResponseEntity<User> result = restTemplate.getForEntity("http://localhost:8080/users/{id}", User.class, 100); User user = result.getBody();
可以看到,getForEntity()方法的返回值是一个ResponseEntity对象,在这个对象中还包含了HTTP消息头等信息。而getForObject()方法返回的只是业务对象本身。这是两个方法组的主要区别,我们可以根据需要对其进行选择。
针对UserController中用于创建用户信息的HTTP端点来说,通过postForEntity()方法发送POST请求的示例代码如代码清单4-12所示。
代码清单4-12 postForEntity()方法调用的示例代码
User user = new User(); user.setName("tianyalan"); user.setPassword("123456"); ResponseEntity<User> responseEntity = restTemplate.postForEntity("http://localhost:8080/users", user, User.class); return responseEntity.getBody();
可以看到,这里通过postForEntity()方法传递一个User对象到UserController所暴露的端点,并获取了该端点的返回值。postForObject()的操作方式也与此类似。
在掌握了get方法组和post方法组之后,理解put方法组和delete方法组就显得非常容易了。其中,put方法组与post方法组相比只是在操作语义上有差别,而delete方法组的使用过程也和get方法组类似,这里就不再展开讲解。
最后,我们还有必要介绍一下exchange方法组。对于RestTemplate而言,exchange()是一个通用且统一的方法,它既能发送GET和POST请求,也能用于其他各种类型的请求。我们来看一下exchange方法组中的一个exchange()方法签名,如代码清单4-13所示。
代码清单4-13 exchange ()方法的定义
public <T> ResponseEntity<T> exchange(String url, HttpMethod method, @Nullable HttpEntity<?> requestEntity, Class<T> responseType, Object... uriVariables) throws RestClientException
请注意,这里的requestEntity变量是一个HttpEntity对象,封装了请求头和请求体。而responseType则用于指定返回的数据类型。使用exchange()方法发起请求的代码示例如代码清单4-14所示。
代码清单4-14 exchange ()方法使用的示例代码
ResponseEntity<User> result = restTemplate.exchange("http://localhost:8080/users/{id}", HttpMethod.GET, null, User.class, 100);