RestTemplate 使用

RestTemplate 是什么

RestTemplate 是 spring 提供的发送HTTP请求的同步客户端工具。

注意:RestTemplate 在 springboot3中已废弃,可使用 RestClient或者WebClient替代。

构造RestTemplate对象

通常的做法是将 RestTemplate 对象作为bean使用,一般有以下两种方式。

直接new

java 复制代码
@Configuration
public class RestTemplateConfig {
    
    @Bean
    public RestTemplate restTemplate() {
        return new RestTemplate();
    }

}

RestTemplateBuilder 注入

java 复制代码
@Configuration
public class RestTemplateConfig {

    @Bean
    public RestTemplate restTemplate(RestTemplateBuilder builder) {
        return builder.build();
    }

}

实际生产环境中,更推荐使用这种方式,这种方式有个好处,就是可以通过spring配置文件进行配置。

比如配置:spring.resttemplate.read-timeout=5s 则会应用到 RestTemplateBuilder中。

常用方法

exchange

exchange 是比较通用的方法,可以发送GET,PUT,POST,DELETE 请求。

GET请求

方式一:没有参数

java 复制代码
ResponseEntity<String> responseEntity = restTemplate.exchange(
        "http://localhost:9090/api/hello", 
        HttpMethod.GET, 
        null,    // 无请求体
        String.class
);

方式二:带路径参数和请求参数:

java 复制代码
ResponseEntity<String> responseEntity = restTemplate.exchange(
        "http://localhost:9090/api/hello/{id}?name={name}",
        HttpMethod.GET,
        null,
        String.class,
        1,     // 参数在后面一一填入
        "CongVee"
);

方式三:url编码:

java 复制代码
URI url = UriComponentsBuilder.fromUri(URI.create("http://localhost:9090"))
        .path("/api/hello/{id}")
        .queryParam("name", "CongVee")
        .buildAndExpand(123)  // 设置路径参数
        .toUri();

ResponseEntity<String> responseEntity = restTemplate.exchange(
        url,
        HttpMethod.GET,
        null,
        String.class
);

POST请求

主要是看如何添加响应体。

java 复制代码
URI url = UriComponentsBuilder.fromUri(URI.create("http://localhost:9090"))
        .path("/api/hello/{id}")
        .buildAndExpand(123)  // 设置路径参数
        .toUri();

// 构造请求体
User user = new User();
user.setName("CongVee");
user.setAge(25);

ResponseEntity<String> responseEntity = restTemplate.exchange(
        url,
        HttpMethod.POST,
        new HttpEntity<>(user),
        String.class
);

PUT和DELETE请求也没必要再说,都是同样的方式添加路径参数、查询参数、请求体。

getForEntity

发送GET请求,获取响应。

java 复制代码
URI url = UriComponentsBuilder.fromUri(URI.create("http://localhost:9090"))
        .path("/api/hello/{id}")
        .queryParam("name", "CongVee")
        .buildAndExpand(123)  // 设置路径参数
        .toUri();

ResponseEntity<String> forEntity = restTemplate.getForEntity(url, String.class);

getForObject

发送GET请求,直接获取响应体。如果不关系响应的响应头和状态码,可以使用这种

java 复制代码
URI url = UriComponentsBuilder
        .fromPath("/api/hello/{id}")
        .queryParam("name", "CongVee")
        .buildAndExpand(123)  // 设置路径参数
        .toUri();


String body = restTemplate.getForObject(url, String.class);

postForEntity 和 postForObject

和get类似。

put

put请求一般也不关心响应体,所以也不区分Object还是Entity。

java 复制代码
URI url = UriComponentsBuilder
        .fromPath("/api/hello/{id}")
        .queryParam("name", "CongVee")
        .buildAndExpand(123)  // 设置路径参数
        .toUri();

User user = new User();
user.setName("CongVee");
user.setAge(25);

restTemplate.put(url, user);

delete

delete和put类似,也不关心响应体,并且delete一般也不传递请求体。

java 复制代码
URI url = UriComponentsBuilder
        .fromPath("/api/hello/{id}")
        .queryParam("name", "CongVee")
        .buildAndExpand(123)  // 设置路径参数
        .toUri();

restTemplate.delete(url);

配置 【待补充完整】

直接new

java 复制代码
@Configuration
public class RestTemplateConfig {

    @Bean
    public RestTemplate restTemplate(ClientHttpRequestFactory clientHttpRequestFactory) {
        return new RestTemplate(clientHttpRequestFactory);
    }

    @Bean
    public ClientHttpRequestFactory clientHttpRequestFactory() {
        HttpComponentsClientHttpRequestFactory requestFactory = new HttpComponentsClientHttpRequestFactory();

        requestFactory.setConnectTimeout(5000); // 设置链接超时 5s
        requestFactory.setReadTimeout(10000);   // 设置读取超时 10s

        return requestFactory;
    }

}

