OpenFeign组件服务间调用时参数传递

微服务间通信的方式??

服务间通信的方式主要有以下两种:


1.基于Http应用层协议

特点

1.使用http rest方式,使用json作为数据交换的

2.效率较低,但是耦合度低(耦合度低意味着如果不同服务使用不同的技术框架进行开发后,进行通信的成本低)

典型的实现
1.RestTemplate
缺点:
1.服务调用使路径写死,耦合度高

2.要想实现负载均衡,必须得结合Ribbon组件,造成冗余代码


2.OpenFeign(推荐)
特点:
1.OpenFeign组件是spring团队基于netflix的Feign组件进行封装和扩展形成的自己的一个项目,它是一个伪HttpClient;

OpenFeign是一个伪HTTP客户端,底层还是RestTemplate,是对RestTemplate的封装

2.OpenFeign支持可插拔的编码器和解码器

比如帮我们默认实现json和其他数据类型的装换

3.OpenFeign默认集成了Ribbon

默认实现了负载均衡的效果,不需要我们再像RestTemlate那样,利用ribbon编写实现负载均衡的相关代码;
并且springcloud为feign添加了springmvc注解的支持。

4.使用方便,代码量少

使用时只需要添加几个注解,编写一个接口类即可,耦合度低


2.基于RPC传输层协议

特点

1.使用的是传输层的协议,以二进制方式传递数据

2.效率高,但是耦合度高,如果不同服务使用不同的技术框架进行开发后,进行通信的成本高

典型的RPC框架:Dubbo

