
RestTemplate是从 Spring3.0 开始支持的一个 HTTP 请求工具,它提供了常见的REST请求方案的模版,例如 GET 请求、POST 请求、PUT 请求、DELETE 请求以及一些通用的请求执行方法 exchange 以及 execute。
getForObject:Retrieves a representation via GET.getForEntity:Retrieves a ResponseEntity (that is, status, headers, and body) by using GET.headForHeaders:Retrieves all headers for a resource by using HEAD.postForLocation:Creates a new resource by using POST and returns the Location header from the response.postForObject:Creates a new resource by using POST and returns the representation from the response.postForEntity:Creates a new resource by using POST and returns the representation from the response.put:Creates or updates a resource by using PUT.delete:Deletes the resources at the specified URI by using DELETE.exchange:More generalized (and less opinionated) version of the preceding methods that provides extra flexibility when needed. It accepts a RequestEntity (including HTTP method, URL, headers, and body as input) and returns a ResponseEntity.execute:The most generalized way to perform a request, with full control over request preparation and response extraction through callback interfaces.getForObject - delete:提供常规的 Rest API(GET、POST、DELETE 等)方法调用;
exchange:接收一个 RequestEntity 参数,可以自己设置 HTTP method,URL,headers 和 body,返回 ResponseEntity;
execute:通过 callback 接口,可以对请求和返回做更加全面的自定义控制。
一般情况下,我们使用第一组和第二组方法就够了。
依赖:
org.springframework.boot spring-boot-starter-web
将RestTemplate配置初始化为一个Bean:
@Configuration
public class RestTemplateConfig {/*** 没有实例化RestTemplate时,初始化RestTemplate*/@ConditionalOnMissingBean(RestTemplate.class)@Beanpublic RestTemplate restTemplate(){RestTemplate restTemplate = new RestTemplate();return restTemplate;}
}
默认使用了 JDK 自带的HttpURLConnection作为底层 HTTP 客户端实现,可以使用ClientHttpRequestFactory指定不同的 HTTP 连接方式。比如,将其改成HttpClient客户端:
@Configuration
public class RestTemplateConfig {@ConditionalOnMissingBean(RestTemplate.class)@Beanpublic RestTemplate restTemplate(ClientHttpRequestFactory clientHttpRequestFactory){RestTemplate restTemplate = new RestTemplate(clientHttpRequestFactory);return restTemplate;}/*** 使用HttpClient作为底层客户端* @return*/@Beanpublic ClientHttpRequestFactory clientHttpRequestFactory() {int timeout = 5000;RequestConfig config = RequestConfig.custom().setConnectTimeout(timeout).setConnectionRequestTimeout(timeout).setSocketTimeout(timeout).build();CloseableHttpClient client = HttpClientBuilder.create().setDefaultRequestConfig(config).build();return new HttpComponentsClientHttpRequestFactory(client);}
}
在需要使用RestTemplate的位置,注入并使用即可!
@Autowired
private RestTemplate restTemplate;
从开发人员的反馈,和网上的各种 HTTP 客户端性能以及易用程度评测来看,OkHttp 优于 Apache的HttpClient、Apache的HttpClient优于HttpURLConnection。
因此,我们还可以通过如下方式,将底层的 HTTP 客户端换成OkHttp:
/*** 使用OkHttpClient作为底层客户端* @return*/
@Bean
public ClientHttpRequestFactory clientHttpRequestFactory() {OkHttpClient okHttpClient = new OkHttpClient.Builder().connectTimeout(5, TimeUnit.SECONDS).writeTimeout(5, TimeUnit.SECONDS).readTimeout(5, TimeUnit.SECONDS).build();return new OkHttp3ClientHttpRequestFactory(okHttpClient);
}
如果需要配置http连接管理器,完整配置如下:
@Configuration
public class RestTemplateConfig {/*** http连接管理器* @return*/@Beanpublic HttpClientConnectionManager poolingHttpClientConnectionManager() {/*// 注册http和https请求Registry registry = RegistryBuilder.create().register("http", PlainConnectionSocketFactory.getSocketFactory()).register("https", SSLConnectionSocketFactory.getSocketFactory()).build();PoolingHttpClientConnectionManager poolingHttpClientConnectionManager = new PoolingHttpClientConnectionManager(registry);*/PoolingHttpClientConnectionManager poolingHttpClientConnectionManager = new PoolingHttpClientConnectionManager();// 最大连接数poolingHttpClientConnectionManager.setMaxTotal(500);// 同路由并发数(每个主机的并发)poolingHttpClientConnectionManager.setDefaultMaxPerRoute(100);return poolingHttpClientConnectionManager;}/*** HttpClient* @param poolingHttpClientConnectionManager* @return*/@Beanpublic HttpClient httpClient(HttpClientConnectionManager poolingHttpClientConnectionManager) {HttpClientBuilder httpClientBuilder = HttpClientBuilder.create();// 设置http连接管理器httpClientBuilder.setConnectionManager(poolingHttpClientConnectionManager);/*// 设置重试次数httpClientBuilder.setRetryHandler(new DefaultHttpRequestRetryHandler(3, true));*/// 设置默认请求头/*List headers = new ArrayList<>();headers.add(new BasicHeader("Connection", "Keep-Alive"));httpClientBuilder.setDefaultHeaders(headers);*/return httpClientBuilder.build();}/*** 请求连接池配置* @param httpClient* @return*/@Beanpublic ClientHttpRequestFactory clientHttpRequestFactory(HttpClient httpClient) {HttpComponentsClientHttpRequestFactory clientHttpRequestFactory = new HttpComponentsClientHttpRequestFactory();// httpClient创建器clientHttpRequestFactory.setHttpClient(httpClient);// 连接超时时间/毫秒(连接上服务器(握手成功)的时间,超出抛出connect timeout)clientHttpRequestFactory.setConnectTimeout(5 * 1000);// 数据读取超时时间(socketTimeout)/毫秒(务器返回数据(response)的时间,超过抛出read timeout)clientHttpRequestFactory.setReadTimeout(10 * 1000);// 连接池获取请求连接的超时时间,不宜过长,必须设置/毫秒(超时间未拿到可用连接,会抛出org.apache.http.conn.ConnectionPoolTimeoutException: Timeout waiting for connection from pool)clientHttpRequestFactory.setConnectionRequestTimeout(10 * 1000);return clientHttpRequestFactory;}/*** rest模板* @return*/@Beanpublic RestTemplate restTemplate(ClientHttpRequestFactory clientHttpRequestFactory) {// boot中可使用RestTemplateBuilder.build创建RestTemplate restTemplate = new RestTemplate();// 配置请求工厂restTemplate.setRequestFactory(clientHttpRequestFactory);return restTemplate;}}

getForObject():返回值是 HTTP 协议的响应体getForEntity():返回的是ResponseEntity,ResponseEntity是对 HTTP 响应的封装,除了包含响应体,还包含HTTP状态码、contentType、contentLength、Header等信息服务端:
@RestController
public class HelloController {@GetMapping("/testGet/{name}/{age}")public ResponseBean testGet(@PathVariable("name") String name, @PathVariable("age") int age){System.out.println("name="+name+",age="+age);ResponseBean response = new ResponseBean();response.setCode("200");response.setMsg("请求成功,方法:testGetByRestFul,请求参数id:" + name + "、请求参数name:" + age);return response;}
}
响应类:
@Data
public class ResponseBean {private String code;private String msg;
}
请求端:
@RestController
public class TestRestTemplateController {@AutowiredRestTemplate restTemplate;@RequestMapping("/testRestGet1")public void testRestGet1(){//请求地址String url = "http://localhost:8080/testGet/{1}/{2}";//发起请求,直接返回对象(restful风格)ResponseBean response = restTemplate.getForObject(url, ResponseBean.class, "lili", 23);System.out.println(response);}
}
访问地址:http://192.168.1.166:8080/testRestGet1

服务端:
@RestController
public class HelloController {@GetMapping("/testGet2")public ResponseBean testGet2(@RequestParam("name") String name, @RequestParam("age") int age){System.out.println("name="+name+",age="+age);ResponseBean response = new ResponseBean();response.setCode("200");response.setMsg("请求成功,方法:testGetByParam,请求参数id:" + name + "、请求参数name:" + age);return response;}
}
请求端:
@RestController
public class TestRestTemplateController {@AutowiredRestTemplate restTemplate;@RequestMapping("/testRestGet2")public void testRestGet2(){//请求地址String url = "http://localhost:8080/testGet2?name={name}&age={age}";//请求参数HashMap map = new HashMap<>();map.put("name","lili");map.put("age",25);//发起请求,直接返回对象(带参数请求)ResponseBean responseBean = restTemplate.getForObject(url, ResponseBean.class, map);System.out.println(responseBean.toString());}
}
访问地址:http://192.168.1.166:8080/testRestGet2

使用name={name}&age={age}这种形式,最后一个参数是一个 map,map 的 key 即为前边占位符的名字,map 的 value 为参数值。
如果你只关注返回的消息体的内容,对其他信息都不关注,此时可以使用
getForObject。
上面的所有的getForObject请求传参方法,getForEntity都可以使用,使用方法上也几乎是一致的,只是在返回结果接收的时候略有差别。
getForEntity方法的返回值是一个ResponseEntity,ResponseEntity是 Spring 对 HTTP 请求响应的封装,包括了几个重要的元素,如响应码、contentType、contentLength、响应消息体等。responseEntity.getBody()获取响应体。
请求端:
@RestController
public class TestRestTemplateController {@AutowiredRestTemplate restTemplate;@RequestMapping("/testRestGet2")public void testRestGet2(){//请求地址String url = "http://localhost:8080/testGet2?name={name}&age={age}";//请求参数HashMap map = new HashMap<>();map.put("name","lili");map.put("age",25);//发起请求ResponseEntity response = restTemplate.getForEntity(url, ResponseBean.class, map);// 获取响应体System.out.println("HTTP 响应body:[" + response.getBody().toString() + "]");// 以下是getForEntity比getForObject多出来的内容HttpStatus statusCode = response.getStatusCode();int statusCodeValue = response.getStatusCodeValue();HttpHeaders headers = response.getHeaders();System.out.println("HTTP 响应状态:[" + statusCode + "]");System.out.println("HTTP 响应状态码:[" + statusCodeValue + "]");System.out.println("HTTP Headers信息:[" + headers + "]");}
}
访问地址:http://192.168.1.166:8080/testRestGet2

注1:restTemplate 会根据 params 的具体类型,调用合适的 HttpMessageConvert 将请求参数写到请求体 body 中,并在请求头中添加合适的 content-type;
注2:也会根据 responseType 的类型(本例返回类类型,默认是 application/json),设置 head 中的 accept 字段,当响应返回的时候再调用合适的 HttpMessageConvert 进行响应转换。

其实 POST 请求方法和 GET 请求方法上大同小异,RestTemplate 的 POST 请求也包含两个主要方法:
postForObject():返回body对象postForEntity():返回全部的信息服务端:
@RestController
public class HelloController {@PostMapping("testPost")public ResponseBean testPost(@RequestParam("name") String name,@RequestParam("age") String age){ResponseBean result = new ResponseBean();result.setCode("200");result.setMsg("请求成功,方法:testPostByForm,请求参数name:" + name + ",age:" + age);return result;}
}
请求类:
@Data
public class RequestBean {private String name;private String age;
}
请求端:
@RestController
public class TestRestTemplateController {@AutowiredRestTemplate restTemplate;@RequestMapping("/testRestPost1")public void testRestPost1(){// 1. 请求地址String url = "http://localhost:8080/testPost";// 2.1 请求头设置,x-www-form-urlencoded格式的数据HttpHeaders headers = new HttpHeaders();headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);// 2.2 提交参数设置MultiValueMap map = new LinkedMultiValueMap<>();map.add("name", "唐三藏");map.add("age", "25");// 2.3组装请求体HttpEntity> request = new HttpEntity<>(map, headers);// 3. 发起请求ResponseBean responseBean = restTemplate.postForObject(url, request, ResponseBean.class);System.out.println(responseBean.toString());}
}
访问地址:http://192.168.1.166:8080/testRestPost1

POST请求报文体需要使用MultiValueMap,不能使用HashMap。
服务端:
@RestController
public class HelloController {@PostMapping("testPost2")public ResponseBean testPost2(@RequestBody RequestBean request){ResponseBean result = new ResponseBean();result.setCode("200");result.setMsg("请求成功,方法:testPostByFormAndObj,请求参数:" + request);return result;}
}
请求端:
@RestController
public class TestRestTemplateController {@AutowiredRestTemplate restTemplate;@RequestMapping("/testRestPost2")public void testRestPost2(){// 1. 请求地址String url = "http://localhost:8080/testPost2";// 2. 入参RequestBean request = new RequestBean();request.setName("唐三藏");request.setAge("23");// 3. 发起请求ResponseBean responseBean = restTemplate.postForObject(url, request, ResponseBean.class);System.out.println(responseBean.toString());}
}
访问地址:http://192.168.1.166:8080/testRestPost2

上面的所有的postForObject请求传参方法,postForEntity都可以使用,使用方法上也几乎是一致的,只是在返回结果接收的时候略有差别。
请求端:
@RestController
public class TestRestTemplateController {@AutowiredRestTemplate restTemplate;@RequestMapping("/testRestPost2")public void testRestPost2(){// 1. 请求地址String url = "http://localhost:8080/testPost2";// 2. 入参RequestBean request = new RequestBean();request.setName("唐三藏");request.setAge("23");// 3. 发起请求ResponseEntity response = restTemplate.postForEntity(url, request, ResponseBean.class);System.out.println("HTTP 响应状态码:[" + response.getBody() + "]");System.out.println("HTTP 响应状态:[" + response.getStatusCode() + "]");System.out.println("HTTP 响应状态码:[" + response.getStatusCodeValue() + "]");System.out.println("HTTP Headers信息:[" + response.getHeaders() + "]");}
}
访问地址:http://192.168.1.166:8080/testRestPost2

postForLocation用于页面重定向,postForLocation 的参数和前面两种的参数基本一致,只不过该方法的返回值为 URI ,这个只需要服务提供者返回一个 URI 即可,该 URI 表示新资源的位置。
服务端:
@RestController
public class HelloController {@PostMapping("testPostByLocation")public String testPostByLocation(@RequestBody RequestBean request){return "redirect:index.html";}
}
请求端:
@RestController
public class TestRestTemplateController {@AutowiredRestTemplate restTemplate;@RequestMapping("/testRestLocation")public void testRestLocation(){// 1. 请求地址String url = "http://localhost:8080/testPostByLocation";// 2. 入参RequestBean request = new RequestBean();request.setName("唐三藏");request.setAge("23");// 3. 用于提交完成数据之后的页面跳转,返回跳转urlURI uri = restTemplate.postForLocation(url, request);System.out.println(uri.toString());}
}
PUT方法的参数和前面介绍的 postForEntity 方法的参数基本一致,只是 put 方法没有返回值而已。它指的是修改一个已经存在的资源或者插入资源,该方法会向URL代表的资源发送一个HTTP PUT方法请求。

服务端:
@RestController
public class HelloController {/*** 模拟JSON请求,put方法测试*/@PutMapping("testPutByJson")public void testPutByJson(@RequestBody RequestBean request){System.out.println("请求成功,方法:testPutByJson,请求参数:" + request);}
}
请求端:
@RestController
public class TestRestTemplateController {@AutowiredRestTemplate restTemplate;/*** 模拟JSON提交,put请求*/@RequestMapping("/testPutByJson")public void testPutByJson(){//请求地址String url = "http://localhost:8080/testPutByJson";//入参RequestBean request = new RequestBean();request.setName("唐三藏");request.setAge("23");//模拟JSON提交,put请求restTemplate.put(url, request);}
}
delete方法协议,表示删除一个已经存在的资源,该方法会向URL代表的资源发送一个HTTP DELETE方法请求。

服务端:
@RestController
public class HelloController {/*** 模拟JSON请求,delete方法测试*/@DeleteMapping("testDeleteByJson")public void testDeleteByJson(){System.out.println("请求成功,方法:testDeleteByJson");}
}
请求端:
@RestController
public class TestRestTemplateController {@AutowiredRestTemplate restTemplate;@RequestMapping("/testDeleteByJson")public void testDeleteByJson(){//请求地址String url = "http://localhost:8080/testDeleteByJson";//模拟JSON提交,delete请求restTemplate.delete(url);}
}
如果以上方法还不满足你的要求。在RestTemplate工具类里面,还有一个exchange通用协议请求方法,它可以发送GET、POST、DELETE、PUT、OPTIONS、PATCH等 HTTP 方法请求。
RequestEntity> requestEntity描述ParameterizedTypeReferenceresponseType描述服务端:
@RestController
public class HelloController {@PostMapping("testExchange")public ResponseBean testExchange(@RequestBody RequestBean request){ResponseBean result = new ResponseBean();result.setCode("200");result.setMsg("请求成功,方法:testExchange,请求参数:" + request);return result;}
}
请求端:
@RestController
public class TestRestTemplateController {@AutowiredRestTemplate restTemplate;@RequestMapping("/testExchange")public void testExchange() {UriComponents uriComponents = UriComponentsBuilder.fromHttpUrl("http://localhost:8080").path("/testExchange").build(true);URI uri = uriComponents.toUri();RequestBean request = new RequestBean();request.setName("唐三藏");request.setAge("23");RequestEntity requestEntity = RequestEntity.post(uri).header(HttpHeaders.COOKIE,"key1=value1").accept(MediaType.APPLICATION_JSON).contentType(MediaType.APPLICATION_JSON).body(request);ResponseEntity responseEntity = restTemplate.exchange(requestEntity, ResponseBean.class);// 响应结果ResponseBean response = responseEntity.getBody();System.out.println("返回报文=" + response);}
}
访问地址:http://192.168.1.166:8080/testExchange

public 中,RequestEntity> requestEntity包含method,URL,contentType、accept、请求报文体等请求配置,Class指定响应参数类型。
参考Spring之RestTemplate详解,懒得写了。
1. 拦截器配置
RestTemplate 也可以设置拦截器做一些统一处理。这个功能感觉和 Spring MVC 的拦截器类似。配置也很简单:
class MyInterceptor implements ClientHttpRequestInterceptor{@Overridepublic ClientHttpResponse intercept(HttpRequest request, byte[] body, ClientHttpRequestExecution execution) throws IOException {logger.info("enter interceptor...");return execution.execute(request,body);}}
@Bean
public RestTemplate restTemplate(ClientHttpRequestFactory factory) {RestTemplate restTemplate = new RestTemplate(factory);MyInterceptor myInterceptor = new MyInterceptor();List list = new ArrayList<>();list.add(myInterceptor);restTemplate.setInterceptors(list);return restTemplate;
}
2. ErrorHandler 配置
3. HttpMessageConverter
配置 RestTemplate 也可以配置 HttpMessageConverter,配置的原理和 Spring MVC 中类似。
引用:
Spring之RestTemplate详解