RestTemplate介绍

一、RestTemplate简介

常见的Http客户端请求工具:

二、RestTemplate的使用:

RestTemplate默认使用HttpURLConnection,可以通过构造方法替换底层的执行引擎也可以通过 setRequestFactory 方法替换,注入等方式替换。常见的执行引擎包括(HttpClient、Netty、okHttp)。参考资料如下:
例如,你如果想切换成Apache的HttpComponents,你可以使用以下建议:
构造函数方式替换引擎

//底层执行引擎HttpURLConnection
RestTemplate template = new RestTemplate();

//底层执行引擎  Apache  HttpComponents  (HttpClient)
RestTemplate template = new RestTemplate(new HttpComponentsClientHttpRequestFactory());

//底层执行引擎  OkHttp
RestTemplate template = new RestTemplate(new OkHttpClientHttpRequestFactory());

默认的构造器使用java.net.HttpURLConnection引擎执行请求。你可以使用ClientHttpRequestFactory的实现类来切换不同的HTTP库。内置支持以下内容:

  • Apache HttpComponents (HttpClient)
  • Netty (网络通信库)
  • OkHttp

通过这个请求工厂,我们可以统一设置请求的超时时间,设置代理以及一些其他细节。通过上面代码配置后,我们直接在代码中注入 RestTemplate 就可以使用了。

有时候我们还需要通过 ClientHttpRequestFactory 配置最大链接数,忽略SSL证书等,大家需要的时候可以自己查看代码设置。

RestTemplate提供的方法:

img

上面的方法我们大致可以分为三组:

  • getForObject — optionsForAllow 分为一组,这类方法是常规的 Rest API(GET、POST、DELETE 等)方法调用;
  • exchange:接收一个 RequestEntity 参数,可以自己设置 HTTP method,URL,headers 和 body,返回 ResponseEntity;
  • execute:通过 callback 接口,可以对请求和返回做更加全面的自定义控制。

一般情况下,我们使用第一组和第二组方法就够了。

相关依赖
<!--spring-web依赖-->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-web</artifactId>
            <version>5.0.4.RELEASE</version>
            <scope>compile</scope>
        </dependency>

<!--RestTemplate是spring的一个rest客户端,在spring-web这个包下,spring boot的依赖如下-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
实施代码
package com.hayabusa.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.client.RestTemplate;

@Configuration
public class RestConfig {

    //将RestTemplate注入近容器中
    @Bean
    public RestTemplate restTemplate(){
        //默认底层执行 HttpURLTemplate
        return new RestTemplate();
    }
 
@Bean
public ClientHttpRequestFactory simpleClientHttpRequestFactory() {
    SimpleClientHttpRequestFactory factory = new SimpleClientHttpRequestFactory();
    factory.setReadTimeout(5000);
    factory.setConnectTimeout(15000);
    // 设置代理
    //factory.setProxy(null);
    return factory;
}
}

三、Http 协议 状态码解析

1xx Informational通知

  • 100 Continue 通知请求继续
  • 101 Switching Protocols
  • 102 Processing

2xx Success 请求成功

  • 200 OK
  • 201 Created
  • 202 Accepted
  • 203 Non-authoritative Information
  • 204 No Content
  • 205 Reset Content
  • 206 Partial Content
  • 207 Multi-Status
  • 208 Already Peported
  • 226 IM Used

3xx Redirection 重定向

  • 300 Multiple Choices
  • 301 Moved Permanently 永久迁移
  • 302 Found 临时迁移
  • 303 See Other
  • 304 Not Modified
  • 305 Use Proxy
  • 307 Temporary Redirect
  • 308 Permanent Redirect

4xx Client Error

  • 400 Bad Request
  • 401 Unanthorized
  • 402 Payment Required
  • 403 Forbidden
  • 404 Not Found 访问的url不存在
  • 405 Method Not Allowed
  • 406 Not Acceptable
  • 407 Proxy Authentication Required
  • 408 Request Timeout

5xx Server Error 服务端异常

  • 500 Internal Server Error 服务器内部错误
  • 501 Not Implemented
  • 502 Bad Gateway
  • 503 Service Unavailable
  • 504 Gateway Timeout