总结:`在springcloud中服务间调用方式主要是使用 http restful方式进行服务间调用

OpenFeign服务间通信时参数传递

1.基本数据类型

GoodsClient接口

@FeignClient(value = "GOODS")
public interface GoodsClient {

    /*
    * 注意:这里的方法需要保证返回类型,形参,请求路径一致
    * 方法名可以与被调用的服务名不同
    *
    * feign默认给我们实现了负载均衡!!
    * */
    @GetMapping("/test")
    String test(String name,Integer age);
}

商品服务controller

 	@GetMapping("/test")
    public String test(String name,Integer age){
        log.info("name:{},age:{}",name,age);
        return name + age;
    }

CategoryController调用商品服务的test方法

@GetMapping
    public String testService(){
        String test = goodsClient.test("jw", 20);
        return test;
    }

启动报错显示太多参数

Caused by: java.lang.IllegalStateException: Method has too many Body parameters: public abstract java.lang.String com.jw.feignclient.GoodsClient.test(java.lang.String,java.lang.Integer)

原因是:

我们知道通过QueryString传递有两种方式,一种是
/test?name=jw&age=20的形式
另一种是rest的方式,直接把参数写在路径中
/test/jw/20

由于OpenFeign是伪客户端,底层在调用服务时还是基于RestTemplate,当我们通过GoodsClient调用test服务是,GoodsClient会把接收的参数传递给RestTemplate进行封装;此时RestTemplate不知道该基于哪种方式进行封装,所以会报错;

如果我们只写一个参数,那么默认就是?name=xx的形式
如果有多个参数就需要我们用注解显示声明

@RequestParams
如果是想以/test?name=xxx&age=xxx 的形式传递参数,那么使@RequestParams;

@FeignClient(value = "GOODS")
public interface GoodsClient {

    /*
    * 注意:这里的方法需要保证返回类型,形参,请求路径一致
    * 方法名可以与被调用的服务名不同
    *
    * feign默认给我们实现了负载均衡!!
    * */
   
    @GetMapping("/test")
    String test(@RequestParam String name,@RequestParam Integer age);
}

注意:如果我们@RequestParam赋值,被调用方需要一致

@GetMapping("/test")
String test(@RequestParam("aa") String name,@RequestParam("bb") Integer age);

//商品服务
@GetMapping("/test")
public String test(String aa,Integer bb){
     	log.info("name:{},age:{}",aa,bb);
       return aa + bb;
}

@GetMapping("/test")
public String test(@RequestParam("aa") String name,@RequestParam("bb") Integer age){
     	log.info("name:{},age:{}",name,age);
       return name + age;
}

@PathVariable
如果是想以/test/jw/20形式传递参数,那么使用@PathVariable

@FeignClient(value = "GOODS")
public interface GoodsClient {

    /*
    * 注意:这里的方法需要保证返回类型,形参,请求路径一致
    * 方法名可以与被调用的服务名不同
    *
    * feign默认给我们实现了负载均衡!!
    * */

    @GetMapping("/test1/{name}/{age}")
    String test1(@PathVariable("name") String name, @PathVariable("age") Integer age);
}

	//商品服务controller
	@GetMapping("/test1/{name}/{age}")
    public String test1(@PathVariable("name")String name,@PathVariable("age") Integer age){
        log.info("name:{},age:{}",name,age);
        return name+age;
    }
    
  	//**CategoryController调用商品服务的test1方法**
	 @GetMapping
    public String testService(){
        String test = goodsClient.test1("jw", 20);
        return test;
    }

2.传递对象类型

使用@RequestBody注解会把对象以aplication/json的形式传参,被调用的服务也需要加上@RequestBody该注解,把收到的json转成对应的对象

	//categoryController
	@GetMapping
    public String testService(){
        //String test = goodsClient.test1("jw", 20);
        goodsClient.save(new Goods(1,"aa",22.12,new Date()));
        return null;
    }

    //接口
	@FeignClient(value = "GOODS")
	public interface GoodsClient {
    /*
    * 注意:这里的方法需要保证返回类型,形参,请求路径一致
    * 方法名可以与被调用的服务名不同
    *
    * feign默认给我们实现了负载均衡!!
    * */
    @PostMapping("/savegoods")
    void save(@RequestBody Goods goods);
	}
	
 	//GoodsController
	@PostMapping("/savegoods")
    public void save(@RequestBody Goods goods){
        log.info("goods:{}",goods);
    }

3.传递数组和集合类型

**数组类型使用@RequestParam会把ids数组拼装成
/test3/?ids=1&ids=2&ids=3的形式

	@FeignClient(value = "GOODS")
	public interface GoodsClient {
    @GetMapping("/test3")
    void test3(@RequestParam("ids") String[] ids);
	}
	==================================
	  //goodsController
	@GetMapping("/test3")
    public void test3( String[] ids){
        log.info("ids:{}",ids);
    }	

集合类型
springMVC中get方式是不能用集合作参数的
比如以/test4/?ids=1&ids=2&ids=3,接收不到

	//不行
   @GetMapping("/test4")
   public void test4(ArrayList<String> ids){
       
   }
 

如果硬要接收集合,那么需要把集合作为类的属性

	@GetMapping("/test3")
    public void test3( GoodsVO vo){
        log.info("ids:{}",ids);
    }	
	
	class ProductVO{
    private ArrayList<String> ids;

    public ArrayList<String> getIds() {
        return ids;
    }

    public void setIds(ArrayList<String> ids) {
        this.ids = ids;
    }
}

此时在FeignClient中还是同数组一样,因为@RequestParam会把接收到的ids拼接成/test4/?ids=1&ids=2&ids=3,在GoodController接收时,就会去Goodvo中找到ids进行赋值

   @FeignClient(value = "GOODS")
   public interface GoodsClient {
   @GetMapping("/test4")
   void test3(@RequestParam("ids") String[] ids);
   }

注意:这里是GET方式需要接收一个List集合
如果是POST方式直接加上@RequestBody注解以json方式传递即可

  • 2
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
在 Solidity 中,合约调用可以通过合约地址进行实现。合约调用的语法如下: ``` contract ContractA { function foo(uint256 x) public returns (uint256) { // do something } } contract ContractB { ContractA contractA = ContractA(0x1234567890123456789012345678901234567890); function bar() public { uint256 result = contractA.foo(123); // do something with result } } ``` 在上面的示例中,合约 B 调用了合约 A 中的函数 `foo`,并将值 `123` 作为参数传递给了该函数。需要注意的是,调用 `foo` 函数会消耗 Gas,因此需要确保调用的合约有足够的 Gas 储备。 在合约调用,还需要注意传递参数的类型和顺序。Solidity 支持多种数据类型,包括整数、布尔值、字符串、地址等等。在传递参数,需要确保参数类型和数量与被调用函数的参数类型和数量相匹配,否则会导致编译错误。 另外,如果被调用的函数是视图函数(即不修改状态的函数),则可以使用 `call` 方法进行调用。例如: ``` contract ContractA { function foo(uint256 x) public view returns (uint256) { // do something } } contract ContractB { ContractA contractA = ContractA(0x1234567890123456789012345678901234567890); function bar() public { (bool success, uint256 result) = contractA.call(abi.encodeWithSignature("foo(uint256)", 123)); require(success, "failed to call ContractA.foo"); // do something with result } } ``` 在上面的示例中,`ContractB` 调用了 `ContractA` 中的函数 `foo`,并使用 `call` 方法进行调用。需要注意的是,使用 `call` 方法需要手动编码参数,因此需要使用 `abi.encodeWithSignature` 函数将参数编码为字节数组。另外,如果调用失败,需要使用 `require` 断言确保调用成功。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值