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
- getForObject()
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)
- getForEntity()
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
- postForObject()
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)
- postForEntity()
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();
//获取RestTemplate默认配置好的所有转换器
List<HttpMessageConverter<?>> messageConverters = restTemplate.getMessageConverters();
//默认的MappingJackson2HttpMessageConverter在第7个 先把它移除掉
messageConverters.remove(6);
//添加上GSON的转换器
messageConverters.add(6, new GsonHttpMessageConverter());
8.2 设置底层连接方式
通过构造参数设置,以切换 HttpClient 为例
//生成一个设置了连接超时时间、请求超时时间、异常最大重试次数的 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();
//使用httpClient创建一个 ClientHttpRequestFactory 的实现
ClientHttpRequestFactory requestFactory = new HttpComponentsClientHttpRequestFactory(httpClient);
//ClientHttpRequestFactory作为参数构造一个使用作为底层的 RestTemplate
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();
//请求方法名 POST、GET等
String methodName = request.getMethod().name();
//请求内容
String requestBody = new String(body);
//……
return execution.execute(request, body);
}
}
创建 RestTemplate 实例的时候,添加拦截器
RestTemplate restTemplate = new RestTemplate();
//向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;
}
@Slf4j
@Configuration
public class RestClientConfig {
@Value("${httpClient.maxTotal:400}")
private Integer maxTotal;
@Value("${httpClient.defaultMaxPerRoute:400}")
private Integer defaultMaxPerRoute;
@Value("${httpClient.timeout:20000}")
private Integer timeout;
@Value("${proxy.enabled}")
Boolean proxyEnable;
@Bean
public RestTemplate restTemplate() {
ClientHttpRequestFactory requestFactory = new HttpComponentsClientHttpRequestFactory(httpClient());
return new RestTemplate(requestFactory);
}
@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(maxTotal);
connectionManager.setDefaultMaxPerRoute(defaultMaxPerRoute);
RequestConfig requestConfig = RequestConfig.custom()
.setSocketTimeout(timeout)
.setConnectTimeout(timeout)
.setConnectionRequestTimeout(timeout)
.build();
HttpClientBuilder httpClientBuilder = HttpClientBuilder.create()
.setDefaultRequestConfig(requestConfig)
.setConnectionManager(connectionManager)
.setConnectionManagerShared(true);
log.info("proxyEnable: " + proxyEnable);
if (proxyEnable) {
//设置代理
HttpHost proxy = new HttpHost("web-proxy.oa.com", 8080);
httpClientBuilder.setProxy(proxy);
}
return httpClientBuilder.build();
}
}
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);