美文网首页
RestTemplate 使用详解

RestTemplate 使用详解

作者: 瞎胡扯1 | 来源:发表于2022-11-02 15:27 被阅读0次

    一、简介

    常见的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));
    

    相关文章

      网友评论

          本文标题:RestTemplate 使用详解

          本文链接:https://www.haomeiwen.com/subject/ioujtdtx.html