SpringBoot中RestTemplate的使用备忘

SpringBoot中RestTemplate的使用备忘

1. 基本介绍

1,什么是 RestTemplate?1RestTemplateSpring 提供的用于访问 Rest 服务的客户端,RestTemplate 提供了多种可以便捷访问远程 Http 服务的方法,能够大大提高客户端的编写效率。

			RestTemplateSpring3 中引入的同步阻塞式 HTTP 客户端。根据 Spring 官方文档介绍,在将来的版本中它可能会被弃用,因已在 Spring5 中引入了 WebClient 作为非阻塞式 Reactive HTTP 客户端。

	(2RestTemplate 定义了 36 个与 REST 资源交互的方法,其中的大多数都对应于 HTTP 的方法。
	注意:
		严格来说只有 11 个独立的方法,其中有 10 个有三种重载形式,
				而第 11 个则重载了 6 次,这样一共形成了 36 个方法。
		实际上,由于 Post 操作的非幂等性,它几乎可以代替其他的 CRUD 操作。
	// 方法列表如下:
	delete():这个方法是在特定的 URL 上对资源执行 HTTP DELETE 操作
	exchange():在 URL 上执行特定的 HTTP 方法,返回包含对象的 ResponseEntity,这个对象是从响应体中映射得到的
	execute():在 URL 上执行特定的 HTTP 方法,返回一个从响应体映射得到的对象
	getForEntity():发送一个 HTTP GET 请求,返回的 ResponseEntity 包含了响应体所映射成的对象
	getForObject():发送一个 HTTP GET 请求,返回的请求体将映射为一个对象
	postForEntity():POST 数据到一个 URL,返回包含一个对象的 ResponseEntity,这个对象是从响应体中映射得到的
	postForObject():POST 数据到一个 URL,返回根据响应体匹配形成的对象
	headForHeaders():发送 HTTP HEAD 请求,返回包含特定资源 URL 的 HTTP 头
	optionsForAllow():发送 HTTP OPTIONS 请求,返回对特定 URL 的 Allow 头信息
	postForLocation():POST 数据到一个 URL,返回新创建资源的 URL
	put():PUT 资源到特定的 URL

2. 安装配置

2-1 引入Maven依赖

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>

2-2 创建 RestTemplate 配置类,设置连接池大小、超时时间、重试机制等等。

@Configuration
public class RestTemplateConfig {
    
    
    @Bean
    public RestTemplate restTemplate(ClientHttpRequestFactory factory){
    
    
        return new RestTemplate(factory);
    }
 
    @Bean
    public ClientHttpRequestFactory simpleClientHttpRequestFactory(){
    
    
        SimpleClientHttpRequestFactory factory = new SimpleClientHttpRequestFactory();
        factory.setConnectTimeout(15000); // 连接超时
        factory.setReadTimeout(5000); // 数据读取超时时间
        return factory;
    }
}

3. 使用示例

@RestController
public class HelloController {
    
    
    @Autowired
    private RestTemplate restTemplate;
 
    @GetMapping("/test")
    public String test() {
    
    
    	// 发起Get请求,获取接口返回的字符串
        String url = "http://jsonplaceholder.typicode.com/posts/1";
        return restTemplate.getForObject(url, String.class);
    }
}

4 GET 请求1:getForObject() 方法的使用

4-1 使用示例

// 		2-1 测试用的实体Bean
@Getter
@Setter
@ToString
public class PostBean {
    
    
    private int userId;
    private int id;
    private String title;
    private String body;
}
// getForObject() 用于发送一个 HTTP GET 请求。它和 getForEntity() 用法几乎相同。
//		区别在于 getForObject() 返回值返回的是响应体,省略了很多 response 的信息。

// 示例1. 获取 String 结果数据
@RestController
public class HelloController {
    
    
    @Autowired
    private RestTemplate restTemplate;
 
    @GetMapping("/test")
    public void test() {
    
    
        String url = "http://jsonplaceholder.typicode.com/posts/1";
        String str = restTemplate.getForObject(url, String.class);
        System.out.println(str);
        return;
    }
}

// 示例2. 将结果转换为对象
//		由于 getForObject() 包含了将 HTTP 结果转成 POJO 的功能,所以我们可以将其转换成自定义的实体类对象
@RestController
public class HelloController {
    
    
    @Autowired
    private RestTemplate restTemplate;
 
    @GetMapping("/test")
    public void test() {
    
    
        String url = "http://jsonplaceholder.typicode.com/posts/1";
        PostBean postBean = restTemplate.getForObject(url, PostBean.class);
        System.out.println(postBean.toString());
        return;
    }
}

// 示例3. 将结果转成数组,如下实例返回对象数组
//		假设接口返回的是一个 json 数组--实体对应上述的PostBean :
@RestController
public class HelloController {
    
    
    @Autowired
    private RestTemplate restTemplate;
 
    @GetMapping("/test")
    public void test() {
    
    
        String url = "http://jsonplaceholder.typicode.com/posts";
        PostBean[] arr = restTemplate.getForObject(url, PostBean[].class);
        System.out.println("结果数:" + arr.length);
        return;
    }
}

4-2 参数传递的几种方式

// 1. 使用占位符的形式传递参数:
String url = "http://jsonplaceholder.typicode.com/{1}/{2}";
PostBean postBean = restTemplate.getForObject(url, PostBean.class, "posts", 1);

// 2. 另一种使用占位符的形式,填充变量:
String url = "http://jsonplaceholder.typicode.com/{type}/{id}";
String type = "posts";
int id = 1;
PostBean postBean = restTemplate.getForObject(url, PostBean.class, type, id);

// 3. 使用 map装载参数:
String url = "http://jsonplaceholder.typicode.com/{type}/{id}";
Map<String,Object> map = new HashMap<>();
map.put("type", "posts");
map.put("id", 1);
PostBean postBean = restTemplate.getForObject(url, PostBean.class, map);

5 GET 请求2:getForEntity() 方法的使用

5-1 使用示例

getForEntity() 同样用于发送一个 HTTP GET 请求。它和 getForObject() 用法几乎相同。
		区别在于 getForEntity() 返回的是 ResponseEntityResponseEntitySpring 对 HTTP 请求响应的封装,包括了几个重要的元素,
		如响应码、contentType、contentLength、响应消息体等。
		其中响应消息体可以通过 ResponseEntity 对象的 getBody() 来获取。

// 示例1 -- 返回字符串
@RestController
public class HelloController {
    
    
    @Autowired
    private RestTemplate restTemplate;
 
    @GetMapping("/test")
    public void test() {
    
    
        String url = "http://jsonplaceholder.typicode.com/posts/5";
        ResponseEntity<String> responseEntity = restTemplate.getForEntity(url, String.class);
        String body = responseEntity.getBody(); // 获取响应体
        HttpStatus statusCode = responseEntity.getStatusCode(); // 获取响应码
        int statusCodeValue = responseEntity.getStatusCodeValue(); // 获取响应码值
        HttpHeaders headers = responseEntity.getHeaders(); // 获取响应头
 
        System.out.println("body:" + body);
        System.out.println("statusCode:" + statusCode);
        System.out.println("statusCodeValue:" + statusCodeValue);
        System.out.println("headers:" + headers);
        return;
    }
}

// 示例2 -- 将消息体转换为对象
@RestController
public class HelloController {
    
    
    @Autowired
    private RestTemplate restTemplate;
 
    @GetMapping("/test")
    public void test() {
    
    
        String url = "http://jsonplaceholder.typicode.com/posts/5";
        ResponseEntity<PostBean> responseEntity = restTemplate.getForEntity(url, PostBean.class);
        PostBean postBean = responseEntity.getBody(); // 获取响应体,其他的参数获取,参考示例1
        System.out.println(postBean);
        return;
    }
}

// 示例3 -- 将结果转成数组,本例返回对象数组
@RestController
public class HelloController {
    
     
    @Autowired
    private RestTemplate restTemplate;
 
    @GetMapping("/test")
    public void test() {
    
    
        String url = "http://jsonplaceholder.typicode.com/posts";
        ResponseEntity<PostBean[]> responseEntity = restTemplate.getForEntity(url, PostBean[].class);
        PostBean[] arr = responseEntity.getBody(); // 获取响应体
        System.out.println("结果数:" + arr.length);
        return;
    }
}		

5-2 参数传递的几种方式

// 1. 使用占位符的形式传递参数:
String url = "http://jsonplaceholder.typicode.com/{1}/{2}";
ResponseEntity<PostBean> responseEntity = restTemplate.getForEntity(url, PostBean.class, "posts", 1);

// 2. 另一种使用占位符的形式,填充变量:
String url = "http://jsonplaceholder.typicode.com/{type}/{id}";
String type = "posts";
int id = 1;
ResponseEntity<PostBean> responseEntity = restTemplate.getForEntity(url, PostBean.class, type, id);

// 3. 使用 map装载参数:
String url = "http://jsonplaceholder.typicode.com/{type}/{id}";
Map<String,Object> map = new HashMap<>();
map.put("type", "posts");
map.put("id", 1);
ResponseEntity<PostBean> responseEntity = restTemplate.getForEntity(url, PostBean.class, map);

6 POST 请求1:postForObject() 方法的使用

6-1 使用示例

postForObject() 用于发送一个 HTTP POST 请求。它和 postForEntity() 用法几乎相同。
		区别在于 postForObject() 返回值返回的是响应体,省略了很多 response 的信息。

// 示例1 -- 发送一个 JSON 格式数据,
//		直接将对象当作参数扔进方法postForObject中即可
//			Bean 对象实际上会转成 JSON 数据提交:
@RestController
public class HelloController {
    
    
    @Autowired
    private RestTemplate restTemplate;
 
    @GetMapping("/test")
    public void test() {
    
    
        // 请求地址
        String url = "http://jsonplaceholder.typicode.com/posts";
 
        // 要发送的数据对象
        PostBean postBean = new PostBean();
        postBean.setUserId(222);
        postBean.setTitle("abc");
        postBean.setBody("航歌");
 
        // 发送post请求,并输出结果
        String result = restTemplate.postForObject(url, postBean, String.class);
        System.out.println(result);
        return;
    }
}

// 示例2 -- 使用 Form 表单的形式提交数据
//		使用 POST 方式发送 multipart/form-data 格式的数据:
//			最终会通过 form 表单方式提交数据
@RestController
public class HelloController {
    
    
    @Autowired
    private RestTemplate restTemplate;
 
    @GetMapping("/test")
    public void test() {
    
    
        // 请求地址
        String url = "http://jsonplaceholder.typicode.com/posts";
 
        // 请求头设置
        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
 
        //提交参数设置
        MultiValueMap<String, String> map = new LinkedMultiValueMap<>();
        map.add("title", "abc");
        map.add("body", "航歌");
 
        // 组装请求体
        HttpEntity<MultiValueMap<String, String>> request =
                new HttpEntity<MultiValueMap<String, String>>(map, headers);
 
        // 发送post请求,并输出结果
        String result = restTemplate.postForObject(url, request, String.class);
        System.out.println(result);
        return;
    }
}

// 上述示例是将响应结果以 String 形式接收,
//		还可以自动将响应结果转成自定的对象或则数组。具体同Get请求类型转换一致:		

6-2 设置 url 参数,同Get请求

7 POST 请求2:postForEntity()方法的使用

7-1 使用示例,和postForObject()基本相似,返回的是ResponseEntity罢了

postForEntity() 用于发送一个 HTTP POST 请求。它和上面的 postForObject() 用法几乎相同。
	区别在于 getForEntity() 返回的是 ResponseEntityResponseEntitySpring 对 HTTP 请求响应的封装,包括了几个重要的元素,
	如响应码、contentType、contentLength、响应消息体等。 
	其中响应消息体可以通过 ResponseEntity 对象的 getBody() 来获取。

// 示例1 -- 发送一个 JSON 格式数据
@RestController
public class HelloController {
    
    
 
    @Autowired
    private RestTemplate restTemplate;
 
    @GetMapping("/test")
    public void test() {
    
    
        // 请求地址
        String url = "http://jsonplaceholder.typicode.com/posts";
 
        // 要发送的数据对象
        PostBean postBean = new PostBean();
        postBean.setUserId(222);
        postBean.setTitle("abc");
        postBean.setBody("航歌");
 
        // 发送post请求,并输出结果
        ResponseEntity<String> responseEntity
                = restTemplate.postForEntity(url, postBean, String.class);
        String body = responseEntity.getBody(); // 获取响应体
        HttpStatus statusCode = responseEntity.getStatusCode(); // 获取响应码
        int statusCodeValue = responseEntity.getStatusCodeValue(); // 获取响应码值
        HttpHeaders headers = responseEntity.getHeaders(); // 获取响应头
 
        System.out.println("body:" + body);
        System.out.println("statusCode:" + statusCode);
        System.out.println("statusCodeValue:" + statusCodeValue);
        System.out.println("headers:" + headers);
        return;
    }
}

7-2 设置 url 参数,同Get请求

8 POST 请求3:postForLocation() 方法的使用,返回的是 Uri

1postForLocation() 也是通过 Post 方式提交新资源,
		postForLocation() 方法的参数和前面两种(postForObject、postForEntity)的参数基本一致。
2)区别在于 postForLocation() 方法的返回值为 Uri,这个只需要服务提供者返回一个 Uri 即可,
		该 Uri 表示新资源的位置。

