?
一、概述
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。
?