玩转 RestTemplate
一、RestTemplate 简介
RestTemplate是Spring提供的用来访问Rest服务的客户端或者说是一个 HTTP 请求工具。
这么说可能有些抽象,那就设想一下:现在有A、B两个服务,两个服务都注册在eureka中,那A服务要调用B服务怎么办?你可以使用Java 自带的 HttpUrlConnection 或者经典的网络访问框架 HttpClient 来实现。但是这些请求工具都是比较原生态的,在使用时开发者还要自己完成部分逻辑,使用起来比较复杂。
Spring给我们提供了RestTemplate,spring采用模板模式对httpClient的再封装,遵循Restful原则。RestTmplate提供了很多便捷的方法,可以大大提供开发效率,在微服务中可以方便地进行接口调用。
二、RestTemplate 有哪些API?
RestTemplate 继承自 InterceptingHttpAccessor 并且实现了 RestOperations 接口,其中 RestOperations 接口定义了基本的 RESTful 操作,这些操作在 RestTemplate 中都得到了实现。RestTemplate 提供了常见的REST请求方案的模版,例如 GET 请求、POST 请求、PUT 请求、DELETE 请求以及一些通用的请求执行方法 exchange 以及 execute。
三、RestTemplate的配置
正常在spring boot项目中,一般都有xml和注解两种配置方式,这里使用注解形式完成配置:
@Configuration
public class RestTemplateConfig {
@Bean
public RestTemplate restTemplate(ClientHttpRequestFactory factory) {
return new RestTemplate(factory);
}
@Bean
public ClientHttpRequestFactory simpleClientHttpRequestFactory() {
SimpleClientHttpRequestFactory factory = new SimpleClientHttpRequestFactory();
factory.setReadTimeout(50000);//ms
factory.setConnectTimeout(150000);//ms
return factory;
}
}
四、RestTemplate 的使用
在说明使用方式前先准备一个服务,简单实现几个功能:
@RestController
@RequestMapping("/dept")
public class DeptController {
@Autowired
private DeptService deptService;
@PostMapping("/add")
public boolean add(@RequestBody Dept dept){
return deptService.addDept(dept);
}
@GetMapping("/getById/{deptno}")
public Dept getById(@PathVariable("deptno") Long deptno){
return deptService.queryById(deptno);
}
@GetMapping("/getAll")
public List<Dept> getAll(){
return deptService.queryAll();
}
}
4.1 Get 请求
4.1.1 不带参数
RestTemplate 的get方法有以上几个,可以分为两类: getForEntity() 和 getForObject()
@RestController
@Slf4j
@RequestMapping("/rest-template")
public class RestTemplateTestController {
@Autowired
private RestTemplate restTemplate;
@GetMapping("/getForEntityList")
public List<Dept> getAllDept() {
String url = "http://localhost:8001/dept/getAll";
ResponseEntity<List> responseEntity = restTemplate.getForEntity(url, List.class);
log.info("headers:{}", responseEntity.getHeaders());
log.info("statusCode:{}", responseEntity.getStatusCode());
log.info("statusCodeValue1:{}", responseEntity.getStatusCodeValue());
log.info("statusCodeValue2:{}", responseEntity.getStatusCode().value());
List<Dept> list = responseEntity.getBody();
log.info("list:{}", list);
return list;
}
}
@GetMapping("/getForObjectList")
public List<Dept> getForObjectList() {
String url = "http://localhost:8001/dept/getAll";
List<Dept> forObject = restTemplate.getForObject(url, List.class);
log.info("list:{}", forObject);
return forObject;
}
4.1.2 带参数
@GetMapping("/getForEntity/{id}")
public Dept getDeptById(@PathVariable("id") Long id) {
String url = "http://localhost:8001/dept/getById/{deptno}";
ResponseEntity<Dept> responseEntity = restTemplate.getForEntity(url, Dept.class, id);
log.info("headers:{}", responseEntity.getHeaders());
log.info("statusCode:{}", responseEntity.getStatusCode());
log.info("statusCodeValue1:{}", responseEntity.getStatusCodeValue());
log.info("statusCodeValue2:{}", responseEntity.getStatusCode().value());
Dept dept = responseEntity.getBody();
log.info("dept:{}", dept);
return dept;
}
@GetMapping("/getForObject/{id}")
public Dept getForObject(@PathVariable("id") Long id) {
String url = "http://localhost:8001/dept/getById/{deptno}";
Dept dept = restTemplate.getForObject(url, Dept.class, id);
log.info("dept:{}", dept);
return dept;
}
4.1.3 map为参数
@GetMapping("/getForEntityWithMap/{id}")
public Dept getForEntityWithMap(@PathVariable("id") Long id) {
String url = "http://localhost:8001/dept/getById/{deptno}";
HashMap<String, Long> map = new HashMap();
map.put("deptno",id);
ResponseEntity<Dept> responseEntity = restTemplate.getForEntity(url, Dept.class, map);
Dept dept = responseEntity.getBody();
log.info("dept:{}", dept);
return dept;
}
@GetMapping("/getForObjectWithMap/{id}")
public Dept getForObjectWithMap(@PathVariable("id") Long id) {
String url = "http://localhost:8001/dept/getById/{deptno}";
HashMap<String, Long> map = new HashMap();
map.put("deptno",id);
Dept dept = restTemplate.getForObject(url, Dept.class, map);
log.info("dept:{}", dept);
return dept;
}
4.2 Post 请求
@PostMapping("/save-dept")
public String saveDept(Dept dept) {
String url = "http://localhost:8001/dept/add";
ResponseEntity<String> stringResponseEntity = restTemplate.postForEntity(url, dept, String.class);
log.info("stringResponseEntity:{}", stringResponseEntity);
return stringResponseEntity.getBody();
}
@PostMapping("/save-dept-object")
public String saveDeptObject(Dept dept) {
String url = "http://localhost:8001/dept/add";
String postForObject = restTemplate.postForObject(url, dept, String.class);
log.info("stringResponseEntity:{}", postForObject);
return postForObject;
}
4.3 exchange 请求
@PostMapping("/save-dept-exchange")
public String saveDeptWithExchange(Dept dept) {
String url = "http://localhost:8001/dept/add";
HttpEntity<Dept> entity = new HttpEntity<Dept>(dept);
ResponseEntity<String> exchange = restTemplate.exchange(url, HttpMethod.POST, entity, String.class);
log.info("exchange:{}", exchange);
return exchange.getBody();
}
五、总结
RestTemplate作为一款非常不错的rest请求工具,屏蔽了复杂的HttpClient的实现细节,向外暴露出简单、易于使用的接口,使得我们的开发工作越来越简单、高效。在微服务中的调用中它也有很重要的位置,因此,掌握其原理及用法还是很必要的。
然而,RestTemplate虽然实现了服务调用,但是并没有实现负载均衡,要实现负载均衡还要使用@LoadBalenced注解结合Ribbon来实现或者Feign来实现。
(以上代码纯手打~)