// 示例: 比如登录或者注册都是 post 请求,
//		而这些操作完成之后大部分都是跳转到别的页面去了。
//		这种场景下,就可以使用 postForLocation 了,提交数据,并获取返回的 URI。		
@RestController
public class HelloController {
    
    
    @Autowired
    private RestTemplate restTemplate;
 
    @GetMapping("/test")
    public void test() {
    
    
        // 请求地址
        String url = "http://jsonplaceholder.typicode.com/posts";
 
        // 要发送的数据对象
        MultiValueMap<String, String> request = new LinkedMultiValueMap<>();
        request.add("username", "hangge");
        request.add("password", "123456");
 
        // 发送post请求,并输出结果
        URI uri = restTemplate.postForLocation(url, request);
        System.out.println(uri);
        return;
    }
}

9 通用请求方法:exchange

9-1 介绍

1)exchange 的用法同前面介绍的 getForEntity、postForEntity 差不多,且返回的都是 ResponseEntityResponseEntitySpring 对 HTTP 请求响应的封装,包括了几个重要的元素,
	如响应码、contentType、contentLength、响应消息体等。
	其中响应消息体可以通过 ResponseEntity 对象的 getBody() 来获取。
2)不同在于 exchange 方法提供统一的方法模板,可以通过指定不同的 HTTP 请求类型,实现 POST、PUT、DELETE、GET 四种请求。

