系列文章目录
目录
一、Calling REST Services with RestTemplate
前言
在java的http开发中,访问第三方网络接口
,通常使用的连接工具为HttpClient
和OKHttp
。
这两种连接工具,使用起来比较复杂
,新手容易出问题。如果我们使用的是spring框架,可以使用RestTemplate
来进行http连接请求。
RestTemplate默认的连接方式是java中的HttpConnection
,可以使用ClientHttpRequestFactory
指定不同的HTTP连接方式。
官方文档:
一、Calling REST Services with RestTemplate
RestTemplateAutoConfiguration
@Configuration(
proxyBeanMethods = false
)
@AutoConfigureAfter({HttpMessageConvertersAutoConfiguration.class})
@ConditionalOnClass({RestTemplate.class})
@Conditional({NotReactiveWebApplicationCondition.class})
public class RestTemplateAutoConfiguration {
public RestTemplateAutoConfiguration() {
}
@Bean
@Lazy
@ConditionalOnMissingBean
public RestTemplateBuilder restTemplateBuilder(ObjectProvider<HttpMessageConverters> messageConverters, ObjectProvider<RestTemplateCustomizer> restTemplateCustomizers, ObjectProvider<RestTemplateRequestCustomizer<?>> restTemplateRequestCustomizers) {
RestTemplateBuilder builder = new RestTemplateBuilder(new RestTemplateCustomizer[0]);
HttpMessageConverters converters = (HttpMessageConverters)messageConverters.getIfUnique();
if (converters != null) {
builder = builder.messageConverters(converters.getConverters());
}
builder = this.addCustomizers(builder, restTemplateCustomizers, RestTemplateBuilder::customizers);
builder = this.addCustomizers(builder, restTemplateRequestCustomizers, RestTemplateBuilder::requestCustomizers);
return builder;
}
private <T> RestTemplateBuilder addCustomizers(RestTemplateBuilder builder, ObjectProvider<T> objectProvider, BiFunction<RestTemplateBuilder, Collection<T>, RestTemplateBuilder> method) {
List<T> customizers = (List)objectProvider.orderedStream().collect(Collectors.toList());
return !customizers.isEmpty() ? (RestTemplateBuilder)method.apply(builder, customizers) : builder;
}
static class NotReactiveWebApplicationCondition extends NoneNestedConditions {
NotReactiveWebApplicationCondition() {
super(ConfigurationPhase.PARSE_CONFIGURATION);
}
@ConditionalOnWebApplication(
type = Type.REACTIVE
)
private static class ReactiveWebApplication {
private ReactiveWebApplication() {
}
}
}
}
RestTemplateConfig
还记得RestTemplate
吗?它是Spring为开发人员提供的一款访问外部restful api的利器,其针对每个HTTP方法进行了更高级别的抽象。在Spring Boot应用中使用RestTemplate极其简单,只需要像下面这样声明一个配置类,然后通过@Resource
或@Autowired
注解将RestTemplate实例注入到业务类中即可。
/**
* RestTemplate工具类,主要用来提供RestTemplate对象
*
*
* @author yangyanping
* @date 2023-03-18
*/
@Slf4j
@Configuration
public class RestTemplateConfig {
@Bean
public RestTemplate restTemplate(RestTemplateBuilder builder) {
log.info("RestTemplateConfig create restTemplate start ......");
builder.setConnectTimeout(Duration.ofSeconds(6000))
.setReadTimeout(Duration.ofSeconds(6000));
log.info("RestTemplateConfig create restTemplate end ......");
return builder.build();
}
}
栗子参考
@Service
public class MyService {
private final RestTemplate restTemplate;
public MyService(RestTemplateBuilder restTemplateBuilder) {
this.restTemplate = restTemplateBuilder.build();
}
public BookDTO someRestCall(Integer bookId) {
BookDetailQuery query = new BookDetailQuery();
query.setBookId(bookId);
return this.restTemplate.postForObject("http://www.test.com/api/author/web/book/getById", query, BookDTO.class);
}
}
getForObject
GET资源,返回的请求体将映射为一个对象
- getForObject(URI url, Class<T> responseType)
栗子:根据书籍ID查询书籍信息请求
/**
* 查询书籍明细
*/
@GetMapping("getById/{bookId}")
public BookInfoDTO getById(@PathVariable Integer bookId) {
BookInfoIdQuery query = new BookInfoIdQuery();
query.setBookId(bookId);
ApiResult<BookInfoDTO> apiResult = new RpcExecutor<BookInfoIdQuery, BookInfoDTO>().invokeMethod(
"book-api",
"BookController.getById",
(param) -> bookService.getById(getProtocol(), param),
query);
return apiResult.getData();
}
@Service
public class MyService {
private final RestTemplate restTemplate;
public MyService(RestTemplateBuilder restTemplateBuilder) {
this.restTemplate = restTemplateBuilder.build();
}
public BookDTO getById(Integer bookId) {
return restTemplate.getForObject("https://www.test.com/api/test/book/getById/21248", BookDTO.class);
}
}
- getForObject(String url, Class<T> responseType, Map<String, ?> uriVariables)
/**
* 查询章节信息
*/
public ChapterInfoDTO getChapter() {
Map<String, Object> map = Maps.newHashMap();
map.put("bookId", 21248);
map.put("position", 1);
return restTemplate.getForObject("https://www.test.com/api/test/book/getChapter?bookId={bookId}&position={position}", ChapterInfoDTO.class, map);
}
- getForObject(String url, Class<T> responseType, Object... uriVariables)
/**
* 查询章节信息
*/
public ChapterInfoDTO getChapter() {
return restTemplate.getForObject("https://www.test.com/api/test/book/getChapter?bookId={bookId}&position={position}", ChapterInfoDTO.class, new Object[]{21248, 1});
}
getForEntity
发送一个HTTP GET请求,返回的ResponseEntity包含了响应体所映射成的对象
-
ResponseEntity<T> getForEntity(URI url, Class<T> responseType)
public ResponseEntity<BookDTO> getById() {
return restTemplate.getForEntity("http://www.test.com/api/test/book/getById/21248", BookDTO.class);
}
-
ResponseEntity<T> getForEntity(String url, Class<T> responseType, Map<String, ?> uriVariables)
/** * 查询章节信息 */ public ResponseEntity<ChapterInfoDTO> getChapter() { Map<String, Object> map = Maps.newHashMap(); map.put("bookId", 21248); map.put("position", 1); return restTemplate.getForEntity("http://www.test.com/api/test/book/getChapter?bookId={bookId}&position={position}", ChapterInfoDTO.class, map); }
-
ResponseEntity<T> getForEntity(String url, Class<T> responseType, Object... uriVariables)
/** * 查询章节信息 */ public ResponseEntity<ChapterInfoDTO> getChapter() { return restTemplate.getForEntity("https://www.test.com/api/test/book/getChapter?bookId={bookId}&position={position}", ChapterInfoDTO.class, new Object[]{21248, 1}); }
postForObject
POST数据,返回的请求体将匹配为一个对象
参数含义
String url 请求的URL路径
Object request 请求的body,通过@RequestBody接收传过去的值
Class responseType 请求完成之后返回的结果类型
Map< String,?> uriVariables POST请求中要传过去的参数
- postForObject(URI url, @Nullable Object request, Class<T> responseType)
public String queryBookCategory() {
BookCategoryListQry query = new BookCategoryListQry();
query.setParentId(0);
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.valueOf("application/json;UTF-8"));
HttpEntity<String> httpEntity = new HttpEntity<>(JSON.toJSONString(query), headers);
return this.restTemplate.postForObject("http://www.test.com/api/test/book/listBookCategory", httpEntity, String.class);
}
通过RestTemplate发送Http接口调用时,对于请求需要携带请求头时,需要额外再进行配置。
给请求携带请求头,有两种实现的方式:
方式一:在每次发送请求时,构建一个HttpEntity对象,传入请求参数与请求头。
方式二:通过配置RestTemplate,使通过RestTemplate调用的http请求都携带上请求头。
- postForEntity(String url, @Nullable Object request, Class<T> responseType, Object... uriVariables)
public ResponseEntity<String> queryBookCategory() {
BookCategoryListQry query = new BookCategoryListQry();
query.setParentId(0);
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.valueOf("application/json;UTF-8"));
HttpEntity<String> httpEntity = new HttpEntity<>(JSON.toJSONString(query), headers);
return this.restTemplate.postForEntity("https://www.test.com/api/test/book/listBookCategory", httpEntity, String.class);
}
交换资源
在URL上执行特定的HTTP方法,返回包含对象的ResponseEntity,这个对象是从响应体中映射得到的
- exchange(String url, HttpMethod method, @Nullable HttpEntity<?> requestEntity, Class<T> responseType, Object... uriVariables)
参数 | 说明 |
---|---|
url | 调用的url地址 |
method | 枚举值,HTTP方法:GET、POST、PUT、DELETE等 |
requestEntity | 发起请求时携带的对象:请求头header 和/或 请求体body |
responseType | 请求响应对象的类型 |
uriVariables | 就是针对url中的@PathVariable参数,可变长度参数列表 |
public ResponseEntity<String> queryBookCategory() {
BookCategoryListQry query = new BookCategoryListQry();
query.setParentId(0);
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.valueOf("application/json;UTF-8"));
HttpEntity<String> httpEntity = new HttpEntity<>(JSON.toJSONString(query), headers);
return this.restTemplate.exchange("https://www.test.com/api/test/book/listBookCategory", HttpMethod.POST, httpEntity, String.class);
}
-
exchange(String url, HttpMethod method, @Nullable HttpEntity<?> requestEntity, ParameterizedTypeReference<T> responseType, Object... uriVariables) 与上面重载的唯一区别是responseType类型变成了ParameterizedTypeReference<T>,其它参数说明不变. 设计这个类的目的:是允许传递泛型类型。用法建议是使用
匿名类
ParameterizedTypeReference<List<String>> parameterized = new ParameterizedTypeReference<List<String>>() {};
栗子:
public ResponseEntity<List<BookCategoryInfoDTO>> queryBookCategory() {
BookCategoryListQry query = new BookCategoryListQry();
query.setParentId(0);
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.valueOf("application/json;UTF-8"));
HttpEntity<String> httpEntity = new HttpEntity<>(JSON.toJSONString(query), headers);
String url = "http://www.test.com/api/test/book/listBookCategory";
ParameterizedTypeReference<List<BookCategoryInfoDTO>> parameterized = new ParameterizedTypeReference<List<BookCategoryInfoDTO>>() {
};
return restTemplate.exchange(url,HttpMethod.POST,httpEntity,parameterized);
}