RestTemplate 的入门使用,直接给上作者的项目Demo

文章目录

    • [一、RestTemplate 是什么?](#一、RestTemplate 是什么?)
    • 二、快速入门
      • [2.1 添加依赖](#2.1 添加依赖)
      • [2.2 配置RestTemplate Bean](#2.2 配置RestTemplate Bean)
      • [2.3 第一个GET请求](#2.3 第一个GET请求)
    • 三、核心方法详解
      • [3.1 GET请求](#3.1 GET请求)
        • [(1) getForObject 示例](#(1) getForObject 示例)
        • [(2) getForEntity 示例](#(2) getForEntity 示例)
      • [3.2 POST请求](#3.2 POST请求)
        • [(1) 发送JSON数据](#(1) 发送JSON数据)
        • [(2) 发送表单数据](#(2) 发送表单数据)
      • [3.3 PUT、DELETE请求](#3.3 PUT、DELETE请求)
      • [3.4 万能的exchange方法](#3.4 万能的exchange方法)
      • [3.5 处理集合类型](#3.5 处理集合类型)
    • 四、进阶配置
      • [4.1 设置超时时间](#4.1 设置超时时间)
      • [4.2 切换底层HTTP客户端](#4.2 切换底层HTTP客户端)
      • [4.3 统一添加请求头(拦截器)](#4.3 统一添加请求头(拦截器))
    • 五、异常处理
    • 六、最佳实践总结
    • 参考文档

一、RestTemplate 是什么?

RestTemplate 是Spring 3.0就开始提供的同步HTTP客户端工具,位于 spring-web 模块中。它封装了底层HTTP库(JDK自带的 HttpURLConnection、Apache HttpClient、OkHttp等)的复杂性,提供了一套简洁的模板方法API。

简单说,它把发请求、处理响应、解析JSON等重复劳动都包办了。我们只需要告诉它:请求地址是什么?用什么方法?参数是什么?期望返回什么类型? 剩下的脏活累活它全搞定。


二、快速入门

2.1 添加依赖

如果你的项目是基于Spring Boot的,只需要引入Web起步依赖:

xml 复制代码
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>

这个依赖已经包含了 spring-web 模块,RestTemplate就在其中。

2.2 配置RestTemplate Bean

在Spring Boot 2.x及以上版本中,RestTemplate不会自动注入到容器里,需要我们手动注册。推荐在配置类中声明:

java 复制代码
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.client.RestTemplate;

@Configuration
public class RestTemplateConfig {

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

2.3 第一个GET请求

配置好之后,在你的Service或Controller里注入RestTemplate,然后就可以愉快地发请求了:

java 复制代码
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;

@RestController
public class TestController {

    @Autowired
    private RestTemplate restTemplate;

    @GetMapping("/test")
    public String testGet() {
        // 请求一个公开的API
        String url = "https://api.github.com/users/defunkt";
        // 直接获取响应体,转换为String
        String result = restTemplate.getForObject(url, String.class);
        return result;
    }
}

启动项目,访问 http://localhost:8080/test,你就能看到从GitHub API返回的JSON数据了!


三、核心方法详解

RestTemplate为每种HTTP方法都提供了对应的模板方法。下面我们逐一讲解最常用的几个。

3.1 GET请求

GET请求主要有两种方法:getForObjectgetForEntity

方法 返回值 说明
getForObject() 直接返回响应体(JSON转成的对象) 简单粗暴,适合只需要数据体的场景
getForEntity() 返回ResponseEntity<T>对象 包含状态码、响应头等完整信息
(1) getForObject 示例

假设我们有一个实体类 User

java 复制代码
public class User {
    private Long id;
    private String name;
    // 省略getter/setter
}
java 复制代码
// 方式1:直接返回User对象
String url = "http://localhost:8080/users/{id}";
User user = restTemplate.getForObject(url, User.class, 1);

// 方式2:使用Map传递多个参数
Map<String, String> params = new HashMap<>();
params.put("id", "1");
params.put("name", "张三");
User user2 = restTemplate.getForObject("http://localhost:8080/users/{id}?name={name}", 
                                       User.class, params);
(2) getForEntity 示例
java 复制代码
ResponseEntity<User> response = restTemplate.getForEntity(url, User.class, 1);

// 获取完整响应信息
HttpStatus statusCode = response.getStatusCode();  // 状态码
int statusCodeValue = response.getStatusCodeValue(); // 200, 404等
HttpHeaders headers = response.getHeaders();        // 响应头
User body = response.getBody();                     // 响应体

if (response.getStatusCode().is2xxSuccessful()) {
    System.out.println("请求成功:" + body.getName());
}

3.2 POST请求

POST请求同样有三个常用方法:

方法 说明
postForObject() 提交数据,直接返回响应体
postForEntity() 提交数据,返回完整响应
postForLocation() 提交数据,只返回响应头中的Location(常用于创建资源后获取新资源地址)
(1) 发送JSON数据
java 复制代码
User newUser = new User();
newUser.setName("李四");

ResponseEntity<User> response = restTemplate.postForEntity(
    "http://localhost:8080/users",
    newUser,   // Spring会自动将对象转成JSON
    User.class
);
(2) 发送表单数据
java 复制代码
// 表单数据需要用MultiValueMap包装
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);

MultiValueMap<String, String> formData = new LinkedMultiValueMap<>();
formData.add("username", "zhangsan");
formData.add("password", "123456");

HttpEntity<MultiValueMap<String, String>> request = new HttpEntity<>(formData, headers);

String result = restTemplate.postForObject(
    "http://localhost:8080/login",
    request,
    String.class
);

3.3 PUT、DELETE请求

PUT和DELETE相对简单,一般不需要处理返回值:

java 复制代码
// PUT - 更新资源
User updatedUser = new User();
updatedUser.setName("王五");
restTemplate.put("http://localhost:8080/users/{id}", updatedUser, 1);

// DELETE - 删除资源
restTemplate.delete("http://localhost:8080/users/{id}", 1);

3.4 万能的exchange方法

如果觉得上面的方法不够灵活,exchange 是RestTemplate最通用的方法,可以应对各种复杂场景:

java 复制代码
// 设置请求头
HttpHeaders headers = new HttpHeaders();
headers.set("Authorization", "Bearer token123");
headers.setContentType(MediaType.APPLICATION_JSON);

// 构建请求实体
HttpEntity<String> requestEntity = new HttpEntity<>(requestJson, headers);

// 发送请求,使用ParameterizedTypeReference处理泛型
ResponseEntity<List<User>> response = restTemplate.exchange(
    "http://localhost:8080/users/list",
    HttpMethod.GET,
    requestEntity,
    new ParameterizedTypeReference<List<User>>() {}
);

3.5 处理集合类型

当接口返回的是List<User>这样的泛型集合时,直接用User[].class或者使用ParameterizedTypeReference

java 复制代码
// 方式1:使用数组(简单)
User[] users = restTemplate.getForObject(url, User[].class);

// 方式2:使用ParameterizedTypeReference(推荐,类型安全)
ResponseEntity<List<User>> response = restTemplate.exchange(
    url,
    HttpMethod.GET,
    null,
    new ParameterizedTypeReference<List<User>>() {}
);
List<User> userList = response.getBody();

四、进阶配置

4.1 设置超时时间

默认情况下,RestTemplate没有设置超时,可能会导致线程长时间阻塞。推荐进行超时配置:

java 复制代码
@Bean
public RestTemplate restTemplate() {
    // 使用HttpComponentsClientHttpRequestFactory
    HttpComponentsClientHttpRequestFactory factory = new HttpComponentsClientHttpRequestFactory();
    
    factory.setConnectTimeout(5000);      // 连接超时 5秒
    factory.setReadTimeout(10000);        // 读取超时 10秒
    factory.setConnectionRequestTimeout(3000); // 从连接池获取连接的超时 3秒
    
    return new RestTemplate(factory);
}

需要先在pom.xml中添加依赖:

xml 复制代码
<dependency>
    <groupId>org.apache.httpcomponents</groupId>
    <artifactId>httpclient</artifactId>
    <version>4.5.13</version>
</dependency>

4.2 切换底层HTTP客户端

RestTemplate默认使用JDK自带的HttpURLConnection,你可以切换到性能更好的实现:

底层库 配置方式
Apache HttpClient new RestTemplate(new HttpComponentsClientHttpRequestFactory())
OkHttp new RestTemplate(new OkHttp3ClientHttpRequestFactory())
java 复制代码
// 切换到OkHttp
@Bean
public RestTemplate restTemplate() {
    return new RestTemplate(new OkHttp3ClientHttpRequestFactory());
}

4.3 统一添加请求头(拦截器)

如果每个请求都需要添加相同的请求头(如认证Token),可以用拦截器统一处理:

java 复制代码
@Bean
public RestTemplate restTemplate() {
    RestTemplate restTemplate = new RestTemplate();
    
    // 添加拦截器
    restTemplate.getInterceptors().add((request, body, execution) -> {
        request.getHeaders().add("User-Agent", "MyApp/1.0");
        request.getHeaders().add("Authorization", "Bearer " + getToken());
        return execution.execute(request, body);
    });
    
    return restTemplate;
}

五、异常处理

RestTemplate在遇到4xx或5xx状态码时会抛出异常,默认由DefaultResponseErrorHandler处理。我们可以自定义异常处理逻辑:

java 复制代码
@Bean
public RestTemplate restTemplate() {
    RestTemplate restTemplate = new RestTemplate();
    
    // 设置自定义错误处理器,避免直接抛异常
    restTemplate.setErrorHandler(new ResponseErrorHandler() {
        @Override
        public boolean hasError(ClientHttpResponse response) throws IOException {
            // 只有5xx才算错误,4xx不抛异常
            return response.getStatusCode().is5xxServerError();
        }
        
        @Override
        public void handleError(ClientHttpResponse response) throws IOException {
            // 自定义错误处理逻辑
            System.err.println("请求出错:" + response.getStatusText());
        }
    });
    
    return restTemplate;
}

在实际开发中,建议用try-catch包裹RestTemplate调用:

java 复制代码
try {
    User user = restTemplate.getForObject(url, User.class);
    return user;
} catch (RestClientException e) {
    log.error("调用远程服务失败", e);
    // 降级处理或抛出自定义业务异常
    throw new BusinessException("服务暂时不可用");
}

六、最佳实践总结

  1. 复用RestTemplate实例:RestTemplate是线程安全的,整个应用应该只创建一个Bean,到处注入使用。

  2. 配置合理的超时:永远不要使用无超时的RestTemplate,否则一个下游故障可能拖垮整个系统。

  3. 使用exchange处理复杂场景 :当需要自定义请求头、处理泛型响应时,exchange是最佳选择。

  4. 异常一定要处理:网络调用不可靠,做好异常捕获和降级是基本功。

  5. 考虑升级到WebClient :如果是新项目,或者对性能要求较高,可以考虑使用WebClient,它的API更现代,支持响应式编程。

参考文档

相关推荐
疯狂打码的少年2 小时前
JDK 7、8、13 和 20区别深度了解
java·开发语言
钝挫力PROGRAMER2 小时前
Java中如何优雅管理接口的多个实现
java·设计模式
迷藏4942 小时前
# 发散创新:基于Python的自动特征工程实战与深度优化在机器学习
java·开发语言·python·机器学习
星晨雪海2 小时前
查询区域列表并统计点位数量
java
Seven972 小时前
用300行代码手写一个mini版的Tomcat
java
隐退山林2 小时前
JavaEE进阶:SpirngMVC入门(2)
java·java-ee
小江的记录本4 小时前
【分布式】分布式核心组件——分布式锁:Redis/ZooKeeper/etcd 实现方案(附全方位对比表)、优缺点、Redlock、时钟回拨问题
java·网络·redis·分布式·后端·zookeeper·架构
好家伙VCC4 小时前
**发散创新:用Rust实现基于RAFT共识算法的轻量级分布式日志系统**在分布式系统中,**一致性协议**是保障数据可靠
java·分布式·python·rust·共识算法
晔子yy5 小时前
【JAVA探索之路】从头开始讲透、实现单例模式
java·开发语言·单例模式