springboot內自帶的resttemplate可以幫助我們實現遠程調用其他服務接口的作用,實際封裝了httpclient,將httpclient繁瑣的
配置用springboot特有的配置類來配置,並交給sprinng管理.
避免在一個項目中頻繁創建httpclient對象,造成的堆內存浪費,確保連接對象的單例性.
優點:配置簡單,請求參數靈活.
缺點:報錯需要try-catch手動捕獲,不看日志不容易發現問題.沒有熔斷器,可以根據熔斷器狀態返回指定錯誤碼,及時發現.
配置類RestTemplateConfig:
@Configuration public class RestTemplateConfig { @Bean public RestTemplate httpRestTemplate() { ClientHttpRequestFactory factory = httpRequestFactory(); RestTemplate restTemplate = new RestTemplate(factory); // 可以添加消息轉換 //restTemplate.setMessageConverters(...); // 可以增加攔截器 //restTemplate.setInterceptors(...); return restTemplate; } public ClientHttpRequestFactory httpRequestFactory() { return new HttpComponentsClientHttpRequestFactory(restTemplateConfigHttpClient()); } public HttpClient restTemplateConfigHttpClient() { Registry<ConnectionSocketFactory> registry = RegistryBuilder.<ConnectionSocketFactory>create() .register("http", PlainConnectionSocketFactory.getSocketFactory()) .register("https", SSLConnectionSocketFactory.getSocketFactory()) .build(); PoolingHttpClientConnectionManager connectionManager = new PoolingHttpClientConnectionManager(registry); // 設置整個連接池最大連接數 根據自己的場景決定 connectionManager.setMaxTotal(200); // 路由是對maxTotal的細分 connectionManager.setDefaultMaxPerRoute(100); RequestConfig requestConfig = RequestConfig.custom() // 服務器返回數據(response)的時間,超過該時間拋出read timeout .setSocketTimeout(10000) // 連接上服務器(握手成功)的時間,超出該時間拋出connect timeout .setConnectTimeout(5000) // 從連接池中獲取連接的超時時間,超過該時間未拿到可用連接, // 會拋出org.apache.http.conn.ConnectionPoolTimeoutException: // Timeout waiting for connection from pool .setConnectionRequestTimeout(5000) .build(); return HttpClientBuilder.create() .setDefaultRequestConfig(requestConfig) .setConnectionManager(connectionManager) .build(); } }
注入:
@Autowired
RestTemplateConfig restTemplateConfig;
發請求:
RestTemplate httpRestTemplate = restTemplateConfig.httpRestTemplate(); try { List<Integer> requestBean = new ArrayList<>(); result.stream().map(a -> { requestBean.add(a.getId()); return a; }).collect(Collectors.toList()); Map map = httpRestTemplate.postForObject(服務url, requestBean, Map.class); result = result.stream().map(a -> { Iterator iterator = map.keySet().iterator(); while (iterator.hasNext()) { String key = (String) iterator.next(); Object obj = map.get(key); if (String.valueOf(a.getId()).equals(key)) { Integer i = (Integer) obj; a.setCourseCount(i); return a; } } return a; }).collect(Collectors.toList()); } catch (Exception e) { System.err.println("調用服務:" + metel2ApiUrl + "查詢課程數量異常"); e.printStackTrace(); } return result;
get請求方式:用占位符的方式,getForObject后面對應請求頭參數順序
application.properties如下:
baidu.translate.api=http://xxxx:80080/translation/add?keyword={1}&product={2}&from={3}&to={4}
//調百度api轉為英文
private String constructEn(String bucketKey) { RestTemplate httpRestTemplate = restTemplateConfig.httpRestTemplate(); try { TransResult requestBean = new TransResult(); requestBean.setSrc(bucketKey); requestBean.setCode("auto"); requestBean.setMsg("en"); String transResult = httpRestTemplate.getForObject(baiDuTranslateApi, String.class, bucketKey, "metel", "zh", "en"); TransResult result = GsonUtil.GsonToBean(transResult, TransResult.class); return result.getDst(); } catch (Exception e) { System.err.println("調用服務:" + baiDuTranslateApi + "轉換為英文異常"); e.printStackTrace(); } return null; }