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。就会导致出现问题。