Spring Cloud 学习笔记——详细介绍 RestTemplate

6.3 RestTemplate

  • RestTemplate 是 Spring 3.0 之后支持 http 请求的一个工具,跟Spring Boot 无关,更跟 Spring Cloud 无关,提供了常见的 Rest 模板,如 GET、POST、PUT、DELETE,以及一些通用的 EXCHANG、EXCUTE方法。
    RestTemplate 实现了 RestOperation 接口,并实现了其中的方法。RestOperation 接口定义了常见的 Restful 操作,

6.3.1 GET

  • 在 provider 服务中定义一个 hello2 接口:
@GetMapping("/hello2")
    public String hello2(String name){
        return "hello" + name;
    }

重新启动 provider 服务

  • 在 consumer 中访问 hello2 接口,是 GET 请求,就调用RestTemplate 中的 getXXX() 方法
    在这里插入图片描述
  • 主要分为 getForObject 和 getForEntity 两大类方法,返回值不一致,getForObject 就是服务端返回的具体值,getForEntity 返回 ReponseEntity ,除了具体值,还有响应头的数据
  • 代码编写
- @GetMapping("hello4")
   public void hello4(){
       String s = balanceRestTemplate.getForObject("http://provider/hello2?name={1}", String.class, "javaboy");
       System.out.println(s);
       ResponseEntity<String> responseEntity = balanceRestTemplate.getForEntity("http://provider/hello2?name={1}", String.class, "javaboy");
       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);
       System.out.println("----------------header------------------");
       HttpHeaders headers = responseEntity.getHeaders();
       Set<Map.Entry<String, List<String>>> entries = headers.entrySet();
       for (Map.Entry<String, List<String>> entry:entries) {
           System.out.println(entry.getKey());
           System.out.println(entry.getValue());
       }
   }
  • 代码执行结果
    在这里插入图片描述

  • 看清楚区别后,接下来看各自的重载方法,getForObject 和 getForEntity 分别有三个重载方法,两者的三个重载方法基本是一致的,所以,这里只看其中一种。三个重载方法,其实代表了三种传参方式。

  • 编写代码

 @GetMapping("/hello5")
    public void hello5() throws UnsupportedEncodingException, URISyntaxException {
        //多个参数的传参方式
//       balanceRestTemplate.getForObject("http://provider/hello2?name={1}&age={2}", String.class, "javaboy", 32);
        String s = balanceRestTemplate.getForObject("http://provider/hello2?name={1}", String.class, "javaboy");
        System.out.println(s);
        HashMap<String, Object> map = new HashMap<>();
        map.put("name", "zhangsan");
        s = balanceRestTemplate.getForObject("http://provider/hello2?name={name}", String.class, map);
        System.out.println(s);
        // URI 形式中文必须转码
        String url = "http://provider/hello2?name=" + URLEncoder.encode("张三", "UTF-8");
        s = balanceRestTemplate.getForObject(new URI(url), String.class);
        System.out.println(s);
    }
  • 代码执行结果
    在这里插入图片描述

6.3.2 POST

  • 首先在 provider 中提供两个 POST接口,同时因为 POST 请求可能需要传递 JSON,所以这里我们创建一个普通的 maven 项目作为 commons 模块,然后这个 commons 模块被 provider 和 consumer 共同引用,这样我们就可以方便的传递 JSON 了
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述

在这里插入图片描述

  • 分别在 provider 和 consumer 中添加 commons 模块的依赖
		<dependency>
            <groupId>org.javaboy</groupId>
            <artifactId>commons</artifactId>
            <version>1.0-SNAPSHOT</version>
        </dependency>
  • 然后再 provider 中提供两个 POST 接口,两个接口代表了 POST 请求的两种传参方式,第一种方式是以 Key-Value 形式传参,第二种是以 JSON 的形式传参
@PostMapping("/user1")
    public User addUser1(User user){
        return user;
    }
    @PostMapping("/user2")
    public User addUser2(@RequestBody User user){
        return user;
    }

重启 provider 服务

  • 接下来,我们在 consumer 中调用这两个 POST 方法
    首先来看一下 POST 的所有方法:
    在这里插入图片描述
    可以看到多出来三个 postForLocation 方法,postForObject 和 postForEntity 与前面的 GET 基本一致,主要看postForObject ,看完之后再来看额外的 postForLocation
  • 在 consumer 中再定义一个方法测试 postForObject
@GetMapping("/hello6")
    public void hello6(){
        MultiValueMap map = new LinkedMultiValueMap<String,Object>();
        map.add("username","javaboy");
        map.add("password","123");
        map.add("id",99);
        User user = balanceRestTemplate.postForObject("http://provider/user1", map, User.class);
        System.out.println(user);

        user.setId(98);
        user = balanceRestTemplate.postForObject("http://provider/user2", user, User.class);
        System.out.println(user);
    }
  • 执行结果
    在这里插入图片描述
  • 额外的 postForLocation
    postForLocation 只对重定向的请求有左右,即响应头中有 location 返回头,返回状态码是 302 的请求
    在 provider 中定义一个两个接口,其中一个是另一个的重定向结果
