JeecgBoot使用总结-Feign的使用总结

当系统为微服务时,需要模块之间的调用,但是不太方便直接将模块整个引入,所以就需要使用Feign进行调用,使用步骤进行总结,比如A模块准备调用B模块的C方法,按照这个进行整理。

第一步:

因为要调用B模块,所以需要在B模块创建一个对外的服务接口,并将业务进行实现,代码如下:

package org.jeecg.modules.api.controller;
/**
 * 服务化 system模块 对外接口请求类
 */
@Api(tags="对外接口请求类")
@RestController
@RequestMapping("/sys/api")
@Slf4j
public class SystemAPIController extends BaseController {

    @Resource
    private SysUserMapper userMapper;

    ....../**
     * 37根据多个用户id(逗号分隔),查询返回多个用户信息
     * @param ids
     * @return
     */
    //todo feign 第三步在该模块声明接口
    @RequestMapping("/queryUsersById")
    LoginUser queryUsersById(@RequestParam("ids") String ids){
        log.info("fegin远程调用:第三步");
        //return this.sysBaseAPI.queryUsersById(ids);
        log.info("fegin远程调用:直接隔断");
        SysUser user = userMapper.selectById(ids);
        LoginUser loginUser = new LoginUser();
        if (user!=null){
            loginUser.setId(user.getId());
            loginUser.setAvatar(user.getAvatar());
            loginUser.setRealname(user.getRealname());
        }
        return loginUser;
    }
  ......
}

以上代码中的对外接口就是”/sys/api/queryUsersById“。

第二步:

因为A模块调用B模块,也会存在其他模块之间的调用,为了提供公共的对外接口,就需要一个额外的公共api模块,于是有了如下路径

jeecg-boot-base\jeecg-boot-base-api\jeecg-system-cloud-api\src\main\java\org\jeecg\common\system\api\ISysBaseAPI.java

为了区分是单体还是微服务,使用jeecg-system-cloud-api以及jeecg-system-local-api,也就是cloud和local进行区分。因为咱们使用的是微服务,所以重点说一下cloud模块。

在cloud模块中还有一下分类,system.api、online.api、bpm.api,见明知义,主要是按照你调用模块的简称进行区分,调用jeecg-system模块的api全都写在system这个api中。

每个模块中的文件夹都是固定的,接下来简单说一下每个文件夹中文件的作用

 如图片所示,先简单说一下2和3,其实他们就是一个东西,熔断器,主要增加一层保险,当接口查询不到数据,默认返回一些假数据,从而达到防止系统查询不到数据导致崩溃的作用。2和3中有对方法的一些重写,其实就是一模一样的接口再重新写一遍,但是返回的值

正常的话会进行处理,具体的使用看下边代码中标红的fallbackFactory参数

接下来就是重点说1的作用了,1其实就是对位的api接口,底层通过http请求来找到对应模块中的接口。代码如下:

package org.jeecg.common.system.api;
@Component
@FeignClient(contextId = "sysBaseRemoteApi", value = ServiceNameConstants.SYSTEM_SERVICE, fallbackFactory = SysBaseAPIFallbackFactory.class)
public interface ISysBaseAPI extends CommonAPI {

    ......//todo feign 第一步声明接口
    @RequestMapping("/sys/api/queryUsersById")
    LoginUser queryUsersById(@RequestParam("ids") String ids);

    ......

}
  //在接口上加 @FeignClient 注解来声明 一个Feign Client,其中 value 为 远程调用其他服务的服务名
  //FeignConfig.class 为 Feign Client 的配置类,注入Retryer类的实例,这样在远程调用失败后,feign会进行重试
  //使用 Spring MVC 的注解来绑定具体该服务提供的 REST 接口
  //fallback 配置回调处理类,该处理类是作为 Feign 熔断器的逻辑处理类,实现FeignHystrixInter 接口
  //fallbackFactory(类似于断容器)与fallback方法。

看到标红的地方没,有没有很熟悉,其实就是第一步中所谓的对外接口,这下基本上就已经对应上了。

需要重点注意@FeignClient后边的三个参数。

  • contextId:api接口的id
  • value:对应模块的名称
  • fallbackFactory:熔断器的文件地址

第三步:

前两步将准备工作已经做好,接下来就只需要引用然后调用即可。

在B模块启动类中,先启用Feign,代码如下:

package org.jeecg;
import lombok.extern.slf4j.Slf4j;
import org.jeecg.common.util.oConvertUtils;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.boot.web.servlet.support.SpringBootServletInitializer;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.openfeign.EnableFeignClients;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.core.env.Environment;
import java.net.InetAddress;
import java.net.UnknownHostException;
@Slf4j
@EnableDiscoveryClient
@SpringBootApplication
@EnableFeignClients
public class JeecgknowledgeCloudApplication extends SpringBootServletInitializer {
    @Override
    protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
        return application.sources(JeecgknowledgeCloudApplication.class);
    }
    public static void main(String[] args) throws UnknownHostException {
        long startTime = System.currentTimeMillis();    //获取开始时间
        ConfigurableApplicationContext application = SpringApplication.run(JeecgknowledgeCloudApplication.class, args);
        Environment env = application.getEnvironment();
        String ip = InetAddress.getLocalHost().getHostAddress();
        String port = env.getProperty("server.port");
        String path = oConvertUtils.getString(env.getProperty("server.servlet.context-path"));
        log.info("\n----------------------------------------------------------\n\t" +
                "Application Jeecg-Boot is running! Access URLs:\n\t" +
                "Local: \t\thttp://localhost:" + port + path + "/doc.html\n" +
                "External: \thttp://" + ip + ":" + port + path + "/doc.html\n" +
                "Swagger文档: \thttp://" + ip + ":" + port + path + "/doc.html\n" +
                "----------------------------------------------------------");
        System.out.println("=====知识库-启动成功=====");
        long endTime = System.currentTimeMillis();    //获取结束时间
        System.out.println("程序运行时间:" + (endTime - startTime)/1000 + "");    //输出程序运行时间
    }
}

标红的位置是在启动类启动fegin的服务应用,然后引入api的模块,接着在你需要的类中引用“ISysBaseAPI”这个类,从而去引用你想要引用的方法

package org.jeecg.modules.wiki.service.impl;/**
 * @Description: 页面信息
 * @Author: jeecg-boot
 * @Date:   2021-11-12
 * @Version: V1.0
 */
@Service
@DS("knowledge")
public class ContentServiceImpl extends ServiceImpl<ContentMapper, Content> implements IContentService {

    @Autowired
    private  ContentMapper contentMapper;

    @Autowired
    private BodycontentMapper bodycontentMapper;

    @Autowired
    private IBodycontentService iBodycontentService;

    @Autowired
    private ISysBaseAPI iSysBaseAPI;

    ......

    @Override
    public List<ContentVO> getAlllatelyWork(Content content) {
        List<ContentVO> list =new ArrayList<>();
        LoginUser user01 =  iSysBaseAPI.queryUsersById("e9ca23d68d884d4ebb19d07889727dae"); // 系统用户信息
        log.debug("数据查询:"+user01.getUsername());
        List<ContentVO> contentVOList = contentMapper.getUserWork(DateUtil.getDate(),DateUtil.getupperDate(),content.getUsername());
        if (contentVOList.size()>0&&contentVOList!=null){
            for (ContentVO contentVO : contentVOList) {
                if (!StringUtils.isEmpty(contentVO.getUsername())){
                    LoginUser user =  iSysBaseAPI.queryUsersById(contentVO.getUsername()); // 系统用户信息
                    if (user!=null){
                        contentVO.setLastName(user.getRealname());
                        contentVO.setActive(user.getAvatar());
                    }
                }
                list.add(contentVO);
            }

        }
        return list;
    }

}

以上过程就完成了模块之间的调用了。

对于feign参数的使用也进行过总结,链接:Feign使用总结-参数传递

大致的流程图如下:

 

 注意:

有些模块已经引用了ISysBaseAPI这个类,但是调用的是local模块,通过以上的流程图进行调用的,当需要一个新的Feign接口时,一定要注意按照已经存在的形式进行使用,不能直接引用以下代码,不然本该走local的直接走cloud,就会导致启动异常。

     <dependency>
            <groupId>org.jeecgframework.boot</groupId>
            <artifactId>jeecg-system-cloud-api</artifactId>
        </dependency>

eg:jeecg-boot-module-system模块中JimuReportTokenService类中引用代码(部分)

/**
 * 自定义积木报表鉴权(如果不进行自定义,则所有请求不做权限控制)
 *  * 1.自定义获取登录token
 *  * 2.自定义获取登录用户
 */
@Component
public class JimuReportTokenService implements JmReportTokenServiceI {
    @Autowired
    private ISysBaseAPI sysBaseAPI;

在没有引cloud之前走的是local,在引用后走的是cloud。就会导致出现问题。

posted @ 2021-12-13 19:56  背着泰山找黄河  阅读(2023)  评论(0编辑  收藏  举报