四、RestTemplate常用方法介绍

Http Get请求介绍

RestTemplate有两个核心方法来执行Get请求

  1. ResetTemplate.getForObject 方法可以获取对象
  2. RestTemplate.getForEntity 方法不仅可以获取对象,还可以获取Http状态码,请求头等详细信息。
ResetTemplate.getForObject样例程序
@RestController
public class TestRestTemplate {
    private final RestTemplate restTemplate;

    public TestRestTemplate(RestTemplate restTemplate) {
        this.restTemplate = restTemplate;
    }


    @GetMapping("/getForObject1")
    public String getForObject1() {
        //远程访问的url
        String url = "http://127.0.0.1:8080/test1";
        //url代表请求的地址,XXX.class代表返回的类型,paramMap代表要传入的参数
        String forObject = restTemplate.getForObject(url, String.class);
        String rest = forObject;
        System.out.println(rest);
        return rest;
    }

    @GetMapping(value = "/getForObject2", produces = "application/json;charset=utf-8")
    public Map getForObject2() {
        //远程访问的url
        String url = "http://127.0.0.1:8080/test2";
        //url代表请求的地址,XXX.class代表返回的类型,paramMap代表要传入的参数
        Map forObject = restTemplate.getForObject(url, Map.class);
        return forObject;
    }

    @GetMapping(value = "/getForObject3", produces = "application/json;charset=utf-8")
    public Map getForObject3() {
        //远程访问的url
        String url = "http://127.0.0.1:8080/test3/1/张三";
        //url代表请求的地址,XXX.class代表返回的类型,paramMap代表要传入的参数
        Map forObject = (Map) restTemplate.getForObject(url, Object.class);
        return forObject;
    }
}

对应的接收方

@RestController
public class TestController {

    @GetMapping("/test1")
    public String test1() {
        return "张三";
    }

    @GetMapping("/test2")
    public Map test2() {
        Map map = new HashMap<>();
        map.put("id", 0);
        map.put("name", "张三");
        map.put("age", 20);
        String[] arrays = new String[]{"A", "B", "C", "D", "E"};
        map.put("love", arrays);
        return map;
    }

    @GetMapping("/test3/{id}/{name}")
    public User test3(@PathVariable("id") Integer id, @PathVariable("name") String name) {
        User user = new User(id, name);
        return user;
    }
}
RestTemplate.getForEntity样例程序
@GetMapping(value = "/getForObject4", produces = "application/json;charset=utf-8")
    public Object getForObject4() {
        //远程访问的url
        String url = "http://127.0.0.1:8080/test4?id={id}&name={name}";
        //请求的入参
        Map<String, Object> paramMap = new HashMap<>();
        paramMap.put("id", 10);
        paramMap.put("name", "莉莉");
        //url代表请求的地址,XXX.class代表返回的类型,paramMap代表要传入的参数
        ResponseEntity<Object> forEntity = restTemplate.getForEntity(url, Object.class, paramMap);
        //返回状态码包装类
        HttpStatus statusCode = forEntity.getStatusCode();
        //返回状态码
        int statusCodeValue = forEntity.getStatusCodeValue();
        //Http的返回头
        HttpHeaders headers = forEntity.getHeaders();
        //Http的返回体
        Object body = forEntity.getBody();
        System.out.println(forEntity);
        return body;
    }


//=========================接收方=========================


@GetMapping("/test4")
    public User test4(Integer id, String name) {
        User user = new User(id, name);
        return user;
    }

RestTemplate之Http Post请求

spring Boot RestTemplate的post方法包含两个核心方法:
1.postForObject
2.postForEntity
SpringBoot RestTemplate的Post和Get方法的区别是Post方法传参Map必须是MultiValueMap

RestTemplate.postForObject样例程序
@GetMapping(value = "/getForObject5", produces = "application/json;charset=utf-8")
    public Object getForObject5() {
        //远程访问的url
        String url = "http://127.0.0.1:8080/test5";
        //请求的入参
        MultiValueMap map=new LinkedMultiValueMap();
        map.add("id", 7);
        map.add("name", "花花");
        //url代表请求的地址,paramMap代表要传入的参数,XXX.class代表返回的类型
        Object rest = restTemplate.postForObject(url, map, Object.class);
        return rest;
    }

