文章目录
- SpringBoot中RestTemplate的使用备忘
- 1. 基本介绍
- 2. 安装配置
- 2-1 引入Maven依赖
- 2-2 创建 RestTemplate 配置类,设置连接池大小、超时时间、重试机制等等。
- 3. 使用示例
- 4 GET 请求1:getForObject() 方法的使用
- 4-1 使用示例
- 4-2 参数传递的几种方式
- 5 GET 请求2:getForEntity() 方法的使用
- 5-1 使用示例
- 5-2 参数传递的几种方式
- 6 POST 请求1:postForObject() 方法的使用
- 6-1 使用示例
- 6-2 设置 url 参数,同Get请求
- 7 POST 请求2:postForEntity()方法的使用
- 7-1 使用示例,和postForObject()基本相似,返回的是ResponseEntity罢了
- 7-2 设置 url 参数,同Get请求
- 8 POST 请求3:postForLocation() 方法的使用,返回的是 Uri
- 9 通用请求方法:exchange
- 9-1 介绍
- 9-2 Get 请求示例
- 9-3 Post 请求示例
- 10 文件下载
- 10-1 简单的文件下载
- 10-2 大文件的下载
- 11 文件上传
- 11-1 示例
SpringBoot中RestTemplate的使用备忘
1. 基本介绍
1,什么是 RestTemplate?
(1)RestTemplate 是 Spring 提供的用于访问 Rest 服务的客户端,RestTemplate 提供了多种可以便捷访问远程 Http 服务的方法,能够大大提高客户端的编写效率。
RestTemplate是 Spring3 中引入的同步阻塞式 HTTP 客户端。根据 Spring 官方文档介绍,在将来的版本中它可能会被弃用,因已在 Spring5 中引入了 WebClient 作为非阻塞式 Reactive HTTP 客户端。
(2)RestTemplate 定义了 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() 返回的是 ResponseEntity:
ResponseEntity 是 Spring 对 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() 返回的是 ResponseEntity:
ResponseEntity 是 Spring 对 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
1)postForLocation() 也是通过 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 差不多,且返回的都是 ResponseEntity:
ResponseEntity 是 Spring 对 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 方法,直接写到目标文件。
缺点:由于需要将文件的字节数组全部放入内存中,极其消耗资源。
当遇到大文件时,内存加载可能会造成 OutOfMemoryError。
2)下面是一个简单的示例,下载一个网络上的图片并保存到本地。
@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";
}
}