目录
系列文章目录
前言
一、Calling REST Services with RestTemplate
RestTemplateAutoConfiguration
RestTemplateConfig
栗子参考
getForObject
getForEntity
postForObject
交换资源
总结
在java的http开发中,访问第三方网络接口
,通常使用的连接工具为HttpClient
和OKHttp
。
这两种连接工具,使用起来比较复杂
,新手容易出问题。如果我们使用的是spring框架,可以使用RestTemplate
来进行http连接请求。
RestTemplate默认的连接方式是java中的HttpConnection
,可以使用ClientHttpRequestFactory
指定不同的HTTP连接方式。
官方文档:
https://docs.spring.io/spring-boot/docs/2.0.2.RELEASE/reference/htmlsingle/#boot-features-resttemplate
RestTemplate
@Configuration(
proxyBeanMethods = false
)
@AutoConfigureAfter({HttpMessageConvertersAutoConfiguration.class})
@ConditionalOnClass({RestTemplate.class})
@Conditional({NotReactiveWebApplicationCondition.class})
public class RestTemplateAutoConfiguration {
public RestTemplateAutoConfiguration() {
}
@Bean
@Lazy
@ConditionalOnMissingBean
public RestTemplateBuilder restTemplateBuilder(ObjectProvider messageConverters, ObjectProvider restTemplateCustomizers, ObjectProvider> 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 RestTemplateBuilder addCustomizers(RestTemplateBuilder builder, ObjectProvider objectProvider, BiFunction, RestTemplateBuilder> method) {
List 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() {
}
}
}
}
还记得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);
}
}
GET资源,返回的请求体将映射为一个对象
栗子:根据书籍ID查询书籍信息请求
/**
* 查询书籍明细
*/
@GetMapping("getById/{bookId}")
public BookInfoDTO getById(@PathVariable Integer bookId) {
BookInfoIdQuery query = new BookInfoIdQuery();
query.setBookId(bookId);
ApiResult apiResult = new RpcExecutor().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);
}
}
/**
* 查询章节信息
*/
public ChapterInfoDTO getChapter() {
Map 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);
}
/**
* 查询章节信息
*/
public ChapterInfoDTO getChapter() {
return restTemplate.getForObject("https://www.test.com/api/test/book/getChapter?bookId={bookId}&position={position}", ChapterInfoDTO.class, new Object[]{21248, 1});
}
发送一个HTTP GET请求,返回的ResponseEntity包含了响应体所映射成的对象
ResponseEntitygetForEntity(URI url, Class responseType)
public ResponseEntity getById() {
return restTemplate.getForEntity("http://www.test.com/api/test/book/getById/21248", BookDTO.class);
}
ResponseEntitygetForEntity(String url, Class responseType, Map uriVariables)
/**
* 查询章节信息
*/
public ResponseEntity getChapter() {
Map 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);
}
ResponseEntitygetForEntity(String url, Class responseType, Object... uriVariables)
/**
* 查询章节信息
*/
public ResponseEntity getChapter() {
return restTemplate.getForEntity("https://www.test.com/api/test/book/getChapter?bookId={bookId}&position={position}", ChapterInfoDTO.class, new Object[]{21248, 1});
}
POST数据,返回的请求体将匹配为一个对象
参数含义
String url 请求的URL路径
Object request 请求的body,通过@RequestBody接收传过去的值
Class responseType 请求完成之后返回的结果类型
Map< String,?> uriVariables POST请求中要传过去的参数
public String queryBookCategory() {
BookCategoryListQry query = new BookCategoryListQry();
query.setParentId(0);
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.valueOf("application/json;UTF-8"));
HttpEntity 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请求都携带上请求头。
public ResponseEntity queryBookCategory() {
BookCategoryListQry query = new BookCategoryListQry();
query.setParentId(0);
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.valueOf("application/json;UTF-8"));
HttpEntity 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,这个对象是从响应体中映射得到的
参数 | 说明 |
---|---|
url | 调用的url地址 |
method | 枚举值,HTTP方法:GET、POST、PUT、DELETE等 |
requestEntity | 发起请求时携带的对象:请求头header 和/或 请求体body |
responseType | 请求响应对象的类型 |
uriVariables | 就是针对url中的@PathVariable参数,可变长度参数列表 |
public ResponseEntity queryBookCategory() {
BookCategoryListQry query = new BookCategoryListQry();
query.setParentId(0);
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.valueOf("application/json;UTF-8"));
HttpEntity 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, ParameterizedTypeReferenceresponseType, Object... uriVariables) 与上面重载的唯一区别是responseType类型变成了ParameterizedTypeReference ,其它参数说明不变. 设计这个类的目的:是允许传递泛型类型。用法建议是使用 匿名类
ParameterizedTypeReference> parameterized = new ParameterizedTypeReference>() {};
栗子:
public ResponseEntity> queryBookCategory() {
BookCategoryListQry query = new BookCategoryListQry();
query.setParentId(0);
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.valueOf("application/json;UTF-8"));
HttpEntity httpEntity = new HttpEntity<>(JSON.toJSONString(query), headers);
String url = "http://www.test.com/api/test/book/listBookCategory";
ParameterizedTypeReference> parameterized = new ParameterizedTypeReference>() {
};
return restTemplate.exchange(url,HttpMethod.POST,httpEntity,parameterized);
}