//===========================接收方===========================


@PostMapping("/test5")
    public User test5(Integer id,String name) {
        User user = new User(id,name);
        return user;
    }

使用@RequestBody传递参数

@GetMapping(value = "/getForObject6", produces = "application/json;charset=utf-8")
    public Object getForObject6() {
        //声明请求头
        HttpHeaders headers=new HttpHeaders();
        //application/json
        headers.setContentType(MediaType.APPLICATION_JSON);
        //远程访问的url
        String url = "http://127.0.0.1:8080/test6";
        //使用@RequestBody传递参数使用MultiValueMap会报错
        //使用HashMap 会有警告
        //好像不使用HttpEntity封装也可以
        //请求的入参
        Map<String, Object> paramMap = new HashMap<>();
        paramMap.put("id", 81);
        paramMap.put("name", "花花");
        //使用HttpEntity形式包装传递参数
        HttpEntity<Map> httpEntity=new HttpEntity<Map>(paramMap,headers);
        //url代表请求的地址,paramMap代表要传入的参数,XXX.class代表返回的类型
        Object rest = restTemplate.postForObject(url, httpEntity, Object.class);
        return rest;
    }


//===========================接收方===========================


@PostMapping("/test6")
    public User test6(@RequestBody Map map) {
        User user = new User((Integer) map.get("id"), (String) map.get("name"));
        return user;
    }

RestTemplate.postForEntity样例程序

@GetMapping(value = "/getForObject7", produces = "application/json;charset=utf-8")
    public Object getForObject7() {
        //远程访问的url
        String url = "http://127.0.0.1:8080/test7";
        Map<String, Object> paramMap = new HashMap<>();
        paramMap.put("id", 901);
        paramMap.put("name", "花花");
        //url代表请求的地址,paramMap代表要传入的参数,XXX.class代表返回的类型
        ResponseEntity<Object> objectResponseEntity = restTemplate.postForEntity(url, paramMap, Object.class);
        //返回状态码包装类
        HttpStatus statusCode = objectResponseEntity.getStatusCode();
        //返回状态码
        int statusCodeValue = objectResponseEntity.getStatusCodeValue();
        //Http的返回头
        HttpHeaders headers = objectResponseEntity.getHeaders();
        //Http的返回体
        Object body = objectResponseEntity.getBody();
        return objectResponseEntity.getBody();
    }

//===========================接收方===========================

@PostMapping("/test7")
    public User test7(@RequestBody Map map) {
        User user = new User((Integer) map.get("id"), (String) map.get("name"));
        return user;
    }

RestTemplate中的Exchange方法

Exchange方法既发送get请求又可以发送post请求。
Exchange方法既可以做getForEntity又可以做postForEntity。

@GetMapping(value = "/getForObject8", produces = "application/json;charset=utf-8")
    public Object getForObject8() {
        //远程访问的url
        String url = "http://127.0.0.1:8080/test8";
        Map<String, Object> paramMap = new HashMap<>();
        paramMap.put("id", 101);
        paramMap.put("name", "花花");
        //使用HttpEntity包装传递的参数
        HttpEntity httpEntity=new HttpEntity(paramMap);
        //url代表请求的地址,HttpMethod.POST请求方式,httpEntity必须使用HttpEntity封装参数,XXX.class代表返回的类型
        ResponseEntity<Object> exchange = restTemplate.exchange(url, HttpMethod.POST, httpEntity, Object.class);
        return exchange.getBody();
    }

//===========================接收方===========================

@PostMapping("/test8")
    public User test8(@RequestBody Map map) {
        User user = new User((Integer) map.get("id"), (String) map.get("name"));
        return user;
    }

接口返回值为泛型

接口代码

@GetMapping("/test/getList")
@ResponseBody
public List<BookDto> getList() {
    return Arrays.asList(
            new BookDto(1, "Spring高手系列"),
            new BookDto(2, "SpringMVC系列")
    );
}

当接口的返回值为泛型的时候,这种情况比较特殊,使用 RestTemplate 调用上面这个接口,代码如下,需要用到restTemplate.exchange的方法,这个方法中有个参数是ParameterizedTypeReference类型,通过这个参数类指定泛型类型

