Spring Boot 中的 RestTemplate

本文深入讲解了Spring Boot中RestTemplate的高级用法,包括构造URI、传递HTTPHeader、类型转换、解析泛型对象等技巧,同时提供了定制RestTemplate的示例,优化了底层请求策略,并详细介绍了连接管理和超时设置的方法。

RestTemplate 访问 Web 资源

  • Spring Boot 中没有自动配置 RestTemplate
  • Spring Boot 提供了 RestTemplateBuilder
RestTemplateBuilder.build()

请求方式

GET 请求

  • getForObject() / getForEntiry()

POST 请求

  • postForObject() / postForObject()

PUT 请求

  • put()

DELETE 请求

  • delete()

请求示例

RestTemplate restTemplate = new RestTemplateBuilder().build();
URI uri = UriComponentsBuilder
        .fromUriString("http://localhost:9090/mapper/user/find/{userId}")
        .encode(StandardCharsets.UTF_8)
        .build(6);
ResponseEntity<UserEntity> result = restTemplate.getForEntity(uri, UserEntity.class);
log.info("statusCode:{}, statusCodeValue:{}, headers:{},body:{}", result.getStatusCode(), result.getStatusCodeValue(), result.getHeaders(), result.getBody());

对应的日志

15:40:14.378 [main] DEBUG org.springframework.web.client.RestTemplate - HTTP GET http://localhost:9090/mapper/user/find/6
15:40:14.443 [main] DEBUG org.springframework.web.client.RestTemplate - Accept=[application/json, application/*+json]
15:40:14.481 [main] DEBUG org.springframework.web.client.RestTemplate - Response 200 OK
15:40:14.485 [main] DEBUG org.springframework.web.client.RestTemplate - Reading to [top.chenfu1201.mapper.entity.UserEntity]
15:48:45.402 [main] INFO top.chenfu1201.mapper.controller.UserController - statusCode:200 OK, statusCodeValue:200, headers:{Content-Type=[application/json;charset=UTF-8], Transfer-Encoding=[chunked], Date=[Tue, 05 May 2020 07:48:45 GMT]},body:UserEntity(userId=6, createTime=Fri Aug 16 20:16:10 CST 2019, updateTime=Fri Aug 16 20:41:47 CST 2019, email=2323@12.com, userName=韩小姐, age=null, gender=0)

RestTemplate 高阶用法

构造 URI

  • UriComponentsBuilder
URI uri = UriComponentsBuilder
        .fromUriString("http://localhost:9090/mapper/user/queryAll")
        .encode(StandardCharsets.UTF_8)
        .build()
        .toUri();
  • ServletUriComponentsBuilder
  • MvcUriComponentsBuilder

传递 HTTP Header

在企业开发中,我们经常会在 header 中携带一些校验信息,比如 token 。使用方式如下

  • RestTemplate.exchange() 配合 RequestEntity<T> / ResponseEntiry<T>

示例

URI uri = UriComponentsBuilder
        .fromUriString("http://localhost:9090/mapper/user/find/{userId}")
        .encode(StandardCharsets.UTF_8)
        .build(6);
RequestEntity<Void> requestEntity = RequestEntity
		.get(uri)
        .header("token", "mytoken")
        .build();
ResponseEntity<UserEntity> result = restTemplate.exchange(requestEntity, UserEntity.class);
log.info("statusCode:{}, statusCodeValue:{}, headers:{},body:{}", result.getStatusCode(), result.getStatusCodeValue(), result.getHeaders(), result.getBody());

类型转换

  • JsonSerializer / JsonDeserializer
  • @JsonComponent

解析泛型对象

  • RestTemplate.exchange() 配合 ParameterizedTypeReference<T>

示例

ParameterizedTypeReference<List<UserEntity>> listPtr =
        new ParameterizedTypeReference<List<UserEntity>>() {};
String url = "http://localhost:9090/mapper/user/queryAll";
ResponseEntity<List<UserEntity>> result = restTemplate.exchange(url, HttpMethod.GET, null, listPtr);
log.info("statusCode:{}, statusCodeValue:{}, headers:{}", result.getStatusCode(), result.getStatusCodeValue(), result.getHeaders());
result.getBody().forEach(u -> log.info("user:{}", u));

日志

16:17:24.351 [main] DEBUG org.springframework.web.client.RestTemplate - HTTP GET http://localhost:9090/mapper/user/queryAll
16:17:24.425 [main] DEBUG org.springframework.web.client.RestTemplate - Accept=[application/json, application/*+json]
16:17:24.524 [main] DEBUG org.springframework.web.client.RestTemplate - Response 200 OK
16:17:24.533 [main] DEBUG org.springframework.web.client.RestTemplate - Reading to [java.util.List<top.chenfu1201.mapper.entity.UserEntity>]
16:17:24.659 [main] INFO top.chenfu1201.mapper.controller.UserController - statusCode:200 OK, statusCodeValue:200, headers:{Content-Type=[application/json;charset=UTF-8], Transfer-Encoding=[chunked], Date=[Tue, 05 May 2020 08:17:24 GMT]}
16:17:24.662 [main] INFO top.chenfu1201.mapper.controller.UserController - user:UserEntity(userId=6, createTime=Fri Aug 16 20:16:10 CST 2019, updateTime=Fri Aug 16 20:41:47 CST 2019, email=2323@12.com, userName=韩小姐, age=null, gender=0)
16:17:24.662 [main] INFO top.chenfu1201.mapper.controller.UserController - user:UserEntity(userId=7, createTime=Fri Aug 16 21:02:47 CST 2019, updateTime=null, email=null, userName=赵司令0, age=17, gender=1)
---

错误示例

List<UserEntity> listPtr = new ArrayList<>();
String url = "http://localhost:9090/mapper/user/queryAll";
List result = restTemplate.getForObject(url, listPtr.getClass());
System.out.println(result.get(0).getClass());

日志

16:38:05.466 [main] DEBUG org.springframework.web.client.RestTemplate - HTTP GET http://localhost:9090/mapper/user/queryAll
16:38:05.516 [main] DEBUG org.springframework.web.client.RestTemplate - Accept=[application/json, application/*+json]
16:38:05.698 [main] DEBUG org.springframework.web.client.RestTemplate - Response 200 OK
16:38:05.713 [main] DEBUG org.springframework.web.client.RestTemplate - Reading to [java.util.ArrayList<?>]
class java.util.LinkedHashMap

可以看到每个实体是用 LinkedHashMap 来封装的,所以 List 集合内的泛型一旦改成某个实体类型,就会报 ClassCastException !

定制 Rest Template

Rest Teamplate 支持的 HTTP 库

通用接口
  • ClientHttpRequestFactory
默认实现
  • SimpleClientHttpRequestFactory
第三方实现

Apache HttpComponents【以前的 Http Client】

  • HttpComponentsClientHttpRequestFactory

Netty

  • Netty4ClientHttpRequestFactory

OkHttp

  • OkHttp3ClientHttpRequestFactory

优化底层请求策略

连接管理
  • PoolingHttpClientConnectionManager
  • KeepAlive 策略
    使用 Apache HttpComponents 后的默认策略 DefaultConnectionKeepAliveStrategy
@Override
public long getKeepAliveDuration(final HttpResponse response, final HttpContext context) {
    Args.notNull(response, "HTTP response");
    final HeaderElementIterator it = new BasicHeaderElementIterator(
            response.headerIterator(HTTP.CONN_KEEP_ALIVE));
    while (it.hasNext()) {
        final HeaderElement he = it.nextElement();
        final String param = he.getName();
        final String value = he.getValue();
        if (value != null && param.equalsIgnoreCase("timeout")) {
            try {
                return Long.parseLong(value) * 1000;
            } catch(final NumberFormatException ignore) {
            }
        }
    }
    return -1;
}
超时设置
  • connectTimeout / readTimeout
SSL 校验
  • 证书检查策略
自定义配置示例【使用 httpcomponents 】
package top.chenfu1201.mapper.config;

import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.DefaultConnectionKeepAliveStrategy;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.springframework.boot.SpringBootConfiguration;
import org.springframework.boot.web.client.RestTemplateBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
import org.springframework.web.client.RestTemplate;

import java.time.Duration;
import java.util.concurrent.TimeUnit;

@SpringBootConfiguration
public class RestTemplateConfig {

    @Bean
    public HttpComponentsClientHttpRequestFactory requestFactory() {
        PoolingHttpClientConnectionManager connectionManager =
                new PoolingHttpClientConnectionManager(30, TimeUnit.SECONDS);
        connectionManager.setMaxTotal(200);
        connectionManager.setDefaultMaxPerRoute(20);

        CloseableHttpClient httpClient = HttpClients.custom()
                .setConnectionManager(connectionManager)
                .evictIdleConnections(30, TimeUnit.SECONDS)
                .disableAutomaticRetries()
                // 有 Keep-Alive 认里面的值,没有的话永久有效
                .setKeepAliveStrategy(DefaultConnectionKeepAliveStrategy.INSTANCE)
                .build();

        HttpComponentsClientHttpRequestFactory requestFactory =
                new HttpComponentsClientHttpRequestFactory(httpClient);

        return requestFactory;
    }

    @Bean
    public RestTemplate restTemplate(RestTemplateBuilder builder) {
        return builder
                .setConnectTimeout(Duration.ofMillis(100))
                .setReadTimeout(Duration.ofMillis(500))
                .requestFactory(this::requestFactory)
                .build();
    }
    
}
<think>好的,我现在需要帮助用户了解如何在Spring Boot中使用RestTemplate进行HTTP请求。用户已经提供了相关的引用内容,我需要整合这些信息并生成一个清晰的回答,同时附上相关问题。 首先,我需要回忆RestTemplate的基本用法。根据引用中的信息,Spring Boot已经配置好了RestTemplate,用户需要添加依赖、创建Bean,然后使用它发送请求。引用[3]提到了需要添加spring-boot-starter-web依赖,并创建一个配置类来生成RestTemplate的Bean。这是关键的第一步,因为如果没有正确配置Bean,后续无法注入使用。 接下来,用户需要一个示例。我应该分步骤说明,从依赖添加、配置Bean到具体的GET、POST请求示例。引用[3]中的代码片段可以直接引用,展示如何创建配置类。然后,在Service中使用@Autowired注入RestTemplate,并调用getForObject或postForObject等方法。需要确保代码示例正确,比如URL占位符的使用和请求体的构建。 还要注意用户提到的LaTeX格式要求,虽然这个问题可能不涉及数学公式,但如果有变量或代码内联,可能需要用$...$包裹。不过在这个案例中,代码块已经用反引号标记,所以可能不需要额外的处理。但需要检查是否有需要格式化的部分,比如方法名或参数,确保符合用户的格式要求。 然后,生成相关问题。根据用户提供的示例中的问题,应该围绕RestTemplate的配置、高级用法、异常处理、性能优化以及与Feign的比较等方面提问。这些问题需要自然相关,帮助用户进一步学习。 同时,需要确保回答结构清晰,分步骤说明,并正确引用提供的参考资料。引用标识应放在相关步骤的末尾,例如在添加依赖的部分引用[3],在配置Bean的部分同样引用[3],在实战示例中引用[2]。需要注意引用标记的位置要自然,不打断阅读流程。 最后,检查是否符合所有系统级指令:使用正确的中文,LaTeX语法正确(虽然这里可能用不上),生成相关问题,引用正确。确保没有使用用户不可见的内容,所有信息都基于提供的引用,并且代码示例正确无误。</think>在Spring Boot中使用RestTemplate进行HTTP请求主要包括依赖配置、Bean创建及方法调用三个步骤。以下是具体实现示例: ### 一、添加依赖配置 首先在pom.xml中添加web模块依赖: ```xml <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> ``` 该依赖包含RestTemplate核心库[^3]。 ### 二、创建RestTemplate Bean 定义配置类注册RestTemplate实例: ```java @Configuration public class RestTemplateConfig { @Bean public RestTemplate restTemplate() { return new RestTemplate(); } } ``` 建议在此处配置连接池、超时时间等参数[^3]。 ### 三、HTTP请求实战示例 #### 1. GET请求 ```java @Service public class ApiService { @Autowired private RestTemplate restTemplate; public User getUser(String userId) { return restTemplate.getForObject( "http://api.example.com/users/{id}", User.class, userId ); } } ``` #### 2. POST请求 ```java public ResponseEntity<String> createUser(User user) { HttpHeaders headers = new HttpHeaders(); headers.setContentType(MediaType.APPLICATION_JSON); HttpEntity<User> request = new HttpEntity<>(user, headers); return restTemplate.postForEntity( "http://api.example.com/users", request, String.class ); } ``` 支持路径变量、请求头设置等特性[^2]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值