SpringBoot中使用RestTemplate


spring框架提供的RestTemplate類可用於在應用中調用rest服務,它簡化了與http服務的通信方式,統一了RESTful的標准,封裝了http鏈接, 我們只需要傳入url及返回值類型即可。相較於之前常用的HttpClient,RestTemplate是一種更優雅的調用RESTful服務的方式。
RestTemplate默認依賴JDK提供http連接的能力(HttpURLConnection),如果有需要的話也可以通過setRequestFactory方法替換為例如 Apache HttpComponents、Netty或OkHttp等其它HTTP library。
本篇介紹如何使用RestTemplate,以及在SpringBoot里面的配置和注入。

實現邏輯
RestTemplate包含以下幾個部分:
HttpMessageConverter 對象轉換器
ClientHttpRequestFactory 默認是JDK的HttpURLConnection
ResponseErrorHandler 異常處理
ClientHttpRequestInterceptor 請求攔截器
用一張圖可以很直觀的理解:

發送GET請求

// 1-getForObject() User user1 = this.restTemplate.getForObject(uri, User.class);  // 2-getForEntity() ResponseEntity<User> responseEntity1 = this.restTemplate.getForEntity(uri, User.class); HttpStatus statusCode = responseEntity1.getStatusCode(); HttpHeaders header = responseEntity1.getHeaders(); User user2 = responseEntity1.getBody();  // 3-exchange() RequestEntity requestEntity = RequestEntity.get(new URI(uri)).build(); ResponseEntity<User> responseEntity2 = this.restTemplate.exchange(requestEntity, User.class); User user3 = responseEntity2.getBody();

發送POST請求

// 1-postForObject() User user1 = this.restTemplate.postForObject(uri, user, User.class);  // 2-postForEntity() ResponseEntity<User> responseEntity1 = this.restTemplate.postForEntity(uri, user, User.class);  // 3-exchange() RequestEntity<User> requestEntity = RequestEntity.post(new URI(uri)).body(user); ResponseEntity<User> responseEntity2 = this.restTemplate.exchange(requestEntity, User.class);

設置HTTP Header

// 1-Content-Type RequestEntity<User> requestEntity = RequestEntity  .post(new URI(uri))  .contentType(MediaType.APPLICATION_JSON)  .body(user);  // 2-Accept RequestEntity<User> requestEntity = RequestEntity  .post(new URI(uri))  .accept(MediaType.APPLICATION_JSON)  .body(user);  // 3-Other RequestEntity<User> requestEntity = RequestEntity  .post(new URI(uri))  .header("Authorization", "Basic " + base64Credentials)  .body(user);

捕獲異常
捕獲HttpServerErrorException

