一、简介
在微服务环境搭建里面的服务调用过程中,通常会使用到的一个叫做RestTemplate的工具类。RestTemplate是一个HTTP请求工具,继承自 InterceptingHttpAccessor 并且实现了RestOperations 接口,其中 RestOperations 接口定义了基本的 RESTful 操作,所以RestTemplate工具类可提供常见的REST请求方案的模版,如:GET 请求、POST 请求、PUT 请求、DELETE 请求以及一些通用的请求执行方法 exchange 以及 execute。
二、基本使用
下文着重介绍GET、POST、PUT、DELETE四个请求的使用。
1. GET
在 RestTemplate 中,GET 请求的方法分为两类:getForEntity 和 getForObject,每一类有三个重载方法。
如下图:
RestTemplate 发送的是 HTTP 请求,响应的数据中具有响应头,若开发者需要获取响应头,则使用getForEntity 来发送 HTTP 请求,返回的对象为 ResponseEntity 实例,该实例中包含了响应数据以及响应头。若开发者不需要获取响应头,则使用getForObject 来发送 HTTP 请求,返回值为provider 返回的数据,无法获取响应头。
第一类:getForEntity
getForEntity 中的参数传递方式有三种:数字占位符、map集合、uri对象。
- 数字占位符,getForEntity 方法中第一个参数为url ,url 中有一个占位符 {1} ,若有多个则使用{2} 、 {3} … 表示。第二个参数为接口返回的数据类型。第三个为可变长度的参数,用来给占位符填值。
示例代码:
@RestController
public class UseHelloController {
@Autowired
DiscoveryClient discoveryClient;
@Autowired
RestTemplate restTemplate;
@GetMapping("/hello")
public String hello(String name) {
List<ServiceInstance> list = discoveryClient.getInstances("provider");
ServiceInstance instance = list.get(0);
String host = instance.getHost();
int port = instance.getPort();
String url = "http://" + host + ":" + port + "/hello?name={1}";
ResponseEntity<String> responseEntity = restTemplate.getForEntity(url, String.class, name);
StringBuffer sb = new StringBuffer();
//getStatusCode 方法用来获取响应状态码
HttpStatus statusCode = responseEntity.getStatusCode();
//getBody 方法用来获取响应数据
String body = responseEntity.getBody();
sb.append("statusCode:")
.append(statusCode)
.append("</br>")
.append("body:")
.append(body)
.append("</br>");
//getHeaders 方法用来获取响应头
HttpHeaders headers = responseEntity.getHeaders();
Set<String> keySet = headers.keySet();
for (String s : keySet) {
sb.append(s)
.append(":")
.append(headers.get(s))
.append("</br>");
}
return sb.toString();
}
}
- map集合,将参数放入map集合中,使用map的key传递,注意map的key和占位符的key要一致。
示例代码:
Map<String, Object> map = new HashMap<>();
String url = "http://" + host + ":" + port + "/hello?name={name}";
map.put("name", name);
ResponseEntity<String> responseEntity = restTemplate.getForEntity(url, String.class, map);
- uri对象,使用 uri 对象时,参数可以直接拼接在地址中,若参数为中文,需要使用URLEncoder.encode 方法对参数进行编码,防止乱码。
示例代码:
String url = "http://" + host + ":" + port + "/hello?name="+ URLEncoder.encode(name,"UTF-8");
URI uri = URI.create(url);
ResponseEntity<String> responseEntity = restTemplate.getForEntity(uri, String.class);
第二类:getForObject
- getForObject 方法和 getForEntity 方法类似,getForObject 方法也有三个重载的方法,参数和传递方式与 getForEntity 一样,不再赘述。
示例代码:
String url = "http://" + host + ":" + port + "/hello?name=" + URLEncoder.encode(name, "UTF-8");
URI uri = URI.create(url);
String s = restTemplate.getForObject(uri, String.class);
2. POST
RestTemplate 中, POST 请求的方法分为三类:postForEntity、postForObject 和postForLocation,每一类有三个重载方法。
如下图:
第一类:postForEntity
在 POST 请求中,参数的传递有两种:key/value、JSON。
- key/value,postForEntity 方法第一个参数是请求地址,也可使用uri对象,第二个参数 map 对象中存放着请求参数 key/value,第三个参数则是返回的数据类型。
示例代码:
@GetMapping("/hello5")
public String hello5(String name) {
List<ServiceInstance> list = discoveryClient.getInstances("provider");
ServiceInstance instance = list.get(0);
String host = instance.getHost();
int port = instance.getPort();
String url = "http://" + host + ":" + port + "/hello2";
MultiValueMap map = new LinkedMultiValueMap();
map.add("name", name);
ResponseEntity<String> responseEntity = restTemplate.postForEntity(url, map, String.class);
return responseEntity.getBody();
}
//post中也可以使用get 请求的方式去传递 key/value 形式的参数,传递方式和 get 请求的传参方式基本一致
String url = "http://" + host + ":" + port + "/hello2?name={1}";
ResponseEntity<String> responseEntity = restTemplate.postForEntity(url, null, String.class,name);
- JSON,post 请求可以直接传递 json 数据,在 post 请求中,可以自动将一个对象转换成 json 进行传输,数据到达 provider 之后,再被转换为一个对象。与key/value唯一的区别就是第二个参数的类型不同,这个参数如果是一个 MultiValueMap 的实例,则以 key/value 的形式发送,如果是一个普通对象,则会被转成 json 发送。
示例代码:
@GetMapping("/hello7")
public User hello7() {
List<ServiceInstance> list = discoveryClient.getInstances("provider");
ServiceInstance instance = list.get(0);
String host = instance.getHost();
int port = instance.getPort();
String url = "http://" + host + ":" + port + "/user";
User u1 = new User();
u1.setUsername("尼古拉斯赵四");
u1.setAddress("杭州");
ResponseEntity<User> responseEntity = restTemplate.postForEntity(url, u1, User.class);
return responseEntity.getBody();
}
第二类:postForObject
postForObject 和 postForEntity 基本一致,就是返回类型不同而已,不再赘述。
第三类:postForLocation
postForLocation 方法的返回值是一个 uri 对象,一般用来添加数据,常用于用户注册。postForLocation 方法返回的 Uri 实际上是指响应头的 Location 字段,所以,provider 中接口的响应头必须要有 Location 字段(即请求的接口实际上是一个重定向的接口),否则 postForLocation 方法的返回值为null。
示例代码:
@GetMapping("/hello8")
public String hello8() {
List<ServiceInstance> list = discoveryClient.getInstances("provider");
ServiceInstance instance = list.get(0);
String host = instance.getHost();
int port = instance.getPort();
String url = "http://" + host + ":" + port + "/register";
MultiValueMap map = new LinkedMultiValueMap();
map.add("username", "尼古拉斯赵四");
map.add("address", "杭州");
URI uri = restTemplate.postForLocation(url, map);
//getForObject 请求 Uri
String s = restTemplate.getForObject(uri, String.class);
return s;
}
3. PUT
RestTemplate 中, PUT请求的方法只有三个可以重载的方法,参数传递和 POST 是一样的,可用 key/value 的形式传参,也可用 JSON 的形式传参,但是无论哪种方式,都没有返回值。
如下图:
- put请求参数传递和 POST 是一样的,可用 key/value 的形式传参,也可用 JSON 的形式传参,但是无论哪种方式,都是没有返回值。
示例代码:
@GetMapping("/hello9")
public void hello9() {
List<ServiceInstance> list = discoveryClient.getInstances("provider");
ServiceInstance instance = list.get(0);
String host = instance.getHost();
int port = instance.getPort();
String url1 = "http://" + host + ":" + port + "/user/name";
String url2 = "http://" + host + ":" + port + "/user/address";
MultiValueMap map = new LinkedMultiValueMap();
map.add("username", "尼古拉斯赵四");
map.add("address", "杭州");
restTemplate.put(url1, map);
User u1 = new User();
u1.setAddress("杭州");
u1.setUsername("尼古拉斯赵四");
restTemplate.put(url2, u1);
}
4. DELETE
RestTemplate 中, DELETE请求的方法只有三个可以重载的方法。
如下图:
- DELETE 请求的参数只能在地址栏传送,可直接放在路径中,也可用 key/value 的形式传递,没有返回值。
示例代码:
@GetMapping("/hello10")
public void hello10() {
List<ServiceInstance> list = discoveryClient.getInstances("provider");
ServiceInstance instance = list.get(0);
String host = instance.getHost();
int port = instance.getPort();
String url1 = "http://" + host + ":" + port + "/user/{1}";
String url2 = "http://" + host + ":" + port + "/user/?username={username}";
Map<String,String> map = new HashMap<>();
map.put("username", "尼古拉斯赵四");
restTemplate.delete(url1, 99);
restTemplate.delete(url2, map);
}