关于rest可参考第3篇,而RestTemplate就是由spring提供的,用于在后台进行rest请求的,比繁琐的HttpClient要方便很多。


pom.xml


从本篇开始,后续文章都使用spring boot2,要求jdk版本至少8。之前的文章仍然适用于低版本的jdk,继续保留。spring boot 1和2大部分用法是一样的,只是有些功能做了细节调整。如默认连接池从tomcat变成了HikariCP,actuator有较大改动等。

<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>2.0.1.RELEASE</version>
</parent>


rest服务端

先创建一个服务端项目,项目中有一个接口方法提供服务,如下。端口为8081,启动项目

@RestController
public class HelloController {
	
	@RequestMapping("/server")
	public String server() {
		return "hello";
	}
}

rest客户端

创建客户端项目,在配置类中,使用RestTemplateBuilder来构建一个RestTemplate。

@Autowired
	RestTemplateBuilder restTemplateBuilder;
	//在配置类中使用restTemplateBuilder构建RestTemplate实例
	@Bean
	public RestTemplate restTemplate(){
		return restTemplateBuilder.build();
	}

在控制层使用restTemplate来访问服务端,客户端端口为8080,启动项目

@RestController
public class ClientController {
	@Autowired
	RestTemplate restTemplate;
	
	@RequestMapping("/client")
	public String client() {
		//通过restTemplate请求rest服务端
		String result = restTemplate.getForObject("http://localhost:8081/server", String.class);
		return result;
	}

getForObject方法

getForObject指get请求,并返回一个Object对象。这里有2个方法参数

  • 第1个参数:请求的url地址
  • 第2个参数:返回的结果类型,这里String.class表示返回结果是一个字符串。

运行结果

spring restTemplate URI编码 resttemplate springboot_restTemplateBuilder

如图,通过浏览器请求http://localhost:8080/client,客户端又通过restTemplate请求了服务端的数据hello,最终返回。

请求参数

  • 可以使用map来封装请求参数,并作为getForObject的第三个参数,同时修改url如下,map中的"1"会替换url中的{1},"2"会替换url中的{2}
Map map = new HashMap();
		map.put("1", "hello");
		map.put("2", "world");
		String result = restTemplate.getForObject("http://localhost:8081/server?param1={1}¶m2={2}", String.class,map);
  • 也可以直接将要传递的值放到getForObject方法的参数结尾,数量不限,它会按顺序替换{1}和{2}
String result = restTemplate.getForObject("http://localhost:8081/server?param1={1}¶m2={2}", String.class, "hello", "world");

getForEntity方法

getForEntity和getForObject的用法是一样的,只是其返回结果是一个ResponseEntity,其中包含了更多的响应信息,比如:

ResponseEntity response = restTemplate.getForEntity("http://localhost:8081/server",String.class);
		response.getHeaders();		//响应头
		response.getStatusCode();	//响应码
		response.getBody();			//响应体,即前面的result

postForObject方法

postForObject指post请求,并返回一个Object对象。

String response = restTemplate.postForObject("http://localhost:8081/server?param1={1}¶m2={2}", null, String.class, "hello", "world");
  • postForObject第1个参数就是getForObject第1个参数。
  • postForObject第3个参数就是getForObject第2个参数。
  • postForObject第4个及以后的参数就是getForObject第3个及以后的参数。

postForObject除了第2个参数为null,其它地方用法和getForObject是一模一样的。但是post请求传参通常不是写在url上实现的,而是放在请求体中。此时,就需要使用第2个参数来传参,同时可省略第4个参数的url传参,如下

Map map = new HashMap();
		map.put("param1", "hello");
		map.put("param2", "world");
		String response = restTemplate.postForObject("http://localhost:8081/server", map, String.class);

注意,服务端端接收不同参数时,语法也有所不同,如下

public String server(@RequestBody Map map,String param1,String param2)
  • @RequestBody Map map:此注解可用于接收请求体,即postForObject的第2个map参数。此注解第3篇有讲过。
  • String param1,String param2:用于接收postForObject第4个及以后参数的url传参 。

HttpEntity

postForObject的第2个参数其实是HttpEntity,这个类主要有三种构造方法,如下

  • new HttpEntity(请求体)
  • new HttpEntity(请求头)
  • new HttpEntity(请求体,请求头)

当我前面传了一个map参数时,系统内部会自动使用第一种方法,将这个map作为 请求体,并 封装成 HttpEntity。以下以第三种方法为例,介绍如何使用HttpEntity同时发送请求体和请求头:

//请求体
		Map map = new HashMap();
		map.put("param1", "hello");
		map.put("param2", "world");
		//请求头
		MultiValueMap headers = new HttpHeaders();
		headers.add("Accept", "text/xml");
		//请求内容封装成httpEntity
		HttpEntity httpEntity= new HttpEntity(map,headers);
		
		restTemplate.postForObject("http://localhost:8081/server", httpEntity, String.class);

postForEntity

和getForEntity原理是一样的

配置超时

如果要设置请求的超时时间,可修改前面restTemplate的构建代码,如下

@Bean
	public RestTemplate restTemplate(){
		RestTemplate restTemplate = restTemplateBuilder
			.setConnectTimeout(1000)		//连接超时为1秒
			.setReadTimeout(1000)			//请求超时为1秒
			.build();
		return restTemplate;
	}