不同微服务之间Feign调用方法(Pigx框架下)

不同微服务之间Feign调用方法(Pigx框架下)

写在前面:近日在写需求时,有个需求需要在ctn端调用cd端的服务去实现,但我们知道为了安全性和效率的考虑,各个微服务之间有认证机制,不能随意调用,那么如何调用其他微服务呢。

Pigx框架下spring cloud中Feign的调用

在使用SpringCloud生态的时候,微服务之间会进行调用,一般我们有两个选择。一是选择使用RestTemplate,二是使用Feign。二者都是基于HTTP的调用,但Feign是直接使用声明式调用,更加符合大家平时写接口的习惯.下面介绍Pigx框架下feign调用方法。

步骤

1. 😐首先要知道自己调用哪个微服务😐

比如我这次要使用的是cd端的微服务,那么我的一系列配置要写在cd端,而且我这里ctn调用cd是内部之间调用,不是外部调用,属于 👌无token请求,服务内部发起情况处理。👌 其他的还有外部调用带token请求先不谈(👌客户端带Token 情况👌)

无token请求(内部请求)

img

带token请求(外部请求)

img

2. 😡先写feign服务😡

注意,调用哪个微服务就在那个服务写,位置在api包下的feign包里

在这里插入图片描述

service服务命名前缀统一加Remote(远程)最好,下面开始写服务内容

package com.xbm.cd.api.feign;

import com.pig4cloud.pigx.common.core.constant.SecurityConstants;
import com.pig4cloud.pigx.common.core.util.R;
import com.xbm.common.constant.XbmServiceNameConstants;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestHeader;

import java.util.List;

/**
 * @author wujie
 * @data 2021.7.2
 */
@FeignClient(contextId = "remoteCdOrderBoxService",value = XbmServiceNameConstants.XBM_CD_SERVICE)
public interface RemoteCdOrderBoxService {
   @PostMapping("/order/updateByUuid")
   R updateByUuid(@RequestBody List<String> uuid,@RequestHeader(SecurityConstants.FROM) String from);
}

👇注意一点:如果是@GetMapping接口通过路径传递值的话要注意了,要定义value是什么,方法定义要这么写👇

	@GetMapping("/eq/select/{name}")
	SysEquipment selectOne(@PathVariable(value = "name") String name, @RequestHeader(SecurityConstants.FROM) String from);
	//一定要记得写成@PathVariable(value = "name") String name 形式
	//不能和平常一样写@PathVariable String name 形式

首先这个@FeignClient注释是必加的,后面括号里面要声明两个属性值,一个contextId声明这个Bean叫什么,最好和service服务名一样,后面value写调哪个服务,这里统一规范Feign写在调用服务下,所以就写当前的服务cd,@PostMapping("/order/updateByUuid")表示这是一个post类型接口,但重点来了,这里不写任何接口要实现的操作,这个接口地址是cd端真实存在的一个接口地址,这里只是调用它。所以这里要求所有Feign服务调用方法都是事先已经存在的(没有就先写在要调用的服务端里面)。

在这里插入图片描述

@SysLog("修改一键放箱状态")
@PostMapping("/updateByUuid")
@Transactional
@Inner
public R updateByUuid(@RequestBody List<String> uuid){
   orderBoxInfoService.update(Wrappers.<CdOrderBoxInfo>lambdaUpdate()
                              .set(CdOrderBoxInfo::GetToPackStatus,0).in(CdOrderBoxInfo::getOrderUuid,uuid))
   return R.ok();
}

@Inner记得加上(无token内部调用需要)

其次还得严格按照调用方法的传送数据格式来传送数据@RequestBody List uuid 和 调用方法一致

 R updateByUuid(@RequestBody List<String> uuid,@RequestHeader(SecurityConstants.FROM) String from);

@RequestHeader(SecurityConstants.FROM) String from————为无token调用所必需的获取请求头中数据的注释。

注意

若@FeignClient注释不能使用,得手动导入相关依赖,在pom.xml中加入即可

<!--feign 工具类-->
<dependency>
   <groupId>com.pig4cloud</groupId>
   <artifactId>pigx-common-feign</artifactId>
</dependency>
3. 😄配置 feignclient 的全类名路径, 避免包名不规范无法扫描问题😄

这个配置要写在api包的resource包里,表明feign服务路径

在这里插入图片描述

# 配置 feignclient 的全类名路径, 避免包名不规范无法扫描问题
com.pig4cloud.pigx.common.feign.PigxFeignAutoConfiguration=\
com.xbm.cd.api.feign.RemoteCdOrderBoxService

