关于Spring RestTemplate


一、概述


RestTemplate 是 Spring Framework 提供的一个同步 HTTP 客户端工具,用于简化与 RESTful API 的交互。它封装了底层 HTTP 通信细节,提供了统一的 API 来发送各种 HTTP 请求(GET、POST、PUT、DELETE 等),并自动处理响应数据的序列化和反序列化。

二、依赖配置


如果使用 Maven 项目,需要在 pom.xml 中添加以下依赖:

xml


    org.springframework.boot
    spring-boot-starter-web

三、基本使用流程

RestTemplate restTemplate = new RestTemplate();

// 示例:发送 GET 请求获取用户信息

String url = "https://api.example.com/users/{id}";
User user = restTemplate.getForObject(url, User.class, 123);

四、HTTP 请求方法详解


1. GET 请求
获取资源的基本方法有两种:

1.1 getForObject() - 直接返回响应体

String url = "https://api.example.com/users/{id}";
User user = restTemplate.getForObject(url, User.class, 123);

参数说明:
url:请求 URL,可以包含占位符(如 {id})
responseType:响应数据类型(通常是实体类)
uriVariables:占位符参数值(可变参数或 Map)
1.2 getForEntity() - 返回完整响应实体

ResponseEntity response = restTemplate.getForEntity(url, User.class, 123);
if (response.getStatusCode() == HttpStatus.OK) {
    User user = response.getBody();
    HttpHeaders headers = response.getHeaders();
}

2. POST 请求
用于创建资源,常用方法有三种:

2.1 postForObject() - 直接返回响应体

User newUser = new User("Alice", 25);
String url = "https://api.example.com/users";
User createdUser = restTemplate.postForObject(url, newUser, User.class);

参数说明:
url:请求 URL
request:请求体对象(会自动序列化为 JSON/XML)
responseType:响应数据类型
2.2 postForEntity() - 返回完整响应实体

ResponseEntity response = restTemplate.postForEntity(url, newUser, User.class);

2.3 postForLocation() - 返回新创建资源的 URL

URI location = restTemplate.postForLocation(url, newUser);

3. PUT 请求
用于更新资源(全量更新):

User updatedUser = new User(123, "Bob", 30);
String url = "https://api.example.com/users/{id}";
restTemplate.put(url, updatedUser, 123);

4. DELETE 请求
用于删除资源:

String url = "https://api.example.com/users/{id}";
restTemplate.delete(url, 123);

5. PATCH 请求(部分更新)
使用通用的 exchange() 方法:

HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);

// 创建包含部分更新数据的 Map

Map updates = new HashMap<>();
updates.put("age", 31);

HttpEntity> request = new HttpEntity<>(updates, headers);
String url = "https://api.example.com/users/{id}";

ResponseEntity response = restTemplate.exchange(
    url, 
    HttpMethod.PATCH, 
    request, 
    User.class, 
    123
);

五、处理复杂请求


1. 自定义请求头
使用 HttpEntity 包装请求体和请求头:

HttpHeaders headers = new HttpHeaders();
headers.set("Authorization", "Bearer token123");
headers.setContentType(MediaType.APPLICATION_JSON);

User requestBody = new User("Charlie", 35);
HttpEntity request = new HttpEntity<>(requestBody, headers);

String url = "https://api.example.com/secure/users";
ResponseEntity response = restTemplate.exchange(url, HttpMethod.POST, request, User.class);

2. 处理查询参数
使用 UriComponentsBuilder 构建带查询参数的 URL:

UriComponents uriComponents = UriComponentsBuilder
    .fromUriString("https://api.example.com/users")
    .queryParam("page", 1)
    .queryParam("size", 20)
    .build();

String url = uriComponents.toUriString();
ResponseEntity response = restTemplate.getForEntity(url, User[].class);

3. 处理文件上传
使用 MultiValueMap 和 HttpEntity:

MultiValueMap body = new LinkedMultiValueMap<>();
body.add("file", new FileSystemResource(new File("path/to/file.jpg")));
body.add("name", "test-file");

HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.MULTIPART_FORM_DATA);

HttpEntity> requestEntity = new HttpEntity<>(body, headers);
String url = "https://api.example.com/upload";

ResponseEntity response = restTemplate.exchange(url, HttpMethod.POST, requestEntity, String.class);

六、异常处理


RestTemplate 在遇到 HTTP 错误(4xx/5xx)时会抛出异常:

HttpClientErrorException:4xx 客户端错误
HttpServerErrorException:5xx 服务器错误
ResourceAccessException:网络连接错误
使用 try-catch 块捕获并处理异常:

