Spring - RestTemplate方法详解

557 阅读3分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第15天,点击查看活动详情

配置

RestTemplate 使用 org.springframework.http.client.SimpleClientHttpRequestFactory建立 java.net.HttpURLConnection;后者采用 HttpURLConnection 的默认超时配置HttpURLConnection 超时属性。

  @Configuration
  public class RestTemplateConfiguration {
  @Bean
  public RestTemplate restTemplate() throws KeyStoreException, NoSuchAlgorithmException, KeyManagementException {
  HttpComponentsClientHttpRequestFactory httpRequestFactory = new HttpComponentsClientHttpRequestFactory();
  httpRequestFactory.setConnectionRequestTimeout(30 * 1000);
  httpRequestFactory.setConnectTimeout(2 * 60 * 1000);
  httpRequestFactory.setReadTimeout(10 * 60 * 1000);
  return new RestTemplate(httpRequestFactory);
  }

同时也可使用配置中心, 动态设置超时时间;高并发采用HttpClient连接池。


@Configuration
public class HttpRestTemplateConfig {
   @Autowired
   private HttpPoolProperties httpPoolProperties;//配置中心属性

   @Bean
   public RestTemplate restTemplate() {
       return new RestTemplate(httpRequestFactory());
   }

   @Bean
   public ClientHttpRequestFactory httpRequestFactory() {
       return new HttpComponentsClientHttpRequestFactory(httpClient());
   }

   @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(httpPoolProperties.getMaxTotal());
       connectionManager.setDefaultMaxPerRoute(httpPoolProperties.getMaxPerRoute());
       connectionManager.setValidateAfterInactivity(httpPoolProperties.getInactivity());
       RequestConfig requestConfig = RequestConfig.custom()
               //服务器返回数据(response)的时间,超过抛出read timeout
               .setSocketTimeout(httpPoolProperties.getSocketTimeout())
               //连接上服务器(握手成功)的时间,超出抛出connect timeout
               .setConnectTimeout(httpPoolProperties.getConnTimeOut())
               //从连接池中获取连接的超时时间,超时间未拿到可用连接,会抛出org.apache.http.conn.ConnectionPoolTimeoutException: Timeout waiting for connection from pool
               .setConnectionRequestTimeout(httpPoolProperties.getConnReqTimeOut())
               .build();
       return HttpClientBuilder.create()
               .setDefaultRequestConfig(requestConfig)
               .setConnectionManager(connectionManager)
               .build();
   }
}

设置请求头

header(HttpHeaders.COOKIE,"key1=value1")//添加 cookie
HttpHeaders headers = new HttpHeaders(); // http请求头
headers.setContentType(MediaType.APPLICATION_JSON_UTF8); // 请求头设置属性
HttpEntity> requestEntity = new HttpEntity<>(userList,headers);//userList这个就是提交的数据List集合
String forObject = restTemplate.postForObject(url, requestEntity, String.class);//url 是提交的后台路径

发送请求

getForObject

optionsForAllow 分为一组,这类方法是常规的 Rest API(GET、POST、DELETE 等)方法调用;

//url 请求路径路径中可以添加参数 List.class标识返回数据类型
 restTemplate.getForEntity(url, List.class);
通过 GET 方式调用,返回一个 String 值,还可以给 URL 变量设置值(也可通过 uriTemplateHandler 这个属性自定义)
Map<String, String> params = Collections.singletonMap("hotel", "42");
String result = restTemplate.getForObject(url, String.class, params);
//restTemplate 会根据 params 的具体类型,调用合适的 HttpMessageConvert 将请求参数写到请求体 body 中,并在请求头中添加合适的 content-type;
// 也会根据 responseType 的类型(本列子中是 JSONObject),设置 head 中的 accept 字段,当响应返回的时候再调用合适的 HttpMessageConvert 进行响应转换
ResponseEntity<JSONObject> responseEntity=restTemplate.postForEntity(url,params,JSONObject.class);
int statusCodeValue = responseEntity.getStatusCodeValue();
HttpHeaders headers = responseEntity.getHeaders();
JSONObject body = responseEntity.getBody();
JSONObject result = restTemplate.postForObject(scheduleUrl, reqEntity, JSONObject.class);
JSONArray obj = result.getJSONArray("dataList");
if (obj != null && obj.size() > 0) {
    List<RmPersonInfoDto> personInfoDtos = JSONArray.parseArray(JSON.toJSONString(obj), RmPersonInfoDto.class);
    log.debug("personInfoDtos = {}", personInfoDtos);
    partnerScheduleDataService.syncEmployees(personInfoDtos);
}

