RestTemplate 使用详解

一、简介

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

  1. JDK 自带 HttpURLConnection
  2. Apache HttpClient
  3. OKHttp

以上 工具虽然常用,但对于 RESTful 操作相对不是太友好。所以,从 Spring3.0开始支持的一个 HTTP 请求工具RestTemplate,提供了常见的 REST请求方案的模板。
RestTemplate只是提供了 Http请求模板,其底层默认是使用HttpURLConnection作为真正的请求工具。它可以通过构造方法替换底层的执行引擎,常见的引擎又HttpClientNettyOkHttp

二、简单的请求

1、GET请求

1. 直接拼接参数

  String params = "http://localhost:10011/user/params?name=诸葛亮&age=100";
  String result = template.getForObject(HOST  + params, String.class);
  LOGGER.info("请求返回结果:{}", result);

2. 占位符参数

  // 1、可以直接在方法中指定参数, 此种方式还可以使用下标的形式。
  // 请求路径还可以为:name={0}&age={1}
 String url = "http://localhost:10011/user/params?name={name}&age={age}";
 String result = template.getForObject(url , String.class, "李四", 20);
 LOGGER.info("请求返回结果:{}", result);

// 2、 通过 Map 传递参数,此种方式必须使用占位符,并且 map 中的 key 值,要与请求
// 路径中的 占位符一致
Map<String, Object> map = new HashMap<>();
map.put("name", "王五");
map.put("age", 30);
ResponseEntity<String> forEntity = template.getForEntity(HOST + url , String.class, map);

2、POST请求

接口实例
如下的接口实例中两个方法的唯一区别为 一个参数中加了注解@RequestBody,一个没有加,两者在 POST请求中传值方式不同。

    // 接口 1
    @RequestMapping("/obj")
    @ResponseBody
    public User getObj(User user){
        return user;
    }
    // 接口 2
    @RequestMapping("/body")
    @ResponseBody
    public User getBody(@RequestBody User user){
        return user;
    }

1、带有 @RequestBody 注解的请求

此种情况下,请求参数可以为 设置User 对象,也可以说使用Map

   String url = "http://localhost:10011/user/body";
   
   User user = new User().setName("张三")
            .setAge(40);
    String result = template.postForObject(url, user, String.class);
    LOGGER.info("请求返回结果:{}", result);

    Map<String, Object> map = new HashMap<>();
    map.put("name", "王五");
    map.put("age", 30);

    ResponseEntity<String> forEntity = template.postForEntity(url, map, String.class);

    LOGGER.info("请求返回结果:{}", forEntity.getBody());

2、不带@RequestBody 注解的请求

此种情况下,传的参数需要使用MultiValueMap

  MultiValueMap<String, Object> map = new LinkedMultiValueMap<>();
  map.add("name", "王五");
  map.add("age", 30);
  ResponseEntity<String> forEntity = template.postForEntity(url, map, String.class);

   LOGGER.info("请求返回结果:{}", forEntity.getBody());

三、带请求头的请求

1、GET 请求

GET请求中的getForObjectgetForEntity 方法不支持传递头信息,需要使用 通用方法exchange,如下所示:

  String url = "http://localhost:10011/user/params?name={name}&age={age}";
   // 定义头信息
   HttpHeaders headers = new HttpHeaders();
   headers.add("token", UUID.randomUUID().toString());
   // 请求参数
   Map<String, Object> map = new HashMap<>();
   map.put("name", "王五");
   map.put("age", 30);

   // 使用 HttpEntity 对 头信息进行封装
   HttpEntity<Map<String, Object>> entity = new HttpEntity<>(headers);
   // 请求方法 exchange
   ResponseEntity<String> response = template.exchange(url, HttpMethod.GET, entity, String.class, map);
   LOGGER.info("请求返回结果:{}", response.getBody());

2、POST请求

POST 请求添加头信息比较简单,只需要使用 HttpEntity 对请求对象进行一次封装即可。

   // 定义头信息
   HttpHeaders headers = new HttpHeaders();
   headers.add("token", UUID.randomUUID().toString());
   User user = new User().setName("张三")
            .setAge(40);
    // 使用 HttpEntity 把请求对象user 和 header 进行组装
   HttpEntity<User> userHttpEntity = new HttpEntity<>(user, headers);
    // 把请求参数改为 httpEntity 对象即可
   String result = template.postForObject(url, userHttpEntity, String.class);
   LOGGER.info("请求返回结果:{}", result);

四、form 表单请求