9-2 Get 请求示例

// 使用 Get 请求,并将响应体、响应头、响应码打印出来。其中响应体的类型为 String。
@RestController
public class HelloController {
    
    
    @Autowired
    private RestTemplate restTemplate;
 
    @GetMapping("/test")
    public void test() {
    
    
        String url = "http://jsonplaceholder.typicode.com/posts/5";
        ResponseEntity<String> responseEntity = restTemplate.exchange(url, HttpMethod.GET,
                null, String.class);
        String body = responseEntity.getBody(); // 获取响应体
        HttpStatus statusCode = responseEntity.getStatusCode(); // 获取响应码
        int statusCodeValue = responseEntity.getStatusCodeValue(); // 获取响应码值
        HttpHeaders headers = responseEntity.getHeaders(); // 获取响应头
 
        System.out.println("body:" + body);
        System.out.println("statusCode:" + statusCode);
        System.out.println("statusCodeValue:" + statusCodeValue);
        System.out.println("headers:" + headers);
        return;
    }
}

9-3 Post 请求示例

// 使用 post 方式发送一个 JSON 格式的数据,并将响应体、响应头、响应码打印出来。其中响应体的类型设置为 String
@RestController
public class HelloController {
    
    
    @Autowired
    private RestTemplate restTemplate;
 