execute:通过 callback 接口,可以对请求和返回做更加全面的自定义控制。

execute方法是RestTemplate的核心方法,含设置String类型请求地址url、HttpMethod类型的请求方法method、在请求发送前设置请求头部RequestCallback类型的requestCallback对象、响应接收处理ResponseExtractor类型的responseExtractor对象以及设置请求参数的各个Object类型的URIVariables对象。execute方法的核心是doExecute方法。


    @Nullable
    public <T> T execute(String url, HttpMethod method, @Nullable RequestCallback requestCallback, @Nullable ResponseExtractor<T> responseExtractor, Object... uriVariables) throws RestClientException {
        URI expanded = this.getUriTemplateHandler().expand(url, uriVariables);
        return this.doExecute(expanded, method, requestCallback, responseExtractor);
    }

exchange

接收一个 RequestEntity 参数,可以自己设置 HTTP method,URL,headers 和 body,返回 ResponseEntity;

String bodyData = new String(JSON.toJSONString(req).getBytes("UTF-8"), "UTF-8");
HttpEntity<String> requestEntity = new HttpEntity<String>(bodyData, requestHeaders);
ResponseEntity<List<PartnerEmployee>> response = restTemplate.exchange(scheduleUrl, HttpMethod.POST, requestEntity, new ParameterizedTypeReference<List<PartnerEmployee>>() {});
List<PartnerEmployee> employeeList = response.getBody();

拦截器配置ErrorHandler 配置

@Bean
public RestTemplate restTemplate() {
    RestTemplate restTemplate = new RestTemplate(httpRequestFactory());
    List<ClientHttpRequestInterceptor> interceptors = new ArrayList<>();
    interceptors.add(new MyInterceptor());
    //设置拦截器
    restTemplate.setInterceptors(interceptors);
    //设置HttpMessageConverter
    restTemplate.setErrorHandler(new MyErrorHander());
    //设置HttpMessageConverter
    restTemplate.setMessageConverters(new );
    return restTemplate;
}
class MyErrorHander extends DefaultResponseErrorHandler{

    public MyErrorHander() {
        super();
    }

    @Override
    public boolean hasError(ClientHttpResponse response) throws IOException {
        return super.hasError(response);
    }

    @Override
    public void handleError(ClientHttpResponse response) throws IOException {
        HttpStatus statusCode = HttpStatus.resolve(response.getRawStatusCode());
        if (statusCode == null) {
            throw new UnknownHttpStatusCodeException(response.getRawStatusCode(), response.getStatusText(),
                    response.getHeaders(), getResponseBody(response), getCharset(response));
        }
        handleError(response, statusCode);

    }

    @Override
    protected void handleError(ClientHttpResponse response, HttpStatus statusCode) throws IOException {
        switch (statusCode.series()) {
            case CLIENT_ERROR:
                HttpClientErrorException exp1 = new HttpClientErrorException(statusCode, response.getStatusText(), response.getHeaders(), getResponseBody(response), getCharset(response));
                log.error("客户端调用异常",exp1);
                throw  exp1;
            case SERVER_ERROR:
                HttpServerErrorException exp2 = new HttpServerErrorException(statusCode, response.getStatusText(),
                        response.getHeaders(), getResponseBody(response), getCharset(response));
                log.error("服务端调用异常",exp2);
                throw exp2;
            default:
                UnknownHttpStatusCodeException exp3 = new UnknownHttpStatusCodeException(statusCode.value(), response.getStatusText(),
                        response.getHeaders(), getResponseBody(response), getCharset(response));
                log.error("网络调用未知异常");
                throw exp3;
        }
    }
}

class MyInterceptor implements ClientHttpRequestInterceptor {
    @Override
    public ClientHttpResponse intercept(org.springframework.http.HttpRequest request, byte[] body, ClientHttpRequestExecution execution) throws IOException {
        log.info("enter interceptor...");
        return execution.execute(request,body);
    }
}