@Test
public void test5() {
    RestTemplate restTemplate = new RestTemplate();
    //返回值为泛型
    String url = "http://localhost:8080/chat16/test/getList";
    //若返回结果是泛型类型的,需要使用到exchange方法,
    //这个方法中有个参数是ParameterizedTypeReference类型,通过这个参数类指定泛型类型
    ResponseEntity<List<BookDto>> responseEntity =
            restTemplate.exchange(url,
                    HttpMethod.GET,
                    null,
                    new ParameterizedTypeReference<List<BookDto>>() {
                    });
    List<BookDto> bookDtoList = responseEntity.getBody();
    System.out.println(bookDtoList);
}
[BookDto{id=1, name='哈雅布撒'}, BookDto{id=2, name='忍者龙剑传'}]

一些其他设置

1. 拦截器配置

RestTemplate 也可以设置拦截器做一些统一处理。这个功能感觉和 Spring MVC 的拦截器类似。配置也很简单:

class MyInterceptor implements ClientHttpRequestInterceptor{
 
        @Override
        public ClientHttpResponse intercept(HttpRequest request, byte[] body, ClientHttpRequestExecution execution) throws IOException {
            logger.info("enter interceptor...");
            return execution.execute(request,body);
        }
    }
 @Bean
public RestTemplate restTemplate(ClientHttpRequestFactory factory) {
    RestTemplate restTemplate = new RestTemplate(factory);
    MyInterceptor myInterceptor = new MyInterceptor();
    List<ClientHttpRequestInterceptor> list = new ArrayList<>();
    list.add(myInterceptor);
    restTemplate.setInterceptors(list);
    return restTemplate;
}

2. ErrorHandler 配置

ErrorHandler 用来对调用错误对统一处理。

public class MyResponseErrorHandler extends DefaultResponseErrorHandler {

    @Override
    public boolean hasError(ClientHttpResponse response) throws IOException {
        return super.hasError(response);
    }
 
    @Override
    public void handleError(ClientHttpResponse response) throws IOException {
        HttpStatus statusCode = HttpStatus.resolve(response.getRawStatusCode());
        if (statusCode == null) {
            throw new UnknownHttpStatusCodeException(response.getRawStatusCode(), response.getStatusText(),
                    response.getHeaders(), getResponseBody(response), getCharset(response));
        }
        handleError(response, statusCode);
    }
    @Override
    protected void handleError(ClientHttpResponse response, HttpStatus statusCode) throws IOException {
        switch (statusCode.series()) {
            case CLIENT_ERROR:
                HttpClientErrorException exp1 = new HttpClientErrorException(statusCode, response.getStatusText(), response.getHeaders(), getResponseBody(response), getCharset(response));
                logger.error("客户端调用异常",exp1);
                throw  exp1;
            case SERVER_ERROR:
                HttpServerErrorException exp2 = new HttpServerErrorException(statusCode, response.getStatusText(),
                        response.getHeaders(), getResponseBody(response), getCharset(response));
                logger.error("服务端调用异常",exp2);
                throw exp2;
            default:
                UnknownHttpStatusCodeException exp3 = new UnknownHttpStatusCodeException(statusCode.value(), response.getStatusText(),
                        response.getHeaders(), getResponseBody(response), getCharset(response));
                logger.error("网络调用未知异常");
                throw exp3;
        }
    }
 
}
@Bean
public RestTemplate restTemplate(ClientHttpRequestFactory factory) {
    RestTemplate restTemplate = new RestTemplate(factory);
    MyResponseErrorHandler errorHandler = new MyResponseErrorHandler();
    restTemplate.setErrorHandler(errorHandler);
    List<HttpMessageConverter<?>> messageConverters = restTemplate.getMessageConverters();
    // 通过下面代码可以添加新的 HttpMessageConverter
    //messageConverters.add(new );
    return restTemplate;
}

五、总结

通过 RestTemplate,我们可以非常方便的进行 Rest API 调用。但是在 Spring 5 中已经不再建议使用 RestTemplate,而是建议使用 WebClient。WebClient 是一个支持异步调用的 Client。

  • 40
    点赞
  • 30
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值