技术栈:SpringBoot+SpringCloud
项目结构组织:项目由多个Module构成,而每个Module又由api模块、model模块、web模块构成
需求:现在需要将A项目(生产者,或者叫服务提供者)的web模块中的某些接口暴露出去,要求在api模块中定义。使得B项目(消费者,或者叫客户端)能远程调用A项目暴露的接口
备注:笔者对SpringCloud只有了解并未实践过,导致实现这个需求时踩了不少坑,本博客适合初次实操SpringCloud或者如何暴露接口的小白。
解决踩坑过程中觉得不错的博客:【SpringCloud】 - Feign 踩坑记录:404 ,调用不成功 , 接口定义规范 等问题记录
这里先给出代码实现以及注意事项,后面有时间再补充微服务相关的知识。
@Api(value = "字典定义", tags = " 字典定义")
@RestController
@RequestMapping(value = "/wcenter/dict/define")
public class WcenterDictDefineRest {
/**
* 获取树状字典
**/
@ApiOperation(value = "获取树状字典")
@ApiImplicitParams({
@ApiImplicitParam(name = "codes", value = "字典编码", paramType = "query", dataType = "String[]"),
})
@GetMapping(value = "/tree")
public ResponsePacket<ResponseTreeEntityDto> tree(HttpServletRequest request, String[] codes) {
//...业务逻辑
return xxx;
}
}
注意:上面那个类,必须加@RestController注解,否则后面调用api模块暴露的接口会出现问题。
<dependency>
<groupId>io.github.openfeign.formgroupId>
<artifactId>feign-form-springartifactId>
<version>3.8.0version>
dependency>
<dependency>
<groupId>io.github.openfeign.formgroupId>
<artifactId>feign-formartifactId>
<version>3.8.0version>
dependency>
<dependency>
<groupId>io.github.openfeigngroupId>
<artifactId>feign-coreartifactId>
<version>10.10.1version>
dependency>
<dependency>
<groupId>io.github.openfeigngroupId>
<artifactId>feign-hystrixartifactId>
<version>10.10.1version>
dependency>
<dependency>
<groupId>io.github.openfeigngroupId>
<artifactId>feign-slf4jartifactId>
<version>10.10.1version>
dependency>
@Api("数据字典远程服务接口")
@FeignClient(value = "接口的实现方法所在项目的微服务名", path = "web以及请求路径")
public interface DictFeign {
@ApiOperation(value = "获取树状字典")
@ApiImplicitParams({
@ApiImplicitParam(name = "codes", value = "字典编码", paramType = "query", dataType = "String[]"),
})
@GetMapping(value = "/tree")
ResponsePacket<ResponseTreeEntityDto> tree(@RequestParam("request") HttpServletRequest request, @RequestParam("codes") String[] codes);
}
注意:
spring.application.name
的值,这里建议用全局变量来填写,方便管理更多的微服务server.servlet.context-path
,必须配上path属性。否则后面调用这个接口会出现404问题too many bad parameter
错误),若是POST请求方式,需要根据情况加@RequestBody注解<dependency>
<groupId>xxx.xxxgroupId>
<artifactId>business-wcenter-apiartifactId>
<version>2.0.0version>
dependency>
@EnableFeignClients(basePackages = "xx.xx.xx")
@SpringCloudApplication
public class CriterionServerApplication {
}
引入SpringBoot的测试依赖,如下:
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-testartifactId>
dependency>
@Slf4j
@RunWith(SpringJUnit4ClassRunner.class)
@SpringBootTest(
classes = 启动类.class
)
public class DictFeignTest {
@Autowired
DictFeign dictFeign;
/**
* 测试 远程调用数据字典
*/
@Test
public void testRpcDictFeign(){
ResponsePacket<ResponseTreeEntityDto> tree = dictFeign.tree(null, null);
log.info("The dict tree is: {}", tree);
}
}
这种暴露接口的测试,必须先启动生产者(服务提供者),再启动消费者(客户端)。
我们先启动A项目,再启动B项目,运行上面的测试方法,测试成功。
前面讲述了远程调用的简单版本,如果调用失败,是没有相应的机制去处理的,那么接下来就实现调用失败的处理机制,这里简称方法回调
代码如下:
@FeignClient(value = "xxx", path = "xxx", fallbackFactory = DictDefineFallbackFactory.class)
public interface DictDefineFeign {
}
解释:使用@FeignClient
注解的fallbackFactory
属性,其值是一个类,代码如下:
@Component
@Slf4j
public class DictDefineFallbackFactory implements FallbackFactory<DictDefineFeign> {
@Override
public DictDefineFeign create(Throwable throwable) {
log.error("字典定义服务调用失败:" + throwable.getMessage());
return new DictDefineFeign() {
@Override
public ResponsePacket<ResponseTreeEntityDto> tree(String[] codes) {
return ResponsePacket.generateFail("字典定义服务--->获取树状字典失败");
}
};
}
}
测试暴露接口的过程中,遇到了一系列形如“xxxClass can not find、xxxMethod is not define”
,一般都是对应的依赖没有下载下来。尤其是依赖中的依赖,有些是设置了
,这个作用是只允许此依赖所在的项目使用,即使别的项目引用了这个依赖,都无法下载下来。
因此解决方法是调整依赖,或者单独引入缺失的依赖