    @GetMapping("/test")
    public void test() {
    
    
        // 请求地址
        String url = "http://jsonplaceholder.typicode.com/posts";
 
        // 请求头设置
        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_JSON);
 
        //提交参数设置
        MultiValueMap<String, String> map = new LinkedMultiValueMap<>();
        map.add("userId", "222");
        map.add("title", "abc");
        map.add("body", "航歌");
 
        // 组装请求体
        HttpEntity<MultiValueMap<String, String>> request =
                new HttpEntity<MultiValueMap<String, String>>(map, headers);
 
        // 发送post请求,并输出结果
        ResponseEntity<String> responseEntity
                = restTemplate.exchange(url, HttpMethod.POST, request, String.class);
        String body = responseEntity.getBody(); // 获取响应体
        HttpStatus statusCode = responseEntity.getStatusCode(); // 获取响应码
        int statusCodeValue = responseEntity.getStatusCodeValue(); // 获取响应码值
        HttpHeaders responseHeaders = responseEntity.getHeaders(); // 获取响应头
 
        System.out.println("body:" + body);
        System.out.println("statusCode:" + statusCode);
        System.out.println("statusCodeValue:" + statusCodeValue);
        System.out.println("headers:" + responseHeaders);
        return;
    }
}

10 文件下载

10-1 简单的文件下载

1)最简单的下载文件方式就是使用的是 restTemplate 调用 getForEntity 获取到字节数组,
	再将字节数组通过 java8 的 Files 工具类的 write 方法,直接写到目标文件。
	
​ 	缺点:由于需要将文件的字节数组全部放入内存中,极其消耗资源。
	当遇到大文件时,内存加载可能会造成 OutOfMemoryError2)下面是一个简单的示例,下载一个网络上的图片并保存到本地。
