SpringBoot 整合 RestTemplate
SpringBoot 整合 RestTemplate
2023-09-11 14:20:02 时间
目录
如果发现本文有错误的地方,请大家毫不吝啬,多多指教,欢迎大家评论,谢谢!
一、概述
当我们业务需求上,需要调用第三方外部接口数据,使用 RestTemplate 调用是一个不错的选择,调用起来比较灵活。
1. 介绍
Spring 框架提供的 RestTemplate 类可用于在应用中调用rest服务,它简化了与http服务的通信方式,统一了RESTful的标准,封装了http链接,我们只需要传入url及返回值类型即可。相较于之前常用的HttpClient,RestTemplate是一种更优雅的调用RESTful服务的方式。
二、整合 RestTemplate
1. RestTemplateConfig 配置类
/**
* RestTemplate配置
* 这是一种JavaConfig的容器配置,用于spring容器的bean收集与注册,并通过参数传递的方式实现依赖注入。
* "@Configuration"注解标注的配置类,都是spring容器配置类,springboot通过"@EnableAutoConfiguration"
* 注解将所有标注了"@Configuration"注解的配置类,"一股脑儿"全部注入spring容器中。
*
* @author Zou.LiPing
*
*/
@Configuration
public class RestTemplateConfig {
@Bean
public RestTemplate restTemplate(@Qualifier("simpleClientHttpRequestFactory") ClientHttpRequestFactory factory){
return new RestTemplate(factory);
}
@Bean
public ClientHttpRequestFactory simpleClientHttpRequestFactory(){
SimpleClientHttpRequestFactory factory = new SimpleClientHttpRequestFactory();
factory.setConnectTimeout(15000);
// 获取数据超时时间 毫秒
factory.setReadTimeout(5000);
return factory;
}
}
2. 工具类
/**
* 从配置文件获取URL
* @date: 2021/4/29 14:48
*/
@Data
@Component
@ConfigurationProperties("remote.call")
public class RemoteCallProperties {
private String productUrl;
}
@Slf4j
public class UrlUtils {
/**
* url拼接参数
* @param url
* @param object
* @date: 2020/6/19 11:51
* @return: java.lang.String
*/
public static String getUrlAppendParm(String url, Object object) {
StringBuffer stringBuffer = new StringBuffer(url);
if (object instanceof Map) {
Iterator iterator = ((Map) object).entrySet().iterator();
if (iterator.hasNext()) {
stringBuffer.append("?");
Object element;
while (iterator.hasNext()) {
element = iterator.next();
Map.Entry<String, Object> entry = (Map.Entry) element;
//过滤value为null,value为null时进行拼接字符串会变成 "null"字符串
if (entry.getValue() != null) {
stringBuffer.append(element).append("&");
}
url = stringBuffer.substring(0, stringBuffer.length() - 1);
}
}
} else {
throw new RuntimeException("url请求:" + url + "请求参数有误不是map类型");
}
log.info("url请求:" + url);
return url;
}
}
/**
* 商品服务URL常量
*/
public interface ProductApiUrlConstants {
/**
* 获取商品信息
*/
String GET_PRODUCT = "/product/getProduct";
String INSERT_PRODUCT = "/product/insertProduct";
}
3. RestTemplate 方法
RestTemplate 定义了36个与 REST 资源交互的方法,其中的大多数都对应于HTTP的方法。
其实,这里面只有 11 个独立的方法,其中有十个有三种重载形式,而第十一个则重载了六次,这样一共形成了 36 个方法。
- delete() 在特定的URL上对资源执行HTTP DELETE操作
- exchange() 在URL上执行特定的HTTP方法,返回包含对象的ResponseEntity,这个对象是从响应体中映射得到的
- execute() 在URL上执行特定的HTTP方法,返回一个从响应体映射得到的对象
- getForEntity() 发送一个HTTP GET请求,返回的ResponseEntity包含了响应体所映射成的对象
- getForObject() 发送一个HTTP GET请求,返回的请求体将映射为一个对象
- postForEntity() POST 数据到一个URL,返回包含一个对象的ResponseEntity,这个对象是从响应体中映射得到的
- postForObject() POST 数据到一个URL,返回根据响应体匹配形成的对象
- headForHeaders() 发送HTTP HEAD请求,返回包含特定资源URL的HTTP头
- optionsForAllow() 发送HTTP OPTIONS请求,返回对特定URL的Allow头信息
- postForLocation() POST 数据到一个URL,返回新创建资源的URL
- put() PUT 资源到特定的URL
4. getForEntity 方法
@Override
public ProductResp getByProductId(Long productId) {
log.info("getProduct.req productId={}", productId);
ProductResp productResp = new ProductResp();
Map<String, Object> mapPram = new HashMap<>(1);
mapPram.put("productId", productId);
String urlAppendParm = UrlUtils.getUrlAppendParm(remoteCallProperties.getProductUrl() + ProductApiUrlConstants.GET_PRODUCT, mapPram);
ResponseEntity<Result> response = restTemplate.getForEntity(urlAppendParm, Result.class, productId);
if (HttpStatus.OK.equals(response.getStatusCode())) {
Result<Product> result = response.getBody();
// java.util.LinkedHashMap cannot be cast to com.zlp.dto.Product
Product product = dataConverObj(result);
BeanUtils.copyProperties(product,productResp);
}
return productResp;
}
private Product dataConverObj(Result<Product> result) {
return new Gson().fromJson(new Gson().toJson(result.getData()), new TypeToken<Product>(){}.getType());
}
4. exchange 方法
@SneakyThrows
@Override
public ProductResp getProduct(Long productId) {
log.info("getProduct.req productId={}", productId);
ProductResp productResp = new ProductResp();
Map<String, Object> mapPram = new HashMap<>(1);
mapPram.put("productId", productId);
HttpHeaders requestHeaders = new HttpHeaders();
requestHeaders.add("Authorization", UUID.randomUUID().toString());
HttpEntity<String> requestEntity = new HttpEntity<>(null, requestHeaders);
// 请求调用
String urlAppendParm = UrlUtils.getUrlAppendParm(remoteCallProperties.getProductUrl() + ProductApiUrlConstants.GET_PRODUCT, mapPram);
log.info("getProduct resp={}", urlAppendParm);
ResponseEntity<String> response = restTemplate.exchange(urlAppendParm, HttpMethod.GET, requestEntity, String.class);
HttpStatus statusCode = response.getStatusCode();
if (HttpStatus.OK.equals(statusCode)) {
String body = response.getBody();
if (StringUtils.isNotBlank(body)) {
String data = JSON.parseObject(body).getString("data");
productResp = JSON.parseObject(data, ProductResp.class);
log.info("getProduct.urlAppendParm={} resp={}", ProductApiUrlConstants.GET_PRODUCT, JSON.toJSONString(productResp));
}
} else {
throw new Exception(String.format("远程调用 [%s] 接口失败!", urlAppendParm));
}
return productResp;
}
5. postForEntity 方法
@Override
public Boolean insertProduct(ProductResp productResp) throws Exception {
log.info("insertProduct.req productResp={}", JSON.toJSONString(productResp));
HttpEntity<String> httpEntity = RestTemplateUtils.buildPostForEntity(JSON.toJSONString(productResp));
String insertPorductUrl = "";
try {
insertPorductUrl = remoteCallProperties.getProductUrl() + ProductApiUrlConstants.INSERT_PRODUCT;
ResponseEntity<String> response = restTemplate.postForEntity(insertPorductUrl, httpEntity, String.class);
HttpStatus statusCode = response.getStatusCode();
if (HttpStatus.OK.equals(statusCode)) {
log.info("insertProduct.resp={}", response.getBody());
}
} catch (Exception e) {
throw new Exception(String.format("远程调用 [%s] 接口失败!", insertPorductUrl));
}
return Boolean.TRUE;
}
三、测试案例
1. RestTemplateController
@RestController
@RequestMapping("remote")
@RequiredArgsConstructor
@Api(value = "远程调用模块", tags = "远程调用模块")
@Slf4j(topic = "RestTemplateController")
public class RestTemplateController {
private final RemoteService remoteService;
@GetMapping("/getProduct")
@ApiOperation(value = "获取商品信息")
public ProductResp getProduct(@RequestParam (value = "productId") Long productId) {
return remoteService.getProduct(productId);
}
@PostMapping("/insertProduct")
@ApiOperation(value = "新增商品信息")
public Boolean insertProduct(@RequestBody ProductResp productResp) throws Exception {
return remoteService.insertProduct(productResp);
}
@GetMapping("/getByProductId")
@ApiOperation(value = "获取商品信息根据商品ID")
public ProductResp getByProductId(@RequestParam (value = "productId") Long productId) {
return remoteService.getByProductId(productId);
}
}
2. 测试开始
服务名称 | 端口 | 访问地址 |
product-service (生产者) | 8300 | http://127.0.0.1:8300 |
user-service (调用方) | 8200 | http://127.0.0.1:8200 |
swagger 接口测试 http://127.0.0.1:8200/doc.html
/remote/getByProductId
参考文档
1. springboot 2.0 整合 RestTemplate 与使用教程
相关文章
- SpringBoot修改启动LOGO
- 55分布式电商项目 - SpringBoot例子
- Springboot学习之 使用@Value()注解给类静态属性赋值
- SpringBoot开启配置全局异常
- SpringBoot最最最常用的注解梳理
- Apollo整合SpringBoot开发
- SpringBoot与MybatisPlus整合之活动记录(十五)
- SpringBoot入门-自动配置详解
- 《SpringBoot篇》24.SpringBoot整合Freemarker
- SpringBoot整合RabbitMQ
- SpringBoot整合MyBatis(注解版)
- springboot初始化项目慢,springboot创建项目慢
- Springboot+Thymeleaf+layui框架的配置与使用
- SpringBoot+Mybaits搭建通用管理系统实例二:实体及数据库表创建
- 浅析如何使用Vue + Xterm.js + SpringBoot + Websocket / Stomp + JSch 实现一个 web terminal 网页版的终端工具
- SpringBoot分布式事务RocketMQ
- springboot jpa mongodb 整合mysql Field in required a bean of type that could not be found Failed to load ApplicationContext
- SpringBoot 整合实现ActiveMQ
- SpringBoot开发案例之整合Dubbo消费者
- SpringBoot开发案例之整合定时任务(Scheduled)
- Docker+Nginx部署前后端分离项目(SpringBoot+Vue)的详细教程
- SpringBoot简单的REST风格例子
- SpringBoot 整合 Dubbo + Zookpeer 错误