概述:
在Springboot中,调用restFul api时常用的方法主要有两种:
通过自带的RestTemplate 或者 自己写http客户端访问工具来实现服务调用
基本上RestTemplate已经可以满足需要了
RestTemplate其实是对http请求中一些模块化代码的封装,比如建立连接、构造请求头 请求体、解析响应信息、关闭连接等,是Springboot对HttpClient的封装,简化了http请求过程,减少冗余代码。
主要方法:
RestTemplate封装了常用http请求,比如GET、POST、PUT、DELETE等,可以方便的调用,主要请求方法如下:
public <T> T getForObject(String url, Class<T> responseType, Object... uriVariables) throws RestClientException
public <T> ResponseEntity<T> getForEntity(String url, Class<T> responseType, Object... uriVariables) throws RestClientException
public <T> T postForObject(String url, @Nullable Object request, Class<T> responseType, Object... uriVariables) throws RestClientException
public <T> ResponseEntity<T> postForEntity(String url, @Nullable Object request, Class<T> responseType, Object... uriVariables) throws RestClientException
public void put(String url, @Nullable Object request, Object... uriVariables) throws RestClientException
public void delete(String url, Object... uriVariables) throws RestClientException
public <T> ResponseEntity<T> exchange(String url, HttpMethod method, @Nullable HttpEntity<?> requestEntity, Class<T> responseType, Object... uriVariables) throws RestClientException
public <T> T execute(String url, HttpMethod method, @Nullable RequestCallback requestCallback, @Nullable ResponseExtractor<T> responseExtractor, Object... uriVariables) throws RestClientException
这些方法使用起来是比较简单的,其中xxForObject返回的是接口返回值,xxForEntity返回的除了接口返回值 还包括http返回信息。
对于exchange和execute使用起来就比较灵活了,里面有个参数 HttpMethod,可以使用各种请求方式进行请求,比如用HttpMethod.GET方法进行GET请求。
HttpMethod是一个枚举:
RestTemplate exchange方法使用:
1、先新建一个springboot工程,端口取默认 8080,然后新建一个Controller,如下:
@RestController
public class RemoteRestController {
@GetMapping("rest")
public String usedForRemoteRest(){
return "Hi there, from remote";
}
}
如果调用成功,会返回一个字符串
2、再新建一个springboot工程,端口取8081,工程名比如取ex,方便辨认
server.port=8081
3、在新建的ex工程中,新建一个Controller,准备调用RestTemplate方法,去访问第一个工程中的接口:
@RestController
public class RestTestController {
private static final String REMOTE_URL = "http://localhost:8080/";
@GetMapping("rtest")
public String restGetValue(HttpServletRequest req){
RestTemplate restTemplate = new RestTemplate();
String ret = restTemplate.getForObject(REMOTE_URL + "rest", String.class);
System.out.println("====================ret: " + ret);
ResponseEntity<String> retEntity = restTemplate.getForEntity(REMOTE_URL + "ret", String.class);
return "";
}
}
分别运行两个spring工程,在浏览器中输入http://localhost:8081/rtest ,可以看到返回:
在ex工程中下断点,可以看到getForObject和getForEntity返回值的区别:
可以看到getForEntity返回信息会包括http的信息
上面是简单的使用
在源码中我们可以看到,xxForObject, xxForEntity都是有返回值,而对于put, delete访问需要得到返回值,使用:
public void put(String url, @Nullable Object request, Object... uriVariables) throws RestClientException
public void delete(String url, Object... uriVariables) throws RestClientException
这两个方法就无能为力了
这时我们可以使用exchange方法来使用,具体如下:
在测试springboot工程中,写一个put方法的controller:
@PutMapping("restput")
public String putMethod(){
return "PUT method invoke";
}
可以封装一个exchange方法:
private <T, A> T exchange(String url, HttpMethod method, Class<T> responseBodyType, A requestBody) {
RestTemplate template = new RestTemplate();
// 请求头
HttpHeaders headers = new HttpHeaders();
MimeType mimeType = MimeTypeUtils.parseMimeType("application/json");
MediaType mediaType = new MediaType(mimeType.getType(), mimeType.getSubtype(), Charset.forName("UTF-8"));
// 请求体
headers.setContentType(mediaType);
// 发送请求
HttpEntity<A> entity = new HttpEntity<>(requestBody, headers);
ResponseEntity<T> resultEntity = template.exchange(url, method, entity, responseBodyType);
return resultEntity.getBody();
}
responseBody: 代表返回值类型
requestBody: 代表请求体中的body参数
在ex工程中写一个测试请求接口:
@GetMapping("rput")
public String restPUTValue(HttpServletRequest req){
String ret = exchange(REMOTE_URL + "restput", HttpMethod.PUT, String.class, null);
return "RETURN: " + ret;
}
在浏览器中输入:
会发现返回结果显示出来了:
exchange方法返回值中有泛型类型情况:
前面介绍的exchange方法是处理RestTemplate自带的put, delete方法中没有返回值的情况,但是包括get, post等方法,如果返回值中有泛型值,RestTemplate自带的getForEntity, getForObject等其实也是处理不了的,这时也可以使用exchange来代替,具体如下:
可以对上面封装的exchange方法进行改造,传入一个ParameterTypeReference对象:
public static <T, A> T exchange(String url, HttpMethod method, ParameterizedTypeReference<T> responseBodyType, A requestBody) {
RestTemplate restTemplate = new RestTemplate();
// 请求头
HttpHeaders headers = new HttpHeaders();
MimeType mimeType = MimeTypeUtils.parseMimeType("application/json");
MediaType mediaType = new MediaType(mimeType.getType(), mimeType.getSubtype(), Charset.forName("UTF-8"));
// 请求体
headers.setContentType(mediaType);
// 发送请求
HttpEntity<A> entity = new HttpEntity<>(requestBody, headers);
ResponseEntity<T> resultEntity = restTemplate.exchange(url, method, entity, responseBodyType);
return resultEntity.getBody();
}
测试代码:
两个springboot工程分别新建一个对象RestBean,使用了泛型:
public class RestBean<T> {
private String name;
private int age;
private T msg;
public RestBean() {
}
public RestBean(String name, int age, T msg) {
this.name = name;
this.age = age;
this.msg = msg;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public T getMsg() {
return msg;
}
public void setMsg(T msg) {
this.msg = msg;
}
}
在测试工程中返回这个对象,泛型为String:
@GetMapping("restex")
public RestBean<String> restMethodEx(){
RestBean<String> bean = new RestBean<>();
bean.setName("eric");
bean.setAge(18);
bean.setMsg("+++++++++++++++++Msg body");
return bean;
}
在ex工程中,写一个测试接口,用来远程调用测试工程的 "resetex" 接口:
@GetMapping("rgetex")
public String testEx(){
ParameterizedTypeReference<RestBean<String>> responseBodyType = new ParameterizedTypeReference<RestBean<String>>() {};
RestBean<String> ret = exchange(REMOTE_URL + "restex", HttpMethod.GET, responseBodyType, null);
return "TEST SUCCESS: " + ret.getName();
}
测试结果如下: