一、简介
常见的http客户端请求工具:
以上 工具虽然常用,但对于 RESTful
操作相对不是太友好。所以,从 Spring3.0
开始支持的一个 HTTP 请求工具RestTemplate
,提供了常见的 REST
请求方案的模板。
RestTemplate
只是提供了 Http
请求模板,其底层默认是使用HttpURLConnection
作为真正的请求工具。它可以通过构造方法替换底层的执行引擎,常见的引擎又HttpClient
、Netty
、OkHttp
。
二、简单的请求
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
请求中的getForObject
和 getForEntity
方法不支持传递头信息,需要使用 通用方法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
中已经提供了大部分的执行引擎,比如 HttpClient
和OkHttp3
等,要想使用这些底层引擎只需要加入响应的依赖,然后再初始化类似,在构造方法中指定响应的执行引擎即可。
// 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));