一、简介

在微服务环境搭建里面的服务调用过程中,通常会使用到的一个叫做RestTemplate的工具类。RestTemplate是一个HTTP请求工具,继承自 InterceptingHttpAccessor 并且实现了RestOperations 接口,其中 RestOperations 接口定义了基本的 RESTful 操作,所以RestTemplate工具类可提供常见的REST请求方案的模版,如:GET 请求、POST 请求、PUT 请求、DELETE 请求以及一些通用的请求执行方法 exchange 以及 execute。

二、基本使用

下文着重介绍GET、POST、PUT、DELETE四个请求的使用。

1. GET

在 RestTemplate 中,GET 请求的方法分为两类:getForEntitygetForObject,每一类有三个重载方法。

如下图:

resttemplate getForObject请求设置headers resttemplate的get请求_响应头


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 请求的方法分为三类:postForEntitypostForObjectpostForLocation,每一类有三个重载方法。

如下图:

resttemplate getForObject请求设置headers resttemplate的get请求_响应头_02

第一类: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 的形式传参,但是无论哪种方式,都没有返回值。

如下图:

resttemplate getForObject请求设置headers resttemplate的get请求_java_03

  • 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请求的方法只有三个可以重载的方法。

如下图:

resttemplate getForObject请求设置headers resttemplate的get请求_响应头_04

  • 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);
}