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 请求拦截器
用一张图可以很直观的理解:

直接使用方式很简单:

public class RestTemplateTest {public static void main(String[] args) {RestTemplate restT = new RestTemplate();//通过Jackson JSON processing library直接将返回值绑定到对象Quote quote = restT.getForObject("http://gturnquist-quoters.cfapps.io/api/random", Quote.class);String quoteString = restT.getForObject("http://gturnquist-quoters.cfapps.io/api/random", String.class);System.out.println(quoteString);}
}

发送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 {public void handleError(ClientHttpResponse response) throws IOException {// todo}
}

然后设置下异常处理器:

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

配置类
创建HttpClientConfig类,设置连接池大小、超时时间、重试机制等。配置如下:

/*** - Supports both HTTP and HTTPS* - Uses a connection pool to re-use connections and save overhead of creating connections.* - Has a custom connection keep-alive strategy (to apply a default keep-alive if one isn't specified)* - Starts an idle connection monitor to continuously clean up stale connections.** @author XiongNeng* @version 1.0* @since 2018/7/5*/public class HttpClientConfig {private static final Logger LOGGER = LoggerFactory.getLogger(HttpClientConfig.class);private HttpClientProperties p;public PoolingHttpClientConnectionManager poolingConnectionManager() {SSLContextBuilder builder = new SSLContextBuilder();try {builder.loadTrustMaterial(null, new TrustStrategy() {public boolean isTrusted(X509Certificate[] arg0, String arg1) {return true;}});} catch (NoSuchAlgorithmException | KeyStoreException e) {LOGGER.error("Pooling Connection Manager Initialisation failure because of " + e.getMessage(), e);}SSLConnectionSocketFactory sslsf = null;try {sslsf = new SSLConnectionSocketFactory(builder.build());} catch (KeyManagementException | NoSuchAlgorithmException e) {LOGGER.error("Pooling Connection Manager Initialisation failure because of " + e.getMessage(), e);}Registry<ConnectionSocketFactory> socketFactoryRegistry = RegistryBuilder.<ConnectionSocketFactory>create().register("https", sslsf).register("http", new PlainConnectionSocketFactory()).build();PoolingHttpClientConnectionManager poolingConnectionManager = new PoolingHttpClientConnectionManager(socketFactoryRegistry);poolingConnectionManager.setMaxTotal(p.getMaxTotalConnections());  //最大连接数poolingConnectionManager.setDefaultMaxPerRoute(p.getDefaultMaxPerRoute());  //同路由并发数return poolingConnectionManager;}public ConnectionKeepAliveStrategy connectionKeepAliveStrategy() {return new ConnectionKeepAliveStrategy() {public long getKeepAliveDuration(HttpResponse response, HttpContext httpContext) {HeaderElementIterator it = new BasicHeaderElementIterator(response.headerIterator(HTTP.CONN_KEEP_ALIVE));while (it.hasNext()) {HeaderElement he = it.nextElement();String param = he.getName();String value = he.getValue();if (value != null && param.equalsIgnoreCase("timeout")) {return Long.parseLong(value) * 1000;}}return p.getDefaultKeepAliveTimeMillis();}};}public CloseableHttpClient httpClient() {RequestConfig requestConfig = RequestConfig.custom().setConnectionRequestTimeout(p.getRequestTimeout()).setConnectTimeout(p.getConnectTimeout()).setSocketTimeout(p.getSocketTimeout()).build();return HttpClients.custom().setDefaultRequestConfig(requestConfig).setConnectionManager(poolingConnectionManager()).setKeepAliveStrategy(connectionKeepAliveStrategy()).setRetryHandler(new DefaultHttpRequestRetryHandler(3, true))  // 重试次数.build();}public Runnable idleConnectionMonitor(final PoolingHttpClientConnectionManager connectionManager) {return new Runnable() {(fixedDelay = 10000)public void run() {try {if (connectionManager != null) {LOGGER.trace("run IdleConnectionMonitor - Closing expired and idle connections...");connectionManager.closeExpiredConnections();connectionManager.closeIdleConnections(p.getCloseIdleConnectionWaitTimeSecs(), TimeUnit.SECONDS);} else {LOGGER.trace("run IdleConnectionMonitor - Http Client Connection manager is not initialised");}} catch (Exception e) {LOGGER.error("run IdleConnectionMonitor - Exception occurred. msg={}, e={}", e.getMessage(), e);}}};}public TaskScheduler taskScheduler() {ThreadPoolTaskScheduler scheduler = new ThreadPoolTaskScheduler();scheduler.setThreadNamePrefix("poolScheduler");scheduler.setPoolSize(50);return scheduler;}
}

然后再配置RestTemplateConfig类,使用之前配置好的CloseableHttpClient类注入,同时配置一些默认的消息转换器:

/*** RestTemplate客户端连接池配置** @author XiongNeng* @version 1.0* @since 2018/1/24*/(proxyTargetClass = true)
public class RestTemplateConfig {private CloseableHttpClient httpClient;public RestTemplate restTemplate(MappingJackson2HttpMessageConverter jackson2HttpMessageConverter) {RestTemplate restTemplate = new RestTemplate(clientHttpRequestFactory());List<HttpMessageConverter<?>> messageConverters = new ArrayList<>();StringHttpMessageConverter stringHttpMessageConverter = new StringHttpMessageConverter(Charset.forName("utf-8"));messageConverters.add(stringHttpMessageConverter);messageConverters.add(jackson2HttpMessageConverter);restTemplate.setMessageConverters(messageConverters);return restTemplate;}public HttpComponentsClientHttpRequestFactory clientHttpRequestFactory() {HttpComponentsClientHttpRequestFactory rf = new HttpComponentsClientHttpRequestFactory();rf.setHttpClient(httpClient);return rf;}}

注意,如果没有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>>() {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注入

public class DeviceService {private static final Logger logger = LoggerFactory.getLogger(DeviceService.class);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源码

https://github.com/yidao620c/SpringBootBucket/tree/master/springboot-resttemplate

SpringBoot系列 - 使用RestTemplate相关推荐

  1. SpringBoot系列: RestTemplate 快速入门

    ==================================== 相关的文章 ==================================== SpringBoot系列: 与Sprin ...

  2. 拦截器获取请求参数post_「SpringBoot WEB 系列」RestTemplate 之自定义请求头

    [WEB 系列]RestTemplate 之自定义请求头 上一篇介绍了 RestTemplate 的基本使用姿势,在文末提出了一些扩展的高级使用姿势,本篇将主要集中在如何携带自定义的请求头,如设置 U ...

  3. httpwebrequest超时时间timeout设置无效_【SpringBoot WEB 系列】RestTemplate 之超时设置...

    [SpringBoot WEB 系列]RestTemplate 之超时设置 一般来讲我们访问外部资源时,需要做一个保护,比如最常见的添加一个超时设置,避免一直被阻塞,RestTemplate 可以通过 ...

  4. java web乱码_【SpringBoot WEB 系列】RestTemplate 之中文乱码问题 fix

    [WEB 系列]RestTemplate 之中文乱码问题 fix 在 RestTemplate 基础用法博文中,post json 表单时,会发现存在中文乱码问题,本文主要介绍对应的解决方案 I. 中 ...

  5. SpringWeb 系列教程 RestTemplate 4xx/5xx 异常信息捕获

    SpringWeb 系列教程 RestTemplate 4xx/5xx 异常信息捕获 参考文章: (1)SpringWeb 系列教程 RestTemplate 4xx/5xx 异常信息捕获 (2)ht ...

  6. Java工程师之SpringBoot系列教程前言目录

    前言 与时俱进是每一个程序员都应该有的意识,当一个Java程序员在当代步遍布的时候,你就行该想到我能多学点什么.可观的是后端的框架是稳定的,它们能够维持更久的时间在应用中,而不用担心技术的更新换代.但 ...

  7. 【j360-boot】Spring-boot系列三(崩溃模式,不是你崩就是电脑崩)

    2019独角兽企业重金招聘Python工程师标准>>> j360-boot spring-boot入门工程之j360-boot:(欢迎star.fork) https://githu ...

  8. springboot 系列技术教程目录

    前些天发现了一个巨牛的人工智能学习网站,通俗易懂,风趣幽默,忍不住分享一下给大家.点击跳转到教程. 一.教程目录地址: springboot系列技术教程目录 二.教程内容: springboot2.X ...

  9. Springboot系列之Shiro、JWT、Redis 进行认证鉴权

    Springboot系列之Shiro.JWT.Redis 进行认证鉴权 Shiro架构 Apache Shiro是一个轻量级的安全框架 Shiro可以非常容易的开发出足够好的应用,其不仅可以用在Jav ...

  10. springboot系列六、springboot配置错误页面及全局异常

    springboot系列六.springboot配置错误页面及全局异常 参考文章: (1)springboot系列六.springboot配置错误页面及全局异常 (2)https://www.cnbl ...

最新文章

  1. linux /etc/profile和/etc/bashrc
  2. 1.6 Dropout 正则化-深度学习第二课《改善深层神经网络》-Stanford吴恩达教授
  3. opencv 高斯模糊
  4. 数学物理方法pdf_中考状元笔记九科(语文+数学+物理+化学+英语+历史+地理+政治+生物)(高清PDF);...
  5. 对话李飞飞:云数据库战争已经进入下半场
  6. java的interface_java中如何实现一个接口interface-百度经验
  7. ffmpeg threads_用ffmpeg命令行转压视频
  8. LINUX FFMPEG编译详细过程记录(最全)
  9. window.print()在页面全部加载完成后才能执行。切记。
  10. 【整理】PYTHON代码审查工具
  11. linux etc xdg,Xdg-menu (简体中文)
  12. arcgis属性表中的某一字段保留1位小数
  13. Python数据处理——pandas
  14. 真正毁掉团队的,是“窄化效应”
  15. ffmpeg 提取音频,音频转换,添加字幕
  16. Echarts图表插件(4.x版本)使用(二、带分类筛选的多个图表/实例化多个ECharts,以关系图/force为例)...
  17. android内存泄漏检测工具,Android内存泄漏的检测工具——LeakCanary
  18. 国科大移动互联网技术考试
  19. 20暨南大学计算机考研经验知乎,暨大应统经验转自知乎
  20. 中国医科大学网络教育计算机应用基础试题,作业与试题选集1906 中国医科大学《计算机应用基础 》复习题.docx...

热门文章

  1. 启动报错:读取 jar时出错; error in opening zip file
  2. delete与垃圾回收机制
  3. BUUCTF misc 喵喵喵
  4. 深入理解裸机与RTOS开发模式
  5. 如何在H3C路由器使用ACL来管理网络安全
  6. 论程序员如何正确上班摸鱼
  7. java实现逐级审批_【YOU学吧】NC审批流如何实现自下而上逐级审批
  8. 【Grpc】grpc中repeated的数据如何set值?
  9. 前端面试之浏览器/HTML/CSS问题
  10. PostgreSQL-11.7关系型数据库源码安装