# ecloud-micro-cloud **Repository Path**: Hubert_Huang_Test/ecloud-micro-cloud ## Basic Information - **Project Name**: ecloud-micro-cloud - **Description**: No description available - **Primary Language**: Java - **License**: Apache-2.0 - **Default Branch**: devlop - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 1 - **Created**: 2023-01-17 - **Last Updated**: 2023-01-17 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README

LOGO

Release Spring Boot Spring Cloud Spring Cloud Alibaba JDK License Status Build Since

## :mega: 框架介绍

如果您觉得有帮助,请点右上角 "Star" 支持一下谢谢

这是一款基于Spring Cloud Alibaba的微服务架构。旨在为公司提供技术框架的基础通用能力的封装,减少开发工作,让您只关注业务逻辑。最大可能减少开发成本,让技术变得简单,把难的都留给架构。结合相应的代码规范可以发挥出框架的极致性能。 ## :dart: 核心组件 | 核心中间件 | 当前版本 | | -------------------- | ------------------------------------------------------------ | | Spring Boot | Spring Boot | | Spring Cloud | Spring Cloud | | Spring Cloud Alibaba | Spring Cloud Alibaba | | Nacos | Nacos | | Sentinel | Sentinel | ## :link: 框架说明 主体框架:采用最新的`Spring Cloud 2020.0.3`, `Spring Boot 2.5.4`, `Spring Cloud Alibaba 2021.1`版本进行系统设计。 注册发现:采用`Nacos`做为服务的配置中心和注册中心,实现多配置、分群组、分命名空间、多业务模块的注册和发现功能。 统一网关:采用最新的`Spring Cloud Gateway`作为系统服务网关,支持动态路由配置、支持负载均衡策略、支持统一鉴权、集成Sentinel支持限流降级和动态规则配置及持久化,非业务控制变更均可免重启,网关做为微服务所有请求的入口能更有效的保障其稳定性。 统一监控:利用`Spring Boot Admin`可以实现对整套微服务的一个监控,界面美观简洁,性能优异。支持对路由管理、缓存管理、类实例监控、服务状态及配置监控等,功能齐全。适合技术对整个微服务进行统一管理、监控。 熔断降级:采用阿里`Sentinel`实现服务间的熔断降级等功能,避免服务之间出现雪崩,实现动态规则持久化等功能(基于`Nacos`),`Sentinel`经过淘宝双十一历年考验,性能强悍、生态齐全、可移植性极强。 动态数据源:基于`Spring`底层接口自研,全自主可控,并完美对接`Spring`的事务管理器(Mybatis已完成,JPA计划中),支持`Spring`原生声明式事务内数据源切换及事务控制,可做到进程内多数据源的事务同一控制,极大减少了SaaS架构下对分布式事务的依赖,注解式使用,支持SpEL表达式及HTTP头信息、参数信息及Session参数,除了注解真正的零编码,比Mybatis Plus 多数据源更强,自动装配,支持任意数据源注入。 代码生成:基于模板引擎和动态数据源实现一套在线的代码生成工具,支持多库多表单表代码生成,集成在线代码编辑器可在线编辑内置模板,打造属于自己的代码模板,支持配置和模板的持久化功能、支持DTO、VO、Convert(模型层转换工具基于mapstruct,性能最强不解释)层代码自动生成,后期计划生成前端代码。 二级缓存:重写Spring Cache底层实现,采用Redis+Caffeine实现分布式二级缓存,完美对接Spring Cache,支持Spring注解、支持L1、L2单独独立模式。利用`Redis`Pub/Sub模式解决分布式缓存的数据一致性同步问题(L2缓存更新或清除L1节点不同步更新),自动装配,零配置 国际化:全系统任意组件均支持动态国际化(网关、Bean校验、业务提示语),支持基于Bean属性注解的数据国际化,可自定义国际化数据源,基于序列化实现结合二级缓存性能强悍,几乎性能无损。 滑动验证码:内置图片滑动验证码功能,全后端抠图,支持默认资源自定义资源注入,采用Base64输出,支持自动装配零配置。 ## :pencil2: 框架设计 ![架构图](images/README/%E6%9E%B6%E6%9E%84%E5%9B%BE.png) ## :file_folder: 工程结构 ```java ecloud-micro-cloud -- 父项目,各模块分离,方便集成和微服务 │ ├─ecloud-common -- 核心通用模块,主模块 │ │ ├─ecloud-common-base -- 封装通用模块 │ │ ├─ecloud-common-cache -- 封装二级缓存模块 │ │ ├─ecloud-common-data -- 封装多数据源模块 │ │ ├─ecloud-common-utils -- 封装通用工具模块 │ │ ├─ecloud-common-vcode -- 封装滑动验证码模块 │ │ ├─ecloud-common-sms -- 封装短信模块(计划中) │ │ ├─ecloud-common-mail -- 封装邮件模块(计划中) │ │ ├─ecloud-common-auth -- 封装认证模块(计划中) │ │ ├─ecloud-common-dubbo -- 封装dubbo基础模块(待定) │ │ ├─ecloud-common-gray -- 封装灰度发布基础模块(计划中) │ │ ├─ecloud-common-oss -- 封装OSS基础模块(实现中) │ │ ├─ecloud-common-mongodb -- 封装MongoDB数据库模块(计划中) │ │ ├─ecloud-common-job -- 封装定时任务模块(实现中) │ │ ├─ecloud-common-web -- 封装通用WEB模块 │ │─ecloud-gateway -- 统一网关模块 [8080] │ │─ecloud-service -- 业务服务模块 │ │ ├─ecloud-service-openapi -- 系统模型通用模块,供其他模块引用 │ │ │ ├─ecloud-openapi-security -- 权限模块模型,供其他模块引用 │ │ │ ├─ecloud-openapi-translate -- 翻译模块模型,供其他模块引用 │ │ ├─ecloud-service-service -- 业务服务模块 │ │ │ ├─ecloud-service-security -- 权限服务 [20010] │ │ │ ├─ecloud-service-translate -- 翻译服务 [20020] │ │─ecloud-support -- 支持中心项目,目前包括代码生成和监控模块 │ │ ├─ecloud-support-generator -- 在线代码生成服务 [8068] │ │ ├─ecloud-support-monitor -- 在线微服务集群监控 [8088] ``` ## :camera: 部分截图
## :green_book: 核心教程 ### 一、基础项目搭建 1. 新建一个WEB项目,只需要在pom.xml引入ecloud-common-web模块,即可拥有动态数据源、自动国际化、自动参数完整性校验、`Jackson`序列化(支持`LocalDateTime`系列)、全局异常处理等功能。而你只需要配置多数据源即可使用。 ```xml com.ecloud ecloud-common-web ${ecloud.cloud.version} ``` 2. 多数据源的配置可参考如下配置,其中`/* TODO 这里处理多数据源动态注册 */`这里可以实现动态数据源的注入,你可以根据自己的实际情况实现,例如从文件、从数据库查询注入。而其中的参数`key`就是你数据源的标识。 ```java /** * 数据库连接池配置
* * @author LiuGangQiang Create in 2020/03/02 */ @Configuration public class DataSourceConfiguration { /** * 主数据源配置 * * @author LiuGangQiang Create in 2021/04/27 * @return {@link DataSource} */ @Primary @Bean(DynamicDataSource.MASTER) @ConfigurationProperties(prefix = "spring.datasource.hikari") public DataSource masterDataSource() { HikariDataSource dataSource = new HikariDataSource(); return dataSource; } /** * 读取动态数据源配置 * * @author LiuGangQiang Create in 2021/05/01 * @return {@link HikariConfig} */ @Bean @ConfigurationProperties(prefix = "spring.datasource.dynamic") public HikariConfig hikariConfig() { return new HikariConfig(); } /** * 动态数据源配置 * * @author LiuGangQiang Create in 2021/04/27 * @return {@link DataSource} */ @Bean public DynamicDataSource dynamicDataSource() { DynamicDataSource dynamicDataSource = new DynamicDataSource() { @Override public DataSource registerDataSource(String key) { if (StringUtils.isNotBlank(key)) { /* TODO 这里处理多数据源动态注册 */ } return null; } }; Map dataSourceMap = new HashMap<>(); /* 默认添加主数据源 这里可以在项目启动时初始化多个数据源 */ dataSourceMap.put(DynamicDataSource.MASTER, masterDataSource()); /* 主数据源设为默认数据源 */ dynamicDataSource.setDefaultTargetDataSource(masterDataSource()); /* 设置多数据源 */ dynamicDataSource.setDataSources(dataSourceMap); return dynamicDataSource; } /** * 配置连接工厂 * * @author LiuGangQiang Create in 2021/04/27 * @return {@link MybatisSqlSessionFactoryBean} */ @Bean @ConfigurationProperties(prefix = "mybatis-plus") public MybatisSqlSessionFactoryBean sqlSessionFactoryBean() { MybatisSqlSessionFactoryBean sessionFactory = new MybatisSqlSessionFactoryBean(); /* 注入分页插件 */ sessionFactory.setPlugins(paginationInterceptor()); /* 注入动态数据源 */ sessionFactory.setDataSource(dynamicDataSource()); /* 注入动态数据源事务管理器 */ sessionFactory.setTransactionFactory(new DynamicTransactionFactory()); return sessionFactory; } /** * 配置分页插件 * * @author LiuGangQiang Create in 2021/04/27 * @return {@link MybatisPlusInterceptor} */ @Bean public MybatisPlusInterceptor paginationInterceptor() { MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor(); interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL)); return interceptor; } /** * 配置事务管理器 * * @author LiuGangQiang Create in 2021/04/27 * @return {@link PlatformTransactionManager} */ @Bean public PlatformTransactionManager transactionManager() { return new DataSourceTransactionManager(dynamicDataSource()); } } ``` > 例如:我添加注解`@DynamicDS("#header.dbid")`在我的sevice或者其方法上,那么框架就会在执行到此对应方法时,先去数据源管理器找对应的数据源是否存在,不存在则会触发如下方法,我只需要实现一个根据key查找对应数据源配置即可。他支持动态注册动态移除数据源,无需重启服务。详情请参考[源码](https://gitee.com/fist-team/ecloud-micro-cloud/tree/devlop/ecloud-common/ecloud-common-data/src/main/java/com/ecloud/common/data),注释非常详细,后期也会抽时间单独出一个教程。 ```java @Override public DataSource registerDataSource(String key) { if (StringUtils.isNotBlank(key)) { /* 查询数据库 */ DbConfigPo dbConfig = dbConfigService.getById(key); if (dbConfig != null) { HikariConfig hikariConfig = hikariConfig(); hikariConfig.setDriverClassName(dbConfig.getDriver()); hikariConfig.setJdbcUrl(dbConfig.getUrl()); hikariConfig.setUsername(dbConfig.getUsername()); hikariConfig.setPassword(dbConfig.getPassword()); hikariConfig.setPoolName(key); /* ...更多参数... */ return new HikariDataSource(hikariConfig); } } return null; } }; ``` 3. 参数完整性校验,可参考`hibernate-validater`相关教程,此框架只是默认配置了他的国际化和快速失败模式,不做其他改变,后期会考虑自定义相互校验实现,例如开始时间和结束时间的关系。 4. 如果你需要进行一些自动翻译,例如码表code需要翻译成对应的值,你只需要加一个注解在你的Vo实体上如下图,示例表示有两个字段需要翻译,一个来源于码表一个来源于翻译表 ```java /** * 机构菜单表 VO模型 * * @author LiuGangQiang Create in 2021/07/04 */ @Getter @Setter public class BaseMenuVo extends BaseVo { private static final long serialVersionUID = 1L; /* 父级ID */ private String pid; /* 父级菜单名称 扩展 */ private String pname; /* 菜单名 */ @AutoTranslate(type = "menu_name", source = TranslateSource.TRANSLATE) private String name; /* 菜单编码 */ @AutoTranslate(type = "menu_code", source = TranslateSource.DICT) private String code; /* 类型 0:菜单 1:按钮 */ private Integer type; /* 排序 */ private Integer sort; /* 是否激活 */ private Boolean enabled; /* 菜单图标 */ private String icon; /* 备注 */ private String remark; /* 修改时间 */ private LocalDateTime updateTime; /* 创建时间 */ private LocalDateTime createTime; } ``` > 之后同数据源一样,你需要配置一下对应的码表数据或者翻译表数据从那里来,这里可以根据自身业务具体实现可扩展,翻译一般带有强业务逻辑所以不做过多设计,提供一个简单的思路即可。 ```java /** * 字典表翻译服务 * * @author LiuGangQiang Create in 2021/08/19 * @return {@link ICustomSerialize} */ private ICustomSerialize dictionarySerialize() { return new ICustomSerialize() { @Override public String serialize(String type, String source) { BaseDictionaryDto dto = new BaseDictionaryDto(); dto.setType(type); dto.setCode(source); dto.setLanguage(LocaleContextHolder.getLocale().toLanguageTag()); Result> result = dictionaryFeign.queryList(dto); if (result.compare(ResultStatus.OK)) { List dicts = result.getData().getRows(); if (CollectionUtils.isGtZero(dicts)) { for (BaseDictionaryListVo vo : dicts) { if (vo.getCode().equals(source)) { return vo.getContent(); } } } } return source; } }; } ``` > 然后注册这个是属于字典还是翻译表的翻译实现 ```java /** * 实例化自定义序列化工厂 * * @author LiuGangQiang Create in 2021/08/19 * @return {@link CustomSerializeFactory} */ @Bean public CustomSerializeFactory customSerializeFactory() { CustomSerializeFactory factory = new CustomSerializeFactory(); factory.register(TranslateSource.DICT, dictionarySerialize()); factory.register(TranslateSource.TRANSLATE, translateSerialize()); return factory; } ``` ### 二、二级缓存使用 1. 如果你需要用到多级缓存也就一个引入的事,无需任何配置。默认配置是开启二级缓存,过期时间都是一天,更多功能请参考[源码](https://gitee.com/fist-team/ecloud-micro-cloud/tree/devlop/ecloud-common/ecloud-common-cache/src/main/java/com/ecloud/common/cache),注释就是教程,基本一看就会。 ```xml com.ecloud ecloud-common-cache ${ecloud.cloud.version} ``` > 如果你想定制你的缓存也是支持的,只需要加一个配置类,像如下配置即可,更多属性请参考API ```java /** * 自定义缓存配置 * * @author LiuGangQiang Create in 2021/09/10 */ @Configuration public class CacheConfiguration { /** * 自定义缓存配置 * * @author LiuGangQiang Create in 2021/09/10 * @return {@link IRedisCaffeineCacheConfig} */ @Bean public IRedisCaffeineCacheConfig redisCaffeineCacheConfig() { CustomizedCacheConfig init = new CustomizedCacheConfig(); init.set("dict", RedisCaffeineConfig.defaultCacheConfig().setExpire(Duration.ofMinutes(1))); init.set("translate", RedisCaffeineConfig.defaultCacheConfig().setExpire(Duration.ofMinutes(1))); return init; } } ``` > 这样就针对dict,translate两个缓存可以定制化配置