0 环境
- 系统环境: win10
- 编辑器: IDEA
1 简介
RestTemplate
- spring3.0开始支持
- Http请求工具
- 该工具与springboot或springcloud无关
- 提供常见的REST请求模版
- 例如支持GET、PUT、POST、DELETE
- 通用请求方法 --> exchange和execute
- 实现RestOperations接口
- 该接口定义了常见的RESTful操作
2 GET操作
2.1 GET相关的2种方法介绍(重载)
@Nullable
<T> T getForObject(String var1, Class<T> var2, Object... var3) throws RestClientException;
@Nullable
<T> T getForObject(String var1, Class<T> var2, Map<String, ?> var3) throws RestClientException;
@Nullable
<T> T getForObject(URI var1, Class<T> var2) throws RestClientException;
<T> ResponseEntity<T> getForEntity(String var1, Class<T> var2, Object... var3) throws RestClientException;
<T> ResponseEntity<T> getForEntity(String var1, Class<T> var2, Map<String, ?> var3) throws RestClientException;
<T> ResponseEntity<T> getForEntity(URI var1, Class<T> var2) throws RestClientException;
public class ResponseEntity<T> extends HttpEntity<T>{xxxx}
// 属性 比如x
public static final HttpEntity<?> EMPTY = new HttpEntity();
private final HttpHeaders headers;
@Nullable
private final T body;
private final Object status;
// 用到的方法 比如
public HttpStatus getStatusCode() {
return this.status instanceof HttpStatus ? (HttpStatus)this.status : HttpStatus.valueOf((Integer)this.status);
}
public int getStatusCodeValue() {
return this.status instanceof HttpStatus ? ((HttpStatus)this.status).value() : (Integer)this.status;
}
这2种方法的返回值
- getForObject返回一个对象(服务返回的具体值)
- getForEntity不仅返回具体数据 还可以返回状态码 头信息...
2.2 首先在provider中定一个hello1接口
/**
* @Description: consumer访问该接口 调用RestTemplate的get请求
* @Param: [name]
* @return: java.lang.String
* @Author: 水面行走
* @Date: 2020/3/4
*/
@GetMapping("/hello1")
public String hello1(String name){
return "hello provider: " + name;
}
2.3 2种方法返回值验证
/**
* @Description: 对比2种方法的不同与相同
* @Param:
* @return:
* @Author: xxxx
* @Date: 2020/xx/xx
*/
@GetMapping("/useHello5")
public void userHello5(){
// 获取服务返回值
String fish = restTemplateOne.getForObject("http://provider/hello1?name={1}", String.class, "love fish");
System.out.println("getForObject --> " + fish);
// 获取服务返回值 http响应码 头信息...
ResponseEntity<String> milk = restTemplateOne.getForEntity("http://provider/hello1?name={1}", String.class, "milk");
String body = milk.getBody();
System.out.println("body --> " + body);
HttpStatus statusCode = milk.getStatusCode();
System.out.println("HttpStatus --> " + statusCode);
int statusCodeValue = milk.getStatusCodeValue();
System.out.println("getStatusCodeValue --> " + statusCodeValue);
System.err.println("----------------------遍历heards----------------------");
// 需要遍历
HttpHeaders headers = milk.getHeaders();
Set<String> strings = headers.keySet();
for (String s : strings) {
System.out.println(s + " => " + headers.get(s));
}
}
启动Eureka server provider consumer 访问consumer useHello5接口
2.4 getForObject三种重载方法
getForObject和getForEntity分别有三个重载方法(传参方式)且很类似 那么只展示一个方法即可
/**
* @Description:
* @Nullable
* <T> T getForObject(String var1, Class<T> var2, Object... var3) throws RestClientException;
*
* @Nullable
* <T> T getForObject(String var1, Class<T> var2, Map<String, ?> var3) throws RestClientException;
*
* @Nullable
* <T> T getForObject(URI var1, Class<T> var2) throws RestClientException;
* -------------------------------------------------------------------------------------------------------------------------------
* <T> ResponseEntity<T> getForEntity(String var1, Class<T> var2, Object... var3) throws RestClientException;
*
* <T> ResponseEntity<T> getForEntity(String var1, Class<T> var2, Map<String, ?> var3) throws RestClientException;
*
* <T> ResponseEntity<T> getForEntity(URI var1, Class<T> var2) throws RestClientException;
* @Param:
* @return:
* @Author: xxxx
* @Date: 2020/xx/xx
*/
@GetMapping("/useHello6")
public void userHello6() throws UnsupportedEncodingException {
// getForObject与getForEntity类似(不是为了偷懒)
// Object... var3
System.out.println(" <---- Object... -----> ");
String fish = restTemplateOne.getForObject("http://provider/hello1?name={1}", String.class, "love fish");
System.out.println("fish --> " + fish);
// Map<String, ?> var3
System.out.println(" <---- Map<String, ?> -----> ");
HashMap<String, Object> map = new HashMap<>();
map.put("name", "lusi");
String object = restTemplateOne.getForObject("http://provider/hello1?name={name}", String.class, map);
System.out.println("map: " + object);
// URI var1
System.out.println(" <---- URI -----> ");
// 汉字需要转码
String encode = "李思思";
String url = "http://provider/hello1?name=" + URLEncoder.encode(encode, "UTF-8");
// string转化为URI
URI uri = URI.create(url);
// 装载
String forUri = restTemplateOne.getForObject(uri, String.class);
System.err.println("url --> " + forUri);
}
启动三个服务
2.5 小结
- getForObject和getForEntity返回值区别
- getForObject返回一个对象(服务返回的具体值)
- getForEntity不仅返回具体数据 还可以返回状态码 头信息...
- getForObject和getForEntity 三种重载方式的类似
- Object... --> 占位符 (?xxx={1}, xx.class, "xxxxx")
- Map<String, ?> --> 占位符为自定义key(name)需要提前声明map (?xxx={key}, xx.class, 返回的map)
- URI --> 字符串中包含中文的需要转码才能创建为URI 在被调用
3 POST操作
3.1 准备
- 因为post请求可能是k:v或是json形式 需要提供2种接口 传参对象 需要创建一个model 为了以后方便使用 直接新建一个普通的maven项目作为commons模块 管理
步骤
1.创建maven项目作为commons项目 添加依赖 也可以不添加直接get set 随意
<dependencies>
<!-- https://mvnrepository.com/artifact/org.projectlombok/lombok -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.10</version>
<scope>provided</scope>
</dependency>
</dependencies>
2.创建一个User类
@Data
@ToString
public class User {
private Integer id;
private String name;
private String nickName;
}
3.provider和consumer引用commons模块
<dependency>
<groupId>xxx你定义的gruopIdxxx</groupId>
<artifactId>commons</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
3.2 provider提供接口
- 不仅要提供2个post接口 因为还有一个postForLocation方法 需要添加类 2个接口 一个重定向和一个重定向的地址
// 在provider 提供2个post接口
/**
* @Description: key:value形式传参
* @Param: [user]
* @return: model.User
* @Author:
* @Date: 2020/xx/xx
*/
@PostMapping("/user")
public User addUser(User user){
return user;
}
/**
* @Description: json形式传参
* @Param: [user]
* @return: model.User
* @Author:
* @Date: 2020/xx/xx
*/
@PostMapping("/user1")
public User addUser1(@RequestBody User user){
return user;
}
- 新建一个类存在重定向
// 为了重定向
@Controller
public class RegisterController {
/**
* @Description: 该post接口重定向到login页面 是为了体验postForLocation方法 所以响应一定是302 否则无效
* @Param: [user]
* @return: java.lang.String
* @Author:
* @Date: 2020/xx/xx
*/
@PostMapping("/register")
public String register(User user) throws UnsupportedEncodingException {
// 一定是绝对路径 否则consumer中会报错
// 因为是重定向 若传参为中文 需要转换为utf-8
return "redirect:http://provider/login?name=" + URLEncoder.encode(user.getName(), "UTF-8");
}
@GetMapping("/login")
@ResponseBody
public String login(String name){
return "login: " + name;
}
}
4 consumer的使用
由于postForObject和ResponseEntity类似 写一种即可
4.1 postForObject的使用
/**
* @Description: 测试postForObject方法 k/v还是json形式 -> 取决于看postForObject第二个参数
* @Param:
* @return:
* @Author: 水面行走
* @Date: 2020/xx/xx
*/
@GetMapping("/useHello7")
public void userHello7(){
MultiValueMap<String, Object> map = new LinkedMultiValueMap<>();
map.add("id", 77);
map.add("name", "小明");
map.add("nickName", "笑嘻嘻");
// k/v形式
User user = restTemplateOne.postForObject("http://provider/user", map, User.class);
System.out.println(user);
user.setId(45);
// 普通object对象 --> json形式
User user1 = restTemplateOne.postForObject("http://provider/user1", user, User.class);
System.err.println(user1);
}
4.2 postForLocation的使用
当我执行post请求完后 立马重定向(例如注册 注册完成后 立马重定向到登陆页面 postForLocation该上场了)
/**
* @Description: 测试postForLocation register接口 k/v传参
* @Param:
* @return:
* @Author: 水面行走
* @Date: 2020/xx/xx
*/
@GetMapping("/useHello8")
public void userHello8(){
MultiValueMap<String, Object> map = new LinkedMultiValueMap<>();
map.add("id", 77);
map.add("name", "小明的");
map.add("nickName", "笑哈哈");
// 返回uri -> 重定向的地址和参数
URI uri = restTemplateOne.postForLocation("http://provider/register", map);
System.out.println("uri:" + uri);
String s = restTemplateOne.getForObject(uri, String.class);
System.out.println("打印:" + s);
}
postForLocation调用返回uri->重定向的地址(例如http://provider/login?name=%E5%B0%8F%E6%98%8E%E7%9A%84) 拿到uri后 获取uri 发送uri请求获取值(例如 打印:login: 小明的)
4.3 小结
- 2种传参方式 处理方式注意一下 使用postForObject 将值传给它的第二个参数上
- k/v形式 需要new LinkedMultiValueMap add值
- json形式 无需添加map进行处理 直接普通的对象即可 但是我们该url时 别忘了添加@RequestBody
- post接口 响应码必须得302 不然postForLocation无效 重定向地址一定是绝对路径 相对路径 consumer调用就凉了
5 PUT操作
PUT重载方法少
5.1 provider提供接口
/**
* @Description: k/v形式 因为是更新操作 put方法返回为void 所以返回值为void就行 有返回值不会报错(put和post传参很像)
* @Param:
* @return:
* @Author: 水面行走
* @Date: 2020/xx/xx
*/
@PutMapping("/user")
public void updateUser(User user){
System.out.println("k/v形式:" + user);
}
/**
* @Description: json形式 别忘了传参添加注解 因为是更新操作 put方法返回为void 所以返回值为void就行 有返回值不会报错
* @Param:
* @return:
* @Author: 水面行走
* @Date: 2020/xx/xx
*/
@PutMapping("/user1")
public void updateUser1(@RequestBody User user){
System.out.println("json形式:" + user);
}
5.2 consumer消费接口
/**
* @Description: 2种形式 put调用的方式
* @Param:
* @return:
* @Author: 水面行走
* @Date: 2020/xx/xx
*/
@GetMapping("/useHello9")
public void userHello9(){
MultiValueMap<String, Object> map = new LinkedMultiValueMap<>();
map.add("id", 38);
map.add("name", "不过烦恼");
map.add("nickName", "笑哈哈");
// k/v形式
restTemplateOne.put("http://provider/user", map);
User user = new User();
user.setId(1);
user.setName("小米是地方");
user.setNickName("母老虎");
restTemplateOne.put("http://provider/user1", user);
}
5.3 在provider查看显示结果
启动项目(三个)
6 Delete操作
介绍2种传参方式 k/v形式(xx?id=xxx) PathVariable(参数放在路径中 xx/1)
6.1 provider提供接口
/**
* @Description: k/v形式的删除 xxx?id=1
* @Param:
* @return:
* @Author: 水面行走
* @Date: 2020/xx/xx
*/
@DeleteMapping("/user")
public void delUser(Integer id){
System.out.println("k/v形式:" + id);
}
/**
* @Description: PathVariable(参数放在路径中 xxx/1)形式的删除
* @Param:
* @return:
* @Author: 水面行走
* @Date: 2020/xx/xx
*/
@DeleteMapping("/user1/{id}")
public void delUser1(@PathVariable Integer id){
System.out.println("json形式:" + id);
}
6.2 consumer消费接口
/**
* @Description:
* public void delete(String url, Object... uriVariables) throws RestClientException {
* this.execute(url, HttpMethod.DELETE, (RequestCallback)null, (ResponseExtractor)null, (Object[])uriVariables);
* }
* // 删除支持map和get类似 自己测试
* public void delete(String url, Map<String, ?> uriVariables) throws RestClientException {
* this.execute(url, HttpMethod.DELETE, (RequestCallback)null, (ResponseExtractor)null, (Map)uriVariables);
* }
*
* public void delete(URI url) throws RestClientException {
* this.execute(url, HttpMethod.DELETE, (RequestCallback)null, (ResponseExtractor)null);
* }
* @Param:
* @return:
* @Author: 水面行走
* @Date: 2020/xx/xx
*/
@GetMapping("/useHello10")
public void useHello10(){
// k/v --> id={1} 或是map形式 id={id},可参考getForObject中的map方式
restTemplateOne.delete("http://provider/user?id={1}", 99);
// PathVariable
restTemplateOne.delete("http://provider/user1/{1}", 99);
}
6.3 在provider上查看结果
启动项目(三个服务)