RestTemplate介绍
- spring3.0开始支持
- Http请求工具
- 该工具与springboot或springcloud无关
- 提供常见的REST请求模版
- 例如支持GET、PUT、POST、DELETE
- 通用请求方法 --> exchange和execute
- 实现RestOperations接口
- 该接口定义了常见的RESTful操作
1.GET操作
首先在provider中定义一个 hello2 接口:
@GetMapping("/hello2")
public String hello2(String name){
return "hello "+name;
}
接下来,我们在consumer去访问这个接囗,调用 RestTemplate中 的GET请求。 可以看到,在RestTemplate中,关于GET请求,一共有两大类方法:
这两大类方法实际上是重载的,唯一不同的,就是返回值类型。 getForObject返回的是一个对象,这个对象就是服务端返回的具体值。getForEntiey返回的是一个 ResponseEntity,这个ResponseEntity中除了服务端返回的具体数据外,还保留了Http应头的数据。
@GetMapping("/hello4")
public void hello4(){
String s1 = restTemplate.getForObject("http://provider/hello2?name={1}",String.class,"javaone");
System.out.println(s1);
ResponseEntity<String> responseEntity = restTemplate.getForEntity("http://provider/hello2", String.class, "javaone");
String body = responseEntity.getBody();
System.out.println("body:"+body);
HttpStatus statusCode = responseEntity.getStatusCode();
System.out.println("HttpStatus:"+statusCode);
int statusCodeValue = responseEntity.getStatusCodeValue();
System.out.println("statusCodeValue:"+statusCodeValue);
HttpHeaders headers = responseEntity.getHeaders();
Set<String> keySet = headers.keySet();
System.out.println("---------headers--------");
for (String s : keySet) {
System.out.println(s+":"+headers.get(s)+"///");
}
}
这里大家可以看到,getForObject直接拿到了服务的返回值,getForEntity不仅仅拿到服务的返回值, 还拿到http应的状态码。然后,后动 Eureka Server、provider以及consumer,访问consumer 中的 hello4 接囗,既可以看到请求结果。
看清楚两者的区别之舌,接下来看下两个各自的重载方法,getForObject 和 getForEntity 分别有三个重载方法,两者的三个重载方法基本都是一致的。所以,这里,我们主要看其中一种。三个重载方法, 其实代表了三种不同的传参方式。
@GetMapping("/hello5")
public void hello5(){
String s1 = restTemplate.getForObject("http://provider/hello2?name={1}",String.class,"javatwo");
System.out.println("1:"+s1);
HashMap<String, Object> map = new HashMap<>();
map.put("name","zhangsan");
s1 = restTemplate.getForObject("http://provider/hello2?name={name}", String.class,map);
System.out.println("2:"+s1);
try {
String url = "http://provider/hello2?name="+ URLEncoder.encode("李四","UTF-8");
URI uri = URI.create(url);
s1 = restTemplate.getForObject(uri, String.class);
System.out.println("3:"+s1);
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
}
小结:
- getForObject和getForEntity返回值区别:
- getForObject返回一个对象(服务返回的具体值)
- getForEntity不仅返回具体数据 还可以返回状态码 头信息...
- getForObject和getForEntity 三种重载方式的类似
- Object... --> 占位符 (?xxx={1}, xx.class, "xxxxx")
- Map<String, ?> --> 占位符为自定义key(name)需要提前声明map (?xxx={key}, xx.class, 返回的map)
- URI --> 字符串中包含中文的需要转码才能创建为URI 在被调用
2.POST操作
2.1准备工作
因为post请求可能是k/v或是json形式,需要提供2种接口,传参对象需要创建一个model, 为了以后方便使用直接新建一个普通的maven项目作为commons模块管理。
创建一个User类。
@Data
@ToString
public class User {
private Integer id;
private String name;
private String nickName;
}
然后provider和consumer分别引用commons模块依赖
<dependency>
<groupId>com.example</groupId>
<artifactId>commons</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
2.2 provider提供2个接口
// key/value形式传递
@PostMapping("/user1")
public User addUser1(User user){
return user;
}
//json传递
@PostMapping("/user2")
public User addUser2(@RequestBody User user){
return user;
}
接下来,我们在consumer中调这两个POST接囗。
这里的post和前面的get很像,只是多出来了三个方法,就是postForLocation,另外,两个postForObject和postForEntiy和前面get基不一致,所以这里我们主要来看postForObject, 看完之后,我们再来看这个额外的postForLocation。
@GetMapping("/hello6")
public void hello6(){
MultiValueMap<String, Object> map = new LinkedMultiValueMap<>();
map.add("username","javajava");
map.add("password","123456");
map.add("id",666);
User user = restTemplate.postForObject("http://provider/user1", map, User.class);
System.out.println("1:"+user);
user.setId(888);
user = restTemplate.postForObject("http://provider/user2", user, User.class);
System.out.println("2:"+user);
}
post参数到底是k/v 形式还是json形式,主要看第二个参数,如果第二个参数是 MultiValueMap,则参数是以k/v形来传递的。 如果是一个普通对象,则参数是以的son形式 传递。
最后再看看一下postForLocation。有的时候,当执行完一个post请求之后,立马要进行重定向, 一个非常常见的场景就是注册,注册是一个post请求,注册完成之后,立马重定向到登录页面去登录。对于这种场景,我们就可以便用postForLocation。
首先我们在 provider上提供一个用户注册接囗:
@Controller
public class RegisterController {
@PostMapping("/register")
public String register(User user){
return "redirect:http://provider/loginPage?username="+user.getUsername();
}
@GetMapping("/loginPage")
@ResponseBody
public String loginPage(String username){
return "loginPage:"+username;
}
}
注意:
- 这里的post接口,响应一定是302,否则 postForLocaton 无效。
- 重定向的地址,一定要写成绝对路径,不要写成相对路径,否则在consumer 中调用时会出问题
@GetMapping("/hello7")
public void hello7() {
MultiValueMap<String, Object> map = new LinkedMultiValueMap<>();
map.add("username", "javajava");
map.add("password", "123456");
map.add("id", 666);
//这就是postForLocation,调用该方法返回的是一个Uri,Uri就是重定向的地址(里面包含重定向的参数),拿到Uri之后,就可以直接发送新的请求了
URI uri = restTemplate.postForLocation("http://provider/register", map);
String s = restTemplate.getForObject(uri, String.class);
System.out.println(s);
}
3.PUT
首先在provider提供一个put接口:
@PutMapping("/user11")
public void updateUser1(User user1){ //k/v形式
System.out.println(user1);
}
@PutMapping("/user12")
public void updateUser2(@RequestBody User user2){ //json形式
System.out.println(user2);
}
在consumer中调用该接口,和上面post类似:
@GetMapping("/hello8")
public void hello8() {
MultiValueMap<String, Object> map = new LinkedMultiValueMap<>();
map.add("username", "javajava");
map.add("password", "123456");
map.add("id", 666);
restTemplate.put("http://provider/user11",map);
User user = new User();
user.setId(98);
user.setUsername("zhangsan");
user.setPassword("123456");
restTemplate.put("http://provider/user12",user);
}
4.DELETE
首先在provider提供一个delete接口:
@DeleteMapping("/user13")
public void deleteUser1(Integer id){
System.out.println(id);
}
@DeleteMapping("/user14/{id}")
public void deleteUser2(@PathVariable Integer id){
System.out.println(id);
}
在consumer中调用这两个删除接口(delete中参数的传递,也支持map,这块实际上和get是一样的):
@GetMapping("/hello9")
public void hello9() {
restTemplate.delete("http://provider/user13?id={1}",99);
restTemplate.delete("http://provider/user14/{1}",99);
}
示例代码地址:https://github.com/astronger/springcloud-simple-samples