微服务学习系列8:RestTemplate

系列文章目录


目录

系列文章目录

前言

一、Calling REST Services with RestTemplate

RestTemplateAutoConfiguration 

RestTemplateConfig 

栗子参考

getForObject

getForEntity

postForObject

交换资源 

总结



前言

在java的http开发中,访问第三方网络接口,通常使用的连接工具为HttpClientOKHttp

这两种连接工具,使用起来比较复杂,新手容易出问题。如果我们使用的是spring框架,可以使用RestTemplate来进行http连接请求。

RestTemplate默认的连接方式是java中的HttpConnection,可以使用ClientHttpRequestFactory指定不同的HTTP连接方式。

官方文档:

https://docs.spring.io/spring-boot/docs/2.0.2.RELEASE/reference/htmlsingle/#boot-features-resttemplate


一、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);
    }

总结

猜你喜欢

转载自blog.csdn.net/yangyanping20108/article/details/129813146