在Spring生态系统中,RestTemplate是一个功能强大的HTTP客户端工具,它简化了与RESTful服务的交互。本文将深入探讨RestTemplate的使用方法,特别是如何发送POST JSON请求,并提供实用的代码示例。
RestTemplate是Spring框架提供的用于访问REST服务的客户端,它提供了多种便捷方法来执行HTTP请求。虽然Spring 5.0后推荐使用WebClient,但RestTemplate在许多项目中仍然广泛使用。
org.springframework
spring-web
5.3.21
@Configuration
public class RestTemplateConfig {
@Bean
public RestTemplate restTemplate() {
return new RestTemplate();
}
// 带超时配置的RestTemplate
@Bean("timeoutRestTemplate")
public RestTemplate timeoutRestTemplate() {
HttpComponentsClientHttpRequestFactory factory =
new HttpComponentsClientHttpRequestFactory();
factory.setConnectTimeout(5000);
factory.setReadTimeout(10000);
return new RestTemplate(factory);
}
}
@Service
public class ApiService {
@Autowired
private RestTemplate restTemplate;
public String sendPostRequest() {
String url = "https://jsonplaceholder.typicode.com/posts";
// 创建请求体
Map requestBody = new HashMap<>();
requestBody.put("title", "Spring RestTemplate示例");
requestBody.put("body", "这是一个POST请求示例");
requestBody.put("userId", 1);
// 发送POST请求
String response = restTemplate.postForObject(url, requestBody, String.class);
return response;
}
}
// 请求实体类
public class PostRequest {
private String title;
private String body;
private Integer userId;
// 构造函数、getter、setter
public PostRequest(String title, String body, Integer userId) {
this.title = title;
this.body = body;
this.userId = userId;
}
// getters and setters...
}
// 响应实体类
public class PostResponse {
private Integer id;
private String title;
private String body;
private Integer userId;
// getters and setters...
}
// 服务类中的使用
public PostResponse createPost() {
String url = "https://jsonplaceholder.typicode.com/posts";
PostRequest request = new PostRequest(
"RestTemplate实战",
"使用实体类发送POST请求",
1
);
PostResponse response = restTemplate.postForObject(
url,
request,
PostResponse.class
);
return response;
}
public String postWithHeaders() {
String url = "https://api.example.com/data";
// 设置请求头
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
headers.set("Authorization", "Bearer your-token");
headers.set("Custom-Header", "custom-value");
// 创建请求体
Map requestBody = new HashMap<>();
requestBody.put("name", "张三");
requestBody.put("email", "[email protected]");
// 组装HttpEntity
HttpEntity
// 简单GET请求
public String getRequest() {
String url = "https://jsonplaceholder.typicode.com/posts/1";
return restTemplate.getForObject(url, String.class);
}
// 带参数的GET请求
public String getWithParams() {
String url = "https://jsonplaceholder.typicode.com/posts?userId={userId}";
return restTemplate.getForObject(url, String.class, 1);
}
// 使用Map传递参数
public String getWithMapParams() {
String url = "https://jsonplaceholder.typicode.com/posts?userId={userId}&id={id}";
Map params = new HashMap<>();
params.put("userId", 1);
params.put("id", 1);
return restTemplate.getForObject(url, String.class, params);
}
// PUT请求
public void updatePost() {
String url = "https://jsonplaceholder.typicode.com/posts/1";
PostRequest request = new PostRequest("更新标题", "更新内容", 1);
restTemplate.put(url, request);
}
// DELETE请求
public void deletePost() {
String url = "https://jsonplaceholder.typicode.com/posts/1";
restTemplate.delete(url);
}
public String safePostRequest() {
try {
String url = "https://api.example.com/data";
Map requestBody = new HashMap<>();
requestBody.put("data", "test");
return restTemplate.postForObject(url, requestBody, String.class);
} catch (HttpClientErrorException e) {
// 4xx错误
log.error("客户端错误: {}, 响应体: {}", e.getStatusCode(), e.getResponseBodyAsString());
return "客户端请求错误";
} catch (HttpServerErrorException e) {
// 5xx错误
log.error("服务器错误: {}, 响应体: {}", e.getStatusCode(), e.getResponseBodyAsString());
return "服务器内部错误";
} catch (ResourceAccessException e) {
// 网络连接错误
log.error("网络连接错误: {}", e.getMessage());
return "网络连接失败";
}
}
@Component
public class CustomResponseErrorHandler implements 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().series() == HttpStatus.Series.SERVER_ERROR) {
// 处理5xx错误
throw new HttpServerErrorException(response.getStatusCode());
} else if (response.getStatusCode().series() == HttpStatus.Series.CLIENT_ERROR) {
// 处理4xx错误
throw new HttpClientErrorException(response.getStatusCode());
}
}
}
// 在配置中使用
@Bean
public RestTemplate customRestTemplate(CustomResponseErrorHandler errorHandler) {
RestTemplate restTemplate = new RestTemplate();
restTemplate.setErrorHandler(errorHandler);
return restTemplate;
}
@Service
public class WeatherService {
@Autowired
private RestTemplate restTemplate;
@Value("${weather.api.key}")
private String apiKey;
public WeatherInfo getWeather(String city) {
String url = "https://api.openweathermap.org/data/2.5/weather?q={city}&appid={apiKey}";
Map params = new HashMap<>();
params.put("city", city);
params.put("apiKey", apiKey);
try {
return restTemplate.getForObject(url, WeatherInfo.class, params);
} catch (Exception e) {
log.error("获取天气信息失败: {}", e.getMessage());
return null;
}
}
public boolean submitWeatherData(WeatherData data) {
String url = "https://api.weather-service.com/submit";
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
headers.set("API-Key", apiKey);
HttpEntity entity = new HttpEntity<>(data, headers);
try {
ResponseEntity response = restTemplate.postForEntity(url, entity, String.class);
return response.getStatusCode().is2xxSuccessful();
} catch (Exception e) {
log.error("提交天气数据失败: {}", e.getMessage());
return false;
}
}
}
@Bean
public RestTemplate pooledRestTemplate() {
PoolingHttpClientConnectionManager connectionManager =
new PoolingHttpClientConnectionManager();
connectionManager.setMaxTotal(100);
connectionManager.setDefaultMaxPerRoute(20);
CloseableHttpClient httpClient = HttpClients.custom()
.setConnectionManager(connectionManager)
.build();
HttpComponentsClientHttpRequestFactory factory =
new HttpComponentsClientHttpRequestFactory(httpClient);
return new RestTemplate(factory);
}
@Bean
public RestTemplate configuredRestTemplate() {
HttpComponentsClientHttpRequestFactory factory =
new HttpComponentsClientHttpRequestFactory();
// 连接超时:5秒
factory.setConnectTimeout(5000);
// 读取超时:10秒
factory.setReadTimeout(10000);
// 连接请求超时:3秒
factory.setConnectionRequestTimeout(3000);
return new RestTemplate(factory);
}
@Component
public class ResilientApiClient {
private final RestTemplate restTemplate;
private final RetryTemplate retryTemplate;
public ResilientApiClient(RestTemplate restTemplate) {
this.restTemplate = restTemplate;
this.retryTemplate = RetryTemplate.builder()
.maxAttempts(3)
.fixedBackoff(1000)
.retryOn(ResourceAccessException.class)
.build();
}
public String callApiWithRetry(String url, Object request) {
return retryTemplate.execute(context -> {
log.info("尝试调用API,第{}次", context.getRetryCount() + 1);
return restTemplate.postForObject(url, request, String.class);
});
}
}
RestTemplate是Spring框架中强大且易用的HTTP客户端工具。通过本文的介绍,你应该能够:
虽然Spring推荐在新项目中使用WebClient,但RestTemplate在现有项目中仍然是一个可靠的选择。掌握其使用方法对于Spring开发者来说是必不可少的技能。
记住,在生产环境中使用时,务必注意异常处理、超时配置和连接池优化,这些细节将直接影响应用的稳定性和性能。