try {
    User user = restTemplate.getForObject(url, User.class, 999);
} catch (HttpClientErrorException e) {
    if (e.getStatusCode() == HttpStatus.NOT_FOUND) {
        System.out.println("用户不存在");
    } else if (e.getStatusCode() == HttpStatus.UNAUTHORIZED) {
        System.out.println("未授权访问");
    }
    System.out.println("错误响应体: " + e.getResponseBodyAsString());
} catch (HttpServerErrorException e) {
    System.out.println("服务器内部错误: " + e.getStatusCode());
} catch (ResourceAccessException e) {
    System.out.println("网络连接失败: " + e.getMessage());
}

七、自定义配置


1. 注册消息转换器

RestTemplate restTemplate = new RestTemplate();
// 添加 JSON 消息转换器(默认使用 Jackson)
restTemplate.getMessageConverters().add(new MappingJackson2HttpMessageConverter());
// 添加 XML 消息转换器
restTemplate.getMessageConverters().add(new Jaxb2RootElementHttpMessageConverter());

2. 配置超时

使用 SimpleClientHttpRequestFactory:

SimpleClientHttpRequestFactory requestFactory = new SimpleClientHttpRequestFactory();
requestFactory.setConnectTimeout(5000); // 连接超时 5 秒
requestFactory.setReadTimeout(5000);    // 读取超时 5 秒

RestTemplate restTemplate = new RestTemplate(requestFactory);


3. 配置错误处理器

自定义 ResponseErrorHandler:

restTemplate.setErrorHandler(new ResponseErrorHandler() {
    @Override
    public boolean hasError(ClientHttpResponse response) throws IOException {
        return response.getStatusCode().series() == HttpStatus.Series.CLIENT_ERROR
            || response.getStatusCode().series() == HttpStatus.Series.SERVER_ERROR;
    }

    @Override
    public void handleError(ClientHttpResponse response) throws IOException {
        // 自定义错误处理逻辑
        if (response.getStatusCode() == HttpStatus.NOT_FOUND) {
            throw new MyResourceNotFoundException("资源未找到");
        }
    }
});


八、使用示例


1. 完整的 GET 请求示例

RestTemplate restTemplate = new RestTemplate();
String url = "https://api.github.com/users/{username}";

try {
    ResponseEntity response = restTemplate.exchange(
        url,
        HttpMethod.GET,
        null,
        User.class,
        "octocat"
    );
    
    if (response.getStatusCode() == HttpStatus.OK) {
        User user = response.getBody();
        System.out.println("用户名: " + user.getLogin());
        System.out.println("ID: " + user.getId());
    }
} catch (HttpClientErrorException e) {
    System.out.println("GitHub API 错误: " + e.getStatusCode());
} catch (Exception e) {
    System.out.println("发生异常: " + e.getMessage());
}

2. 完整的 POST 请求示例

// 创建请求对象
Map requestBody = new HashMap<>();
requestBody.put("title", "foo");
requestBody.put("body", "bar");
requestBody.put("userId", "1");

// 设置请求头
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);

// 创建 HttpEntity 对象
HttpEntity> request = new HttpEntity<>(requestBody, headers);

// 发送 POST 请求
RestTemplate restTemplate = new RestTemplate();
String url = "https://jsonplaceholder.typicode.com/posts";

ResponseEntity response = restTemplate.exchange(
    url,
    HttpMethod.POST,
    request,
    Post.class
);

// 处理响应
if (response.getStatusCode() == HttpStatus.CREATED) {
    Post createdPost = response.getBody();
    System.out.println("创建的帖子 ID: " + createdPost.getId());
}

九、替代方案


从 Spring 5 开始,推荐使用 WebClient 替代 RestTemplate,因为它支持响应式编程和非阻塞 I/O:

WebClient webClient = WebClient.create();

// 异步 GET 请求示例
Mono userMono = webClient.get()
    .uri("https://api.example.com/users/{id}", 123)
    .retrieve()
    .bodyToMono(User.class);

// 订阅并处理结果

userMono.subscribe(user -> System.out.println("用户: " + user.getName()));

十、总结


RestTemplate 是 Spring 框架中处理 REST API 的经典工具,适合同步、阻塞的 HTTP 通信场景。它提供了简洁的 API 和强大的消息转换机制,能大幅简化与外部服务的交互。不过,对于高并发场景,建议使用更现代的 WebClient。

关于Spring RestTemplate_第1张图片

你可能感兴趣的:(关于Spring RestTemplate)