form表单的提交只需要需要把头信息ContentType 设置为MediaType.APPLICATION_FORM_URLENCODED ,同时参数需要使用 MultiValueMap 封装。如下所示:

     String url = "http://localhost:10011/user/obj";
      
     HttpHeaders headers = new HttpHeaders();
     headers.add("token", UUID.randomUUID().toString());
     // 设置请求类型
     headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
     // 组装参数
     MultiValueMap<String, Object> multiValueMap = new LinkedMultiValueMap<>();
     multiValueMap.add("name", "王五");
     multiValueMap.add("age", 30);
     // 发送请求
     HttpEntity< MultiValueMap<String, Object>> request = new HttpEntity<>(multiValueMap, headers);
     ResponseEntity<String> exchange = template.exchange(url, HttpMethod.POST, request, String.class);
     LOGGER.info("请求返回结果:{}", exchange.getBody());

五、上传下载

1、上传

  String url = "http://localhost:10011/user/upload";
  HttpHeaders headers = new HttpHeaders();

  // 模拟读取文件
  File file = new File("F:/run.bat");
  //从File句柄创建一个新的FileSystemResource
  FileSystemResource resource = new FileSystemResource(file);

  MultiValueMap<String, Object> multiValueMap = new LinkedMultiValueMap<>();
  multiValueMap.add("name", "update.bat");
  multiValueMap.add("file", resource);

  HttpEntity< MultiValueMap<String, Object>> request = new HttpEntity<>(multiValueMap, headers);
  ResponseEntity<String> exchange = template.exchange(url, HttpMethod.POST, request, String.class);
  LOGGER.info("请求返回结果:{}", exchange.getBody());

2、下载

1. 小文件下载
小文件下载比较简单,只需要把请求响应类型设置为byte[] 即可,如下所示:

   String url = "http://localhost:10011/user/downLoad";
   // 请求下载
   ResponseEntity<byte[]> entity = template.getForEntity(url, byte[].class);
   // 写文件
   byte[] body = entity.getBody();
   Files.write(Paths.get("D:/download.jpg"), body);

这种下载方法实际上是将下载文件一次性加载到客户端本地内存,然后从内存将文件写入磁盘。这种方式对于小文件的下载还比较适合,如果文件比较大或者文件下载并发量比较大,容易造成内存的大量占用,从而降低应用的运行效率。

2. 大文件下载

这种下载方式的区别在于

  • 设置了请求头APPLICATION_OCTET_STREAM,表示以流的形式进行数据加载
  • RequestCallback 结合File.copy保证了接收到一部分文件内容,就向磁盘写入一部分内容。而不是全部加载到内存,最后再写入磁盘文件。
   String url = "http://localhost:10011/user/downLoad";

   String targetPath = "D:/download.jpg";

   // 定义请求头的接收类型
   RequestCallback requestCallback = request -> request.getHeaders()
           .setAccept(Arrays.asList(MediaType.APPLICATION_OCTET_STREAM, MediaType.ALL));
   //对响应进行流式处理而不是将其全部加载到内存中
   template.execute(url, HttpMethod.GET, requestCallback, clientHttpResponse -> {
       Files.copy(clientHttpResponse.getBody(), Paths.get(targetPath));
       return null;
   });

六、更换底层请求执行引擎

Spring中已经提供了大部分的执行引擎,比如 HttpClientOkHttp3 等,要想使用这些底层引擎只需要加入响应的依赖,然后再初始化类似,在构造方法中指定响应的执行引擎即可。

// 1、使用 HttpClient 引擎。
RestTemplate restTemplate = new RestTemplate(new HttpComponentsClientHttpRequestFactory());
// 2、使用OkHttp3 引擎
RestTemplate restTemplate = new RestTemplate(new OkHttp3ClientHttpRequestFactory());

七、拦截器

当所有的请求需要设置公共信息时,就可以使用拦截器,为每个请求设置。设置方法如下:

  RestTemplate template = new RestTemplate();
  // 此处设置了一个公共请求头 AUTHORIZATION
  ClientHttpRequestInterceptor interceptor = new ClientHttpRequestInterceptor() {
       @Override
       public ClientHttpResponse intercept(HttpRequest request, byte[] body, ClientHttpRequestExecution execution) throws IOException {
           HttpHeaders headers = request.getHeaders();
           headers.set(HttpHeaders.AUTHORIZATION, "636213dc4ac6e9220a0f5107");
           return execution.execute(request, body);
       }
   };
   template.setInterceptors(Arrays.asList(interceptor));
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值