在这里插入图片描述

如果以后有多个feign调用服务,需要像下面这样加逗号和斜杠(最后一个不用)

在这里插入图片描述

com.pig4cloud.pigx.admin.api.feign.RemoteRoleService,\
com.pig4cloud.pigx.admin.api.feign.RemoteMenuService,\
com.pig4cloud.pigx.admin.api.feign.RemoteFileService
4. 😁 在其他服务端调用😁

首先声明一下

private final RemoteUserService userService;

final修饰符:只能被赋值一次

  • final可以修饰类、方法、变量
      a.修饰类的时候此类不能被继承。
      b.修饰方法时方法不能被重写。
      c.修饰变量时不能被重新赋值。
  • 修饰基本类型时,基本类型的值不能发生改变。
      修饰引用类型时,引用类型的地址值不能改变,但是该对象堆内存的值可以改变。如final Student s1=new Student( ); 对象s1的地址不可以改变,s1的成员变量可以改变
 //查询删除的放箱订单是否有uuid(用于筛选判断是不是由车队端运单一键放箱过来的)
        List<CtnOrderInfo> orderInfos = ctnOrderInfoService.list(Wrappers.<CtnOrderInfo>lambdaQuery().in(CtnOrderInfo::getNo, orderNos));
		List<String> uuid = orderInfos.stream().map(CtnOrderInfo::getUuid).collect(Collectors.toList());
//将车队运单里orderUuid与放箱端的uuid对比,相同则说明是由运单一键放箱过来,将运单的一键放箱状态改为0
if (uuid !=null){
   cdOrderBoxService.updateByUuid(uuid,SecurityConstants.FROM_IN);
}

在ctn端调用时也要严格按照要求发送数据,这里传入的uuid要符合调用方法中 List 类型。

到这里是不是以为结束了,确实,pigx教程里是这样的,但细心的小伙伴应该已经发现了隐藏bug,Pigx框架下是有租户这个概念的,所以在@RequestHeader(SecurityConstants.FROM) String from 请求内容中,如果调用服务端的租户和被调用服务端的租户不一样,那么这个认证就会不通过,该怎么办呢?

5. 😂如何绕过租户😂
  • 在service服务层自己写直接调用数据库的方法,不通过已有方法

  • 首先在相关service里加方法

    int updateByOrderUuid(List<String> uuid);
    

在这里插入图片描述

别忘了把调用的接口里的方法更改为这个自己写的方法

@SysLog("修改一键放箱状态")
@PostMapping("/updateByUuid")
@Transactional
@Inner
public R updateByUuid(@RequestBody List<String> uuid){
   orderBoxInfoService.updateByOrderUuid(uuid);
   return R.ok();
}
  • 在serviceImpl里写具体方法实现

    @Override
    public int updateByOrderUuid(List<String> uuid){
       UpdateWrapper<CdOrderBoxInfo> wrapper = new UpdateWrapper<>();
       wrapper.lambda().set(CdOrderBoxInfo::getToPackStatus,0).in(CdOrderBoxInfo::getOrderUuid,uuid);
       return getBaseMapper().updateBySomething(wrapper);
    }
    

(这里的updateBySomething在下面会说怎么来的)

写到这里是不是还是一头雾水,为什么要自己写方法呢?

因为接下来我们要在Mapper层写具体的不想被多租户过滤的方法,然后给方法实现类serviceImpl使用,不能随意改变原有的方法的多租户过滤,所以得自己另写不需要过滤的方法,保证安全性。

👇注意:

如果你的系统没有租户概念,或者你跨服务调用数据也只是调用自己租户的数据的话,就不需要自己另外写绕开多租户的方法,数据量大了会影响运行速度,直接用自带的get、list等方法即可,直接将updateBySomething换为自带的update方法即可,然后到这里就结束了,就可以拿去用了

@SqlParser(filter = true)
@Update("update cd_order_box_info set ${ew.sqlSet} ${ew.customSqlSegment}")
int updateBySomething(@Param(Constants.WRAPPER) Wrapper<CdOrderBoxInfo> wrapper);

在这里插入图片描述

@SqlParser(filter = true) 固定写法,避开多租户。

@Update(“update cd_order_box_info set ${ew.sqlSet} ${ew.customSqlSegment}”) 写上更新的表的名称,后面两个

${ew.sqlSet} ${ew.customSqlSegment}固定写法

int updateBySomething(@Param(Constants.WRAPPER) Wrapper wrapper);

定义该方法用在serviceImpl里的 return getBaseMapper().updateBySomething(wrapper);

😁至此全部结束😁

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值