springboot中使用RestTemplate调用web服务小结
我们在开发中对于http接口的调用习惯使用Httpclient或者okhttp等客户端的封装,然后在代码中进行调用。
在springboot中,可以使用RestTemplate模板进行Http服务的调用,整合容易,使用简便而且优雅。不废话,直接上代码。
借助 RestTemplate,Spring应用能够方便地使用REST资源
Spring的 RestTemplate访问使用了模版方法的设计模式.
模版方法将过程中与特定实现相关的部分委托给接口,而这个接口的不同实现定义了接口的不同行为.
概述
spring web 项目提供的RestTemplate,使java访问url更方便,更优雅。
它是spring提供的异步的客户端http访问的核心class,它提供非常简单的RESTful方式与http server端进行数据交互,根据所提动的URLs进行http访问,并处理返回结果。它是基于JDK HTTP connection建立的。因此他可以使用不同的HTTP库(apache,netty and OkHttp)来setRequestFactory。
它实现了以下6个主要的HTTP meshod:
HTTP method | RestTemplate methods |
---|---|
DELETE | delete |
GET | getForObject,getForEntity |
HEAD | headForHeaders |
OPTIONS | optionsForAllow |
PUT | put |
any | exchange,execute |
使用方法
RestTemplate配置类
首先在代码中加入RestTemplate的配置类,确保能够纳入Spring的bean管理范围中。
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.client.ClientHttpRequestFactory;
import org.springframework.http.client.SimpleClientHttpRequestFactory;
import org.springframework.web.client.RestTemplate;
/**
* RestTemplate配置类
*/
@Configuration
public class RestTemplateConfig {
@Bean
public RestTemplate restTemplate(ClientHttpRequestFactory factory){
return new RestTemplate(factory);
}
@Bean
public ClientHttpRequestFactory simpleClientHttpRequestFactory(){
SimpleClientHttpRequestFactory factory = new SimpleClientHttpRequestFactory();
factory.setReadTimeout(5000);//单位为ms
factory.setConnectTimeout(5000);//单位为ms
return factory;
}
}
然后在需要访问url的类中注入RestTemplate
@Autowired
private RestTemplate restTemplate;
使用RestTemplate发送get请求
//get json数据
JSONObject json = restTemplate.getForEntity(url, JSONObject.class).getBody();
使用RestTemplate发送post请求
//post json数据
JSONObject postData = new JSONObject();
postData.put("data", "request for post");
JSONObject json = restTemplate.postForEntity(url, postData, JSONObject.class).getBody();
设置请求头
//post json string data
//return string
HttpHeaders headers = new HttpHeaders();
MediaType type = MediaType.parseMediaType("application/json; charset=UTF-8");
headers.setContentType(type);
headers.add("Accept", MediaType.APPLICATION_JSON.toString());
JSONObject jsonObj = JSONObject.parseObject(paras);
HttpEntity<String> formEntity = new HttpEntity<String>(jsonObj.toString(), headers);
String result = restTemplate.postForObject(url, formEntity, String.class);
实战讲解–发送application/json
这里以发送application/json为例着重讲解一下完整的使用流程
设置Header,将contentType配置为application/json
// 2.请求开始,设置请求头,contentType=application/json
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
设置业务参数,这里使用Map作为参数容器
Map<String, Object> requestParam = new HashMap<>();
requestParam.put("param1", param1);
requestParam.put("param2", param2);
配置HttpEntity
HttpEntity<Map<String, Object>> httpEntity =
new HttpEntity<>(requestParam, headers);
发送请求
ResponseEntity<String> responseEntity = null;
try {
// 2.1 发起请求
responseEntity = restTemplate.postForEntity(requestUrl, httpEntity, String.class);
// 2.2. 解析返回参数
String responseBody = responseEntity.getBody();
LOGGER.info("返回body:{}", responseBody);
业务返回实体 response = JSON.parseObject(responseBody, 业务返回实体.class);
} catch (Exception e) {
e.printStackTrace();
}
这里通过
public <T> ResponseEntity<T> postForEntity(String url, @Nullable Object request,
Class<T> responseType, Object... uriVariables)
发起请求,将responseBody中的业务返回实体通过FastJSON等json库转换为业务实体进行业务操作即可。
详解
RestTemplate定义了36个与REST资源交互的方法,其中的大多数都对应于HTTP的方法。
其实,这里面只有11个独立的方法,其中有十个有三种重载形式,而第十一个则重载了六次,这样一共形成了36个方法。
- 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
Get请求
RestTemplate 的get方法有以上几个,可以分为两类: getForEntity() 和 getForObject()
首先看 getForEntity() 的返回值类型 ResponseEntity
<T> ResponseEntity<T> getForEntity()
ResponseEntity 继承了HttpEntity. 封装了返回的响应信息,包括 响应状态,响应头 和 响应体.
在测试之前我们首先 创建一个Rest服务,模拟提供Rest数据,这里给出Controller层代码,
@RestController
public class UserController {
@Autowired
private UserService userService;
@RequestMapping(value = "getAll")
public List<UserEntity> getUser() {
List<UserEntity> list = userService.getAll();
return list;
}
@RequestMapping("get/{id}")
public UserEntity getById(@PathVariable(name = "id") String id) {
return userService.getById(id);
}
@RequestMapping(value = "save")
public String save(UserEntity userEntity) {
return "保存成功";
}
@RequestMapping(value = "saveByType/{type}")
public String saveByType(UserEntity userEntity,@PathVariable("type")String type) {
return "保存成功,type="+type;
}
}
测试: getForEntity
无参数的 getForEntity 方法
@RequestMapping(“getForEntity”)
public List<UserEntity> getAll2() { ResponseEntity<List> responseEntity = restTemplate.getForEntity("http://localhost/getAll", List.class); HttpHeaders headers = responseEntity.getHeaders(); HttpStatus statusCode = responseEntity.getStatusCode(); int code = statusCode.value(); List<UserEntity> list = responseEntity.getBody(); System.out.println(list.toString()); return list; }
有参数的 getForEntity 请求,参数列表,可以使用 {} 进行url路径占位符
//有参数的 getForEntity 请求,参数列表 @RequestMapping("getForEntity/{id}") public UserEntity getById2(@PathVariable(name = "id") String id) { ResponseEntity<UserEntity> responseEntity = restTemplate.getForEntity("http://localhost/get/{id}", UserEntity.class, id); UserEntity userEntity = responseEntity.getBody(); return userEntity; }
有参数的 get 请求,使用map封装参数
//有参数的 get 请求,使用map封装参数 @RequestMapping("getForEntity/{id}") public UserEntity getById4(@PathVariable(name = "id") String id) { HashMap<String, String> map = new HashMap<>(); map.put("id",id); ResponseEntity<UserEntity> responseEntity = restTemplate.getForEntity("http://localhost/get/{id}", UserEntity.class, map); UserEntity userEntity = responseEntity.getBody(); return userEntity; }
通常情况下我们并不想要Http请求的全部信息,只需要相应体即可.对于这种情况,RestTemplate提供了 getForObject() 方法用来只获取 响应体信息.
getForObject 和 getForEntity 用法几乎相同,指示返回值返回的是 响应体,省去了我们 再去 getBody() 。
测试: getForObject
无参数的 getForObject 请求
//无参数的 getForObject 请求 @RequestMapping("getAll2") public List<UserEntity> getAll() { List<UserEntity> list = restTemplate.getForObject("http://localhost/getAll", List.class);
System.out.println(list.toString());
return list;
}
有参数的 getForObject 请求,使用参数列表
//有参数的 getForObject 请求 @RequestMapping("get2/{id}") public UserEntity getById(@PathVariable(name = "id") String id) { UserEntity userEntity = restTemplate.getForObject("http://localhost/get/{id}", UserEntity.class, id); return userEntity; }
有参数的 get 请求,使用map封装请求参数
//有参数的 get 请求,使用map封装请求参数 @RequestMapping("get3/{id}") public UserEntity getById3(@PathVariable(name = "id") String id) { HashMap<String, String> map = new HashMap<>(); map.put("id",id); UserEntity userEntity = restTemplate.getForObject("http://localhost/get/{id}", UserEntity.class, map); return userEntity; }
Post请求
POST请求方法主要如下
<T> T postForObject(String url, Object request, Class<T> responseType, Object... uriVariables)
throws RestClientException;
<T> T postForObject(String url, Object request, Class<T> responseType, Map<String, ?> uriVariables)
throws RestClientException;
<T> T postForObject(URI url, Object request, Class<T> responseType) throws RestClientException;
<T> ResponseEntity<T> postForEntity(String url, Object request, Class<T> responseType, Object... uriVariables)
throws RestClientException;
<T> ResponseEntity<T> postForEntity(String url, Object request, Class<T> responseType, Map<String, ?> uriVariables)
throws RestClientException;
<T> ResponseEntity<T> postForEntity(URI url, Object request, Class<T> responseType) throws RestClientException;
测试: postForEntity
post 请求,保存 UserEntity 对像
//post 请求,提交 UserEntity 对像 @RequestMapping("saveUser") public String save(UserEntity userEntity) { ResponseEntity<String> responseEntity = restTemplate.postForEntity("http://localhost/save", userEntity, String.class); String body = responseEntity.getBody(); return body; }
有参数的 postForEntity 请求
// 有参数的 postForEntity 请求 @RequestMapping("saveUserByType/{type}") public String save2(UserEntity userEntity,@PathVariable("type")String type) { ResponseEntity<String> responseEntity = restTemplate.postForEntity("http://localhost/saveByType/{type}", userEntity, String.class, type); String body = responseEntity.getBody(); return body; } // 有参数的 postForEntity 请求,使用map封装 @RequestMapping("saveUserByType2/{type}") public String save3(UserEntity userEntity,@PathVariable("type")String type) { HashMap<String, String> map = new HashMap<>(); map.put("type", type);
ResponseEntity<String> responseEntity = restTemplate.postForEntity("http://localhost/saveByType/{type}", userEntity, String.class,map);
String body = responseEntity.getBody();
return body;
}