Skip to content
On this page

1 简介

比如商城系统,有一个订单服务,有一个中户中心服务,在订单详情中要根据userid获取订单创建人的昵称可以如下这样写:

java
    @Trans(type = TransType.RPC,targetClassName = "com.fhs.ucenter.pojo.User",fields = "userName",serviceName = "ucenter")
    private String createUserId;

2 字典如何处理

推荐将字典数据放到redis中去,详情使用见缓存相关说明章节 和 字典处理章节

3 权限控制

推荐在网关通过过滤器拦截/easyTrans/proxy开头的所有请求,解决前段能直接调用接口的问题。
推荐自定义resttemplate来给header加token配合拦截器的方式做校验
如果是多个团队共同开发一个项目,推荐配置 easy-trans.is-enable-custom-rpc=true,然后哪个PO给其他微服务做翻译用手动标记@RpcTrans注解 注意:@RpcTrans注解 从 3.0.1 和 2.2.12 版本开始提供

4 原理讲解(出了坑请看这里)

我们是通过一个控制器来暴漏接口给消费者调用,所以一定要保证服务A调用服务B的/easyTrans/proxy/*可以调用通。
代码如下(不同版本的代码可能不同,原理类似):

java
@RestController
@RequestMapping("/easyTrans/proxy")
public class TransProxyController {


    private SimpleTransService.SimpleTransDiver simpleTransDiver;

    /**
     * findByIds
     *
     * @param targetClass 目标类
     */
    @PostMapping("/{targetClass}/findByIds")
    public List findByIds(@PathVariable("targetClass") String targetClass, @RequestBody FindByIdsQueryPayload payload) throws ClassNotFoundException {
        Assert.notNull(targetClass, "targetClass 不可为空");
        return simpleTransDiver.findByIds(payload.getIds(), (Class<? extends VO>) Class.forName(targetClass)).stream().map(vo -> {
            try {
                return vo2BasicVO(vo);
            } catch (IllegalAccessException e) {
                return null;
            }
        }).collect(Collectors.toList());
    }

    /**
     * 根据id查询
     *
     * @param targetClass 目标类
     */
    @GetMapping("/{targetClass}/findById/{id}")
    public Object findByIds(@PathVariable("targetClass") String targetClass, @PathVariable("id") String id) throws ClassNotFoundException, IllegalAccessException {
        Assert.notNull(targetClass, "targetClass 不可为空");
        Assert.notNull(targetClass, "id 不可为空");
        return vo2BasicVO(simpleTransDiver.findById(id, (Class<? extends VO>) Class.forName(targetClass)));
    }

}

然后通过restTemplate进行调用,如果进行服务间调用认证请自己注入一个restTemplate,因为我们的restTemplate是这么写的:

java
    @Bean
    @LoadBalanced
    @ConditionalOnMissingBean(RestTemplate.class)//如果你自己注入了,这个就不起作用就会用你自己注入的
    public RestTemplate restTemplate(RestTemplateBuilder builder) {
        return builder.build();
    }

然后RpcTransService是这么写的:

java
public class RpcTransService extends SimpleTransService {

    private RestTemplate restTemplate;


    @Override
    public List<? extends VO> findByIds(List<String> ids, Trans tempTrans) {
        Map<String, Object> paramMap = new HashMap<>();
        paramMap.put("ids", ids);
        //执行远程调用
        try {
            String respJson = restTemplate.postForObject("http://" + tempTrans.serviceName()
                    + "/easyTrans/proxy/" + tempTrans.targetClassName() + "/findByIds", paramMap, String.class);
            return JSONArray.parseArray(respJson, BasicVO.class);
        } catch (Exception e) {
            log.error("trans service执行RPC Trans 远程调用错误:" + tempTrans.serviceName(), e);
        }
        return new ArrayList<>();
    }

    @Override
    public VO findById(String id, Trans tempTrans) {
        //执行远程调用
        try {
            return restTemplate.getForObject("http://" + tempTrans.serviceName()
                    + "/easyTrans/proxy/" + tempTrans.targetClassName() + "/findById/" + id, BasicVO.class);
        } catch (Exception e) {
            log.error("trans service执行RPC Trans 远程调用错误:" + tempTrans.serviceName(), e);
        }
        return null;
    }
}

以上就是RPC Trans实现的大部分代码了,有了坑一般就是权限框架拦截的问题,排除后还不行就根据代码分析吧!

5 context-path 配置

java
 @Autowired
 private RpcTransService rpcTransService;
 //配置contextpath
 rpcTransService.addContextPath("easyTrans","/api");
 //或者
  @Trans(type = TransType.RPC, targetClassName = "com.fhs.test.pojo.School", fields = {"schoolName"}, serviceName = "easyTrans", alias = "middle",serviceContextPath = "/api")
  private String middleSchoolId;

Apache 2.0 Licensed