try {  responseEntity = restTemplate.exchange(requestEntity, String.class); } catch (HttpServerErrorException e) {  // log error }

自定義異常處理器

public class CustomErrorHandler extends DefaultResponseErrorHandler {  @Override  public void handleError(ClientHttpResponse response) throws IOException {  // todo  } }

然后設置下異常處理器:

@Configuration public class RestClientConfig {  @Bean  public RestTemplate restTemplate() {  RestTemplate restTemplate = new RestTemplate();  restTemplate.setErrorHandler(new CustomErrorHandler());  return restTemplate;  } }

配置類
創建RestClientConfig類,設置連接池大小、超時時間、重試機制等。配置如下:

 
@Configuration public class RestClientConfig {  @Bean  public RestTemplate restTemplate() {  RestTemplate restTemplate = new RestTemplate();  restTemplate.setRequestFactory(clientHttpRequestFactory());  restTemplate.setErrorHandler(new DefaultResponseErrorHandler());  return restTemplate;  }  @Bean  public HttpComponentsClientHttpRequestFactory clientHttpRequestFactory() {  try {  HttpClientBuilder httpClientBuilder = HttpClientBuilder.create();  SSLContext sslContext = new SSLContextBuilder().loadTrustMaterial(null, new TrustStrategy() {  public boolean isTrusted(X509Certificate[] arg0, String arg1) throws CertificateException {  return true;  }  }).build();  httpClientBuilder.setSSLContext(sslContext);  HostnameVerifier hostnameVerifier = NoopHostnameVerifier.INSTANCE;  SSLConnectionSocketFactory sslConnectionSocketFactory = new SSLConnectionSocketFactory(sslContext, hostnameVerifier);  Registry<ConnectionSocketFactory> socketFactoryRegistry = RegistryBuilder.<ConnectionSocketFactory>create()  .register("http", PlainConnectionSocketFactory.getSocketFactory())  .register("https", sslConnectionSocketFactory).build();// 注冊http和https請求  // 開始設置連接池  PoolingHttpClientConnectionManager poolingHttpClientConnectionManager = new PoolingHttpClientConnectionManager(socketFactoryRegistry);  poolingHttpClientConnectionManager.setMaxTotal(500); // 最大連接數500  poolingHttpClientConnectionManager.setDefaultMaxPerRoute(100); // 同路由並發數100  httpClientBuilder.setConnectionManager(poolingHttpClientConnectionManager);  httpClientBuilder.setRetryHandler(new DefaultHttpRequestRetryHandler(3, true)); // 重試次數  HttpClient httpClient = httpClientBuilder.build();  HttpComponentsClientHttpRequestFactory clientHttpRequestFactory = new HttpComponentsClientHttpRequestFactory(httpClient); // httpClient連接配置  clientHttpRequestFactory.setConnectTimeout(20000); // 連接超時  clientHttpRequestFactory.setReadTimeout(30000); // 數據讀取超時時間  clientHttpRequestFactory.setConnectionRequestTimeout(20000); // 連接不夠用的等待時間  return clientHttpRequestFactory;  } catch (KeyManagementException | NoSuchAlgorithmException | KeyStoreException e) {  log.error("初始化HTTP連接池出錯", e);  }  return null;  } }

注意,如果沒有apache的HttpClient類,需要在pom文件中添加:

 
<dependency>  <groupId>org.apache.httpcomponents</groupId>  <artifactId>httpclient</artifactId>  <version>4.5.3</version> </dependency>

發送文件

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

下載文件

 
// 小文件 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);

Service注入

 
@Service public class DeviceService {  private static final Logger logger = LoggerFactory.getLogger(DeviceService.class);   @Resource  private RestTemplate restTemplate; }

實際使用例子

 
// 開始推送消息 logger.info("解綁成功后推送消息給對應的POS機"); LoginParam loginParam = new LoginParam(); loginParam.setUsername(managerInfo.getUsername()); loginParam.setPassword(managerInfo.getPassword()); HttpBaseResponse r = restTemplate.postForObject(  p.getPosapiUrlPrefix() + "/notifyLogin", loginParam, HttpBaseResponse.class); if (r.isSuccess()) {  logger.info("推送消息登錄認證成功");  String token = (String) r.getData();  UnbindParam unbindParam = new UnbindParam();  unbindParam.setImei(pos.getImei());  unbindParam.setLocation(location);  // 設置HTTP Header信息  URI uri;  try {  uri = new URI(p.getPosapiUrlPrefix() + "/notify/unbind");  } catch (URISyntaxException e) {  logger.error("URI構建失敗", e);  return 1;  }  RequestEntity<UnbindParam> requestEntity = RequestEntity  .post(uri)  .contentType(MediaType.APPLICATION_JSON)  .accept(MediaType.APPLICATION_JSON)  .header("Authorization", token)  .body(unbindParam);  ResponseEntity<HttpBaseResponse> responseEntity = restTemplate.exchange(requestEntity, HttpBaseResponse.class);  HttpBaseResponse r2 = responseEntity.getBody();  if (r2.isSuccess()) {  logger.info("推送消息解綁網點成功");  } else {  logger.error("推送消息解綁網點失敗,errmsg = " + r2.getMsg());  } } else {  logger.error("推送消息登錄認證失敗"); }

GitHub源碼

springboot-resttemplate


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM