RestTemplate是Spring框架提供的一个工具类,用于进行网络请求。通过RestTemplate,可以简化开发,提高开发效率,避免重复造轮子等。本文将介绍RestTemplate的常见用法,包括GET和POST请求、文件上传、以及常用配置。

RestTemplate简单使用

创建RestTemplate

使用RestTemplate需要创建一个RestTemplate对象。下面的代码展示了如何创建一个RestTemplate对象:

@Configuration
public class RestTemplateConfig {
    @Bean
    public RestTemplate restTemplate(ClientHttpRequestFactory factory) {
        RestTemplate restTemplate = new RestTemplate(factory);
        return restTemplate;
    }

    /**
     * 可以通过 ClientHttpRequestFactory 配置最大链接数,
     * 忽略SSL证书等,可以根据具体开发需求进行配置。
     */
    @Bean
    public ClientHttpRequestFactory simpleClientHttpRequestFactory() {
        SimpleClientHttpRequestFactory factory = new SimpleClientHttpRequestFactory();
        factory.setReadTimeout(5000);
        factory.setConnectTimeout(15000);
        // 设置代理
        //factory.setProxy(null);
        return factory;
    }

}

接口调用

Get请求

RestTemplate提供了两种发送HTTP GET请求的方法:getForObject()和getForEntity()。其中,getForObject()返回值是HTTP协议的响应体,而getForEntity()返回的是ResponseEntity,ResponseEntity是对HTTP响应的封装,除了包含响应体,还包含HTTP状态码、contentType、contentLength、Header等信息。下面的代码展示了如何发送HTTP GET请求:

public void getTest() {
    // 1. 简单参数拼接
    long id = 1L;
    String result1 = restTemplate.getForObject("http://localhost:8000/req?id=" + id, String.class);

    // 2. 通过占位符
    String url = "http://127.0.0.1:8080/hello/get/{class}/sex/{sex}";
    Map<String, String> vars = Collections.singletonMap("三年二班", "男");
    // 返回数组
    String[] result2 = restTemplate.getForObject(url, String[].class, vars);

    // 带头部的get请求
    String requestParam = "三年二班";
    UriComponents uriComponents = UriComponentsBuilder.fromHttpUrl("127.0.0.1:8080").
            path("/class").build(true);
    URI uri = uriComponents.toUri();
    RequestEntity<JSONObject> requestEntity = RequestEntity.post(uri)
            // 添加 cookie
            .header(HttpHeaders.COOKIE, "key1=value1")
            // 添加 header
            .header(("MyRequestHeader", "MyValue")
            .accept(MediaType.APPLICATION_JSON)
            .contentType(MediaType.APPLICATION_JSON)
            .body(requestParam);
    ResponseEntity<JSONObject> responseEntity = restTemplate.exchange(requestEntity, JSONObject.class);
    JSONObject responseEntityBody = responseEntity.getBody();
}
Post请求

RestTemplate的POST请求包含两个主要方法:postForObject()和postForEntity()。这两个方法的主要区别在于,postForObject()返回HTTP协议的响应体,而postForEntity()返回的是ResponseEntity。ResponseEntity是对HTTP响应的封装,除了包含响应体外,还包含HTTP状态码、contentType、contentLength、Header等信息。

public void sendPostRequest1() {
    // 请求地址
    String url = "http://127.0.0.1:8080/hello";

    // 要发送的数据对象
    ClassInfo classInfo = new ClassInfo();
    classInfo.setClassName("三年二班");
    classInfo.setSex("男");

    // 发送post请求,并输出结果
    ResponseEntity<Result<String>> responseEntity = restTemplate.exchange(url, HttpMethod.POST, new HttpEntity<>(classInfo), new ParameterizedTypeReference<Result<String>>() {});
    Result<String> result = responseEntity.getBody();
    String body = result.getData();
}

private void sendPostRequest2() {
    // 发送post请求,x-www-form-urlencoded格式的数据
    HttpHeaders headers = new HttpHeaders();
    headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);

    MultiValueMap<String, String> map = new LinkedMultiValueMap<>();
    map.add("class", "三年二班");
    map.add("sex", "男");

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

    // 发送post请求
    String result2 = restTemplate.postForObject(url, request, String.class);
}

RestTemplate发送/下载文件

上传文件

public String fileUpload(String url, File value) {
    String uploadUrl = "http://localhost:8888/hello/m3";
    // 设置请求头
    HttpHeaders headers = new HttpHeaders();
    headers.setContentType(MediaType.MULTIPART_FORM_DATA);

    // 创建MultiValueMap对象,用于设置请求体的参数
    MultiValueMap<String, Object> parts = new LinkedMultiValueMap<>();
    // 添加文件对象
    parts.add("file", new FileSystemResource(value));

    // 创建HttpEntity对象,用于设置请求体和请求头
    HttpEntity<MultiValueMap<String, Object>> requestEntity = new HttpEntity<>(parts, headers);
    return restTemplate.postForObject(uploadUrl, requestEntity, String.class);
}

下载文件

public void download(String fileName, HttpServletResponse httpResponse) throws IOException {
    	String downloadUrl = "http://localhost:8888/hello/m3";

        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_JSON_UTF8);
        ResponseEntity<byte[]> response = restTemplate.exchange(downloadUrl, HttpMethod.GET,
                new HttpEntity<>(headers), byte[].class);
        byte[] fileBytes = response.getBody();
        httpResponse.setHeader("Content-Disposition", "attachment; filename=" + "file.txt");
        httpResponse.getOutputStream().write(fileBytes);
    }

其他

拦截器

定义了一个CustomClientHttpRequestInterceptor类,它实现了ClientHttpRequestInterceptor接口,这个接口定义了一个intercept方法,该方法在每个HTTP请求发送前都会被调用。

public class CustomClientHttpRequestInterceptor implements ClientHttpRequestInterceptor {

    @Override
    public ClientHttpResponse intercept(HttpRequest request, byte[] body, ClientHttpRequestExecution execution) throws IOException {
        // 添加自定义的逻辑
        HttpHeaders headers = request.getHeaders();
        headers.add("Authorization", "Bearer your-access-token");
        return execution.execute(request, body);
    }
}

public class CustomRestTemplate extends RestTemplate {

    public CustomRestTemplate() {
        List<ClientHttpRequestInterceptor> interceptors = new ArrayList<>();
        interceptors.add(new CustomClientHttpRequestInterceptor());
        setInterceptors(interceptors);
    }
}

接下来,我们定义了一个CustomRestTemplate类,它扩展了RestTemplate类。在CustomRestTemplate的构造函数中,我们将CustomClientHttpRequestInterceptor添加到了RestTemplate的拦截器列表中。
现在,我们可以使用CustomRestTemplate来发送HTTP请求,它会自动将我们定义的拦截器应用到所有的HTTP请求中:

CustomRestTemplate restTemplate = new CustomRestTemplate();
String response = restTemplate.getForObject("https://api.example.com/resource", String.class);

在上面的例子中,我们使用CustomRestTemplate来发送GET请求。由于我们已经添加了一个拦截器,所以在请求发送之前,CustomClientHttpRequestInterceptor的intercept方法会被调用,我们的自定义逻辑也会被执行。

**ErrorHandler **

在使用RestTemplate发送HTTP请求时,有时我们可能需要处理一些异常情况,例如请求超时、连接失败等。为了处理这些异常,RestTemplate提供了一个ErrorHandler接口,可以让我们自定义异常处理逻辑。
ErrorHandler接口定义了两个方法:hasError和handleError。hasError方法用于判断HTTP响应是否包含错误信息,而handleError方法则用于处理异常情况。以下是一个简单的例子,演示了如何在RestTemplate中使用ErrorHandler:

public class CustomResponseErrorHandler implements ResponseErrorHandler {

    @Override
    public boolean hasError(ClientHttpResponse response) throws IOException {
        return response.getStatusCode().is4xxClientError()
                || response.getStatusCode().is5xxServerError();
    }

    @Override
    public void handleError(ClientHttpResponse response) throws IOException {
        if (response.getStatusCode().is4xxClientError()) {
            // 处理4xx错误
            throw new HttpClientErrorException(response.getStatusCode());
        } else if (response.getStatusCode().is5xxServerError()) {
            // 处理5xx错误
            throw new HttpServerErrorException(response.getStatusCode());
        }
    }
}

RestTemplate restTemplate = new RestTemplate();
restTemplate.setErrorHandler(new CustomResponseErrorHandler());
String response = restTemplate.getForObject("https://api.example.com/resource", String.class);

在上面的例子中,我们定义了一个CustomResponseErrorHandler类,它实现了ResponseErrorHandler接口。在CustomResponseErrorHandler的hasError方法中,我们判断HTTP响应是否包含错误信息。在这个例子中,我们只处理4xx和5xx的错误。如果HTTP响应包含错误信息,hasError方法会返回true,否则返回false。
在CustomResponseErrorHandler的handleError方法中,我们处理异常情况。在这个例子中,我们只是抛出了一个HttpClientErrorException或HttpServerErrorException异常,以便让调用者可以处理异常。
最后,我们将CustomResponseErrorHandler添加到RestTemplate的errorHandler属性中。这样,当RestTemplate发生异常时,它会自动调用CustomResponseErrorHandler的hasError和handleError方法来处理异常。