需要指定一个 ClientHttpRequestFactory,ClientHttpRequestFactory 是一个接口,有很多实现类:

1、SimpleClientHttpRequestFactory

2、HttpComponentsClientHttpRequestFactory (生产环境推荐这个)

通过 RestTemplateBuilder

java 复制代码
@Configuration
public class RestTemplateConfig {

    @Bean
    public RestTemplate restTemplate(RestTemplateBuilder builder) {
        return builder
                .rootUri("http://localhost:8080")
                .connectTimeout(Duration.ofSeconds(5))
                .readTimeout(Duration.ofSeconds(10))
                .build();
    }

}

异常处理

RestTemplate 默认会将 HTTP 错误响应码(4xx和5xx)转换为特定的异常抛出。以下是关于这种机制及其处理方式的详细说明。

RestTemplate 抛出的异常主要是 RestClientException,而RestClientException又可以再细分:

1、HttpClientErrorException:4xx

2、HttpServerErrorException:5xx

3、ResourceAccessException:网络原因

4、xx

java 复制代码
String url = UriComponentsBuilder.fromUri(URI.create("http://localhost:9090"))
        .path("/api/hello/{id}")
        .queryParam("name", "CongVee")
        .buildAndExpand(123)  // 设置路径参数
        .toUriString();

try {
    ResponseEntity<String> responseEntity = restTemplate.exchange(
            url,
            HttpMethod.GET,
            null,
            String.class
    );

    // 成功响应,也就是 2xx
    log.info("Calling third party API");

    return responseEntity.getBody();

} catch (HttpClientErrorException e) {
    // 4xx
    log.error("Error calling third party API", e);
    throw e;
} catch (HttpServerErrorException e) {
    // 5xx 服务器错误
    log.error("Error calling third party API", e);
    throw e;
} catch (ResourceAccessException e) {
    // 网络错误, 通常需要重试
    log.error("Error calling third party API", e);
    throw e;
}

重试

一般对 5xx 和 网络问题进行重试,也就是 HttpServerErrorException 和 ResourceAccessException 异常进行重试。

java 复制代码
@Service
@RequiredArgsConstructor
public class ThirdPartyClient {

    private static final Logger log = LoggerFactory.getLogger(ThirdPartyClient.class);

    @Autowired
    private RestTemplate restTemplate;

    @Retryable(retryFor = {RestClientException.class}, 
               noRetryFor = {HttpClientErrorException.class}, 
               maxAttempts = 3, 
               backoff = @Backoff(delay = 5000))
    public String getHello() {

        URI url = UriComponentsBuilder
                .fromPath("/api/hello/{id}")
                .queryParam("name", "CongVee")
                .buildAndExpand(123)  // 设置路径参数
                .toUri();

        User user = new User();
        user.setName("CongVee");
        user.setAge(25);

        ResponseEntity<String> responseEntity = restTemplate.exchange(
                url,
                HttpMethod.POST,
                new HttpEntity<>(user),
                String.class
        );

        restTemplate.delete(url);

        // 只有 2xx 和 3xx 不会进入catch
        log.info("Calling third party API");


        return responseEntity.getBody();
    }

    @Recover
    public String recover(RestClientException e, String url) {
        return "Fallback Data"; // 重试全部失败后的降级处理
    }

}
相关推荐
Q_Q5110082852 小时前
python的校园兼职系统
开发语言·spring boot·python·django·flask·node.js·php
booooooty2 小时前
【Java项目设计】基于Springboot+Vue的OA办公自动化系统
java·vue.js·spring boot·毕业设计·课程设计·程序开发
屋外雨大,惊蛰出没4 小时前
Vue+spring boot前后端分离项目搭建---小白入门
前端·vue.js·spring boot
武昌库里写JAVA4 小时前
Vue状态管理实践:使用Vuex进行前端状态管理
java·vue.js·spring boot·课程设计·宠物管理
努力的小郑4 小时前
深入Spring源码揭秘:@Value注解如何给普通字段注入魔法?
spring boot·spring
爱捣鼓的XiaoPu4 小时前
基于Spring Boot+Vue的“暖寓”宿舍管理系统设计与实现(源码及文档)
vue.js·spring boot·后端
Cosmoshhhyyy5 小时前
Spring-AI-Alibaba快速体验(配置流程和注意事项)
java·spring boot·spring
HeartException5 小时前
Spring Boot + MyBatis Plus + SpringAI + Vue 毕设项目开发全解析(源码)
人工智能·spring boot·学习
Koma-forever6 小时前
Rabbitmq的五种消息类型介绍,以及集成springboot的使用
spring boot·rabbitmq·java-rabbitmq