@RestController
public class HelloController {
    
    
    @Autowired
    private RestTemplate restTemplate;
 
    @GetMapping("/test")
    public void test() {
    
    
        // 记录下开始下载时的时间
        Instant now = Instant.now();
        // 待下载的文件地址
        String url = "http://www.hangge.com/blog/images/logo.png";
        ResponseEntity<byte[]> rsp = restTemplate.getForEntity(url, byte[].class);
        System.out.println("状态码:" + rsp.getStatusCode());
        try {
    
    
            // 将下载下来的文件内容保存到本地
            String targetPath = "/Users/hangge/Desktop/logo.png";
            Files.write(Paths.get(targetPath), Objects.requireNonNull(rsp.getBody(),
                    "未获取到下载文件"));
        } catch (IOException e) {
    
    
            System.out.println("文件写入失败:" + e.getMessage());
        }
        System.out.println("文件下载完成,耗时:" + ChronoUnit.MILLIS.between(now, Instant.now())
                + " 毫秒");
        return;
    }
}

10-2 大文件的下载

// 对于大文件的下载,建议使用流的方式来解决。
//	即每次接收到一部分数据就直接写入到文件。比如使用 Files 的 copy 方法来处理流。
@RestController
public class HelloController {
    
    
    @Autowired
    private RestTemplate restTemplate;
 
    @GetMapping("/test")
    public void test() {
    
    
        // 记录下开始下载时的时间
        Instant now = Instant.now();
        // 待下载的文件地址
        String url = "http://www.hangge.com/blog/images/logo.png";
        // 文件保存的本地路径
        String targetPath = "/Users/hangge/Desktop/logo.png";
        //定义请求头的接收类型
        RequestCallback requestCallback = request -> request.getHeaders()
                .setAccept(Arrays.asList(MediaType.APPLICATION_OCTET_STREAM, MediaType.ALL));
        //对响应进行流式处理而不是将其全部加载到内存中
        restTemplate.execute(url, HttpMethod.GET, requestCallback, clientHttpResponse -> {
    
    
            Files.copy(clientHttpResponse.getBody(), Paths.get(targetPath));
            return null;
        });
        
        System.out.println("文件下载完成,耗时:" + ChronoUnit.MILLIS.between(now, Instant.now())
                + " 毫秒");
        return;
    }
}

11 文件上传

11-1 示例

1)下面通过样例演示如何使用 RestTemplate 上传文件。
	这里使用 Form 表单的方式进行提交,上传时除了一个文件外还附带有两个自定义参数。
2)接收端收到文件后会打印出相关参数、以及文件相关数据,并返回成功信息。
3)发送方收到反馈后将反馈信息打印出来:

// 简单的示例,如要进一步操作,比如:文件重命名、文件保存、相关上传参数的配置等自己完善哈
// 1. 文件发送端代码:
@RestController
public class HelloController {
    
    
    @Autowired
    private RestTemplate restTemplate;
 
    @GetMapping("/test")
    public void test() {
    
    
        // 上传接口
        String url = "http://localhost:8080/upload";
        // 待上传的文件
        String filePath = "/Users/hangge/Desktop/test.txt";
 
        // 封装请求参数
        FileSystemResource resource = new FileSystemResource(new File(filePath));
        MultiValueMap<String, Object> param = new LinkedMultiValueMap<>();
        param.add("myFile", resource);
        param.add("param1", "12345");
        param.add("param2", "hangge");
 
        // 发送请求并输出结果
        System.out.println("--- 上传文件 ---");
        String s = restTemplate.postForObject(url, param, String.class);
        System.out.println(s);
    }
}


// 2. 接收端代码:  
@RestController
public class HelloController {
    
    
    @PostMapping("/upload")
    public String upload(String param1, String param2, MultipartFile myFile) {
    
    
        System.out.println("--- 接收文件 ---");
        System.out.println("param1:" + param1);
        System.out.println("param2:" + param2);
        String originalFilename = myFile.getOriginalFilename();
        System.out.println("文件原始名称:" + originalFilename);
        try {
    
    
            String string = new String(myFile.getBytes(), "UTF-8");
            System.out.println("文件内容:" + string);
        } catch (UnsupportedEncodingException e) {
    
    
            e.printStackTrace();
        } catch (IOException e) {
    
    
            e.printStackTrace();
        }
        // 处理文件内容...
        return "OK";
    }
}


猜你喜欢

转载自blog.csdn.net/qq_17847881/article/details/130480112