@Controller
public class UserController {
    @PostMapping("/register")
    public String register(User user){
        return "redirect:http://provider/loginPage?username=" + user.getUsername();
    }
    @GetMapping("/loginPage")
    @ResponseBody
    public String loginPage(String username){
        return "login  " + username;
    }
}

在 consumer 中调用第一个接口,使用返回的 URI 调用第二个接口

@GetMapping("/hello7")
    public void hello7(){
        MultiValueMap map = new LinkedMultiValueMap<String,Object>();
        map.add("username","javaboy");
        map.add("password","123");
        map.add("id",99);
        URI uri = balanceRestTemplate.postForLocation("http://provider/register", map, User.class);
        System.out.println(uri);

        String s = balanceRestTemplate.getForObject(uri, String.class);
        System.out.println(s);
    }

访问 hello7
在这里插入图片描述
注意在 proivder 中为 postForLocation 的接口,重定向的地址必须为绝对路径,如果是相对路径,会补上 provider 服务的 ip 和端口,但是我们使用的是 ribbon 的 restTemplate ,他会把 ip 和端口,当作服务的名字去 服务注册表中查询,导致服务失败。

  • postForObject 失败的例子
@Controller
public class UserController {
    @PostMapping("/register")
    public String register(User user){
        return "redirect:/loginPage?username=" + user.getUsername();
    }
    @GetMapping("/loginPage")
    @ResponseBody
    public String loginPage(String username){
        return "login  " + username;
    }
}

在这里插入图片描述
单独拿出来重定向地址是可以请求成功的:
在这里插入图片描述

6.3.3 PUT

  • 没有返回值在这里插入图片描述

  • 在 provider 中定义两个 PUT 接口,与 POST 请求类似,也是有 Key - Value 和 JSON 两种形式

@PutMapping("/user1")
    @ResponseBody
    public void updateUser1(User user){
        System.out.println(user);
    }
    @PutMapping("/user2")
    @ResponseBody
    public void updateUser2(@RequestBody User user){
        System.out.println(user);
    }

然后再 consumer 服务中调用,也是 Key - Value 和 JSON 形式两种方式请求

@GetMapping("/hello8")
    public void hello8(){
        MultiValueMap<String,Object> map = new LinkedMultiValueMap<>();
        map.add("id",99);
        map.add("username","javaboy");
        map.add("password","123");
        balanceRestTemplate.put("http://provider/user1",map);
        User user = new User();
        user.setId(100);
        user.setUsername("xuan");
        user.setPassword("456");
        balanceRestTemplate.put("http://provider/user2", user);
    }

在 provider 服务控制台显示:
在这里插入图片描述

6.3.4 DELET

  • 没有返回值
    在这里插入图片描述

  • delete 请求也有两种方式,分别是 Key - Value 和 PathVariable 形式
    首先在 provider 中定义两种类型的接口

@DeleteMapping("/user1")
    @ResponseBody
    public void deleteUser1(Integer id){

        System.out.println(id);
    }
    @DeleteMapping("/user2/{id}")
    @ResponseBody
    public void deleteUser2(@PathVariable Integer id){
        System.out.println(id);
    }

在 consumer 中调用这两种请求:

@GetMapping("/hello9")
    public  void hello9(){
        balanceRestTemplate.delete("http://provider/user1?id=11");
        balanceRestTemplate.delete("http://provider/user1?id={1}",22);
        balanceRestTemplate.delete("http://provider/user2/{1}",33);
    }

在 provider 服务的控制台:
在这里插入图片描述
至此,RestTemplate 的 基本用法介绍完了

6.4 RestTemplate 负载均衡

  • RestTemplate 负载均衡是客户端负载均衡,客户端负载均衡是相对服务端负载均衡而言的
  • 服务端负载均衡就是传统的 Nginx 方式,用 Nginx 做负载均衡,我们称之为服务端负债均衡
    在这里插入图片描述
    这种负载均衡,我们称之为服务端负债均衡,它的一个特点是,调用的客户端不知道具体哪一个服务端提供服务,它也不关心,就是客户端发给 Nginx,Nginx 再将请求发给 Tomcat ,客户端只需要记住 Nginx 地址就行了
  • 服务端负载均衡则是另外一种形式:
    在这里插入图片描述
    客户端负载均衡,就是客户端本身知道所有 Server 的详细信息,当需要调用 Server 上的接口时,客户端从所维护的 Server 列表中,根据已配置好的负债均衡策略,自己挑选一个 Server 来调用,此时,客户端知道它所调用的 是哪一个 Tomcat
  • 在 RestTemplate 中,要使用这种客户端负载均衡,只需在 RestTemplate 实例上加上 @ReloadBalanced 注解即可,默认是线性负载均衡
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值