RestTemplate 属于 Spring-Web,是 Spring 的同步客户端HTTP访问的中心类。简化了与 HTTP 服务器的通信,并应用了 RESTful 原则。
RestTemplate 默认依赖 JDK 的 HttpURLConnection 来建立 HTTP 连接。 可切换到使用不同的 HTTP 库,例如 Apache HttpComponents,Netty 和 OkHttp。
1 组成 RestTemplate 包含以下几个部分:
HttpMessageConverter:对象转换器
ClientHttpRequestFactory:客户端连接器,默认是 JDK 的 HttpURLConnection
ResponseErrorHandler:异常处理
ClientHttpRequestInterceptor:请求拦截器
2 初始化 初始化时,可以传入 ClientHttpRequestFactory,自定义参数。
@Bean RestTemplate restTemplate(){ SimpleClientHttpRequestFactory requestFactory = new SimpleClientHttpRequestFactory(); //设置超时时间 requestFactory.setConnectTimeout(1000); requestFactory.setReadTimeout(1000); RestTemplate restTemplate = new RestTemplate(requestFactory); return restTemplate; }
注入
@Autowired private RestTemplate restTemplate;
3 访问服务 3.1 HTTP 方法 使用 java.net.URI 代替 String 形式的 URI,不会被 URL 编码两次 以 get 和 post 为例,更多见 官网api
1)GET
public <T> T getForObject (URI url, Class<T> responseType) public <T> T getForObject (String url, Class<T> responseType, Object... urlVariables) public <T> T getForObject (String url, Class<T> responseType, Map<String, ?> urlVariables)
public <T> ResponseEntity<T> getForEntity (URI url,Class<T> responseType) public <T> ResponseEntity<T> getForEntity (String url,Class<T> responseType,Object... uriVariables) public <T> ResponseEntity<T> getForEntity (String url,Class<T> responseType,Map<String,?> uriVariables)
2)POST
public <T> T postForObject (URI url,Object request,Class<T> responseType) public <T> T postForObject (String url,Object request,Class<T> responseType,Object... uriVariables) public <T> T postForObject (String url,Object request,Class<T> responseType,Map<String,?> uriVariables)
public <T> ResponseEntity<T> postForEntity (String url,@NullableObject request,Class<T> responseType,Object... uriVariables) public <T> ResponseEntity<T> postForEntity (String url,Object request,Class<T> responseType,Map<String,?> uriVariables) public <T> ResponseEntity<T> postForEntity (URI url,Object request,Class<T> responseType)
3)实例 HttpHeaders headers = new HttpHeaders ();headers.add("X-Auth-Token" , "" ); MultiValueMap<String, String> postParameters = new LinkedMultiValueMap <String, String>(); postParameters.add("parameter1" , "111" ); postParameters.add("parameter2" , "222" ); postParameters.add("parameter3" , "333" ); HttpEntity<MultiValueMap<String, String>> requestEntity = new HttpEntity <MultiValueMap<String, String>>(postParameters, headers); Object result = null ; try { result = restTemplate.postForObject("http://demo" , requestEntity, ParseResultVo.class); } catch (RestClientException e) { }
4 异常处理 1)捕获 HttpServerErrorException int retryCount = 0 ; while (true ) { try { responseEntity = restTemplate.exchange(requestEntity, String.class); break ; } catch (HttpServerErrorException e) { if (retryCount == 3 ) { throw e; } retryCount++; } }
2)自定义异常处理 public class CustomErrorHandler extends DefaultResponseErrorHandler { @Override public boolean hasError (ClientHttpResponse response) throws IOException { return true ; } @Override public void handleError (ClientHttpResponse response, HttpStatus statusCode) throws IOException { if (statusCode.isError()){ switch (statusCode.series()) { case CLIENT_ERROR: throw new HttpClientErrorException (statusCode, response.getStatusText(), response.getHeaders(), this .getResponseBody(response), this .getCharset(response)); case SERVER_ERROR: throw new HttpServerErrorException (statusCode, response.getStatusText(), response.getHeaders(), this .getResponseBody(response), this .getCharset(response)); default : throw new UnknownHttpStatusCodeException (statusCode.value(), response.getStatusText(), response.getHeaders(), this .getResponseBody(response), this .getCharset(response)); } } } } @Configuration public class RestClientConfig { @Bean public RestTemplate restTemplate () { RestTemplate restTemplate = new RestTemplate (); restTemplate.setErrorHandler(new CustomErrorHandler ()); return restTemplate; } }
5 设置连接池 @Configuration public class RestClientConfig { @Bean public ClientHttpRequestFactory httpRequestFactory () { return new HttpComponentsClientHttpRequestFactory (httpClient()); } @Bean public RestTemplate restTemplate () { return new RestTemplate (httpRequestFactory()); } @Bean public HttpClient httpClient () { Registry<ConnectionSocketFactory> registry = RegistryBuilder.<ConnectionSocketFactory> create() .register("http" , PlainConnectionSocketFactory.getSocketFactory()) .register("https" , SSLConnectionSocketFactory.getSocketFactory()) .build(); PoolingHttpClientConnectionManager connectionManager = new PoolingHttpClientConnectionManager (registry); connectionManager.setMaxTotal(200 ); connectionManager.setDefaultMaxPerRoute(20 ); RequestConfig requestConfig = RequestConfig.custom() .setSocketTimeout(8000 ) .setConnectTimeout(8000 ) .setConnectionRequestTimeout(8000 ) .build(); return HttpClientBuilder.create() .setDefaultRequestConfig(requestConfig) .setConnectionManager(connectionManager) .setConnectionManagerShared(true ) .build(); } }
6 处理文件 6.1 发送文件 MultiValueMap<String, Object> multiPartBody = new LinkedMultiValueMap <>(); multiPartBody.add("file" , new ClassPathResource ("/tmp/user.txt" )); RequestEntity<MultiValueMap<String, Object>> requestEntity = RequestEntity .post(uri) .contentType(MediaType.MULTIPART_FORM_DATA) .body(multiPartBody);
6.2 下载文件 RequestEntity requestEntity = RequestEntity.get(uri).build(); ResponseEntity<byte []> responseEntity = restTemplate.exchange(requestEntity, byte [].class); byte [] downloadContent = responseEntity.getBody(); ResponseExtractor<ResponseEntity<File>> responseExtractor = new ResponseExtractor <ResponseEntity<File>>() { @Override public ResponseEntity<File> extractData (ClientHttpResponse response) throws IOException { File rcvFile = File.createTempFile("rcvFile" , "zip" ); FileCopyUtils.copy(response.getBody(), new FileOutputStream (rcvFile)); return ResponseEntity.status(response.getStatusCode()).headers(response.getHeaders()).body(rcvFile); } }; File getFile = this .restTemplate.execute(targetUri, HttpMethod.GET, null , responseExtractor);
7 Spring Boot RestTemplateBuilder
@Component public class CustomRestTemplateCustomizer implements RestTemplateCustomizer { @Override public void customize (RestTemplate restTemplate) { new RestTemplateBuilder () .detectRequestFactory(false ) .basicAuthorization("username" , "password" ) .uriTemplateHandler(new OkHttp3ClientHttpRequestFactory ()) .errorHandler(new CustomResponseErrorHandler ()) .configure(restTemplate); } }
单独设置
@Service public class MyRestClientService { private RestTemplate restTemplate; public MyRestClientService (RestTemplateBuilder restTemplateBuilder) { this .restTemplate = restTemplateBuilder .basicAuthorization("username" , "password" ) .setConnectTimeout(3000 ) .setReadTimeout(5000 ) .rootUri("http://api.example.com/" ) .errorHandler(new CustomResponseErrorHandler ()) .additionalMessageConverters(new CustomHttpMessageConverter ()) .uriTemplateHandler(new OkHttp3ClientHttpRequestFactory ()) .build(); } public String site () { return this .restTemplate.getForObject("http://rensanning.iteye.com/" , String.class); } }
8 参数设置 8.1 指定转换器 RestTemplate 默认注册了一组 HttpMessageConverter 用来处理一些不同的 contentType 的请求。
StringHttpMessageConverter 来处理 text/plain;
MappingJackson2HttpMessageConverter 来处理 application/json;
MappingJackson2XmlHttpMessageConverter 来处理 application/xml。
可实现 org.springframework.http.converter.HttpMessageConverter 接口自己写一个转换器。
替换例子:
RestTemplate restTemplate = new RestTemplate ();List<HttpMessageConverter<?>> messageConverters = restTemplate.getMessageConverters(); messageConverters.remove(6 ); messageConverters.add(6 , new GsonHttpMessageConverter ());
8.2 设置底层连接方式 通过构造参数设置,以切换 HttpClient 为例
RequestConfig config = RequestConfig.custom().setConnectionRequestTimeout(10000 ).setConnectTimeout(10000 ).setSocketTimeout(30000 ).build();HttpClientBuilder builder = HttpClientBuilder.create().setDefaultRequestConfig(config).setRetryHandler(new DefaultHttpRequestRetryHandler (5 , false ));HttpClient httpClient = builder.build();ClientHttpRequestFactory requestFactory = new HttpComponentsClientHttpRequestFactory (httpClient);RestTemplate restTemplate = new RestTemplate (requestFactory);
8.3 设置拦截器 拦截器需要我们实现 org.springframework.http.client.ClientHttpRequestInterceptor 接口。
public class TokenInterceptor implements ClientHttpRequestInterceptor { @Override public ClientHttpResponse intercept (HttpRequest request, byte [] body, ClientHttpRequestExecution execution) throws IOException { String checkTokenUrl = request.getURI().getPath(); String methodName = request.getMethod().name(); String requestBody = new String (body); return execution.execute(request, body); } }
创建 RestTemplate 实例的时候,添加拦截器
RestTemplate restTemplate = new RestTemplate ();restTemplate.getInterceptors().add(new TokenInterceptor ());
8.4 使用 Proxy RestTemplate @Bean RestTemplate restTemplate () { SimpleClientHttpRequestFactory requestFactory = new SimpleClientHttpRequestFactory (); Proxy proxy = new Proxy (Proxy.Type.HTTP, new InetSocketAddress ("your.proxy.server" , 8080 )); requestFactory.setProxy(proxy); RestTemplate restTemplate = new RestTemplate (requestFactory); return restTemplate; }
System properties Properties props = System.getProperties();props.put("https.proxyHost" , "your.proxy.server" ); props.put("https.proxyPort" , "8080" ); props.put("http.proxyHost" , "your.proxy.server" ); props.put("http.proxyPort" , "8080" ); RestTemplate restTemplate = new RestTemplate ();String tt = restTemplate.getForObject("https://baike.baidu.com/" ,String.class);System.out.println(tt);