1、引文
之前做需求的时候,有一次遇到一个场景:判断某一天是工作日、休息日或节假日。从网上找了一个接口http://tool.bitefu.net/jiari/ 用法如下图
如上所示,我们仅在这个接口尾部输入yyyyMMDD格式的日期参数,就能知道当天是工作日(0)、休息日(1)和节假日(2)了。
做法如下:
public static String httpClient(String dateString){
//创建客户端
CloseableHttpClient httpClient = HttpClients.createDefault();
//拼接uri
String uri = "http://tool.bitefu.net/jiari/?d=%s";
String format = String.format(uri, dateString);
//创建请求
HttpGet httpGet = new HttpGet(format);
try {
//调用接口,返回结果
CloseableHttpResponse response = httpClient.execute(httpGet);
if (response!=null){
HttpEntity entity = response.getEntity();
String result = EntityUtils.toString(entity,"UTF-8");
return result;
}else{
return "error";
}
} catch (IOException e) {
e.printStackTrace();
}
return "error";
}
可以发现当前代码中其实只有极少的代码与调用接口有关,我们希望仅仅需要传入uri和参数,就能够返回我们想要的结果。在这里我们不得不捕获或抛出检查型异常IOException。如果我们在编写一个方法,调用其他接口,又需要我们写非常多的重复的代码。这并不符合我的期望。
Spring 提供给我们一些模版,给我们的很大的便利。举个例子,我们在使用传统的jdbc去操作数据库的时候,我们需要加载驱动、建立连接、写sql、传参、执行和返回结果,在完成之后我们还需要去关闭链接,不得不去捕获抛出的检查型异常。但是spring提供给我们的jdbcTempalte,在设置了dataSource之后,我们仅仅需要执行类似这样一句
jdbcTemplate.setDataSource(dataSource);
String sql = "select count(*) from user";
Long num = (long) jdbcTemplate.queryForObject(sql, Long.class);
即可返回user的数量,它已经帮我们完成连接的建立、关闭以及异常处理等等操作。
RestTemplate也是这样为了提供给我们方便的而生的,它定义了36个与REST资源交互的方法,其中的大多数都对应于HTTP的方法。但是,没有足够的篇幅涵盖所有的36个方法。其实,这里面只有11个独立的方法,其中有十个有三种重载形式,而第十一个则重载了六次,这样一共形成了36个方法。
除了TRACE以外,RestTemplate涵盖了所有的HTTP动作。除此之外,execute()和exchange()提供了较低层次的通用方法来使用任意的HTTP方法。
2、Get
从上面的三个方法中进行分析:
第一个方法传参是直接调用url,responseType代表了返回值的类型。
第二个方法提供了多个参数的植入,通常来说,这些参数是根据url中填参部分,依次填入。
第三个方法利用Map填参,Map的key值与url缺少的参数名要保持一致。
上图展示了三种方法的使用方式,它们均可以给出我们想要的结果。
此外还有一个方法getForEntity( ),它的使用方式和getForObject( )大同小异,它们都执行根据URL检索资源的GET请求。它们都将资源根据responseType参数匹配为一定的类型。唯一的区别在于getForObject()只返回所请求类型的对象,而getForEntity()方法会返回请求的对象以及响应相关的额外信息。如下所示,它还能返回http状态码以及的响应头信息。
为了实现更通用的HTTP头信息访问,HttpHeaders提供了get()方法和getFirst()方法。两个方法都接受String参数来标识所需要的头信息。get()将会返回一个String值的列表,其中的每个值都是赋给该头部信息的,而getFirst()方法只会返回第一个头信息的值。
3、POST
不管是URL类型还是String类型,第一个参数都是资源要POST到的URL;
第二个参数是要发送的对象;
第三个参数是预期返回的Java类型。
在将URL作为String类型的两个版本中,第四个参数指定了URL变量(要么是可变参数列表,要么是一个Map,与上一节的使用方法一致)。
postForLocation 、postForObject 、postForEntity的区别:
类似于get类型,postForObject 和postForEntity拥有的作用类似,他们讲第二个参数要发送的对象推送到服务器进行处理。而postForEntity的场景还是为了查看一些响应中的头信息,比如说一些Location信息,我们可以使用ResponseEntity.getHeaders().getLocation()的方式获得。如果要同时接收所发送的资源和响应头,postForEntity()方法是很便利的。但通常你并不需要将资源发送回来(毕竟,将其发送到服务器端是第一位的)。如果你需要的仅仅是Location头信息的值,那么使用RestTemplate的postForLocation()方法会更简单。
4、Delete
实际上,delete是RestTemlate中最简单的方法,唯一需要我们提供的就是url和要删除的对象的ID即可,在这里就不举例了。
5、Put
在RestFul接口规范中,我们通常使用put来进行数据的更新修改。
RestTemplate提供了三个简单的put()方法,第一个参数是指定的Url,第二个参数是需要更新的对象,后面的参数是对utl的补全。
从getForObject()和getForEntity()方法中我们也看到了,使用基于String的其他put()方法能够为我们减少创建URI的不便。对象将被转换成什么样的内容类型很大程度上取决于传递给put()的类型。如果给一个String值,那么将会使用StringHttpMessageConverter:这个值直接被写到请求体中,内容类型设置为“text/plain”。如果给定一个MultiValueMap<String,String>,那么这个Map中的值将会被FormHttpMessageConverter以“application/x-www-form-urlencoded”的格式写到请求体中。
6、exchange
RestTempalte中定义很多重载的exchange()方法,如下
String|URL :请求路径
HttpMethod:Http的动作,如Get、delete等
requestEntity():在请求中发送资源,get可以为null
responseType(如果要获取状态码和header可使用ResponseEntity<T>):返回数据的类型
Map/Object... :填充Url的参数
exchange()利用HttpMethod这个参数,可以完成其他RestTemplate方法的工作,如上GET、POST、DELETE、PUT等。exchange()优于其他方法的点事它可以在发送给服务器的请求中加入头信息。
MultiValueMap<String,String> headers = new LinkedMultiValueMap<>();
headers.add("User-Agent","Java/1.8.0_161");
...
HttpEntity<Object> requestEntity = new HttpEntity<>(headers);