关于Spring RestTemplate
一、概述
RestTemplate 是 Spring Framework 提供的一个同步 HTTP 客户端工具,用于简化与 RESTful API 的交互。它封装了底层 HTTP 通信细节,提供了统一的 API 来发送各种 HTTP 请求(GET、POST、PUT、DELETE 等),并自动处理响应数据的序列化和反序列化。
二、依赖配置
如果使用 Maven 项目,需要在 pom.xml 中添加以下依赖:
xml
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId>
</dependency>
三、基本使用流程
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<User> 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<User> 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<String, Object> updates = new HashMap<>();
updates.put("age", 31);HttpEntity<Map<String, Object>> request = new HttpEntity<>(updates, headers);
String url = "https://api.example.com/users/{id}";ResponseEntity<User> 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<User> request = new HttpEntity<>(requestBody, headers);String url = "https://api.example.com/secure/users";
ResponseEntity<User> 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<User[]> response = restTemplate.getForEntity(url, User[].class);
3. 处理文件上传
使用 MultiValueMap 和 HttpEntity:
MultiValueMap<String, Object> 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<MultiValueMap<String, Object>> requestEntity = new HttpEntity<>(body, headers);
String url = "https://api.example.com/upload";ResponseEntity<String> 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() {@Overridepublic boolean hasError(ClientHttpResponse response) throws IOException {return response.getStatusCode().series() == HttpStatus.Series.CLIENT_ERROR|| response.getStatusCode().series() == HttpStatus.Series.SERVER_ERROR;}@Overridepublic 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<User> 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<String, String> 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<Map<String, String>> request = new HttpEntity<>(requestBody, headers);// 发送 POST 请求
RestTemplate restTemplate = new RestTemplate();
String url = "https://jsonplaceholder.typicode.com/posts";ResponseEntity<Post> 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<User> 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。