├── doc └── img │ ├── core_modules.png │ ├── CQRS_and_concepts.png │ ├── ice_cola_framework.png │ └── ice_cola_persistence.png ├── ice-cola-components ├── component-distributed │ ├── src │ │ └── main │ │ │ ├── resources │ │ │ └── META-INF │ │ │ │ └── spring.factories │ │ │ └── java │ │ │ └── cn │ │ │ └── stephen12 │ │ │ └── icecola │ │ │ └── component │ │ │ └── distributed │ │ │ ├── id │ │ │ ├── LeafIdService.java │ │ │ ├── SnowflakeIdService.java │ │ │ └── LeafIdNoGenerator.java │ │ │ ├── opt │ │ │ ├── OptimisticLock.java │ │ │ └── VersionOptimisticLock.java │ │ │ └── DistributedLockUtil.java │ └── pom.xml ├── component-mock │ ├── src │ │ └── main │ │ │ ├── resources │ │ │ └── META-INF │ │ │ │ └── spring.factories │ │ │ └── java │ │ │ └── cn │ │ │ └── stephen12 │ │ │ └── icecola │ │ │ └── component │ │ │ └── mock │ │ │ ├── Customizer.java │ │ │ ├── Mock.java │ │ │ ├── MockAutoConfiguration.java │ │ │ └── MockResponseAspect.java │ └── pom.xml ├── component-office │ ├── src │ │ └── main │ │ │ ├── resources │ │ │ └── META-INF │ │ │ │ └── spring.factories │ │ │ └── java │ │ │ └── cn │ │ │ └── stephen12 │ │ │ └── icecola │ │ │ └── component │ │ │ └── office │ │ │ ├── autoconfig │ │ │ └── OfficeAutoConfiguration.java │ │ │ └── excel │ │ │ ├── handler │ │ │ ├── DictionaryDataHandler.java │ │ │ └── ExcelDataHandleDispatcher.java │ │ │ ├── annotation │ │ │ └── ExportExcel.java │ │ │ ├── model │ │ │ └── ExcelVO.java │ │ │ ├── ExcelContext.java │ │ │ └── ExportExcelAspect.java │ └── pom.xml ├── component-utils │ ├── src │ │ └── main │ │ │ ├── resources │ │ │ └── META-INF │ │ │ │ └── spring.factories │ │ │ └── java │ │ │ └── cn │ │ │ └── stephen12 │ │ │ └── icecola │ │ │ └── component │ │ │ └── utils │ │ │ ├── autoconfig │ │ │ └── UtilsAutoConfiguration.java │ │ │ ├── number │ │ │ ├── Internal.java │ │ │ ├── OpenInternal.java │ │ │ ├── CloseInternal.java │ │ │ ├── NumberAxis.java │ │ │ └── NumberUtil.java │ │ │ ├── validaterule │ │ │ ├── Rule.java │ │ │ ├── RuleGroup.java │ │ │ └── ValidationRuleExecutor.java │ │ │ ├── fastjson │ │ │ ├── LongToLocalDateTimeDeserializer.java │ │ │ ├── LongToLocalDateDeserializer.java │ │ │ ├── LocalDateTimeToLongSerializer.java │ │ │ └── LocalDateToLongSerializer.java │ │ │ ├── collection │ │ │ └── SetUtil.java │ │ │ └── ClassUtil.java │ └── pom.xml ├── component-dictionary │ ├── src │ │ └── main │ │ │ ├── resources │ │ │ └── META-INF │ │ │ │ └── spring.factories │ │ │ └── java │ │ │ └── cn │ │ │ └── stephen12 │ │ │ └── icecola │ │ │ └── component │ │ │ └── dictionary │ │ │ ├── model │ │ │ ├── ToDictionaryVO.java │ │ │ ├── CommonDictionary.java │ │ │ ├── DictWrapper.java │ │ │ ├── DictionaryVO.java │ │ │ ├── Dict.java │ │ │ ├── Dictionary.java │ │ │ └── DefaultDictWrapper.java │ │ │ ├── DictionaryKey.java │ │ │ ├── autoconfig │ │ │ ├── DictionaryProperties.java │ │ │ ├── DictionaryAutoConfiguration.java │ │ │ ├── DictionaryScannedHandlers.java │ │ │ └── DictionaryScanner.java │ │ │ ├── apidoc │ │ │ ├── ApiDictionaryType.java │ │ │ ├── DictionaryTypeParamPlugin.java │ │ │ ├── DictionaryParamDescriptor.java │ │ │ └── EnumModelPropertyPlugin.java │ │ │ ├── DictionaryFiled.java │ │ │ ├── fastjson │ │ │ ├── DictionaryObjSerializer.java │ │ │ ├── FastJsonSettingHelper.java │ │ │ ├── DictionaryDeserializer.java │ │ │ └── DictionaryCodeSerializer.java │ │ │ ├── DictionaryManager.java │ │ │ ├── mybatis │ │ │ ├── MyBatisSettingHelper.java │ │ │ └── MybatisEnumTypeHandler.java │ │ │ ├── hutool │ │ │ └── ConverterSettingHelper.java │ │ │ ├── DictionaryManagerImpl.java │ │ │ ├── DictionaryRegistry.java │ │ │ └── jpa │ │ │ └── DictUserType.java │ └── pom.xml ├── component-multi-tenant │ ├── src │ │ └── main │ │ │ └── java │ │ │ └── cn │ │ │ └── stephen12 │ │ │ └── icecola │ │ │ └── component │ │ │ └── mutitenant │ │ │ └── package-info.java │ └── pom.xml ├── component-op-log │ ├── src │ │ └── main │ │ │ └── java │ │ │ └── cn │ │ │ └── stephen12 │ │ │ └── icecola │ │ │ └── component │ │ │ └── oplog │ │ │ ├── spi │ │ │ ├── OpLogListener.java │ │ │ └── RocketMqOpLogListener.java │ │ │ ├── aop │ │ │ ├── OpLog.java │ │ │ └── OpLogAspect.java │ │ │ └── OpLogModel.java │ └── pom.xml └── pom.xml ├── ice-cola-framework ├── framework-core-exception │ ├── src │ │ └── main │ │ │ ├── java │ │ │ └── cn │ │ │ │ └── stephen12 │ │ │ │ └── icecola │ │ │ │ └── framework │ │ │ │ └── exception │ │ │ │ ├── package-info.java │ │ │ │ ├── autoconfig │ │ │ │ └── CoreExceptionAutoConfiguration.java │ │ │ │ ├── ErrorCodeBizException.java │ │ │ │ └── CoreExceptionHandler.java │ │ │ └── resources │ │ │ └── META-INF │ │ │ └── spring.factories │ └── pom.xml ├── framework-core-infr │ ├── src │ │ └── main │ │ │ ├── resources │ │ │ └── META-INF │ │ │ │ └── spring.factories │ │ │ └── java │ │ │ └── cn │ │ │ └── stephen12 │ │ │ └── icecola │ │ │ └── framework │ │ │ └── core │ │ │ └── infr │ │ │ ├── model │ │ │ ├── IdV.java │ │ │ ├── IJpaEntity.java │ │ │ └── BaseJpaEntity.java │ │ │ ├── api │ │ │ └── FindAggregateRootInterceptor.java │ │ │ ├── repository │ │ │ ├── BaseJpaRepository.java │ │ │ ├── RepositoryWrapper.java │ │ │ └── PaddingRepositoryWrapper.java │ │ │ ├── id │ │ │ ├── IdNoGenerator.java │ │ │ ├── DefaultIdNoGeneratorImpl.java │ │ │ └── IdGeneratorGatewayImpl.java │ │ │ ├── autoconfig │ │ │ └── CoreInfrAutoConfiguration.java │ │ │ ├── datafiller │ │ │ ├── DataFillStrategy.java │ │ │ ├── DefaultDataFillStrategy.java │ │ │ ├── DataFiller.java │ │ │ └── MergedDataFillStrategy.java │ │ │ ├── annotation │ │ │ └── FindV.java │ │ │ ├── jpa │ │ │ ├── LocalDateTimeToLongConvertor.java │ │ │ └── LocalDateToLongConvertor.java │ │ │ ├── context │ │ │ ├── RequestContextCacheManager.java │ │ │ ├── RequestContext.java │ │ │ └── RequestScopeCacheSweeper.java │ │ │ └── IEntityConverter.java │ └── pom.xml ├── framework-core-app │ ├── src │ │ └── main │ │ │ └── java │ │ │ └── cn │ │ │ └── stephen12 │ │ │ └── icecola │ │ │ └── framework │ │ │ └── app │ │ │ ├── IAppService.java │ │ │ ├── BaseAppServiceImpl.java │ │ │ ├── BaseCmdExecutorImpl.java │ │ │ ├── annotation │ │ │ └── CmdExecutor.java │ │ │ ├── ICmdExecutor.java │ │ │ ├── ICmdProcessor.java │ │ │ ├── DomainEventListener.java │ │ │ └── AppServiceSupport.java │ └── pom.xml ├── framework-core-model │ ├── src │ │ └── main │ │ │ └── java │ │ │ └── cn │ │ │ └── stephen12 │ │ │ └── icecola │ │ │ └── framework │ │ │ └── model │ │ │ ├── dto │ │ │ ├── AsCollection.java │ │ │ └── ErrorCodeEnumI.java │ │ │ ├── unpacker │ │ │ ├── Unpacker.java │ │ │ └── DefaultUnpacker.java │ │ │ └── vo │ │ │ └── RestResult.java │ └── pom.xml ├── framework-core-domain │ ├── src │ │ └── main │ │ │ └── java │ │ │ └── cn │ │ │ └── stephen12 │ │ │ └── icecola │ │ │ └── framework │ │ │ └── core │ │ │ └── domain │ │ │ ├── model │ │ │ ├── DomainEvent.java │ │ │ ├── AfterDataInitializing.java │ │ │ ├── BaseV.java │ │ │ ├── BaseDomainEvent.java │ │ │ ├── BaseE.java │ │ │ └── BaseAggregateRoot.java │ │ │ ├── IdGeneratorGateway.java │ │ │ ├── BaseFactoryImpl.java │ │ │ ├── annotation │ │ │ └── BizTag.java │ │ │ ├── GatewayManager.java │ │ │ ├── BaseGatewayI.java │ │ │ └── PersistenceI.java │ └── pom.xml ├── framework-archetype │ └── pom.xml └── pom.xml ├── ice-cola-example ├── example-mall-server │ ├── example-mall-server-adapter │ │ ├── src │ │ │ └── main │ │ │ │ └── java │ │ │ │ └── cn │ │ │ │ └── stephen12 │ │ │ │ └── icecola │ │ │ │ └── example │ │ │ │ └── mall │ │ │ │ └── adapter │ │ │ │ └── OrderCmdController.java │ │ └── pom.xml │ ├── example-mall-server-bootstrap │ │ ├── src │ │ │ └── main │ │ │ │ └── java │ │ │ │ └── cn │ │ │ │ └── stephen12 │ │ │ │ └── icecola │ │ │ │ └── example │ │ │ │ └── mall │ │ │ │ └── bootstrap │ │ │ │ └── ExampleMallServerApplication.java │ │ └── pom.xml │ └── pom.xml └── pom.xml ├── .gitignore └── README.md /doc/img/core_modules.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stephen-ouys/ice-cola/HEAD/doc/img/core_modules.png -------------------------------------------------------------------------------- /doc/img/CQRS_and_concepts.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stephen-ouys/ice-cola/HEAD/doc/img/CQRS_and_concepts.png -------------------------------------------------------------------------------- /doc/img/ice_cola_framework.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stephen-ouys/ice-cola/HEAD/doc/img/ice_cola_framework.png -------------------------------------------------------------------------------- /doc/img/ice_cola_persistence.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stephen-ouys/ice-cola/HEAD/doc/img/ice_cola_persistence.png -------------------------------------------------------------------------------- /ice-cola-components/component-distributed/src/main/resources/META-INF/spring.factories: -------------------------------------------------------------------------------- 1 | org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ 2 | DbVersionOptimisticLockConfig 3 | -------------------------------------------------------------------------------- /ice-cola-components/component-mock/src/main/resources/META-INF/spring.factories: -------------------------------------------------------------------------------- 1 | org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ 2 | cn.stephen12.icecola.component.mock.MockAutoConfiguration -------------------------------------------------------------------------------- /ice-cola-components/component-office/src/main/resources/META-INF/spring.factories: -------------------------------------------------------------------------------- 1 | org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ 2 | cn.stephen12.icecola.component.office.autoconfig.OfficeAutoConfiguration -------------------------------------------------------------------------------- /ice-cola-components/component-utils/src/main/resources/META-INF/spring.factories: -------------------------------------------------------------------------------- 1 | org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ 2 | cn.stephen12.icecola.component.utils.autoconfig.UtilsAutoConfiguration 3 | -------------------------------------------------------------------------------- /ice-cola-framework/framework-core-exception/src/main/java/cn/stephen12/icecola/framework/exception/package-info.java: -------------------------------------------------------------------------------- 1 | /** 2 | * @author ouyangsheng 3 | * @date 2022-05-12 4 | **/ 5 | package cn.stephen12.icecola.framework.exception; -------------------------------------------------------------------------------- /ice-cola-framework/framework-core-infr/src/main/resources/META-INF/spring.factories: -------------------------------------------------------------------------------- 1 | org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ 2 | cn.stephen12.icecola.framework.core.infr.autoconfig.CoreInfrAutoConfiguration 3 | -------------------------------------------------------------------------------- /ice-cola-components/component-dictionary/src/main/resources/META-INF/spring.factories: -------------------------------------------------------------------------------- 1 | org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ 2 | cn.stephen12.icecola.component.dictionary.autoconfig.DictionaryAutoConfiguration 3 | -------------------------------------------------------------------------------- /ice-cola-components/component-mock/src/main/java/cn/stephen12/icecola/component/mock/Customizer.java: -------------------------------------------------------------------------------- 1 | package cn.stephen12.icecola.component.mock; 2 | 3 | public interface Customizer { 4 | 5 | Object custom(Object result); 6 | 7 | } 8 | -------------------------------------------------------------------------------- /ice-cola-components/component-multi-tenant/src/main/java/cn/stephen12/icecola/component/mutitenant/package-info.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 多租户插件 3 | * @author ouyangsheng 4 | * @since 2022-09-11 5 | **/ 6 | package cn.stephen12.icecola.component.mutitenant; -------------------------------------------------------------------------------- /ice-cola-framework/framework-core-exception/src/main/resources/META-INF/spring.factories: -------------------------------------------------------------------------------- 1 | org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ 2 | cn.stephen12.icecola.framework.exception.autoconfig.CoreExceptionAutoConfiguration 3 | -------------------------------------------------------------------------------- /ice-cola-framework/framework-core-infr/src/main/java/cn/stephen12/icecola/framework/core/infr/model/IdV.java: -------------------------------------------------------------------------------- 1 | package cn.stephen12.icecola.framework.core.infr.model; 2 | 3 | /** 4 | * 用于自动充血外部值对象 5 | * @author ouyangsheng 6 | * @date 2022-05-25 7 | **/ 8 | public interface IdV { 9 | 10 | /** 11 | * 获取ID 12 | * @return 13 | */ 14 | Long obtainId(); 15 | } 16 | -------------------------------------------------------------------------------- /ice-cola-example/example-mall-server/example-mall-server-adapter/src/main/java/cn/stephen12/icecola/example/mall/adapter/OrderCmdController.java: -------------------------------------------------------------------------------- 1 | package cn.stephen12.icecola.example.mall.adapter; 2 | 3 | import org.springframework.stereotype.Controller; 4 | 5 | /** 6 | * @author ouyangsheng 7 | * @since 2022-09-11 8 | **/ 9 | @Controller 10 | public class OrderCmdController { 11 | } 12 | -------------------------------------------------------------------------------- /ice-cola-framework/framework-core-infr/src/main/java/cn/stephen12/icecola/framework/core/infr/model/IJpaEntity.java: -------------------------------------------------------------------------------- 1 | package cn.stephen12.icecola.framework.core.infr.model; 2 | 3 | /** 4 | * 基本模型基类 5 | * @author youyangsheng 6 | * @since 2022-04-18 7 | */ 8 | public interface IJpaEntity { 9 | /** 10 | * id 11 | * @return 12 | */ 13 | Long getId(); 14 | 15 | } 16 | -------------------------------------------------------------------------------- /ice-cola-framework/framework-core-app/src/main/java/cn/stephen12/icecola/framework/app/IAppService.java: -------------------------------------------------------------------------------- 1 | package cn.stephen12.icecola.framework.app; 2 | 3 | import cn.stephen12.icecola.framework.core.domain.model.BaseAggregateRoot; 4 | 5 | /** 6 | * AppService or CommandService 7 | * 8 | * @author ouyangsheng 9 | * @since 2022-03-12 10 | */ 11 | public interface IAppService> { 12 | 13 | 14 | } 15 | -------------------------------------------------------------------------------- /ice-cola-example/example-mall-server/example-mall-server-bootstrap/src/main/java/cn/stephen12/icecola/example/mall/bootstrap/ExampleMallServerApplication.java: -------------------------------------------------------------------------------- 1 | package cn.stephen12.icecola.example.mall.bootstrap; 2 | 3 | import org.springframework.boot.autoconfigure.SpringBootApplication; 4 | 5 | /** 6 | * @author ouyangsheng 7 | * @since 2022-09-11 8 | **/ 9 | @SpringBootApplication 10 | public class ExampleMallServerApplication { 11 | } 12 | -------------------------------------------------------------------------------- /ice-cola-framework/framework-core-model/src/main/java/cn/stephen12/icecola/framework/model/dto/AsCollection.java: -------------------------------------------------------------------------------- 1 | package cn.stephen12.icecola.framework.model.dto; 2 | 3 | import java.util.Collection; 4 | 5 | /** 6 | * 能转换为集合的 7 | * @author ouyangsheng 8 | * @date 2022-03-31 9 | **/ 10 | public interface AsCollection { 11 | /** 12 | * 将数据转换为集合 13 | * @return 14 | */ 15 | Collection toCollection(); 16 | 17 | 18 | } 19 | -------------------------------------------------------------------------------- /ice-cola-components/component-mock/src/main/java/cn/stephen12/icecola/component/mock/Mock.java: -------------------------------------------------------------------------------- 1 | package cn.stephen12.icecola.component.mock; 2 | 3 | import java.lang.annotation.ElementType; 4 | import java.lang.annotation.Retention; 5 | import java.lang.annotation.RetentionPolicy; 6 | import java.lang.annotation.Target; 7 | 8 | @Target({ElementType.METHOD, ElementType.TYPE}) 9 | @Retention(RetentionPolicy.RUNTIME) 10 | public @interface Mock { 11 | } 12 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | target/ 2 | 3 | ### eclipse ### 4 | .apt_generated 5 | .classpath 6 | .factorypath 7 | .project 8 | .settings 9 | .springBeans 10 | 11 | ### IntelliJ IDEA ### 12 | .idea 13 | *.iws 14 | *.iml 15 | *.ipr 16 | out/ 17 | 18 | ### NetBeans ### 19 | nbproject/private/ 20 | build/ 21 | nbbuild/ 22 | dist/ 23 | nbdist/ 24 | .DS_Store 25 | 26 | target 27 | /.idea/ 28 | /lib/ 29 | /build 30 | *.swp 31 | /config 32 | 33 | 34 | jar 35 | 36 | 37 | .idea/ 38 | -------------------------------------------------------------------------------- /ice-cola-components/component-dictionary/src/main/java/cn/stephen12/icecola/component/dictionary/model/ToDictionaryVO.java: -------------------------------------------------------------------------------- 1 | package cn.stephen12.icecola.component.dictionary.model; 2 | 3 | /** 4 | * 将当前字典转为ToDictionaryVO 5 | * 6 | * @author ouyangsheng 7 | * @since 2022-07-28 8 | **/ 9 | public interface ToDictionaryVO { 10 | 11 | /** 12 | * 转为VO 13 | * 14 | * @return 15 | */ 16 | DictionaryVO toDictionaryVO(); 17 | 18 | 19 | } 20 | -------------------------------------------------------------------------------- /ice-cola-framework/framework-core-domain/src/main/java/cn/stephen12/icecola/framework/core/domain/model/DomainEvent.java: -------------------------------------------------------------------------------- 1 | package cn.stephen12.icecola.framework.core.domain.model; 2 | 3 | /** 4 | * 领域事件接口 5 | * @author ouyangsheng 6 | * @date 2022-05-13 7 | * 8 | * @see DomainEventListener 9 | **/ 10 | public interface DomainEvent { 11 | /** 12 | * 获取聚合根ID 13 | * @return 14 | */ 15 | Long getAggregateId(); 16 | 17 | } 18 | -------------------------------------------------------------------------------- /ice-cola-framework/framework-core-infr/src/main/java/cn/stephen12/icecola/framework/core/infr/api/FindAggregateRootInterceptor.java: -------------------------------------------------------------------------------- 1 | package cn.stephen12.icecola.framework.core.infr.api; 2 | 3 | /** 4 | * 充血一个聚合跟之后的通知 5 | * @author ouyangsheng 6 | * @date 2022-05-25 7 | **/ 8 | public interface FindAggregateRootInterceptor { 9 | 10 | /** 11 | * 聚合跟充血后处理 12 | * @param aggregateRoot 13 | */ 14 | void postHandle(Object aggregateRoot); 15 | 16 | 17 | } 18 | -------------------------------------------------------------------------------- /ice-cola-framework/framework-core-model/src/main/java/cn/stephen12/icecola/framework/model/unpacker/Unpacker.java: -------------------------------------------------------------------------------- 1 | package cn.stephen12.icecola.framework.model.unpacker; 2 | 3 | import java.util.List; 4 | 5 | /** 6 | * 拆包器 7 | * 8 | * @author ouyangsheng 9 | * @date 2022-03-31 10 | **/ 11 | public interface Unpacker { 12 | 13 | /** 14 | * 返回结果拆包器 15 | * @param returnObj 16 | * @return 17 | */ 18 | List unpack(Object returnObj); 19 | } 20 | -------------------------------------------------------------------------------- /ice-cola-framework/framework-core-domain/src/main/java/cn/stephen12/icecola/framework/core/domain/model/AfterDataInitializing.java: -------------------------------------------------------------------------------- 1 | package cn.stephen12.icecola.framework.core.domain.model; 2 | 3 | /** 4 | * 充血完成后调用的接口 5 | *

6 | * //TODO 暂时没有具体实现,各业务系统自行实现 7 | *

8 | * @author ouyangsheng 9 | * @date 2022-06-11 10 | **/ 11 | public interface AfterDataInitializing { 12 | 13 | /** 14 | * 充血完成后调用 15 | */ 16 | default void afterDataInitializing(){} 17 | } 18 | -------------------------------------------------------------------------------- /ice-cola-components/component-distributed/src/main/java/cn/stephen12/icecola/component/distributed/id/LeafIdService.java: -------------------------------------------------------------------------------- 1 | package cn.stephen12.icecola.component.distributed.id; 2 | 3 | /** 4 | * LeafId生成器 5 | * @author ouyangsheng 6 | * @since 2022-09-11 7 | **/ 8 | public class LeafIdService { 9 | public Long generateId(String tag){ 10 | return 0L; 11 | } 12 | public String generateNo(String tag){ 13 | //TODO NO生成器 14 | return null; 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /ice-cola-components/component-distributed/src/main/java/cn/stephen12/icecola/component/distributed/id/SnowflakeIdService.java: -------------------------------------------------------------------------------- 1 | package cn.stephen12.icecola.component.distributed.id; 2 | 3 | /** 4 | * LeafId生成器 5 | * @author ouyangsheng 6 | * @since 2022-09-11 7 | **/ 8 | public class SnowflakeIdService { 9 | public Long generateId(String tag){ 10 | return 0L; 11 | } 12 | public String generateNo(String tag){ 13 | //TODO NO生成器 14 | return null; 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /ice-cola-framework/framework-core-app/src/main/java/cn/stephen12/icecola/framework/app/BaseAppServiceImpl.java: -------------------------------------------------------------------------------- 1 | package cn.stephen12.icecola.framework.app; 2 | 3 | import cn.stephen12.icecola.framework.core.domain.model.BaseAggregateRoot; 4 | 5 | /** 6 | * App Service 基类 7 | * 8 | * @see ICmdExecutor 9 | * @see IAppService 10 | * 11 | * @author ouyangsheng 12 | * @date 2022-03-20 13 | **/ 14 | public abstract class BaseAppServiceImpl> extends AppServiceSupport { 15 | } 16 | -------------------------------------------------------------------------------- /ice-cola-components/component-op-log/src/main/java/cn/stephen12/icecola/component/oplog/spi/OpLogListener.java: -------------------------------------------------------------------------------- 1 | package cn.stephen12.icecola.component.oplog.spi; 2 | 3 | import cn.stephen12.icecola.component.oplog.OpLogModel; 4 | 5 | /** 6 | * 操作日志监听器 7 | * @author ouyangsheng 8 | * @since 2022-08-11 9 | **/ 10 | public interface OpLogListener { 11 | 12 | /** 13 | * 记录业务日志 14 | * @param opLogModel 业务日志对象 15 | * @param e 16 | */ 17 | void onLog(OpLogModel opLogModel,Throwable e); 18 | 19 | } 20 | -------------------------------------------------------------------------------- /ice-cola-framework/framework-core-app/src/main/java/cn/stephen12/icecola/framework/app/BaseCmdExecutorImpl.java: -------------------------------------------------------------------------------- 1 | package cn.stephen12.icecola.framework.app; 2 | 3 | import cn.stephen12.icecola.framework.app.annotation.CmdExecutor; 4 | import cn.stephen12.icecola.framework.core.domain.model.BaseAggregateRoot; 5 | 6 | /** 7 | * 基础的执行器基类 8 | * @author ouyangsheng 9 | * @date 2022-05-23 10 | **/ 11 | @CmdExecutor 12 | public abstract class BaseCmdExecutorImpl> extends AppServiceSupport{ 13 | } 14 | -------------------------------------------------------------------------------- /ice-cola-framework/framework-core-infr/src/main/java/cn/stephen12/icecola/framework/core/infr/repository/BaseJpaRepository.java: -------------------------------------------------------------------------------- 1 | package cn.stephen12.icecola.framework.core.infr.repository; 2 | 3 | import cn.stephen12.icecola.framework.core.infr.model.IJpaEntity; 4 | import org.springframework.data.jpa.repository.JpaRepository; 5 | 6 | /** 7 | * JPA 仓库 8 | * 9 | * @author ouyangsheng 10 | * @date 2022-03-23 11 | * 12 | **/ 13 | public interface BaseJpaRepository extends JpaRepository { 14 | } 15 | -------------------------------------------------------------------------------- /ice-cola-components/component-distributed/src/main/java/cn/stephen12/icecola/component/distributed/opt/OptimisticLock.java: -------------------------------------------------------------------------------- 1 | package cn.stephen12.icecola.component.distributed.opt; 2 | 3 | import java.util.function.Consumer; 4 | 5 | /** 6 | * 乐观锁顶层接口 7 | * @author ouyangsheng 8 | * @since 2022-09-01 9 | **/ 10 | public interface OptimisticLock { 11 | 12 | /** 13 | * 如果目标资源(可能是版本或者某个value) 等于 当前值 v 则执行 action 14 | * @param v 15 | * @param action 16 | * @return 17 | */ 18 | boolean computeIfMatch(T v, Consumer action); 19 | } 20 | -------------------------------------------------------------------------------- /ice-cola-components/component-utils/src/main/java/cn/stephen12/icecola/component/utils/autoconfig/UtilsAutoConfiguration.java: -------------------------------------------------------------------------------- 1 | package cn.stephen12.icecola.component.utils.autoconfig; 2 | 3 | import org.springframework.context.annotation.ComponentScan; 4 | import org.springframework.context.annotation.Configuration; 5 | 6 | /** 7 | * 工具组件自动装配 8 | * 9 | * @author ouyangsheng 10 | * @date 2022-04-29 11 | **/ 12 | @Configuration 13 | @ComponentScan(basePackages = { 14 | "cn.stephen12.icecola.component.utils" 15 | }) 16 | public class UtilsAutoConfiguration { 17 | } 18 | -------------------------------------------------------------------------------- /ice-cola-components/component-dictionary/src/main/java/cn/stephen12/icecola/component/dictionary/DictionaryKey.java: -------------------------------------------------------------------------------- 1 | package cn.stephen12.icecola.component.dictionary; 2 | 3 | import java.lang.annotation.ElementType; 4 | import java.lang.annotation.Retention; 5 | import java.lang.annotation.RetentionPolicy; 6 | import java.lang.annotation.Target; 7 | 8 | /** 9 | * 枚举KEY 10 | * 11 | * @author ouyangsheng 12 | * @date 2022-03-16 13 | **/ 14 | @Target(ElementType.TYPE) 15 | @Retention(RetentionPolicy.RUNTIME) 16 | public @interface DictionaryKey { 17 | String value() default ""; 18 | } 19 | -------------------------------------------------------------------------------- /ice-cola-framework/framework-core-domain/src/main/java/cn/stephen12/icecola/framework/core/domain/model/BaseV.java: -------------------------------------------------------------------------------- 1 | package cn.stephen12.icecola.framework.core.domain.model; 2 | 3 | import lombok.Data; 4 | import lombok.NoArgsConstructor; 5 | import lombok.ToString; 6 | import lombok.experimental.SuperBuilder; 7 | 8 | /** 9 | * 基本值对象基类 10 | * 11 | * @author ouyangsheng 12 | * @since 2022-05-13 13 | */ 14 | @ToString 15 | @NoArgsConstructor 16 | @SuperBuilder 17 | @Data 18 | public abstract class BaseV> { 19 | 20 | /** 21 | * id 22 | */ 23 | protected Long id; 24 | 25 | } 26 | -------------------------------------------------------------------------------- /ice-cola-components/component-dictionary/src/main/java/cn/stephen12/icecola/component/dictionary/autoconfig/DictionaryProperties.java: -------------------------------------------------------------------------------- 1 | package cn.stephen12.icecola.component.dictionary.autoconfig; 2 | 3 | import lombok.Data; 4 | import org.springframework.boot.context.properties.ConfigurationProperties; 5 | 6 | /** 7 | * 字典配置项 8 | * 9 | * @author ouyangsheng 10 | * @date 2022-03-16 11 | **/ 12 | @Data 13 | @ConfigurationProperties(prefix = "ice-cola.component.dictionary") 14 | public class DictionaryProperties { 15 | 16 | /** 17 | * 扫描路径,默认"" 18 | */ 19 | private String typeEnumsPackage = ""; 20 | } 21 | -------------------------------------------------------------------------------- /ice-cola-framework/framework-core-exception/src/main/java/cn/stephen12/icecola/framework/exception/autoconfig/CoreExceptionAutoConfiguration.java: -------------------------------------------------------------------------------- 1 | package cn.stephen12.icecola.framework.exception.autoconfig; 2 | 3 | import org.springframework.context.annotation.ComponentScan; 4 | import org.springframework.context.annotation.Configuration; 5 | 6 | /** 7 | * Core-exception 组件自动配置 8 | * 9 | * @author ouyangsheng 10 | * @date 2022-06-01 11 | **/ 12 | @Configuration 13 | @ComponentScan(basePackages = { 14 | "cn.stephen12.icecola.framework.exception" 15 | }) 16 | public class CoreExceptionAutoConfiguration { 17 | } 18 | -------------------------------------------------------------------------------- /ice-cola-components/component-distributed/src/main/java/cn/stephen12/icecola/component/distributed/opt/VersionOptimisticLock.java: -------------------------------------------------------------------------------- 1 | package cn.stephen12.icecola.component.distributed.opt; 2 | 3 | import java.util.function.Consumer; 4 | 5 | /** 6 | * 版本乐观锁 7 | * @author ouyangsheng 8 | * @since 2022-09-01 9 | **/ 10 | public interface VersionOptimisticLock extends OptimisticLock{ 11 | 12 | /** 13 | * 如果目标版本 小于等于 当前值 version 则执行 action 14 | * @param version 15 | * @param action 16 | * @return 17 | */ 18 | @Override 19 | boolean computeIfMatch(Long version, Consumer action); 20 | } 21 | -------------------------------------------------------------------------------- /ice-cola-components/component-office/src/main/java/cn/stephen12/icecola/component/office/autoconfig/OfficeAutoConfiguration.java: -------------------------------------------------------------------------------- 1 | package cn.stephen12.icecola.component.office.autoconfig; 2 | 3 | import org.springframework.context.annotation.ComponentScan; 4 | import org.springframework.context.annotation.Configuration; 5 | import org.springframework.context.annotation.EnableAspectJAutoProxy; 6 | 7 | /** 8 | * @author ouyangsheng 9 | * @since 2022-03-31 10 | */ 11 | @ComponentScan("cn.stephen12.icecola.component.office") 12 | @Configuration 13 | @EnableAspectJAutoProxy 14 | public class OfficeAutoConfiguration { 15 | 16 | } 17 | -------------------------------------------------------------------------------- /ice-cola-framework/framework-archetype/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | cn.stephen12.icecola 7 | ice-cola-framework 8 | 1.0.6-SNAPSHOT 9 | 10 | 4.0.0 11 | 12 | framework-archetype 13 | 14 | 15 | -------------------------------------------------------------------------------- /ice-cola-components/component-multi-tenant/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | ice-cola-components 7 | cn.stephen12.icecola 8 | 1.0.6-SNAPSHOT 9 | 10 | 4.0.0 11 | 12 | component-multi-tenant 13 | 14 | 15 | -------------------------------------------------------------------------------- /ice-cola-components/component-dictionary/src/main/java/cn/stephen12/icecola/component/dictionary/apidoc/ApiDictionaryType.java: -------------------------------------------------------------------------------- 1 | package cn.stephen12.icecola.component.dictionary.apidoc; 2 | 3 | import java.lang.annotation.ElementType; 4 | import java.lang.annotation.Retention; 5 | import java.lang.annotation.RetentionPolicy; 6 | import java.lang.annotation.Target; 7 | 8 | /** 9 | * 枚举类型 10 | * 11 | * @author ouyangsheng 12 | * @date 2022-03-15 13 | **/ 14 | @Target({ElementType.PARAMETER,ElementType.FIELD}) 15 | @Retention(RetentionPolicy.RUNTIME) 16 | public @interface ApiDictionaryType { 17 | String parameterType() default "path"; 18 | } 19 | -------------------------------------------------------------------------------- /ice-cola-framework/framework-core-domain/src/main/java/cn/stephen12/icecola/framework/core/domain/IdGeneratorGateway.java: -------------------------------------------------------------------------------- 1 | package cn.stephen12.icecola.framework.core.domain; 2 | 3 | /** 4 | * Id 编号、生成器 5 | * 6 | * @author ouyangsheng 7 | * @date 2022-03-22 8 | **/ 9 | public interface IdGeneratorGateway { 10 | 11 | /** 12 | * 生成ID 13 | * @param domainClass 需要生成ID的类,实现者可自学觉得生成规则 14 | * @return 15 | */ 16 | Long generateId(Class domainClass); 17 | 18 | /** 19 | * 生成全局编号 20 | * 21 | * @param domainClass 22 | * @return 23 | */ 24 | String generateNo(Class domainClass); 25 | 26 | } 27 | -------------------------------------------------------------------------------- /ice-cola-framework/framework-core-model/src/main/java/cn/stephen12/icecola/framework/model/dto/ErrorCodeEnumI.java: -------------------------------------------------------------------------------- 1 | package cn.stephen12.icecola.framework.model.dto; 2 | 3 | 4 | 5 | /** 6 | * 错误码枚举接口 7 | * @author ouyangsheng 8 | * @date 2022-05-26 9 | **/ 10 | public interface ErrorCodeEnumI> { 11 | /** 12 | * 编码 13 | * @return 14 | */ 15 | Integer getCode(); 16 | /** 17 | * 错误消息 18 | * @return 19 | */ 20 | String getMessage(); 21 | 22 | /** 23 | * 名称默认为消息 24 | * @return 25 | */ 26 | default String getName(){ 27 | return this.getMessage(); 28 | } 29 | 30 | } 31 | -------------------------------------------------------------------------------- /ice-cola-components/component-op-log/src/main/java/cn/stephen12/icecola/component/oplog/aop/OpLog.java: -------------------------------------------------------------------------------- 1 | package cn.stephen12.icecola.component.oplog.aop; 2 | 3 | import java.lang.annotation.ElementType; 4 | import java.lang.annotation.Retention; 5 | import java.lang.annotation.RetentionPolicy; 6 | import java.lang.annotation.Target; 7 | 8 | /** 9 | * 操作日志注解 10 | * @author ouyangsheng 11 | * @since 2022-08-11 12 | **/ 13 | @Target({ElementType.METHOD, ElementType.TYPE}) 14 | @Retention(RetentionPolicy.RUNTIME) 15 | public @interface OpLog { 16 | String value(); 17 | 18 | String label(); 19 | 20 | String description(); 21 | 22 | String idEL(); 23 | } 24 | -------------------------------------------------------------------------------- /ice-cola-framework/framework-core-domain/src/main/java/cn/stephen12/icecola/framework/core/domain/model/BaseDomainEvent.java: -------------------------------------------------------------------------------- 1 | package cn.stephen12.icecola.framework.core.domain.model; 2 | 3 | /** 4 | * 领域事件基类 5 | * @author ouyangsheng 6 | * @since 2022-05-13 7 | **/ 8 | public abstract class BaseDomainEvent implements DomainEvent{ 9 | /** 10 | * 领域对象 11 | * 通常应该设计成不能被其他领域访问 12 | */ 13 | private D domain; 14 | 15 | public BaseDomainEvent(D domain){ 16 | this.domain = domain; 17 | } 18 | 19 | @Override 20 | public Long getAggregateId() { 21 | return domain.getId(); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /ice-cola-framework/framework-core-infr/src/main/java/cn/stephen12/icecola/framework/core/infr/id/IdNoGenerator.java: -------------------------------------------------------------------------------- 1 | package cn.stephen12.icecola.framework.core.infr.id; 2 | 3 | /** 4 | * Id 或者 No生成器( 基于Tag) 5 | * 6 | * @author ouyangsheng 7 | * @date 2022-05-29 8 | * @see cn.stephen12.icecola.framework.core.domain.annotation.BizTag 9 | **/ 10 | public interface IdNoGenerator { 11 | 12 | /** 13 | * 生成Id 14 | * 15 | * @param tag 16 | * @return 17 | */ 18 | Long generateId(String tag); 19 | 20 | /** 21 | * 生成 no 22 | * 23 | * @param tag 24 | * @return 25 | */ 26 | String generateNo(String tag); 27 | 28 | } 29 | -------------------------------------------------------------------------------- /ice-cola-framework/framework-core-infr/src/main/java/cn/stephen12/icecola/framework/core/infr/autoconfig/CoreInfrAutoConfiguration.java: -------------------------------------------------------------------------------- 1 | package cn.stephen12.icecola.framework.core.infr.autoconfig; 2 | 3 | import org.springframework.cache.annotation.EnableCaching; 4 | import org.springframework.context.annotation.ComponentScan; 5 | import org.springframework.context.annotation.Configuration; 6 | 7 | /** 8 | * Core-Infr组件自动配置 9 | * 10 | * @author ouyangsheng 11 | * @date 2022-06-01 12 | **/ 13 | @EnableCaching 14 | @Configuration 15 | @ComponentScan(basePackages = { 16 | "cn.stephen12.icecola.framework.core.infr" 17 | }) 18 | public class CoreInfrAutoConfiguration { 19 | } 20 | -------------------------------------------------------------------------------- /ice-cola-framework/framework-core-infr/src/main/java/cn/stephen12/icecola/framework/core/infr/datafiller/DataFillStrategy.java: -------------------------------------------------------------------------------- 1 | package cn.stephen12.icecola.framework.core.infr.datafiller; 2 | 3 | import cn.stephen12.icecola.framework.core.domain.model.BaseV; 4 | 5 | /** 6 | * 数据填充策略 7 | * 8 | * @see MergedDataFillStrategy 9 | * 10 | * @author ouyangsheng 11 | * @date 2022-05-25 12 | **/ 13 | public interface DataFillStrategy { 14 | 15 | /** 16 | * 数据填充策略 17 | * 18 | * @param id 19 | * @param targetVType 20 | * @param 21 | * @return 22 | */ 23 | V findById(Long id, Class targetVType); 24 | 25 | 26 | 27 | } 28 | -------------------------------------------------------------------------------- /ice-cola-framework/framework-core-domain/src/main/java/cn/stephen12/icecola/framework/core/domain/BaseFactoryImpl.java: -------------------------------------------------------------------------------- 1 | package cn.stephen12.icecola.framework.core.domain; 2 | 3 | import cn.stephen12.icecola.framework.core.domain.model.BaseAggregateRoot; 4 | import org.springframework.beans.factory.annotation.Autowired; 5 | import org.springframework.context.ApplicationContext; 6 | 7 | /** 8 | * 聚合根工厂 9 | * 10 | * @author ouyangsheng 11 | * @date 2022-03-23 12 | **/ 13 | public class BaseFactoryImpl> { 14 | @Autowired(required = false) 15 | protected BaseGatewayI baseGateway; 16 | 17 | @Autowired 18 | protected ApplicationContext applicationContext; 19 | 20 | } 21 | -------------------------------------------------------------------------------- /ice-cola-framework/framework-core-infr/src/main/java/cn/stephen12/icecola/framework/core/infr/annotation/FindV.java: -------------------------------------------------------------------------------- 1 | package cn.stephen12.icecola.framework.core.infr.annotation; 2 | 3 | import java.lang.annotation.ElementType; 4 | import java.lang.annotation.Inherited; 5 | import java.lang.annotation.Retention; 6 | import java.lang.annotation.RetentionPolicy; 7 | import java.lang.annotation.Target; 8 | 9 | /** 10 | * 值对象查找绑定注解 11 | * @author ouyangsheng 12 | * @date 2022-05-25 13 | **/ 14 | @Inherited 15 | @Retention(RetentionPolicy.RUNTIME) 16 | @Target({ElementType.TYPE}) 17 | public @interface FindV { 18 | /** 19 | * 能支持查找的值对象 20 | * @return 21 | */ 22 | Class[] value() default {}; 23 | } 24 | -------------------------------------------------------------------------------- /ice-cola-example/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | ice-cola-parent 7 | cn.stephen12.icecola 8 | 1.0.6-SNAPSHOT 9 | 10 | 4.0.0 11 | 12 | ice-cola-example 13 | pom 14 | 15 | example-mall-server 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /ice-cola-components/component-utils/src/main/java/cn/stephen12/icecola/component/utils/number/Internal.java: -------------------------------------------------------------------------------- 1 | package cn.stephen12.icecola.component.utils.number; 2 | 3 | import java.math.BigDecimal; 4 | 5 | /** 6 | * 区间的抽象类 7 | * @author ouyangsheng 8 | * @date 2022-05-24 9 | **/ 10 | abstract class Internal implements Comparable { 11 | 12 | protected BigDecimal left; 13 | protected BigDecimal right; 14 | 15 | public Internal(BigDecimal left, BigDecimal right) { 16 | this.left = left; 17 | this.right = right; 18 | } 19 | 20 | /** 21 | * 某一个数是否在本区间内 22 | * 23 | * @param num 24 | * @return 25 | */ 26 | abstract boolean isIn(BigDecimal num); 27 | } 28 | -------------------------------------------------------------------------------- /ice-cola-framework/framework-core-domain/src/main/java/cn/stephen12/icecola/framework/core/domain/annotation/BizTag.java: -------------------------------------------------------------------------------- 1 | package cn.stephen12.icecola.framework.core.domain.annotation; 2 | 3 | import java.lang.annotation.Inherited; 4 | import java.lang.annotation.Retention; 5 | import java.lang.annotation.Target; 6 | 7 | import static java.lang.annotation.ElementType.TYPE; 8 | import static java.lang.annotation.RetentionPolicy.RUNTIME; 9 | 10 | /** 11 | * 实体的Id标识 12 | * @author ouyangsheng 13 | * @date 2022-05-25 14 | **/ 15 | @Inherited 16 | @Target({TYPE}) 17 | @Retention(RUNTIME) 18 | public @interface BizTag { 19 | 20 | /** 21 | * Id标识 22 | * @return 23 | */ 24 | String value() default ""; 25 | } 26 | -------------------------------------------------------------------------------- /ice-cola-components/component-dictionary/src/main/java/cn/stephen12/icecola/component/dictionary/autoconfig/DictionaryAutoConfiguration.java: -------------------------------------------------------------------------------- 1 | package cn.stephen12.icecola.component.dictionary.autoconfig; 2 | 3 | import org.springframework.boot.context.properties.EnableConfigurationProperties; 4 | import org.springframework.context.annotation.ComponentScan; 5 | import org.springframework.context.annotation.Configuration; 6 | 7 | /** 8 | * 字典组件自动装配 9 | * 10 | * @author ouyangsheng 11 | * @date 2022-03-15 12 | **/ 13 | @Configuration 14 | @ComponentScan(basePackages = { 15 | "cn.stephen12.icecola.component.dictionary" 16 | }) 17 | @EnableConfigurationProperties(DictionaryProperties.class) 18 | public class DictionaryAutoConfiguration { 19 | } 20 | -------------------------------------------------------------------------------- /ice-cola-components/component-utils/src/main/java/cn/stephen12/icecola/component/utils/validaterule/Rule.java: -------------------------------------------------------------------------------- 1 | package cn.stephen12.icecola.component.utils.validaterule; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Data; 5 | 6 | import java.util.function.Predicate; 7 | import java.util.function.Supplier; 8 | 9 | /** 10 | * @author ouyangsheng 11 | * @date 2022-05-23 12 | **/ 13 | @AllArgsConstructor 14 | @Data 15 | public class Rule

{ 16 | private Predicate

condition; 17 | private Supplier message; 18 | 19 | public void run(P param, ValidationRuleExecutor executor) { 20 | if (this.condition.test(param)) { 21 | String message = this.message.get(); 22 | executor.result.add(message); 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /ice-cola-components/component-dictionary/src/main/java/cn/stephen12/icecola/component/dictionary/DictionaryFiled.java: -------------------------------------------------------------------------------- 1 | package cn.stephen12.icecola.component.dictionary; 2 | 3 | import cn.stephen12.icecola.component.dictionary.model.DefaultDictWrapper; 4 | import cn.stephen12.icecola.component.dictionary.model.DictWrapper; 5 | 6 | import java.lang.annotation.ElementType; 7 | import java.lang.annotation.Retention; 8 | import java.lang.annotation.RetentionPolicy; 9 | import java.lang.annotation.Target; 10 | 11 | /** 12 | * 声明枚举字段 13 | * 14 | * @author ouyangsheng 15 | * @date 2022-04-24 16 | **/ 17 | @Target(ElementType.FIELD) 18 | @Retention(RetentionPolicy.RUNTIME) 19 | public @interface DictionaryFiled { 20 | Class wrapperClass() default DefaultDictWrapper.class; 21 | } 22 | -------------------------------------------------------------------------------- /ice-cola-example/example-mall-server/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | ice-cola-example 7 | cn.stephen12.icecola 8 | 1.0.6-SNAPSHOT 9 | 10 | 4.0.0 11 | 12 | example-mall-server 13 | pom 14 | 15 | example-mall-server-adapter 16 | example-mall-server-bootstrap 17 | 18 | 19 | -------------------------------------------------------------------------------- /ice-cola-framework/framework-core-app/src/main/java/cn/stephen12/icecola/framework/app/annotation/CmdExecutor.java: -------------------------------------------------------------------------------- 1 | package cn.stephen12.icecola.framework.app.annotation; 2 | 3 | import org.springframework.context.annotation.Scope; 4 | import org.springframework.stereotype.Component; 5 | import org.springframework.validation.annotation.Validated; 6 | 7 | import java.lang.annotation.ElementType; 8 | import java.lang.annotation.Inherited; 9 | import java.lang.annotation.Retention; 10 | import java.lang.annotation.RetentionPolicy; 11 | import java.lang.annotation.Target; 12 | 13 | /** 14 | * 命令执行器 15 | * @author ouyangsheng 16 | * @date 2022-05-23 17 | **/ 18 | @Inherited 19 | @Retention(RetentionPolicy.RUNTIME) 20 | @Target({ElementType.TYPE}) 21 | @Component 22 | @Validated 23 | @Scope("prototype") 24 | public @interface CmdExecutor { 25 | } 26 | -------------------------------------------------------------------------------- /ice-cola-framework/framework-core-domain/src/main/java/cn/stephen12/icecola/framework/core/domain/model/BaseE.java: -------------------------------------------------------------------------------- 1 | package cn.stephen12.icecola.framework.core.domain.model; 2 | 3 | import lombok.AccessLevel; 4 | import lombok.Data; 5 | import lombok.NoArgsConstructor; 6 | import lombok.ToString; 7 | import lombok.experimental.FieldDefaults; 8 | import lombok.experimental.SuperBuilder; 9 | 10 | /** 11 | * 基本实体基类 12 | * 13 | * @author yuchenggong 14 | * @version 1.0 15 | * @date 2021/9/1 16 | */ 17 | @FieldDefaults(level = AccessLevel.PRIVATE) 18 | @ToString 19 | @NoArgsConstructor 20 | @SuperBuilder 21 | @Data 22 | public abstract class BaseE> { 23 | 24 | /** 25 | * id 26 | */ 27 | protected Long id; 28 | 29 | /** 30 | * 负载信息,由基础设施自由维护 31 | */ 32 | protected Object payload; 33 | 34 | } 35 | -------------------------------------------------------------------------------- /ice-cola-components/component-dictionary/src/main/java/cn/stephen12/icecola/component/dictionary/model/CommonDictionary.java: -------------------------------------------------------------------------------- 1 | package cn.stephen12.icecola.component.dictionary.model; 2 | 3 | import io.swagger.annotations.ApiModel; 4 | import io.swagger.annotations.ApiModelProperty; 5 | 6 | /** 7 | * 通用字典接口 8 | * 9 | * @author ouyangsheng 10 | * @date 2022-03-08 11 | **/ 12 | @ApiModel(value ="CommonDictionary",description = "通用枚举") 13 | public interface CommonDictionary> extends Dictionary{ 14 | 15 | /** 16 | * 字典Key 17 | * 18 | * @return 19 | */ 20 | @Override 21 | @ApiModelProperty("编码") 22 | String getCode(); 23 | 24 | /** 25 | * 字典名称(中文) 26 | * 27 | * @return 28 | */ 29 | @Override 30 | @ApiModelProperty("名称") 31 | String getName(); 32 | 33 | } 34 | -------------------------------------------------------------------------------- /ice-cola-components/component-utils/src/main/java/cn/stephen12/icecola/component/utils/validaterule/RuleGroup.java: -------------------------------------------------------------------------------- 1 | package cn.stephen12.icecola.component.utils.validaterule; 2 | 3 | import lombok.Getter; 4 | 5 | import java.util.Arrays; 6 | import java.util.List; 7 | 8 | /** 9 | * @author ouyangsheng 10 | * @date 2022-05-23 11 | **/ 12 | public class RuleGroup

extends Rule

{ 13 | @Getter 14 | private final List> rules; 15 | public RuleGroup(List> rules) { 16 | super(null, null); 17 | this.rules = rules; 18 | } 19 | public RuleGroup(Rule

... rules) { 20 | this(Arrays.asList(rules)); 21 | } 22 | 23 | @Override 24 | public void run(P param, ValidationRuleExecutor executor) { 25 | for (Rule

r : rules) { 26 | r.run(param, executor); 27 | } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /ice-cola-components/component-op-log/src/main/java/cn/stephen12/icecola/component/oplog/OpLogModel.java: -------------------------------------------------------------------------------- 1 | package cn.stephen12.icecola.component.oplog; 2 | 3 | import lombok.Data; 4 | 5 | /** 6 | * 业务日志对象 7 | * @author ouyangsheng 8 | * @since 2022-08-11 9 | **/ 10 | @Data 11 | public class OpLogModel { 12 | 13 | /** 14 | * 操作标识 15 | */ 16 | private String label; 17 | 18 | /** 19 | * 描述信息 20 | */ 21 | private String description; 22 | 23 | /** 24 | * 所操作数据的ID 25 | */ 26 | private Object bizId; 27 | /** 28 | * 先前状态 29 | */ 30 | private String previousState; 31 | 32 | /** 33 | * 之后状态 34 | */ 35 | private String postState; 36 | 37 | /** 38 | * 参数 39 | */ 40 | private String param; 41 | 42 | /** 43 | * 响应信息 44 | */ 45 | private String feedback; 46 | } 47 | -------------------------------------------------------------------------------- /ice-cola-framework/framework-core-app/src/main/java/cn/stephen12/icecola/framework/app/ICmdExecutor.java: -------------------------------------------------------------------------------- 1 | package cn.stephen12.icecola.framework.app; 2 | 3 | import javax.validation.Valid; 4 | 5 | /** 6 | * Cmd 执行器 7 | * 8 | * @author ouyangsheng 9 | * @date 2022-05-17 10 | * @see ICmdProcessor 两者只能实现一个 11 | **/ 12 | public interface ICmdExecutor { 13 | /** 14 | * 执行,无返回结果 15 | *

16 | * 配合注解 CmdExecutor 默认会在调用其进行参数校验 17 | *

18 | *

19 | * //TODO NOTE 有个值得注意的点,java validation 设计必须在接口上加 @Valid 而非实现是基于里氏替换的原则:
20 | * https://beanvalidation.org/1.1/spec/#constraintdeclarationvalidationprocess-methodlevelconstraints-inheritance 21 | *

22 | * 23 | * @param cmd 24 | * @see cn.stephen12.icecola.framework.app.annotation.CmdExecutor 25 | */ 26 | void execute(@Valid CMD cmd); 27 | } 28 | -------------------------------------------------------------------------------- /ice-cola-framework/framework-core-app/src/main/java/cn/stephen12/icecola/framework/app/ICmdProcessor.java: -------------------------------------------------------------------------------- 1 | package cn.stephen12.icecola.framework.app; 2 | 3 | import javax.validation.Valid; 4 | 5 | /** 6 | * Cmd 执行器 有返回值 7 | * 8 | * @author ouyangsheng 9 | * @date 2022-05-17 10 | * @see ICmdExecutor 两者只能实现一个 11 | **/ 12 | public interface ICmdProcessor { 13 | /** 14 | * 执行,有返回结果 15 | *

16 | * 配合注解 CmdExecutor 默认会在调用其进行参数校验 17 | *

18 | *

19 | * //TODO NOTE 有个值得注意的点,java validation 设计必须在接口上加 @Valid 而非实现是基于里氏替换的原则:
20 | * https://beanvalidation.org/1.1/spec/#constraintdeclarationvalidationprocess-methodlevelconstraints-inheritance 21 | *

22 | * 23 | * @param cmd 24 | * @return 25 | * @see cn.stephen12.icecola.framework.app.annotation.CmdExecutor 26 | */ 27 | R execute(@Valid CMD cmd); 28 | } 29 | -------------------------------------------------------------------------------- /ice-cola-components/component-office/src/main/java/cn/stephen12/icecola/component/office/excel/handler/DictionaryDataHandler.java: -------------------------------------------------------------------------------- 1 | package cn.stephen12.icecola.component.office.excel.handler; 2 | 3 | import cn.stephen12.icecola.component.dictionary.model.Dictionary; 4 | import org.springframework.stereotype.Component; 5 | 6 | 7 | /** 8 | * 自定义excel数据处理 9 | * @author xiongliuyang 10 | * @version 1.0 11 | * @date 2022/4/18 12 | */ 13 | @Component 14 | public class DictionaryDataHandler implements ExcelDataHandleDispatcher.DataHandler { 15 | 16 | @Override 17 | public boolean supported(Object obj, String name, Object value) { 18 | return Dictionary.class.isAssignableFrom(value.getClass()); 19 | } 20 | 21 | @Override 22 | public Object handle(Object obj, String name, Object value) { 23 | Dictionary dictionary = (Dictionary) value; 24 | return dictionary.getName(); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /ice-cola-components/component-op-log/src/main/java/cn/stephen12/icecola/component/oplog/spi/RocketMqOpLogListener.java: -------------------------------------------------------------------------------- 1 | package cn.stephen12.icecola.component.oplog.spi; 2 | 3 | /** 4 | * @author ouyangsheng 5 | * @since 2022-08-11 6 | **/ 7 | //@ConditionalOnClass(com.aliyun.openservices.shade.com.alibaba.rocketmq.client.MQAdmin.class) 8 | //@Component 9 | //class AliRocketMqOpLogListener implements OpLogListener { 10 | // 11 | // /** 12 | // * 成功产生业务日志 13 | // */ 14 | // @Override 15 | // void onLog(OpLogModel opLogModel) { 16 | // 17 | // } 18 | // 19 | // /** 20 | // * 发生异常 21 | // * @param e 22 | // */ 23 | // void onError(Throwable e){ 24 | // 25 | // } 26 | //} 27 | // 28 | ///** 29 | // * @author ouyangsheng 30 | // * @since 2022-08-11 31 | // **/ 32 | //@ConditionalOnClass(org.apache.rocketmq.client.MQAdmin.class) 33 | //@Component 34 | //class ApacheRocketMqOpLogListener implements { 35 | //} 36 | -------------------------------------------------------------------------------- /ice-cola-framework/framework-core-infr/src/main/java/cn/stephen12/icecola/framework/core/infr/repository/RepositoryWrapper.java: -------------------------------------------------------------------------------- 1 | package cn.stephen12.icecola.framework.core.infr.repository; 2 | 3 | import org.springframework.cache.annotation.Cacheable; 4 | 5 | import java.util.Collection; 6 | import java.util.List; 7 | 8 | /** 9 | * Repository 包装器 10 | *

11 | * 把外部(非JPA、非数据库资源)进行包装,如RPC、配置文件、JVM缓存,使其保持与SpringData Repository 相同的特性 12 | *

13 | * @param 统一的承载对象 14 | * @author ouyangsheng 15 | * @date 2022-05-23 16 | **/ 17 | public interface RepositoryWrapper{ 18 | /** 19 | * 获取实体的ID 20 | * @param entity 21 | * @return 22 | */ 23 | ID getIdOf(E entity); 24 | 25 | /** 26 | * 通过ID获取一个对象 27 | * @param id 28 | * @return 29 | */ 30 | E findById(ID id); 31 | 32 | /** 33 | * 批量获取 34 | * @param ids 35 | * @return 36 | */ 37 | List findByIds(Collection ids); 38 | 39 | } 40 | -------------------------------------------------------------------------------- /ice-cola-components/component-distributed/src/main/java/cn/stephen12/icecola/component/distributed/id/LeafIdNoGenerator.java: -------------------------------------------------------------------------------- 1 | package cn.stephen12.icecola.component.distributed.id; 2 | 3 | import cn.stephen12.icecola.framework.core.infr.id.IdNoGenerator; 4 | import org.springframework.beans.factory.annotation.Autowired; 5 | import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; 6 | import org.springframework.stereotype.Component; 7 | 8 | /** 9 | * LeafIdNo生成器 10 | * @author ouyangsheng 11 | * @date 2022-05-29 12 | **/ 13 | @ConditionalOnClass(IdNoGenerator.class) 14 | @Component 15 | public class LeafIdNoGenerator implements IdNoGenerator { 16 | 17 | @Autowired 18 | protected LeafIdService leafService; 19 | 20 | @Override 21 | public Long generateId(String tag) { 22 | return leafService.generateId(tag); 23 | } 24 | 25 | @Override 26 | public String generateNo(String tag) { 27 | return leafService.generateNo(tag); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /ice-cola-components/component-op-log/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | cn.stephen12.icecola 7 | ice-cola-components 8 | 1.0.6-SNAPSHOT 9 | 10 | 4.0.0 11 | 12 | component-op-log 13 | 14 | 15 | 16 | org.projectlombok 17 | lombok 18 | 19 | 20 | org.springframework.boot 21 | spring-boot-starter-aop 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /ice-cola-framework/framework-core-model/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | cn.stephen12.icecola 7 | ice-cola-framework 8 | 1.0.6-SNAPSHOT 9 | 10 | 4.0.0 11 | 12 | framework-core-model 13 | 14 | 15 | 16 | org.projectlombok 17 | lombok 18 | 19 | 20 | com.alibaba.cola 21 | cola-component-exception 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /ice-cola-components/component-dictionary/src/main/java/cn/stephen12/icecola/component/dictionary/model/DictWrapper.java: -------------------------------------------------------------------------------- 1 | package cn.stephen12.icecola.component.dictionary.model; 2 | 3 | 4 | 5 | 6 | 7 | import cn.stephen12.icecola.component.utils.ClassUtil; 8 | 9 | import java.util.Collection; 10 | 11 | /** 12 | * 枚举包装器 13 | * 14 | * @author ouyangsheng 15 | * @date 2022-04-24 16 | **/ 17 | public interface DictWrapper

{ 18 | 19 | /** 20 | * 设置包装原型类 21 | * 当实现类未指定具体泛型参数时,需要覆盖此方法 22 | * 23 | * @param prototypeClass 24 | */ 25 | default void setPrototypeClass(Class

prototypeClass) { 26 | } 27 | 28 | /** 29 | * 获取包装原型类 30 | * 当实现类未指定具体泛型参数时,需要覆盖此方法 31 | * 32 | * @return 33 | */ 34 | default Class

getPrototypeClass(){ 35 | return (Class

) ClassUtil.getSuperClassGenericType(this.getClass(), DictWrapper.class, 0); 36 | } 37 | 38 | /** 39 | * 包装值 40 | * 41 | * @return 42 | */ 43 | Collection getDictionaries(); 44 | } 45 | -------------------------------------------------------------------------------- /ice-cola-components/component-mock/src/main/java/cn/stephen12/icecola/component/mock/MockAutoConfiguration.java: -------------------------------------------------------------------------------- 1 | package cn.stephen12.icecola.component.mock; 2 | 3 | import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; 4 | import org.springframework.context.annotation.Bean; 5 | import org.springframework.context.annotation.Configuration; 6 | import org.springframework.context.annotation.EnableAspectJAutoProxy; 7 | import uk.co.jemos.podam.api.PodamFactory; 8 | import uk.co.jemos.podam.api.PodamFactoryImpl; 9 | 10 | /** 11 | * @author ouys 12 | */ 13 | @Configuration(proxyBeanMethods = false) 14 | @EnableAspectJAutoProxy 15 | @ConditionalOnProperty(prefix = "ice-cola.component.mock", name = "enabled", havingValue = "true") 16 | public class MockAutoConfiguration { 17 | 18 | @Bean 19 | public PodamFactory podamFactory() { 20 | return new PodamFactoryImpl(); 21 | } 22 | 23 | @Bean 24 | public MockResponseAspect mockResponseAspect() { 25 | return new MockResponseAspect(); 26 | } 27 | 28 | } 29 | -------------------------------------------------------------------------------- /ice-cola-components/component-office/src/main/java/cn/stephen12/icecola/component/office/excel/annotation/ExportExcel.java: -------------------------------------------------------------------------------- 1 | package cn.stephen12.icecola.component.office.excel.annotation; 2 | 3 | 4 | import cn.stephen12.icecola.framework.model.unpacker.DefaultUnpacker; 5 | import cn.stephen12.icecola.framework.model.unpacker.Unpacker; 6 | 7 | import java.lang.annotation.*; 8 | 9 | /** 10 | * 导出Excel注解 11 | * 12 | * @author ouyangsheng 13 | * @since 2021-03-31 14 | */ 15 | @Documented 16 | @Retention(RetentionPolicy.RUNTIME) 17 | @Target({ElementType.METHOD}) 18 | public @interface ExportExcel { 19 | 20 | /** 21 | * 导出文件名 22 | * 23 | * @param 24 | */ 25 | String fileName() default "excel1"; 26 | 27 | /** 28 | * 导出Shell名 29 | * 30 | * @param 31 | * @return {@link String} 导出Shell名 32 | */ 33 | String shellName() default "shell1"; 34 | 35 | /** 36 | * 转换器方法 37 | * @return 38 | */ 39 | Class unpacker() default DefaultUnpacker.class; 40 | 41 | } 42 | -------------------------------------------------------------------------------- /ice-cola-example/example-mall-server/example-mall-server-adapter/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | example-mall-server 7 | cn.stephen12.icecola 8 | 1.0.6-SNAPSHOT 9 | 10 | 4.0.0 11 | 12 | example-mall-server-adapter 13 | 14 | 15 | 16 | org.springframework.boot 17 | spring-boot-starter-web 18 | 19 | 20 | org.springframework.boot 21 | spring-boot-starter-web 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /ice-cola-example/example-mall-server/example-mall-server-bootstrap/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | example-mall-server 7 | cn.stephen12.icecola 8 | 1.0.6-SNAPSHOT 9 | 10 | 4.0.0 11 | 12 | example-mall-server-bootstrap 13 | 14 | 15 | 16 | org.springframework.boot 17 | spring-boot-starter-web 18 | 19 | 20 | org.springframework.boot 21 | spring-boot-starter-undertow 22 | 23 | 24 | -------------------------------------------------------------------------------- /ice-cola-framework/framework-core-app/src/main/java/cn/stephen12/icecola/framework/app/DomainEventListener.java: -------------------------------------------------------------------------------- 1 | package cn.stephen12.icecola.framework.app; 2 | 3 | import cn.stephen12.icecola.framework.core.domain.model.DomainEvent; 4 | import org.springframework.context.ApplicationListener; 5 | import org.springframework.context.PayloadApplicationEvent; 6 | 7 | /** 8 | * 领域事件监听器 9 | * @author ouyangsheng 10 | * @date 2022-05-13 11 | * 12 | * @see DomainEvent 13 | * @see org.springframework.context.ApplicationEventPublisher 14 | * @see ApplicationListener 15 | **/ 16 | public interface DomainEventListener extends ApplicationListener> { 17 | 18 | /** 19 | * 监听Spring 事件 20 | * @param event 21 | */ 22 | @Override 23 | default void onApplicationEvent(PayloadApplicationEvent event){ 24 | DE payload = event.getPayload(); 25 | onDomainEvent(payload); 26 | } 27 | 28 | /** 29 | * 领域事件监听 30 | * @param event 31 | */ 32 | void onDomainEvent(DE event); 33 | } 34 | -------------------------------------------------------------------------------- /ice-cola-framework/framework-core-exception/src/main/java/cn/stephen12/icecola/framework/exception/ErrorCodeBizException.java: -------------------------------------------------------------------------------- 1 | package cn.stephen12.icecola.framework.exception; 2 | 3 | import cn.stephen12.icecola.framework.model.dto.ErrorCodeEnumI; 4 | import com.alibaba.cola.exception.BizException; 5 | import lombok.Getter; 6 | 7 | 8 | /** 9 | * 枚举错误码异常 10 | * @author ouyangsheng 11 | * @date 2022-05-26 12 | **/ 13 | @Getter 14 | public class ErrorCodeBizException extends BizException { 15 | private final ErrorCodeEnumI codeEnum; 16 | private final Integer code; 17 | private final String msg; 18 | 19 | public ErrorCodeBizException(ErrorCodeEnumI codeEnum){ 20 | super(codeEnum.getName()); 21 | this.codeEnum = codeEnum; 22 | this.code = codeEnum.getCode(); 23 | this.msg = codeEnum.getMessage(); 24 | } 25 | 26 | public ErrorCodeBizException(ErrorCodeEnumI codeEnum, String msg){ 27 | super(msg); 28 | this.codeEnum = codeEnum; 29 | this.code = codeEnum.getCode(); 30 | this.msg = msg; 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /ice-cola-components/component-utils/src/main/java/cn/stephen12/icecola/component/utils/number/OpenInternal.java: -------------------------------------------------------------------------------- 1 | package cn.stephen12.icecola.component.utils.number; 2 | 3 | import java.math.BigDecimal; 4 | 5 | /** 6 | * 开区间 7 | *
8 | * { a < x < b } 9 | *
10 | * ------a-----------------b-----> x 11 | *

12 | *
13 | * 14 | * @author ouyangsheng 15 | * @since 2022-05-24 16 | */ 17 | public class OpenInternal extends Internal { 18 | public OpenInternal(BigDecimal left, BigDecimal right) { 19 | super(left, right); 20 | } 21 | 22 | /** 23 | * 是否在此开区间内 24 | * if min < num < max 25 | * @param num 校验参数 26 | * @return 如果在此区间内 返回 true, 否则返回false 27 | **/ 28 | @Override 29 | boolean isIn(BigDecimal num) { 30 | 31 | if (num == null) { 32 | return false; 33 | } 34 | // min < x < max 35 | return NumberUtil.isGreater(num, left) && NumberUtil.isLess(num, right); 36 | } 37 | 38 | @Override 39 | public int compareTo(Internal o) { 40 | return 0; 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /ice-cola-components/component-utils/src/main/java/cn/stephen12/icecola/component/utils/number/CloseInternal.java: -------------------------------------------------------------------------------- 1 | package cn.stephen12.icecola.component.utils.number; 2 | 3 | import java.math.BigDecimal; 4 | 5 | /** 6 | * 7 | * 闭区间 8 | *
9 | * { a <= x <= b } 10 | *
11 | * ------a-----------------b-----> x 12 | *

13 | *
14 | * @author ouyangsheng 15 | * @since 2022-05-24 16 | */ 17 | public class CloseInternal extends Internal { 18 | 19 | public CloseInternal(BigDecimal left, BigDecimal right) { 20 | super(left, right); 21 | } 22 | 23 | /** 24 | * 是否在此闭区间内 25 | * if min <= num <= max 26 | * @param num 校验参数 27 | * @return 如果在此区间内 返回 true, 否则返回false 28 | **/ 29 | @Override 30 | public boolean isIn(BigDecimal num) { 31 | if (num == null) { 32 | return false; 33 | } 34 | // min <= x <= max 35 | return NumberUtil.isGreaterOrEqual(num,left) && NumberUtil.isLessOrEqual(num,right); 36 | } 37 | 38 | @Override 39 | public int compareTo(Internal o) { 40 | return 0; 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /ice-cola-components/component-dictionary/src/main/java/cn/stephen12/icecola/component/dictionary/model/DictionaryVO.java: -------------------------------------------------------------------------------- 1 | package cn.stephen12.icecola.component.dictionary.model; 2 | 3 | import com.alibaba.fastjson.annotation.JSONField; 4 | import io.swagger.annotations.ApiModel; 5 | import io.swagger.annotations.ApiModelProperty; 6 | import lombok.AllArgsConstructor; 7 | import lombok.Data; 8 | 9 | /** 10 | * 字典VO 11 | * 12 | * @author ouyangsheng 13 | * @date 2022-03-15 14 | **/ 15 | @ApiModel(value = "DictionaryVO", description = "字典VO") 16 | @AllArgsConstructor 17 | @Data 18 | public class DictionaryVO { 19 | @ApiModelProperty("编码") 20 | @JSONField(name = "value") 21 | private Object code; 22 | 23 | @ApiModelProperty("名称") 24 | @JSONField(name = "label") 25 | private String name; 26 | 27 | public DictionaryVO(Dictionary dictionary) { 28 | this.code = dictionary.getCode(); 29 | this.name = String.valueOf(dictionary.getName()); 30 | } 31 | 32 | public DictionaryVO(Dictionary dictionary, String name) { 33 | this.code = dictionary.getCode(); 34 | this.name = name; 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /ice-cola-framework/framework-core-domain/src/main/java/cn/stephen12/icecola/framework/core/domain/GatewayManager.java: -------------------------------------------------------------------------------- 1 | package cn.stephen12.icecola.framework.core.domain; 2 | 3 | import cn.hutool.core.util.ClassUtil; 4 | import cn.stephen12.icecola.framework.core.domain.model.BaseE; 5 | import com.alibaba.cola.domain.ApplicationContextHelper; 6 | 7 | import java.util.Map; 8 | import java.util.Optional; 9 | 10 | /** 11 | * 各 gateway 管理器 12 | * 13 | * @author ouyangsheng 14 | * @date 2022-03-29 15 | **/ 16 | public class GatewayManager { 17 | 18 | public static > Optional findGatewayByDomainClass(Class domainClass) { 19 | Map beans = ApplicationContextHelper.getApplicationContext().getBeansOfType(BaseGatewayI.class); 20 | for (BaseGatewayI gatewayBean : beans.values()) { 21 | Class typeArgument = ClassUtil.getTypeArgument(gatewayBean.getClass(),0); 22 | if (domainClass.equals(typeArgument)) { 23 | return Optional.of(gatewayBean); 24 | } 25 | } 26 | return Optional.empty(); 27 | } 28 | 29 | 30 | 31 | } 32 | -------------------------------------------------------------------------------- /ice-cola-framework/framework-core-infr/src/main/java/cn/stephen12/icecola/framework/core/infr/id/DefaultIdNoGeneratorImpl.java: -------------------------------------------------------------------------------- 1 | package cn.stephen12.icecola.framework.core.infr.id; 2 | 3 | import cn.hutool.core.util.IdUtil; 4 | import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; 5 | 6 | /** 7 | * 默认IdNo生成器 8 | * 9 | * @author ouyangsheng 10 | * @date 2022-09-14 11 | **/ 12 | @ConditionalOnMissingBean(IdNoGenerator.class) 13 | public class DefaultIdNoGeneratorImpl implements IdNoGenerator{ 14 | 15 | /** 16 | * 生成Id 17 | *

18 | * 注意: 本方法无法生成分布式ID,如有分布式场景,建议自行实现或使用 distributed组件 19 | *

20 | * 21 | * @param tag 22 | * @return 23 | */ 24 | @Override 25 | public Long generateId(String tag){ 26 | return IdUtil.createSnowflake(1,1).nextId(); 27 | } 28 | 29 | /** 30 | * 生成 no 31 | *

32 | * 注意: 本方法无法生成分布式编号,如有分布式场景,建议自行实现或使用 distributed组件 33 | *

34 | * @param tag 35 | * @return 36 | */ 37 | @Override 38 | public String generateNo(String tag){ 39 | return IdUtil.fastUUID(); 40 | } 41 | 42 | } 43 | -------------------------------------------------------------------------------- /ice-cola-framework/framework-core-infr/src/main/java/cn/stephen12/icecola/framework/core/infr/jpa/LocalDateTimeToLongConvertor.java: -------------------------------------------------------------------------------- 1 | package cn.stephen12.icecola.framework.core.infr.jpa; 2 | 3 | import javax.persistence.AttributeConverter; 4 | import javax.persistence.Converter; 5 | import java.sql.Timestamp; 6 | import java.time.LocalDateTime; 7 | import java.time.ZoneOffset; 8 | 9 | /** 10 | * @author xiongliuyang 11 | * @version 1.0 12 | * @date 2022/3/17 13 | */ 14 | @Converter(autoApply = true) 15 | public class LocalDateTimeToLongConvertor implements AttributeConverter { 16 | 17 | @Override 18 | public Long convertToDatabaseColumn(LocalDateTime locDateTime) { 19 | if (locDateTime == null) { 20 | return 0L; 21 | } 22 | return locDateTime.toInstant(ZoneOffset.of("+8")).toEpochMilli(); 23 | } 24 | 25 | @Override 26 | public LocalDateTime convertToEntityAttribute(Long sqlTimestamp) { 27 | if (sqlTimestamp == null || sqlTimestamp == 0L) { 28 | return null; 29 | } 30 | return new Timestamp(sqlTimestamp).toLocalDateTime(); 31 | } 32 | } 33 | 34 | -------------------------------------------------------------------------------- /ice-cola-components/component-dictionary/src/main/java/cn/stephen12/icecola/component/dictionary/model/Dict.java: -------------------------------------------------------------------------------- 1 | package cn.stephen12.icecola.component.dictionary.model; 2 | 3 | import java.io.Serializable; 4 | import java.lang.reflect.Method; 5 | import java.lang.reflect.Type; 6 | 7 | /** 8 | * 顶层字典接口 9 | * 10 | * @author ouyangsheng 11 | * @date 2022-03-18 12 | **/ 13 | public interface Dict> { 14 | /** 15 | * 字典Key 16 | * 17 | * @return 18 | */ 19 | C getCode(); 20 | 21 | /** 22 | * 字典名称(中文) 23 | * 24 | * @return 25 | */ 26 | N getName(); 27 | 28 | /** 29 | * 获取Code()方法的类型 30 | * @param clazz 31 | * @return 32 | */ 33 | static Type getCodeType(Class clazz){ 34 | try { 35 | Method getCodeMethod = clazz.getMethod("getCode"); 36 | return getCodeMethod.getReturnType(); 37 | } catch (NoSuchMethodException e) { 38 | throw new IllegalStateException("The class["+clazz.getName()+"] must implement interface Dict",e); 39 | } 40 | } 41 | 42 | } 43 | -------------------------------------------------------------------------------- /ice-cola-framework/framework-core-app/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | cn.stephen12.icecola 7 | ice-cola-framework 8 | 1.0.6-SNAPSHOT 9 | 10 | 4.0.0 11 | 12 | framework-core-app 13 | 14 | 15 | org.springframework 16 | spring-context 17 | 18 | 19 | cn.stephen12.icecola 20 | framework-core-domain 21 | 22 | 23 | javax.validation 24 | validation-api 25 | 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /ice-cola-components/component-office/src/main/java/cn/stephen12/icecola/component/office/excel/model/ExcelVO.java: -------------------------------------------------------------------------------- 1 | package cn.stephen12.icecola.component.office.excel.model; 2 | 3 | import lombok.Data; 4 | 5 | import java.util.ArrayList; 6 | import java.util.Collection; 7 | import java.util.List; 8 | 9 | /** 10 | * Excel 输出结果 11 | *

12 | * 如果使用此VO输出,则会优先使用此VO中的文件名和sheetName 13 | *

14 | * 15 | * @author ouyangsheng 16 | * @date 2022-06-06 17 | **/ 18 | @Data 19 | public class ExcelVO { 20 | /** 21 | * 文件名 22 | */ 23 | private String fileName; 24 | 25 | /** 26 | * sheet名 27 | */ 28 | private String sheetName; 29 | /** 30 | * 记录 31 | */ 32 | private List rows; 33 | 34 | /** 35 | * 构造实例 36 | * @param rows 37 | * @param fileName 38 | * @param sheetName 39 | * @param 40 | * @return 41 | */ 42 | public static ExcelVO instance(Collection rows, String fileName, String sheetName) { 43 | ExcelVO instance = new ExcelVO<>(); 44 | instance.setFileName(fileName); 45 | instance.setSheetName(sheetName); 46 | instance.setRows(new ArrayList<>(rows)); 47 | return instance; 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /ice-cola-framework/framework-core-model/src/main/java/cn/stephen12/icecola/framework/model/unpacker/DefaultUnpacker.java: -------------------------------------------------------------------------------- 1 | package cn.stephen12.icecola.framework.model.unpacker; 2 | 3 | import cn.stephen12.icecola.framework.model.dto.AsCollection; 4 | import cn.stephen12.icecola.framework.model.vo.RestResult; 5 | 6 | import java.util.ArrayList; 7 | import java.util.Collection; 8 | import java.util.Collections; 9 | import java.util.List; 10 | 11 | /** 12 | * 默认拆包器 13 | * 14 | * @author ouyangsheng 15 | * @date 2022-03-31 16 | **/ 17 | public class DefaultUnpacker implements Unpacker{ 18 | 19 | @Override 20 | public List unpack(Object returnObj) { 21 | if(returnObj instanceof List){ 22 | return (List) returnObj; 23 | }else if(returnObj instanceof Collection){ 24 | return new ArrayList<>((Collection) returnObj); 25 | } else if(returnObj instanceof AsCollection) { 26 | return new ArrayList<>(((AsCollection)returnObj).toCollection()); 27 | } else if(returnObj instanceof RestResult){ 28 | Object data = ((RestResult) returnObj).getData(); 29 | return unpack(data); 30 | } 31 | return Collections.emptyList(); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /ice-cola-components/component-office/src/main/java/cn/stephen12/icecola/component/office/excel/ExcelContext.java: -------------------------------------------------------------------------------- 1 | package cn.stephen12.icecola.component.office.excel; 2 | 3 | import java.util.ArrayList; 4 | import java.util.Collection; 5 | import java.util.HashSet; 6 | import java.util.List; 7 | import java.util.Set; 8 | 9 | /** 10 | * Excel 导入导出上下文 11 | * 12 | * @author ouyangsheng 13 | * @date 2022-06-06 14 | **/ 15 | public class ExcelContext { 16 | 17 | private static final ThreadLocal> excludedFieldsThreadLocal = new ThreadLocal<>(); 18 | 19 | /** 20 | * 排除某些列 21 | * 22 | * @param fields 23 | */ 24 | public static void excludeFields(Collection fields) { 25 | if (excludedFieldsThreadLocal.get() == null) { 26 | excludedFieldsThreadLocal.set(new HashSet<>(16)); 27 | } 28 | 29 | excludedFieldsThreadLocal.get().addAll(fields); 30 | } 31 | 32 | /** 33 | * 获取所有需要导出的列 34 | * 35 | * @return 36 | */ 37 | public static List getExcludedFields() { 38 | 39 | return new ArrayList<>(); 40 | } 41 | 42 | /** 43 | * 清理 44 | */ 45 | public static void clear() { 46 | excludedFieldsThreadLocal.remove(); 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /ice-cola-framework/framework-core-infr/src/main/java/cn/stephen12/icecola/framework/core/infr/jpa/LocalDateToLongConvertor.java: -------------------------------------------------------------------------------- 1 | package cn.stephen12.icecola.framework.core.infr.jpa; 2 | 3 | import javax.persistence.AttributeConverter; 4 | import javax.persistence.Converter; 5 | import java.sql.Timestamp; 6 | import java.time.LocalDate; 7 | import java.time.LocalDateTime; 8 | import java.time.LocalTime; 9 | import java.time.ZoneOffset; 10 | 11 | /** 12 | * @author xiongliuyang 13 | * @version 1.0 14 | * @date 2022/3/17 15 | */ 16 | @Converter(autoApply = true) 17 | public class LocalDateToLongConvertor implements AttributeConverter { 18 | 19 | @Override 20 | public Long convertToDatabaseColumn(LocalDate localDate) { 21 | if (localDate == null) { 22 | return 0L; 23 | } 24 | LocalDateTime localDateTime = LocalDateTime.of(localDate, LocalTime.MIN); 25 | return localDateTime.toInstant(ZoneOffset.of("+8")).toEpochMilli(); 26 | } 27 | 28 | @Override 29 | public LocalDate convertToEntityAttribute(Long sqlTimestamp) { 30 | if(sqlTimestamp == null || sqlTimestamp == 0L){ 31 | return null; 32 | } 33 | return new Timestamp(sqlTimestamp).toLocalDateTime().toLocalDate(); 34 | } 35 | } 36 | 37 | -------------------------------------------------------------------------------- /ice-cola-components/component-dictionary/src/main/java/cn/stephen12/icecola/component/dictionary/fastjson/DictionaryObjSerializer.java: -------------------------------------------------------------------------------- 1 | package cn.stephen12.icecola.component.dictionary.fastjson; 2 | 3 | import cn.stephen12.icecola.component.dictionary.model.Dictionary; 4 | import com.alibaba.fastjson.serializer.JSONSerializer; 5 | import com.alibaba.fastjson.serializer.ObjectSerializer; 6 | import com.alibaba.fastjson.serializer.SerializeWriter; 7 | 8 | import java.lang.reflect.Type; 9 | 10 | /** 11 | * 字典对象输出序列化 12 | * 13 | * @author jiangxinjun 14 | * @date 2020/06/03 15 | */ 16 | public class DictionaryObjSerializer implements ObjectSerializer { 17 | 18 | static final DictionaryObjSerializer INSTANCE = new DictionaryObjSerializer(); 19 | 20 | @Override 21 | public void write(JSONSerializer jsonSerializer, Object object, Object fieldName, Type fieldType, int features) { 22 | SerializeWriter out = jsonSerializer.getWriter(); 23 | if (object == null) { 24 | out.writeNull(); 25 | return; 26 | } 27 | Dictionary dictionary = (Dictionary) object; 28 | out.writeFieldValue('{',"code",String.valueOf(dictionary.getCode())); 29 | out.writeFieldValue(',',"name",String.valueOf(dictionary.getName())); 30 | out.write('}'); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /ice-cola-framework/framework-core-app/src/main/java/cn/stephen12/icecola/framework/app/AppServiceSupport.java: -------------------------------------------------------------------------------- 1 | package cn.stephen12.icecola.framework.app; 2 | 3 | import cn.stephen12.icecola.framework.core.domain.BaseGatewayI; 4 | import cn.stephen12.icecola.framework.core.domain.model.BaseAggregateRoot; 5 | import org.springframework.beans.factory.annotation.Autowired; 6 | import org.springframework.context.ApplicationContext; 7 | 8 | /** 9 | * AppService 能力支持 10 | * 11 | * @author ouyangsheng 12 | * @date 2022-03-20 13 | * @see IAppService 14 | **/ 15 | public abstract class AppServiceSupport> implements IAppService { 16 | 17 | @Autowired 18 | protected BaseGatewayI baseGatewayI; 19 | 20 | @Autowired 21 | protected ApplicationContext applicationContext; 22 | 23 | 24 | /** 25 | * 执行修改并保存 26 | * 27 | * @param id 28 | */ 29 | protected D getDomain(Long id) { 30 | return baseGatewayI.findDomainById(id).orElseThrow(() -> new IllegalArgumentException("数据不存在")); 31 | } 32 | 33 | /** 34 | * 获取命令执行器 35 | * 36 | * @param clazz 37 | * @param 38 | * @return 39 | */ 40 | protected T getCmdExecutor(Class clazz) { 41 | return applicationContext.getBean(clazz); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /ice-cola-framework/framework-core-domain/src/main/java/cn/stephen12/icecola/framework/core/domain/BaseGatewayI.java: -------------------------------------------------------------------------------- 1 | package cn.stephen12.icecola.framework.core.domain; 2 | 3 | import cn.stephen12.icecola.framework.core.domain.model.BaseAggregateRoot; 4 | import cn.stephen12.icecola.framework.core.domain.model.DomainEvent; 5 | 6 | /** 7 | * 基础的gateway接口 8 | * 9 | * @author ouyangsheng 10 | * @date 2022-03-22 11 | **/ 12 | public interface BaseGatewayI> extends PersistenceI { 13 | 14 | /** 15 | * 推送事件 16 | * 17 | * @param eventObj 18 | */ 19 | void publishEvent(DE eventObj); 20 | 21 | /** 22 | * 推送事件并且不关注结果,不受事件异常引响 23 | * 24 | * @param eventObj 25 | */ 26 | void publishAndIgnoreEvent(DE eventObj); 27 | 28 | /** 29 | * 生成ID 30 | * @return 31 | */ 32 | Long generateId(); 33 | 34 | /** 35 | * 生成编号 36 | * @return 37 | */ 38 | String generateNo(); 39 | 40 | 41 | /** 42 | * 生成ID 43 | * @param domainClass 44 | * @return 45 | */ 46 | Long generateId(Class domainClass); 47 | 48 | /** 49 | * 生成全局编号 50 | * @param domainClass 51 | * @return 52 | */ 53 | String generateNo(Class domainClass); 54 | } 55 | -------------------------------------------------------------------------------- /ice-cola-components/component-dictionary/src/main/java/cn/stephen12/icecola/component/dictionary/model/Dictionary.java: -------------------------------------------------------------------------------- 1 | package cn.stephen12.icecola.component.dictionary.model; 2 | 3 | import java.io.Serializable; 4 | import java.util.Objects; 5 | import java.util.Optional; 6 | 7 | /** 8 | *

9 | * 通用字典接口 10 | *

11 | * 12 | * @author ouyangsheng 13 | * @date 2022-03-08 14 | **/ 15 | public interface Dictionary> extends Dict { 16 | 17 | /** 18 | * 获取枚举字段 19 | * 20 | * @param clazz 21 | * @param code 22 | * @param 23 | * @param 24 | * @param 25 | * @return 26 | */ 27 | static & Dictionary> Optional getByCode(Class clazz, Object code) { 28 | E[] enumList = clazz.getEnumConstants(); 29 | for (E e : enumList) { 30 | if (Objects.equals(code, e.getCode())) { 31 | return Optional.of(e); 32 | } 33 | } 34 | return Optional.empty(); 35 | } 36 | 37 | /** 38 | * 枚举Code ToString 方法,会用于判断两个枚举是否相等 39 | * 40 | * @return 41 | */ 42 | default String codeToStr() { 43 | return String.valueOf(getCode()); 44 | } 45 | 46 | } 47 | -------------------------------------------------------------------------------- /ice-cola-components/component-utils/src/main/java/cn/stephen12/icecola/component/utils/fastjson/LongToLocalDateTimeDeserializer.java: -------------------------------------------------------------------------------- 1 | package cn.stephen12.icecola.component.utils.fastjson; 2 | 3 | import com.alibaba.fastjson.parser.DefaultJSONParser; 4 | import com.alibaba.fastjson.parser.deserializer.ObjectDeserializer; 5 | 6 | import java.lang.reflect.Type; 7 | import java.time.LocalDateTime; 8 | import java.time.ZoneOffset; 9 | 10 | /** 11 | * 将时间戳反序列化为LocalDateTime 12 | * 13 | * @author ouyangsheng 14 | * @date 2022-03-17 15 | */ 16 | public class LongToLocalDateTimeDeserializer implements ObjectDeserializer { 17 | public static final LongToLocalDateTimeDeserializer INSTANCE = new LongToLocalDateTimeDeserializer(); 18 | 19 | @Override 20 | public LocalDateTime deserialze(DefaultJSONParser defaultJSONParser, Type type, Object o) { 21 | Long timestamp = defaultJSONParser.parseObject(Long.class); 22 | if (timestamp == null) { 23 | return null; 24 | } 25 | return convertLongToLocalDateTime(timestamp); 26 | } 27 | 28 | @Override 29 | public int getFastMatchToken() { 30 | return 0; 31 | } 32 | 33 | private LocalDateTime convertLongToLocalDateTime(Long timestamp) { 34 | return LocalDateTime.ofEpochSecond(timestamp / 1000, 0, ZoneOffset.ofHours(8)); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /ice-cola-components/component-utils/src/main/java/cn/stephen12/icecola/component/utils/fastjson/LongToLocalDateDeserializer.java: -------------------------------------------------------------------------------- 1 | package cn.stephen12.icecola.component.utils.fastjson; 2 | 3 | import com.alibaba.fastjson.parser.DefaultJSONParser; 4 | import com.alibaba.fastjson.parser.deserializer.ObjectDeserializer; 5 | 6 | import java.lang.reflect.Type; 7 | import java.time.LocalDate; 8 | import java.time.LocalDateTime; 9 | import java.time.ZoneOffset; 10 | 11 | /** 12 | * 将时间戳反序列化为LocalDate 13 | * 14 | * @author ouyangsheng 15 | * @date 2022-03-17 16 | */ 17 | public class LongToLocalDateDeserializer implements ObjectDeserializer { 18 | public static final LongToLocalDateDeserializer INSTANCE = new LongToLocalDateDeserializer(); 19 | 20 | @Override 21 | public LocalDate deserialze(DefaultJSONParser defaultJSONParser, Type type, Object o) { 22 | Long timestamp = defaultJSONParser.parseObject(Long.class); 23 | if (timestamp == null) { 24 | return null; 25 | } 26 | return convertLongToLocalDate(timestamp); 27 | } 28 | 29 | @Override 30 | public int getFastMatchToken() { 31 | return 0; 32 | } 33 | 34 | private LocalDate convertLongToLocalDate(Long timestamp) { 35 | return LocalDateTime.ofEpochSecond(timestamp / 1000, 0, ZoneOffset.ofHours(8)).toLocalDate(); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /ice-cola-components/component-utils/src/main/java/cn/stephen12/icecola/component/utils/fastjson/LocalDateTimeToLongSerializer.java: -------------------------------------------------------------------------------- 1 | package cn.stephen12.icecola.component.utils.fastjson; 2 | 3 | import com.alibaba.fastjson.serializer.JSONSerializer; 4 | import com.alibaba.fastjson.serializer.ObjectSerializer; 5 | import com.alibaba.fastjson.serializer.SerializeWriter; 6 | 7 | import java.lang.reflect.Type; 8 | import java.time.LocalDateTime; 9 | import java.time.ZoneOffset; 10 | 11 | /** 12 | * BigDecimal格式化 13 | * 14 | * @author jiangxinjun 15 | * @date 2020/06/03 16 | */ 17 | public class LocalDateTimeToLongSerializer implements ObjectSerializer { 18 | public static final LocalDateTimeToLongSerializer INSTANCE = new LocalDateTimeToLongSerializer(); 19 | 20 | @Override 21 | public void write(JSONSerializer jsonSerializer, Object object, Object fieldName, Type fieldType, int features) { 22 | SerializeWriter out = jsonSerializer.getWriter(); 23 | if (object == null) { 24 | out.writeNull(); 25 | return; 26 | } 27 | Long timestamp = convertLocalDateTimeToLong((LocalDateTime) object); 28 | out.writeLong(timestamp); 29 | } 30 | 31 | private Long convertLocalDateTimeToLong(LocalDateTime localDateTime){ 32 | return localDateTime.toInstant(ZoneOffset.of("+8")).toEpochMilli(); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /ice-cola-components/component-dictionary/src/main/java/cn/stephen12/icecola/component/dictionary/model/DefaultDictWrapper.java: -------------------------------------------------------------------------------- 1 | package cn.stephen12.icecola.component.dictionary.model; 2 | 3 | import lombok.Getter; 4 | import lombok.Setter; 5 | import lombok.extern.slf4j.Slf4j; 6 | 7 | import java.util.Arrays; 8 | import java.util.Collections; 9 | import java.util.List; 10 | import java.util.stream.Collectors; 11 | 12 | /** 13 | * 枚举包装器 14 | * 15 | * @author ouyangsheng 16 | * @date 2022-04-24 17 | **/ 18 | @Slf4j 19 | public class DefaultDictWrapper implements DictWrapper { 20 | @Setter 21 | @Getter 22 | private Class prototypeClass; 23 | 24 | /** 25 | * 包装值 26 | * 27 | * @return 28 | */ 29 | @Override 30 | public List getDictionaries() { 31 | if (prototypeClass.isEnum()) { 32 | return Arrays.stream(prototypeClass.getEnumConstants()).map(e -> { 33 | //如果枚举有实现 ToDictionaryVO 34 | if (ToDictionaryVO.class.isAssignableFrom(prototypeClass)) { 35 | return ((ToDictionaryVO) e).toDictionaryVO(); 36 | } 37 | return new DictionaryVO((Dictionary) e); 38 | }).collect(Collectors.toList()); 39 | } 40 | log.error("Error: the prototype class is not a enum."); 41 | return Collections.EMPTY_LIST; 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /ice-cola-framework/framework-core-infr/src/main/java/cn/stephen12/icecola/framework/core/infr/repository/PaddingRepositoryWrapper.java: -------------------------------------------------------------------------------- 1 | package cn.stephen12.icecola.framework.core.infr.repository; 2 | 3 | /** 4 | * DataPadding功能的增强 5 | * 6 | * @param 统一的承载对象 7 | * @author ouyangsheng 8 | * @date 2022-05-23 9 | **/ 10 | //public interface PaddingRepositoryWrapper extends RepositoryWrapper, QueryCache { 11 | // 12 | // /** 13 | // * 默认获取Id的策略 14 | // * 15 | // * @param entity 16 | // * @return 17 | // */ 18 | // @Override 19 | // default Long getIdOf(E entity) { 20 | // if (entity instanceof IdV) { 21 | // return ((IdV) entity).obtainId(); 22 | // } else if (entity instanceof BaseV) { 23 | // return ((BaseV) entity).getId(); 24 | // } else { 25 | // return BeanUtil.getProperty(entity, "id"); 26 | // } 27 | // } 28 | // 29 | // /** 30 | // * 自动填充函数 31 | // * 32 | // * @param ids 33 | // * @return 34 | // */ 35 | // @Override 36 | // default Map getCacheById(Set ids) { 37 | // if (CollectionUtils.isEmpty(ids)) { 38 | // return Collections.emptyMap(); 39 | // } 40 | // return this.findByIds(ids).stream().collect(Collectors.toMap(e -> getIdOf(e), Function.identity(), (pre, curr) -> pre)); 41 | // } 42 | //} 43 | -------------------------------------------------------------------------------- /ice-cola-components/component-dictionary/src/main/java/cn/stephen12/icecola/component/dictionary/fastjson/FastJsonSettingHelper.java: -------------------------------------------------------------------------------- 1 | package cn.stephen12.icecola.component.dictionary.fastjson; 2 | 3 | import cn.stephen12.icecola.component.dictionary.DictionaryManager; 4 | import cn.stephen12.icecola.component.dictionary.autoconfig.DictionaryScannedHandlers; 5 | import com.alibaba.fastjson.parser.ParserConfig; 6 | import com.alibaba.fastjson.serializer.SerializeConfig; 7 | import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; 8 | import org.springframework.stereotype.Component; 9 | 10 | /** 11 | * 序列化、反序列化器注册 12 | * 13 | * @author ouyangsheng 14 | * @date 2022-03-17 15 | **/ 16 | @ConditionalOnClass(ParserConfig.class) 17 | @Component 18 | public class FastJsonSettingHelper implements DictionaryScannedHandlers.Handler { 19 | 20 | @Override 21 | public void handle(DictionaryManager dictionaryManager) { 22 | dictionaryManager.getAllEnums().stream().forEach(this::setting); 23 | } 24 | 25 | private void setting(Class clazz) { 26 | ParserConfig parserConfig = ParserConfig.getGlobalInstance(); 27 | SerializeConfig serializeConfig = SerializeConfig.getGlobalInstance(); 28 | 29 | serializeConfig.put(clazz, DictionaryCodeSerializer.INSTANCE); 30 | parserConfig.putDeserializer(clazz, DictionaryDeserializer.INSTANCE); 31 | } 32 | 33 | } 34 | -------------------------------------------------------------------------------- /ice-cola-framework/framework-core-infr/src/main/java/cn/stephen12/icecola/framework/core/infr/context/RequestContextCacheManager.java: -------------------------------------------------------------------------------- 1 | package cn.stephen12.icecola.framework.core.infr.context; 2 | 3 | import org.springframework.cache.Cache; 4 | import org.springframework.cache.CacheManager; 5 | import org.springframework.cache.concurrent.ConcurrentMapCache; 6 | import org.springframework.stereotype.Component; 7 | 8 | import java.util.Collection; 9 | import java.util.Map; 10 | import java.util.concurrent.ConcurrentHashMap; 11 | 12 | /** 13 | * 请求上下文(基于线程变量)缓存管理器 14 | * 15 | * @author ouyangsheng 16 | * @date 2022-06-24 17 | **/ 18 | @Component 19 | public class RequestContextCacheManager implements CacheManager { 20 | private final static String CACHE_MAP_KEY = "REQUEST_CONTEXT_CACHE_MAP"; 21 | 22 | @Override 23 | public Cache getCache(String name) { 24 | //获取全部Cache对象 25 | Map cacheMap = getCacheMap(); 26 | 27 | //如果已存在则获取,不存在则新建 28 | return cacheMap.computeIfAbsent(name, key -> new ConcurrentMapCache(key, true)); 29 | } 30 | 31 | @Override 32 | public Collection getCacheNames() { 33 | return getCacheMap().keySet(); 34 | } 35 | 36 | /** 37 | * Map 装载 当前请求 所有有效的缓存 38 | * @return 39 | */ 40 | private Map getCacheMap() { 41 | return RequestContext.computeIfAbsent(CACHE_MAP_KEY, key -> new ConcurrentHashMap<>(16)); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /ice-cola-components/component-utils/src/main/java/cn/stephen12/icecola/component/utils/fastjson/LocalDateToLongSerializer.java: -------------------------------------------------------------------------------- 1 | package cn.stephen12.icecola.component.utils.fastjson; 2 | 3 | import com.alibaba.fastjson.serializer.JSONSerializer; 4 | import com.alibaba.fastjson.serializer.ObjectSerializer; 5 | import com.alibaba.fastjson.serializer.SerializeWriter; 6 | 7 | import java.lang.reflect.Type; 8 | import java.time.LocalDate; 9 | import java.time.LocalDateTime; 10 | import java.time.LocalTime; 11 | import java.time.ZoneOffset; 12 | 13 | /** 14 | * 将LocalDate序列化为时间戳 15 | * 16 | * @author ouyangsheng 17 | * @since 2022-03-17 18 | */ 19 | public class LocalDateToLongSerializer implements ObjectSerializer { 20 | public static final LocalDateToLongSerializer INSTANCE = new LocalDateToLongSerializer(); 21 | 22 | @Override 23 | public void write(JSONSerializer jsonSerializer, Object object, Object fieldName, Type fieldType, int features) { 24 | SerializeWriter out = jsonSerializer.getWriter(); 25 | if (object == null) { 26 | out.writeNull(); 27 | return; 28 | } 29 | Long timestamp = convertLocalDateToLong((LocalDate) object); 30 | out.writeLong(timestamp); 31 | } 32 | 33 | 34 | private Long convertLocalDateToLong(LocalDate localDate){ 35 | LocalDateTime localDateTime = LocalDateTime.of(localDate, LocalTime.MIN); 36 | return localDateTime.toInstant(ZoneOffset.of("+8")).toEpochMilli(); 37 | } 38 | 39 | } 40 | -------------------------------------------------------------------------------- /ice-cola-components/component-dictionary/src/main/java/cn/stephen12/icecola/component/dictionary/fastjson/DictionaryDeserializer.java: -------------------------------------------------------------------------------- 1 | package cn.stephen12.icecola.component.dictionary.fastjson; 2 | 3 | import cn.stephen12.icecola.component.dictionary.model.Dictionary; 4 | import com.alibaba.fastjson.parser.DefaultJSONParser; 5 | import com.alibaba.fastjson.parser.deserializer.ObjectDeserializer; 6 | 7 | import java.lang.reflect.Type; 8 | import java.util.Arrays; 9 | import java.util.Objects; 10 | 11 | /** 12 | * BigDecimal格式化 13 | * 14 | * @author jiangxinjun 15 | * @date 2020/06/03 16 | */ 17 | public class DictionaryDeserializer implements ObjectDeserializer { 18 | static final DictionaryDeserializer INSTANCE = new DictionaryDeserializer(); 19 | 20 | @Override 21 | public T deserialze(DefaultJSONParser parser, Type type, Object fieldName) { 22 | Object code = parser.parseObject(Object.class); 23 | Class clazz = (Class) type; 24 | return getByCode(clazz,code); 25 | } 26 | 27 | @Override 28 | public int getFastMatchToken() { 29 | return 0; 30 | } 31 | 32 | private T getByCode(Class clazz ,Object code){ 33 | return Arrays.stream(clazz.getEnumConstants()).filter(item->equalsOrStrEquals(code,((Dictionary)item).getCode())).findFirst().orElse(null); 34 | } 35 | private boolean equalsOrStrEquals(Object a,Object b){ 36 | return Objects.equals(a,b)||Objects.equals(String.valueOf(a),String.valueOf(b)); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /ice-cola-components/component-dictionary/src/main/java/cn/stephen12/icecola/component/dictionary/DictionaryManager.java: -------------------------------------------------------------------------------- 1 | package cn.stephen12.icecola.component.dictionary; 2 | 3 | 4 | import cn.stephen12.icecola.component.dictionary.model.DictWrapper; 5 | import cn.stephen12.icecola.component.dictionary.model.DictionaryVO; 6 | 7 | import java.util.Collection; 8 | import java.util.List; 9 | import java.util.Map; 10 | import java.util.Set; 11 | 12 | /** 13 | * 字典管理器 14 | * 15 | * @author ouyangsheng 16 | * @since 2022-03-14 17 | */ 18 | public interface DictionaryManager { 19 | 20 | /** 21 | * 通用枚举类型获取枚举 22 | * 23 | * @param type 枚举类型 24 | * @return 25 | */ 26 | List listDictByType(String type); 27 | 28 | /** 29 | * 通用枚举类型获取枚举 30 | * 31 | * @param types 枚举类型 32 | * @return 33 | */ 34 | Map> getDictionariesByTypes(Collection types); 35 | 36 | /** 37 | * 注册字典 38 | * 39 | * @param dictClazz 40 | */ 41 | void register(Class dictClazz); 42 | 43 | /** 44 | * 注册字典 45 | * 46 | * @param type 47 | * @param dictClazz 48 | */ 49 | void register(String type, Class dictClazz); 50 | 51 | 52 | /** 53 | * 获取所有枚举 54 | * 55 | * @return type, enumType 56 | */ 57 | Set> getAllEnums(); 58 | 59 | /** 60 | * 获取所有字典 61 | * 62 | * @return 63 | */ 64 | Map getAllDictionaries(); 65 | } 66 | -------------------------------------------------------------------------------- /ice-cola-components/component-utils/src/main/java/cn/stephen12/icecola/component/utils/number/NumberAxis.java: -------------------------------------------------------------------------------- 1 | package cn.stephen12.icecola.component.utils.number; 2 | 3 | import java.math.BigDecimal; 4 | import java.util.ArrayList; 5 | import java.util.Collection; 6 | import java.util.List; 7 | 8 | /** 9 | * 数轴工具类 10 | *

11 | * ----[---a---]--(---b----)----(----c----]-----> 12 | *

13 | * @author ouyangsheng 14 | * @date 2022-05-24 15 | **/ 16 | public class NumberAxis { 17 | /** 18 | * 数轴上的所有区间 19 | */ 20 | private final List internals; 21 | 22 | public NumberAxis(){ 23 | this.internals = new ArrayList<>(); 24 | } 25 | 26 | public NumberAxis(List internals){ 27 | this.internals = internals; 28 | } 29 | /** 30 | * 在数轴上添加区间 31 | * @param internals 32 | */ 33 | public void addInternals(Collection internals){ 34 | internals.addAll(internals); 35 | } 36 | 37 | /** 38 | * 在数轴上添加区间 39 | * @param internal 40 | */ 41 | public void addInternal(T internal){ 42 | internals.add(internal); 43 | } 44 | 45 | /** 46 | * 匹配,看该数落在哪个区间,如果未命中,则返回null 47 | *

48 | * ----[---a---]--(■■■ b ■■■)----(----c----]-----> 49 | *

50 | * @param num 51 | * @return 52 | */ 53 | public T matchInternal(BigDecimal num){ 54 | for(T internal: internals){ 55 | if(internal.isIn(num)){ 56 | return internal; 57 | } 58 | } 59 | return null; 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /ice-cola-framework/framework-core-exception/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | cn.stephen12.icecola 7 | ice-cola-framework 8 | 1.0.6-SNAPSHOT 9 | 10 | 4.0.0 11 | 12 | framework-core-exception 13 | 14 | 15 | 16 | org.projectlombok 17 | lombok 18 | 19 | 20 | org.springframework.boot 21 | spring-boot-starter-web 22 | 23 | 24 | com.alibaba.cola 25 | cola-component-exception 26 | true 27 | 28 | 29 | cn.stephen12.icecola 30 | framework-core-model 31 | true 32 | 33 | 34 | cn.stephen12.icecola 35 | framework-core-model 36 | 37 | 38 | 39 | -------------------------------------------------------------------------------- /ice-cola-components/component-dictionary/src/main/java/cn/stephen12/icecola/component/dictionary/fastjson/DictionaryCodeSerializer.java: -------------------------------------------------------------------------------- 1 | package cn.stephen12.icecola.component.dictionary.fastjson; 2 | 3 | import cn.stephen12.icecola.component.dictionary.model.Dictionary; 4 | import com.alibaba.fastjson.serializer.JSONSerializer; 5 | import com.alibaba.fastjson.serializer.ObjectSerializer; 6 | import com.alibaba.fastjson.serializer.SerializeWriter; 7 | 8 | import java.lang.reflect.Type; 9 | 10 | /** 11 | * 字典编码序列化器 12 | * 13 | * @author ouyangsheng 14 | * @date 2022-03-17 15 | */ 16 | public class DictionaryCodeSerializer implements ObjectSerializer { 17 | 18 | static final DictionaryCodeSerializer INSTANCE = new DictionaryCodeSerializer(); 19 | 20 | @Override 21 | public void write(JSONSerializer jsonSerializer, Object object, Object fieldName, Type fieldType, int features) { 22 | SerializeWriter out = jsonSerializer.getWriter(); 23 | if (object == null) { 24 | out.writeNull(); 25 | return; 26 | } 27 | Dictionary dictionary = (Dictionary) object; 28 | 29 | if (dictionary.getCode() == null) { 30 | out.writeNull(); 31 | } else if (dictionary.getCode() instanceof Number) { 32 | out.writeLong(((Number) dictionary.getCode()).longValue()); 33 | } else if (dictionary.getCode() instanceof CharSequence) { 34 | out.writeString(String.valueOf( dictionary.getCode())); 35 | } else { 36 | out.writeString(String.valueOf(dictionary.getCode())); 37 | } 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /ice-cola-framework/framework-core-infr/src/main/java/cn/stephen12/icecola/framework/core/infr/context/RequestContext.java: -------------------------------------------------------------------------------- 1 | package cn.stephen12.icecola.framework.core.infr.context; 2 | 3 | import java.util.HashMap; 4 | import java.util.Map; 5 | import java.util.function.Function; 6 | import java.util.function.Supplier; 7 | 8 | /** 9 | * 基础设施层,请求上下文 10 | * 11 | * @author ouyangsheng 12 | * @date 2022-05-23 13 | **/ 14 | public class RequestContext { 15 | 16 | private static final ThreadLocal> requestCache = new ThreadLocal<>(); 17 | 18 | static void init() { 19 | requestCache.set(new HashMap<>(16)); 20 | } 21 | 22 | static void clear() { 23 | requestCache.remove(); 24 | } 25 | 26 | /** 27 | * 所有对缓存的操作,需要调用此接口 28 | * @return 29 | */ 30 | static Map getOrInit() { 31 | if (requestCache.get() == null) { 32 | init(); 33 | } 34 | return requestCache.get(); 35 | } 36 | 37 | public static void put(String key, Object value) { 38 | getOrInit().put(key, value); 39 | } 40 | 41 | public static T getObj(String key) { 42 | return (T) getOrInit().get(key); 43 | } 44 | 45 | public static T computeIfAbsent(String key, Function value) { 46 | return (T) getOrInit().computeIfAbsent(key, value); 47 | } 48 | 49 | public static String getString(String key) { 50 | return (String) getOrInit().get(key); 51 | } 52 | 53 | public static Long getLong(String key) { 54 | return (Long) getOrInit().get(key); 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /ice-cola-components/component-office/src/main/java/cn/stephen12/icecola/component/office/excel/handler/ExcelDataHandleDispatcher.java: -------------------------------------------------------------------------------- 1 | package cn.stephen12.icecola.component.office.excel.handler; 2 | 3 | import cn.afterturn.easypoi.handler.impl.ExcelDataHandlerDefaultImpl; 4 | import org.springframework.beans.factory.annotation.Autowired; 5 | import org.springframework.stereotype.Component; 6 | 7 | import java.util.List; 8 | 9 | 10 | /** 11 | * Excel数据处理分发器 12 | * 13 | * @author ouyangsheng 14 | * @since 2022-06-06 15 | */ 16 | @Component 17 | public class ExcelDataHandleDispatcher extends ExcelDataHandlerDefaultImpl { 18 | 19 | @Autowired 20 | private List dataHandlers; 21 | 22 | @Override 23 | public Object exportHandler(Object obj, String name, Object value) { 24 | for (DataHandler dataHandler : dataHandlers) { 25 | if (dataHandler.supported(obj, name, value)) { 26 | return dataHandler.handle(obj, name, value); 27 | } 28 | } 29 | return value; 30 | } 31 | 32 | /** 33 | * Excel 数据处理器 34 | */ 35 | public interface DataHandler { 36 | 37 | /** 38 | * 支持什么类型的数据 39 | * 40 | * @param obj 41 | * @param name 42 | * @param value 43 | * @return 44 | */ 45 | boolean supported(Object obj, String name, Object value); 46 | 47 | /** 48 | * 实际处理 49 | * 50 | * @param obj 51 | * @param name 52 | * @param value 53 | * @return new Value 54 | */ 55 | Object handle(Object obj, String name, Object value); 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /ice-cola-framework/framework-core-domain/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | cn.stephen12.icecola 7 | ice-cola-framework 8 | 1.0.6-SNAPSHOT 9 | 10 | 4.0.0 11 | 12 | framework-core-domain 13 | 14 | 15 | 16 | org.projectlombok 17 | lombok 18 | 19 | 20 | org.springframework.boot 21 | spring-boot-starter 22 | 23 | 24 | org.projectlombok 25 | lombok 26 | 27 | 28 | 29 | com.alibaba.cola 30 | cola-component-domain-starter 31 | 32 | 33 | com.alibaba.cola 34 | cola-component-exception 35 | 36 | 37 | 38 | 39 | cn.hutool 40 | hutool-all 41 | 42 | 43 | -------------------------------------------------------------------------------- /ice-cola-framework/framework-core-infr/src/main/java/cn/stephen12/icecola/framework/core/infr/context/RequestScopeCacheSweeper.java: -------------------------------------------------------------------------------- 1 | package cn.stephen12.icecola.framework.core.infr.context; 2 | 3 | import org.springframework.context.annotation.Configuration; 4 | import org.springframework.lang.Nullable; 5 | import org.springframework.web.servlet.HandlerInterceptor; 6 | import org.springframework.web.servlet.config.annotation.InterceptorRegistry; 7 | import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; 8 | 9 | import javax.servlet.http.HttpServletRequest; 10 | import javax.servlet.http.HttpServletResponse; 11 | 12 | /** 13 | * 请求域缓存拦截器清理器 14 | * @author ouyangsheng 15 | * @date 2022-05-23 16 | **/ 17 | @Configuration 18 | public class RequestScopeCacheSweeper implements HandlerInterceptor, WebMvcConfigurer { 19 | @Override 20 | public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { 21 | RequestContext.init(); 22 | return true; 23 | } 24 | 25 | @Override 26 | public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable Exception ex) throws Exception { 27 | RequestContext.clear(); 28 | } 29 | /** 30 | * Add Spring MVC lifecycle interceptors for pre- and post-processing of 31 | * controller method invocations and resource handler requests. 32 | * Interceptors can be registered to apply to all requests or be limited 33 | * to a subset of URL patterns. 34 | */ 35 | @Override 36 | public void addInterceptors(InterceptorRegistry registry) { 37 | registry.addInterceptor(this).addPathPatterns("/**"); 38 | } 39 | 40 | } 41 | 42 | -------------------------------------------------------------------------------- /ice-cola-components/component-mock/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | cn.stephen12.icecola 7 | ice-cola-components 8 | 1.0.6-SNAPSHOT 9 | 10 | 4.0.0 11 | 12 | component-mock 13 | 14 | 15 | 8 16 | 8 17 | 18 | 19 | 20 | 21 | uk.co.jemos.podam 22 | podam 23 | 24 | 25 | org.projectlombok 26 | lombok 27 | 28 | 29 | org.springframework.boot 30 | spring-boot-starter-aop 31 | 32 | 33 | org.springframework.boot 34 | spring-boot-configuration-processor 35 | true 36 | 37 | 38 | cn.stephen12.icecola 39 | framework-core-model 40 | ${ice.cola.version} 41 | 42 | 43 | 44 | -------------------------------------------------------------------------------- /ice-cola-components/component-utils/src/main/java/cn/stephen12/icecola/component/utils/collection/SetUtil.java: -------------------------------------------------------------------------------- 1 | package cn.stephen12.icecola.component.utils.collection; 2 | 3 | import java.util.HashSet; 4 | import java.util.Set; 5 | import java.util.stream.Collectors; 6 | 7 | /** 8 | * SetUtil (Hutool的 CollUtil是基于Collection进行交集、并集、差集运算,不能满足狭义上的集合运算) 9 | * 10 | * @author ouyangsheng 11 | * @since 2022-08-04 12 | **/ 13 | public class SetUtil { 14 | /** 15 | * 多个集合的并集
16 | * 例如:集合1:[a, b, d, e, h],集合2:[a, c, f]
17 | * 结果:[a, b, c, d, e, f, h] 18 | * 19 | * @param 集合元素类型 20 | * @param set1 集合1 21 | * @param set2 集合2 22 | * @return 并集的集合,返回 {@link Set} 23 | */ 24 | public static Set union(Set set1, Set set2) { 25 | HashSet result = new HashSet<>(set1); 26 | result.addAll(set2); 27 | return result; 28 | } 29 | 30 | /** 31 | * 两个集合的交集
32 | * 例如:集合1:[a, b, c, d, e],集合2:[a, b, c, f]
33 | * 结果:[a, b, c] 34 | * 35 | * @param 集合元素类型 36 | * @param set1 集合1 37 | * @param set2 集合2 38 | * @return 并集的集合,返回 {@link Set} 39 | */ 40 | public static Set intersect(Set set1, Set set2) { 41 | return set1.stream().filter(set2::contains).collect(Collectors.toSet()); 42 | } 43 | 44 | /** 45 | * 两个集合的差集
46 | * 例如:集合1:[a, b, c, d, e],集合2:[a, b, c, f]
47 | * 结果:[d, e] 48 | * 49 | * @param set1 50 | * @param set2 51 | * @param 52 | * @return 53 | */ 54 | public static Set subtract(Set set1, Set set2) { 55 | HashSet result = new HashSet<>(set1); 56 | result.removeAll(set2); 57 | return result; 58 | } 59 | 60 | } 61 | -------------------------------------------------------------------------------- /ice-cola-components/component-dictionary/src/main/java/cn/stephen12/icecola/component/dictionary/mybatis/MyBatisSettingHelper.java: -------------------------------------------------------------------------------- 1 | package cn.stephen12.icecola.component.dictionary.mybatis; 2 | 3 | import cn.stephen12.icecola.component.dictionary.DictionaryManager; 4 | import cn.stephen12.icecola.component.dictionary.autoconfig.DictionaryScannedHandlers; 5 | import lombok.extern.slf4j.Slf4j; 6 | import org.apache.ibatis.session.SqlSessionFactory; 7 | import org.apache.ibatis.type.TypeHandlerRegistry; 8 | import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; 9 | import org.springframework.context.support.ApplicationObjectSupport; 10 | import org.springframework.stereotype.Component; 11 | 12 | /** 13 | * config MyBatis EnumTypeHandler 14 | * 15 | * @author ouyangsheng 16 | * @date 2022-09-17 17 | **/ 18 | @Slf4j 19 | @ConditionalOnClass(SqlSessionFactory.class) 20 | @Component 21 | public class MyBatisSettingHelper extends ApplicationObjectSupport implements DictionaryScannedHandlers.Handler { 22 | /** 23 | * MyBatis TypeHandlerRegistry 24 | */ 25 | private TypeHandlerRegistry typeHandlerRegistry; 26 | 27 | @Override 28 | public void handle(DictionaryManager dictionaryManager) { 29 | SqlSessionFactory sqlSessionFactory = this.getApplicationContext().getBean(SqlSessionFactory.class); 30 | if (sqlSessionFactory == null) { 31 | log.warn("Miss bean SqlSessionFactory"); 32 | return; 33 | } 34 | this.typeHandlerRegistry = sqlSessionFactory.getConfiguration().getTypeHandlerRegistry(); 35 | dictionaryManager.getAllEnums().stream().forEach(this::setting); 36 | } 37 | 38 | private void setting(Class clazz) { 39 | typeHandlerRegistry.register(clazz, MybatisEnumTypeHandler.class); 40 | } 41 | 42 | } 43 | -------------------------------------------------------------------------------- /ice-cola-components/component-dictionary/src/main/java/cn/stephen12/icecola/component/dictionary/apidoc/DictionaryTypeParamPlugin.java: -------------------------------------------------------------------------------- 1 | package cn.stephen12.icecola.component.dictionary.apidoc; 2 | 3 | import cn.stephen12.icecola.component.dictionary.DictionaryManager; 4 | import lombok.NoArgsConstructor; 5 | import lombok.extern.slf4j.Slf4j; 6 | import org.springframework.beans.factory.annotation.Autowired; 7 | import org.springframework.core.annotation.Order; 8 | import org.springframework.stereotype.Component; 9 | import springfox.bean.validators.plugins.Validators; 10 | import springfox.documentation.spi.DocumentationType; 11 | import springfox.documentation.spi.service.ParameterBuilderPlugin; 12 | import springfox.documentation.spi.service.contexts.ParameterContext; 13 | 14 | import java.util.Optional; 15 | 16 | /** 17 | * dictionaryType 参数文档 18 | * 19 | * @author ouyangsheng 20 | * @date 2022-03-15 21 | **/ 22 | @Component 23 | @NoArgsConstructor 24 | @Order 25 | @Slf4j 26 | public class DictionaryTypeParamPlugin implements ParameterBuilderPlugin { 27 | @Autowired 28 | private DictionaryManager dictionaryManager; 29 | 30 | @Override 31 | public boolean supports(DocumentationType delimiter) { 32 | return true; 33 | } 34 | 35 | @Override 36 | public void apply(ParameterContext context) { 37 | Optional apiDictionaryType = Validators.annotationFromParameter(context, ApiDictionaryType.class); 38 | if (apiDictionaryType.isPresent()) { 39 | log.debug("@ApiDictionaryType present"); 40 | context.parameterBuilder() 41 | .parameterType(apiDictionaryType.get().parameterType()) 42 | .description(DictionaryParamDescriptor.buildDescription(dictionaryManager)); 43 | } 44 | } 45 | 46 | } 47 | -------------------------------------------------------------------------------- /ice-cola-components/component-dictionary/src/main/java/cn/stephen12/icecola/component/dictionary/apidoc/DictionaryParamDescriptor.java: -------------------------------------------------------------------------------- 1 | package cn.stephen12.icecola.component.dictionary.apidoc; 2 | 3 | import cn.stephen12.icecola.component.dictionary.DictionaryManager; 4 | import cn.stephen12.icecola.component.dictionary.model.DictWrapper; 5 | import io.swagger.annotations.ApiModel; 6 | import org.springframework.core.annotation.AnnotationUtils; 7 | 8 | import java.util.stream.Collectors; 9 | 10 | /** 11 | * 字典参数描述器 12 | * 13 | * @author ouyangsheng 14 | * @date 2022-03-17 15 | **/ 16 | public class DictionaryParamDescriptor { 17 | 18 | /** 19 | * dictionaryType 参数描述信息 20 | * 21 | * @return 22 | */ 23 | public static String buildDescription(DictionaryManager dictionaryManager) { 24 | return dictionaryManager.getAllDictionaries().entrySet().stream().map(entry -> 25 | { 26 | if (entry.getValue() != null) { 27 | String type = entry.getKey(); 28 | String description = ""; 29 | DictWrapper dictWrapper = entry.getValue(); 30 | 31 | //先从包装器中获取 32 | ApiModel apiModel = AnnotationUtils.getAnnotation(dictWrapper.getClass(), ApiModel.class); 33 | if (apiModel != null) { 34 | description = apiModel.description(); 35 | } else { 36 | //如果没有,再从原型类上获取 37 | apiModel = AnnotationUtils.getAnnotation(dictWrapper.getPrototypeClass(), ApiModel.class); 38 | if (apiModel != null) { 39 | description = apiModel.description(); 40 | } 41 | } 42 | return type + ": " + description; 43 | } 44 | return null; 45 | }).collect(Collectors.joining(";", "可选项:", "")); 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /ice-cola-framework/framework-core-infr/src/main/java/cn/stephen12/icecola/framework/core/infr/datafiller/DefaultDataFillStrategy.java: -------------------------------------------------------------------------------- 1 | package cn.stephen12.icecola.framework.core.infr.datafiller; 2 | 3 | import cn.hutool.core.bean.BeanUtil; 4 | import cn.hutool.core.bean.copier.CopyOptions; 5 | import cn.stephen12.icecola.framework.core.domain.model.BaseV; 6 | import cn.stephen12.icecola.framework.core.infr.repository.RepositoryWrapper; 7 | import org.springframework.stereotype.Component; 8 | 9 | /** 10 | * 默认数据填充策略 11 | * 12 | * @author ouyangsheng 13 | * @date 2022-05-25 14 | **/ 15 | @Component 16 | public class DefaultDataFillStrategy implements DataFillStrategy { 17 | 18 | /** 19 | * 每次都直接调用 repository 查,很浪费I/O资源 20 | *
21 | * //TODO NOTE: 仅用于测试 或者 数据量少的场景 22 | * 23 | * @param id 24 | * @param targetVType 25 | * @param 26 | * @return 27 | */ 28 | @Override 29 | public V findById(Long id, Class targetVType) { 30 | RepositoryWrapper repository = DataFiller.getRepository(targetVType); 31 | Object result = repository.findById(id); 32 | return toV(result, targetVType); 33 | } 34 | 35 | /** 36 | * 将一个对象转换未 指定值对象 37 | * 38 | * @param source 39 | * @param targetVType 40 | * @param 41 | * @return 42 | */ 43 | private V toV(Object source, Class targetVType) { 44 | if (source != null) { 45 | V vObj = null; 46 | try { 47 | vObj = targetVType.newInstance(); 48 | } catch (Exception e) { 49 | throw new IllegalStateException("targetVType (" + targetVType.toString() + ") is not implementable"); 50 | } 51 | BeanUtil.copyProperties(source, vObj, CopyOptions.create().ignoreError()); 52 | return vObj; 53 | } 54 | return null; 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /ice-cola-components/component-office/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | cn.stephen12.icecola 7 | ice-cola-components 8 | 1.0.6-SNAPSHOT 9 | 10 | 4.0.0 11 | 12 | component-office 13 | 14 | 15 | 16 | org.projectlombok 17 | lombok 18 | 19 | 20 | org.springframework.boot 21 | spring-boot-starter 22 | 23 | 24 | org.springframework.boot 25 | spring-boot-starter-aop 26 | 27 | 28 | cn.hutool 29 | hutool-all 30 | 31 | 32 | cn.afterturn 33 | easypoi-spring-boot-starter 34 | 35 | 36 | cn.afterturn 37 | easypoi-annotation 38 | 39 | 40 | 41 | cn.stephen12.icecola 42 | component-dictionary 43 | true 44 | 45 | 46 | 47 | cn.stephen12.icecola 48 | framework-core-exception 49 | 50 | 51 | 52 | 53 | -------------------------------------------------------------------------------- /ice-cola-components/component-op-log/src/main/java/cn/stephen12/icecola/component/oplog/aop/OpLogAspect.java: -------------------------------------------------------------------------------- 1 | package cn.stephen12.icecola.component.oplog.aop; 2 | 3 | import cn.stephen12.icecola.component.oplog.OpLogModel; 4 | import cn.stephen12.icecola.component.oplog.spi.OpLogListener; 5 | import org.aspectj.lang.ProceedingJoinPoint; 6 | import org.aspectj.lang.annotation.Around; 7 | import org.aspectj.lang.annotation.Aspect; 8 | import org.aspectj.lang.annotation.Pointcut; 9 | import org.springframework.beans.factory.annotation.Autowired; 10 | import org.springframework.core.annotation.Order; 11 | 12 | import java.util.List; 13 | 14 | /** 15 | * //TODO 要注意环绕通知要在事务外 16 | * 操作日志AOP 17 | * @author ouyangsheng 18 | * @since 2022-08-11 19 | */ 20 | @Aspect 21 | @Order(0) 22 | public class OpLogAspect { 23 | @Autowired 24 | private List opLogListeners; 25 | 26 | @Pointcut("@annotation(cn.stephen12.icecola.component.oplog.aop.OpLog)") 27 | public void pointcut() { 28 | } 29 | 30 | @Around(value = "pointcut()") 31 | public Object doAround(ProceedingJoinPoint joinPoint) throws Throwable { 32 | OpLogModel opLogModel = new OpLogModel(); 33 | Object[] args = joinPoint.getArgs(); 34 | opLogModel.setParam(args.toString()); 35 | //TODO 获取ID 36 | opLogModel.setBizId(null); 37 | try { 38 | Object result = joinPoint.proceed(); 39 | //TODO 结果ToString 40 | opLogModel.setFeedback(result.toString()); 41 | 42 | log(opLogModel); 43 | return result; 44 | }catch (Throwable e){ 45 | handleError(opLogModel,e); 46 | throw e; 47 | } 48 | } 49 | 50 | private void log(OpLogModel opLogModel){ 51 | for(OpLogListener logListener: opLogListeners){ 52 | logListener.onLog(opLogModel,null); 53 | } 54 | } 55 | 56 | private void handleError(OpLogModel opLogModel,Throwable e){ 57 | for(OpLogListener logListener: opLogListeners){ 58 | logListener.onLog(opLogModel,e); 59 | } 60 | } 61 | 62 | 63 | 64 | } 65 | -------------------------------------------------------------------------------- /ice-cola-components/component-distributed/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | cn.stephen12.icecola 7 | ice-cola-components 8 | 1.0.6-SNAPSHOT 9 | 10 | 4.0.0 11 | 12 | component-distributed 13 | 14 | 15 | 16 | org.springframework.boot 17 | spring-boot-starter 18 | 19 | 20 | org.projectlombok 21 | lombok 22 | 23 | 24 | com.alibaba.cola 25 | cola-component-exception 26 | 27 | 28 | org.redisson 29 | redisson-spring-boot-starter 30 | 31 | 32 | org.springframework.boot 33 | spring-boot-starter-data-jpa 34 | true 35 | 36 | 37 | javax.persistence 38 | javax.persistence-api 39 | true 40 | 41 | 42 | com.alibaba.cola 43 | cola-component-domain-starter 44 | 45 | 46 | cn.stephen12.icecola 47 | framework-core-infr 48 | true 49 | 50 | 51 | 52 | -------------------------------------------------------------------------------- /ice-cola-framework/framework-core-infr/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | cn.stephen12.icecola 7 | ice-cola-framework 8 | 1.0.6-SNAPSHOT 9 | 10 | 4.0.0 11 | 12 | framework-core-infr 13 | 14 | 15 | 16 | 17 | cn.stephen12.icecola 18 | framework-core-domain 19 | 20 | 21 | cn.stephen12.icecola 22 | framework-core-exception 23 | 24 | 25 | jakarta.persistence 26 | jakarta.persistence-api 27 | 28 | 29 | org.springframework.data 30 | spring-data-commons 31 | 32 | 33 | org.hibernate 34 | hibernate-core 35 | 36 | 37 | org.springframework.data 38 | spring-data-jpa 39 | 40 | 41 | 42 | org.springframework.boot 43 | spring-boot-starter-web 44 | 45 | 46 | cn.hutool 47 | hutool-all 48 | 49 | 50 | org.mapstruct 51 | mapstruct 52 | 53 | 54 | 55 | -------------------------------------------------------------------------------- /ice-cola-components/component-dictionary/src/main/java/cn/stephen12/icecola/component/dictionary/hutool/ConverterSettingHelper.java: -------------------------------------------------------------------------------- 1 | package cn.stephen12.icecola.component.dictionary.hutool; 2 | 3 | import cn.hutool.core.convert.AbstractConverter; 4 | import cn.hutool.core.convert.ConverterRegistry; 5 | import cn.stephen12.icecola.component.dictionary.DictionaryManager; 6 | import cn.stephen12.icecola.component.dictionary.autoconfig.DictionaryScannedHandlers; 7 | import cn.stephen12.icecola.component.dictionary.model.Dictionary; 8 | import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; 9 | import org.springframework.stereotype.Component; 10 | 11 | /** 12 | * HuTool Converter注册 13 | * 14 | * @author ouyangsheng 15 | * @date 2022-05-31 16 | **/ 17 | @ConditionalOnClass(ConverterRegistry.class) 18 | @Component 19 | public class ConverterSettingHelper implements DictionaryScannedHandlers.Handler { 20 | 21 | @Override 22 | public void handle(DictionaryManager dictionaryManager) { 23 | dictionaryManager.getAllEnums().stream().forEach(this::setting); 24 | } 25 | 26 | private void setting(Class clazz) { 27 | ConverterRegistry registry = ConverterRegistry.getInstance(); 28 | registry.putCustom(clazz, new DictionaryConverter(clazz)); 29 | } 30 | 31 | 32 | /** 33 | * 字典转换器 34 | */ 35 | static class DictionaryConverter extends AbstractConverter { 36 | /** 37 | * 枚举类 38 | */ 39 | private final Class enumClass; 40 | 41 | /** 42 | * 构造 43 | * 44 | * @param enumClass 转换成的目标Enum类 45 | */ 46 | public DictionaryConverter(Class enumClass) { 47 | this.enumClass = enumClass; 48 | } 49 | 50 | /** 51 | * 基础类型 或 String 转化为枚举 52 | * 53 | * @param value 54 | * @return 55 | */ 56 | @Override 57 | protected Object convertInternal(Object value) { 58 | return Dictionary.getByCode((Class) enumClass, value).orElse(null); 59 | } 60 | 61 | @Override 62 | public Class getTargetType() { 63 | return this.enumClass; 64 | } 65 | } 66 | } -------------------------------------------------------------------------------- /ice-cola-components/component-utils/src/main/java/cn/stephen12/icecola/component/utils/number/NumberUtil.java: -------------------------------------------------------------------------------- 1 | package cn.stephen12.icecola.component.utils.number; 2 | 3 | import cn.hutool.core.lang.Assert; 4 | 5 | import java.math.BigDecimal; 6 | 7 | /** 8 | * @author ouyangsheng 9 | * @date 2022-05-20 10 | **/ 11 | public class NumberUtil extends cn.hutool.core.util.NumberUtil { 12 | 13 | /** 14 | * 获取小数位数 15 | **/ 16 | public static int getPrecision(BigDecimal bigDecimal) { 17 | if (bigDecimal == null) { 18 | return 0; 19 | } 20 | String string = bigDecimal.stripTrailingZeros().toPlainString(); 21 | int index = string.indexOf("."); 22 | return index < 0 ? 0 : string.length() - index - 1; 23 | } 24 | 25 | /** 26 | * 是否在此开区间内 27 | * if min < x < max 28 | * 29 | * @param x 给定的值 30 | * @param min 开区间左端点 31 | * @param max 开区间右端点 32 | * @return 33 | */ 34 | public static boolean inOpenInternal(BigDecimal x, BigDecimal min, BigDecimal max) { 35 | Assert.notNull(min); 36 | Assert.notNull(max); 37 | 38 | return new OpenInternal(min, max).isIn(x); 39 | } 40 | 41 | /** 42 | * 是否在此闭区间内 43 | * if min <= x <= max 44 | * 45 | * @param x 给定的值 46 | * @param min 开区间左端点 47 | * @param max 开区间右端点 48 | * @return 49 | */ 50 | public static boolean inCloseInternal(BigDecimal x, BigDecimal min, BigDecimal max) { 51 | Assert.notNull(min); 52 | Assert.notNull(max); 53 | return new CloseInternal(min, max).isIn(x); 54 | } 55 | 56 | /** 57 | * 为空或者负数 则返回0 58 | * 59 | * @param number 60 | * @return 61 | */ 62 | public static BigDecimal defaultZeroIfNullOrNegative(BigDecimal number) { 63 | if (isNullOrNegative(number)) { 64 | return BigDecimal.ZERO; 65 | } 66 | return number; 67 | } 68 | 69 | /** 70 | * 为空或者负数 71 | * 72 | * @param number 73 | * @return 74 | */ 75 | public static boolean isNullOrNegative(BigDecimal number) { 76 | return number == null || NumberUtil.isLess(number, BigDecimal.ZERO); 77 | } 78 | 79 | } 80 | -------------------------------------------------------------------------------- /ice-cola-framework/framework-core-infr/src/main/java/cn/stephen12/icecola/framework/core/infr/id/IdGeneratorGatewayImpl.java: -------------------------------------------------------------------------------- 1 | package cn.stephen12.icecola.framework.core.infr.id; 2 | 3 | import cn.hutool.core.annotation.AnnotationUtil; 4 | import cn.hutool.core.lang.Assert; 5 | import cn.stephen12.icecola.framework.core.domain.IdGeneratorGateway; 6 | import cn.stephen12.icecola.framework.core.domain.annotation.BizTag; 7 | import org.springframework.beans.factory.annotation.Autowired; 8 | import org.springframework.context.annotation.Primary; 9 | import org.springframework.stereotype.Component; 10 | 11 | import java.util.Map; 12 | import java.util.concurrent.ConcurrentHashMap; 13 | 14 | /** 15 | * 默认Id生成Gateway 16 | * @author ouyangsheng 17 | * @since 2022-04-22 18 | * @see IdNoGenerator 19 | * @see BizTag 20 | **/ 21 | @Primary 22 | @Component 23 | public class IdGeneratorGatewayImpl implements IdGeneratorGateway { 24 | /** 25 | * Jvm 缓存,避免重复反射获取注解 26 | */ 27 | private final static Map domainTypeToTagMap = new ConcurrentHashMap<>(16); 28 | 29 | @Autowired 30 | protected IdNoGenerator idNoGenerator; 31 | 32 | @Override 33 | public Long generateId(Class domainClass) { 34 | String tag = getBizTag(domainClass); 35 | return idNoGenerator.generateId(tag); 36 | } 37 | 38 | @Override 39 | public String generateNo(Class entityClass) { 40 | String tag = getBizTag(entityClass); 41 | return idNoGenerator.generateNo(tag); 42 | } 43 | 44 | /** 45 | * 获取业务标识,用于获取ID 46 | * @param domainClass 47 | * @return 48 | */ 49 | protected String getBizTag(Class domainClass){ 50 | //尝试从缓存中获取,如果没有,则从注解中获取 51 | String tag = domainTypeToTagMap.get(domainClass); 52 | if (tag == null) { 53 | BizTag bizTag = AnnotationUtil.getAnnotation(domainClass, BizTag.class); 54 | Assert.state(bizTag != null, "domainClass({}) must contain annotation @BizTag", domainClass.toGenericString()); 55 | 56 | //重新写入缓存 57 | tag = bizTag.value(); 58 | domainTypeToTagMap.put(domainClass,tag); 59 | } 60 | return tag; 61 | } 62 | 63 | 64 | } 65 | 66 | -------------------------------------------------------------------------------- /ice-cola-framework/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | ice-cola-parent 7 | cn.stephen12.icecola 8 | 1.0.6-SNAPSHOT 9 | 10 | 4.0.0 11 | 12 | ice-cola-framework 13 | pom 14 | 15 | 16 | framework-core-model 17 | framework-core-app 18 | framework-core-domain 19 | framework-core-infr 20 | framework-core-exception 21 | framework-archetype 22 | 23 | 24 | 25 | 26 | 27 | cn.stephen12.icecola 28 | framework-core-model 29 | ${ice.cola.version} 30 | 31 | 32 | cn.stephen12.icecola 33 | framework-core-exception 34 | ${ice.cola.version} 35 | 36 | 37 | cn.stephen12.icecola 38 | framework-core-domain 39 | ${ice.cola.version} 40 | 41 | 42 | cn.stephen12.icecola 43 | framework-core-app 44 | ${ice.cola.version} 45 | 46 | 47 | cn.stephen12.icecola 48 | framework-core-infr 49 | ${ice.cola.version} 50 | 51 | 52 | 53 | 54 | 55 | -------------------------------------------------------------------------------- /ice-cola-components/component-utils/src/main/java/cn/stephen12/icecola/component/utils/validaterule/ValidationRuleExecutor.java: -------------------------------------------------------------------------------- 1 | package cn.stephen12.icecola.component.utils.validaterule; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | import java.util.Queue; 6 | import java.util.concurrent.ArrayBlockingQueue; 7 | import java.util.function.Predicate; 8 | import java.util.function.Supplier; 9 | import java.util.stream.Collectors; 10 | 11 | /** 12 | * 校验规则执行器 13 | * 14 | * @author ouyangsheng 15 | * @date 2022-05-17 16 | **/ 17 | public class ValidationRuleExecutor { 18 | 19 | /** 20 | * {@link #rules} 所有待执行的规则,目前为列表做的队列 21 | * {@link #result} 成功执行的规则结果 22 | */ 23 | Queue> rules = new ArrayBlockingQueue<>(16); 24 | List result = new ArrayList<>(16); 25 | 26 | public ValidationRuleExecutor addRule(Rule rule) { 27 | rules.add(rule); 28 | return this; 29 | } 30 | 31 | public ValidationRuleExecutor addRules(List> rules) { 32 | rules.addAll(rules); 33 | return this; 34 | } 35 | 36 | public ValidationRuleExecutor addRule(Predicate condition, Supplier action) { 37 | rules.add(new Rule(condition, action)); 38 | return this; 39 | } 40 | 41 | /** 42 | * 运行规则 43 | * 44 | * @param fact 被规则校验的参数 45 | * @return 执行成功结果数据 46 | */ 47 | public Results run(T fact) { 48 | for (Rule r : rules) { 49 | r.run(fact, this); 50 | } 51 | return new Results(); 52 | } 53 | 54 | /** 55 | * 执行结果 56 | *

57 | * 因为校验结果通常是 Message,所以这里定义 result 为 String 类型,如有必要会提取顶层规则执行器 58 | *

59 | */ 60 | public class Results { 61 | private List results; 62 | 63 | Results() { 64 | this.results = result; 65 | } 66 | 67 | /** 68 | * 有多少规则命中 69 | * @return 70 | */ 71 | public int getCount() { 72 | return results.size(); 73 | } 74 | 75 | /** 76 | * 获取结果文本信息 77 | * 78 | * @return 79 | */ 80 | @Override 81 | public String toString() { 82 | return results.stream().collect(Collectors.joining(",")); 83 | } 84 | 85 | } 86 | } 87 | -------------------------------------------------------------------------------- /ice-cola-components/component-mock/src/main/java/cn/stephen12/icecola/component/mock/MockResponseAspect.java: -------------------------------------------------------------------------------- 1 | package cn.stephen12.icecola.component.mock; 2 | 3 | import cn.stephen12.icecola.framework.model.vo.RestResult; 4 | import org.aspectj.lang.ProceedingJoinPoint; 5 | import org.aspectj.lang.annotation.Around; 6 | import org.aspectj.lang.annotation.Aspect; 7 | import org.aspectj.lang.annotation.Pointcut; 8 | import org.springframework.beans.factory.annotation.Autowired; 9 | import org.springframework.core.annotation.Order; 10 | import uk.co.jemos.podam.api.PodamFactory; 11 | 12 | import java.lang.reflect.Method; 13 | import java.lang.reflect.ParameterizedType; 14 | import java.lang.reflect.Type; 15 | import java.util.List; 16 | 17 | @Aspect 18 | @Order(0) 19 | public class MockResponseAspect { 20 | 21 | @Autowired 22 | private PodamFactory podamFactory; 23 | 24 | // todo 25 | // @Autowired(required = false) 26 | private List customizers; 27 | 28 | @Pointcut("@annotation(cn.stephen12.icecola.component.mock.Mock)") 29 | public void pointcut() { 30 | } 31 | 32 | @Around(value = "pointcut()") 33 | public Object doAround(ProceedingJoinPoint joinPoint) throws Throwable { 34 | Object result = null; 35 | Class declaringType = joinPoint.getTarget().getClass(); 36 | Method method = joinPoint.getArgs() != null && joinPoint.getArgs().length>0 37 | ? declaringType.getMethod(joinPoint.getSignature().getName(),joinPoint.getArgs()[0].getClass()) 38 | : declaringType.getMethod(joinPoint.getSignature().getName()); 39 | Type genericReturnType = method.getGenericReturnType(); 40 | if (genericReturnType instanceof ParameterizedType) { 41 | ParameterizedType parameterizedType = (ParameterizedType) genericReturnType; 42 | Type[] actualTypeArguments = parameterizedType.getActualTypeArguments(); 43 | result = podamFactory.manufacturePojo(method.getReturnType(), actualTypeArguments); 44 | } 45 | return adapter(result); 46 | } 47 | 48 | private Object adapter(Object result) { 49 | if (result instanceof RestResult) { 50 | RestResult restResponse = (RestResult) result; 51 | return RestResult.success(restResponse.getData()); 52 | } 53 | return result; 54 | } 55 | 56 | } 57 | -------------------------------------------------------------------------------- /ice-cola-components/component-dictionary/src/main/java/cn/stephen12/icecola/component/dictionary/autoconfig/DictionaryScannedHandlers.java: -------------------------------------------------------------------------------- 1 | package cn.stephen12.icecola.component.dictionary.autoconfig; 2 | 3 | import cn.stephen12.icecola.component.dictionary.DictionaryManager; 4 | import lombok.extern.slf4j.Slf4j; 5 | import org.springframework.beans.factory.annotation.Autowired; 6 | import org.springframework.context.ApplicationContext; 7 | import org.springframework.context.ApplicationListener; 8 | import org.springframework.context.event.ContextRefreshedEvent; 9 | import org.springframework.core.Ordered; 10 | import org.springframework.core.annotation.Order; 11 | import org.springframework.stereotype.Component; 12 | 13 | import java.util.Collection; 14 | import java.util.List; 15 | 16 | /** 17 | * 字典扫描完成后处理器 18 | * 19 | * @author ouyangsheng 20 | * @date 2022-06-06 21 | **/ 22 | @Slf4j 23 | @Component 24 | public class DictionaryScannedHandlers implements ApplicationListener { 25 | 26 | @Autowired 27 | private DictionaryManager dictionaryManager; 28 | @Autowired 29 | private ApplicationContext applicationContext; 30 | @Autowired 31 | private List handlers; 32 | 33 | @Override 34 | public void onApplicationEvent(ContextRefreshedEvent event) { 35 | //注意,Feign等组件会构建自己的容器(ApplicationContext),这里判断主容器加载完后,注册序列化器 36 | if (event.getApplicationContext().equals(this.applicationContext)) { 37 | //调用具体处理器 38 | for (Handler handler : handlers) { 39 | handler.handle(dictionaryManager); 40 | } 41 | } 42 | } 43 | 44 | /** 45 | * 扫描完成后要处理的事项交给本处理器 46 | */ 47 | public interface Handler { 48 | 49 | /** 50 | * 完成扫描后处理 51 | * 52 | * @param dictionaryManager 53 | */ 54 | void handle(DictionaryManager dictionaryManager); 55 | } 56 | 57 | /** 58 | * 打印扫描结果 59 | */ 60 | @Order(Ordered.HIGHEST_PRECEDENCE) 61 | @Component 62 | class Printer implements Handler{ 63 | 64 | @Override 65 | public void handle(DictionaryManager dictionaryManager) { 66 | if (log.isDebugEnabled()) { 67 | Collection> enumClasses = dictionaryManager.getAllEnums(); 68 | log.debug("Have found these dictionary classes: {}", enumClasses); 69 | } 70 | } 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /ice-cola-framework/framework-core-infr/src/main/java/cn/stephen12/icecola/framework/core/infr/model/BaseJpaEntity.java: -------------------------------------------------------------------------------- 1 | package cn.stephen12.icecola.framework.core.infr.model; 2 | 3 | import lombok.Data; 4 | import org.hibernate.annotations.DynamicInsert; 5 | import org.hibernate.annotations.DynamicUpdate; 6 | import org.springframework.core.annotation.AnnotationUtils; 7 | import org.springframework.data.annotation.CreatedBy; 8 | import org.springframework.data.annotation.CreatedDate; 9 | import org.springframework.data.annotation.LastModifiedBy; 10 | import org.springframework.data.annotation.LastModifiedDate; 11 | import org.springframework.data.jpa.domain.support.AuditingEntityListener; 12 | 13 | import javax.persistence.Column; 14 | import javax.persistence.EntityListeners; 15 | import javax.persistence.Id; 16 | import javax.persistence.MappedSuperclass; 17 | import javax.persistence.Table; 18 | import java.time.LocalDateTime; 19 | 20 | /** 21 | * 基本模型基类 22 | * @author yuchenggong 23 | * @version 1.0 24 | * @date 2021/9/1 25 | */ 26 | @EntityListeners({AuditingEntityListener.class}) 27 | @MappedSuperclass 28 | @Data 29 | @DynamicUpdate 30 | @DynamicInsert 31 | public abstract class BaseJpaEntity implements IJpaEntity { 32 | /** 33 | * id 34 | */ 35 | @Id 36 | protected Long id; 37 | 38 | /** 39 | * 创建人工号 40 | */ 41 | @CreatedBy 42 | @Column(name = "c_u",updatable = false) 43 | protected String createUserNo; 44 | 45 | /** 46 | * 创建人名称 47 | */ 48 | @CreatedBy 49 | @Column(name = "c_name",updatable = false) 50 | protected String createUserName; 51 | 52 | /** 53 | * 创建时间 54 | */ 55 | @CreatedDate 56 | @Column(name = "c_t",updatable = false) 57 | protected LocalDateTime createTime; 58 | 59 | /** 60 | * 最后修改人工号 61 | */ 62 | @Column(name = "u_u") 63 | @LastModifiedBy 64 | protected String updateUserNo; 65 | 66 | /** 67 | * 最后修改人名称 68 | */ 69 | @Column(name = "u_name") 70 | @LastModifiedBy 71 | protected String updateUserName; 72 | 73 | /** 74 | * 最后修改时间 75 | */ 76 | @Column(name = "u_t") 77 | @LastModifiedDate 78 | protected LocalDateTime updateTime; 79 | 80 | /** 81 | * 获取分布式ID标识 82 | * @return 83 | */ 84 | public static String getLeafTag(Class clazz){ 85 | Table annotation = AnnotationUtils.findAnnotation(clazz, Table.class); 86 | return annotation.schema() + "_" + annotation.name(); 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /ice-cola-components/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | ice-cola-parent 7 | cn.stephen12.icecola 8 | 1.0.6-SNAPSHOT 9 | 10 | 4.0.0 11 | 12 | ice-cola-components 13 | pom 14 | 15 | 16 | component-dictionary 17 | component-distributed 18 | component-mock 19 | component-office 20 | component-op-log 21 | component-utils 22 | component-multi-tenant 23 | 24 | 25 | 26 | 27 | 28 | cn.stephen12.icecola 29 | ice-cola-framework 30 | ${ice.cola.version} 31 | pom 32 | import 33 | 34 | 35 | 36 | cn.stephen12.icecola 37 | component-utils 38 | ${ice.cola.version} 39 | 40 | 41 | 42 | cn.stephen12.icecola 43 | component-dictionary 44 | ${ice.cola.version} 45 | 46 | 47 | cn.stephen12.icecola 48 | component-distributed 49 | ${ice.cola.version} 50 | 51 | 52 | cn.stephen12.icecola 53 | component-mock 54 | ${ice.cola.version} 55 | 56 | 57 | cn.stephen12.icecola 58 | component-office 59 | ${ice.cola.version} 60 | 61 | 62 | 63 | -------------------------------------------------------------------------------- /ice-cola-framework/framework-core-domain/src/main/java/cn/stephen12/icecola/framework/core/domain/PersistenceI.java: -------------------------------------------------------------------------------- 1 | package cn.stephen12.icecola.framework.core.domain; 2 | 3 | import com.alibaba.cola.exception.SysException; 4 | import cn.stephen12.icecola.framework.core.domain.model.BaseAggregateRoot; 5 | 6 | import java.util.Collection; 7 | import java.util.Iterator; 8 | import java.util.List; 9 | import java.util.Optional; 10 | import java.util.Set; 11 | import java.util.stream.Collectors; 12 | 13 | /** 14 | * 持久化接口 15 | * 16 | * @author ouyangsheng 17 | * @date 2022-03-22 18 | * 19 | * @see BaseGatewayI 20 | **/ 21 | public interface PersistenceI> { 22 | 23 | /** 24 | * 查找一个聚合根 25 | * @param id 26 | * @return 27 | */ 28 | Optional findDomainById(Long id); 29 | 30 | /** 31 | * 批量按ID获取聚合根 32 | * @param ids 33 | * @return 34 | */ 35 | List findAllDomainById(Collection ids); 36 | 37 | /** 38 | * 获取值对象 39 | * @param id 40 | * @param clazz 41 | * @param 值对象类型 42 | * @return 43 | */ 44 | Optional findValObjById(Long id, Class clazz); 45 | 46 | /** 47 | * 批量按ID获取值对象 48 | * @param ids 49 | * @param clazz 50 | * @param 51 | * @return 52 | */ 53 | List findAllValObjById(Collection ids, Class clazz); 54 | 55 | /** 56 | * 持久化聚合根 57 | * @param domainE 58 | * @return savedDomain 59 | */ 60 | D save(D domainE); 61 | 62 | /** 63 | * 保存全部 64 | * @param domainEs 65 | * @return 66 | */ 67 | default Iterator saveAll(Collection domainEs){ 68 | throw new SysException("Must override the method"); 69 | } 70 | 71 | /** 72 | * 移除 73 | * @param domainEs 74 | * @return 75 | */ 76 | default void removeAll(Collection domainEs){ 77 | Set ids = domainEs.stream().map(D::getId).collect(Collectors.toSet()); 78 | removeAllByIds(ids); 79 | } 80 | 81 | /** 82 | * 通过Id移除 83 | * @param ids 84 | */ 85 | default void removeAllByIds(Collection ids){ 86 | for (Long id: ids) { 87 | removeById(id); 88 | } 89 | } 90 | 91 | /** 92 | * 移除 93 | * @param domain 94 | * @return 95 | */ 96 | default void remove(D domain){ 97 | removeById(domain.getId()); 98 | } 99 | 100 | /** 101 | * 通过Id移除 102 | * @param id 103 | */ 104 | default void removeById(Long id){ 105 | throw new SysException("Must override the method: removeById(Long id)"); 106 | } 107 | } 108 | -------------------------------------------------------------------------------- /ice-cola-components/component-dictionary/src/main/java/cn/stephen12/icecola/component/dictionary/DictionaryManagerImpl.java: -------------------------------------------------------------------------------- 1 | package cn.stephen12.icecola.component.dictionary; 2 | 3 | import cn.stephen12.icecola.component.dictionary.model.DictWrapper; 4 | import cn.stephen12.icecola.component.dictionary.model.DictionaryVO; 5 | import com.alibaba.cola.exception.SysException; 6 | import lombok.extern.slf4j.Slf4j; 7 | import org.springframework.stereotype.Component; 8 | 9 | import java.util.ArrayList; 10 | import java.util.Collection; 11 | import java.util.Collections; 12 | import java.util.HashSet; 13 | import java.util.List; 14 | import java.util.Map; 15 | import java.util.Set; 16 | import java.util.function.Function; 17 | import java.util.stream.Collectors; 18 | 19 | /** 20 | * 字典管理器 21 | * 22 | * @author ouyangsheng 23 | * @since 2022-03-14 24 | */ 25 | @Component 26 | @Slf4j 27 | public class DictionaryManagerImpl implements DictionaryManager { 28 | 29 | @Override 30 | public List listDictByType(String type) { 31 | DictWrapper wrapper = DictionaryRegistry.dictionaryMap.get(type); 32 | if (wrapper == null) { 33 | return Collections.emptyList(); 34 | } 35 | return new ArrayList<>(wrapper.getDictionaries()); 36 | } 37 | 38 | @Override 39 | public Map> getDictionariesByTypes(Collection types) { 40 | if (types == null) { 41 | return Collections.EMPTY_MAP; 42 | } 43 | return types.stream().collect(Collectors.toMap(Function.identity(), this::listDictByType, (pre, curr) -> curr)); 44 | } 45 | 46 | @Override 47 | public void register(Class dictClazz) { 48 | if (DictionaryRegistry.isDictionary(dictClazz)) { 49 | DictionaryRegistry.registerDict(dictClazz); 50 | } else if (DictionaryRegistry.isDictWrapper(dictClazz)) { 51 | DictionaryRegistry.registerDictWrapper(dictClazz); 52 | } 53 | throw new SysException("The dictClass must implement Dictionary or DictWrapper."); 54 | } 55 | 56 | @Override 57 | public void register(String key, Class dictClazz) { 58 | if (DictionaryRegistry.isDictionary(dictClazz)) { 59 | DictionaryRegistry.registerDict(key, dictClazz); 60 | } else if (DictionaryRegistry.isDictWrapper(dictClazz)) { 61 | DictionaryRegistry.registerDictWrapper(key, dictClazz); 62 | } 63 | throw new SysException("The dictClass must implement Dictionary or DictWrapper."); 64 | } 65 | 66 | @Override 67 | public Set> getAllEnums() { 68 | return new HashSet<>(DictionaryRegistry.wrapperToPrototypeMap.values()); 69 | } 70 | 71 | @Override 72 | public Map getAllDictionaries() { 73 | return DictionaryRegistry.dictionaryMap; 74 | } 75 | 76 | 77 | } 78 | -------------------------------------------------------------------------------- /ice-cola-components/component-utils/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | cn.stephen12.icecola 7 | ice-cola-components 8 | 1.0.6-SNAPSHOT 9 | 10 | 4.0.0 11 | 12 | component-utils 13 | 14 | 15 | 16 | org.apache.maven.plugins 17 | maven-compiler-plugin 18 | 19 | 8 20 | 8 21 | 22 | 23 | 24 | 25 | 26 | 27 | cn.hutool 28 | hutool-all 29 | 30 | 31 | org.springframework.boot 32 | spring-boot-starter 33 | 34 | 35 | com.alibaba.cola 36 | cola-component-domain-starter 37 | 38 | 39 | org.projectlombok 40 | lombok 41 | 42 | 43 | com.alibaba 44 | fastjson 45 | 46 | 47 | io.springfox 48 | springfox-spi 49 | 50 | 51 | io.springfox 52 | springfox-schema 53 | 54 | 55 | io.springfox 56 | springfox-core 57 | 58 | 59 | io.swagger 60 | swagger-annotations 61 | 62 | 63 | org.apache.commons 64 | commons-lang3 65 | 66 | 67 | com.google.guava 68 | guava 69 | 70 | 71 | javax.validation 72 | validation-api 73 | 74 | 75 | 76 | -------------------------------------------------------------------------------- /ice-cola-framework/framework-core-infr/src/main/java/cn/stephen12/icecola/framework/core/infr/datafiller/DataFiller.java: -------------------------------------------------------------------------------- 1 | package cn.stephen12.icecola.framework.core.infr.datafiller; 2 | 3 | import cn.hutool.core.annotation.AnnotationUtil; 4 | import cn.stephen12.icecola.framework.core.domain.model.BaseV; 5 | import cn.stephen12.icecola.framework.core.infr.annotation.FindV; 6 | import cn.stephen12.icecola.framework.core.infr.model.IdV; 7 | import cn.stephen12.icecola.framework.core.infr.repository.RepositoryWrapper; 8 | import org.springframework.beans.factory.annotation.Autowired; 9 | import org.springframework.stereotype.Component; 10 | 11 | import java.util.List; 12 | import java.util.Map; 13 | import java.util.concurrent.ConcurrentHashMap; 14 | 15 | /** 16 | * 外部数据充血器 17 | *

18 | * //TODO NOTE: 警告,本类仅设计用于Gateway充血使用,其他场景未经测试,不要乱用 19 | *

20 | * 21 | * @author ouyangsheng 22 | * @date 2022-05-25 23 | **/ 24 | @Component 25 | public class DataFiller { 26 | 27 | /** 28 | * 值对象对于的 RepositoryWrapper 29 | */ 30 | private static final Map vTypeToDataWrapperMap = new ConcurrentHashMap<>(16); 31 | /** 32 | * 默认策略 33 | */ 34 | private static DataFillStrategy dataFillStrategy; 35 | 36 | /** 37 | * 绑定值对象类型与 RepositoryWrapper的映射关系 38 | * 39 | * @param wrappers 40 | */ 41 | @Autowired(required = false) 42 | public void setRepositoryWrappers(List wrappers) { 43 | for (RepositoryWrapper wrapper : wrappers) { 44 | FindV findV = AnnotationUtil.getAnnotation(wrapper.getClass(), FindV.class); 45 | 46 | if (findV != null && findV.value() != null) { 47 | for (Class vType : findV.value()) { 48 | vTypeToDataWrapperMap.put(vType, wrapper); 49 | } 50 | } 51 | } 52 | } 53 | 54 | @Autowired 55 | public void setDataFillStrategy(DataFillStrategy dataFillStrategy) { 56 | DataFiller.dataFillStrategy = dataFillStrategy; 57 | } 58 | 59 | /** 60 | * 获取值对象 61 | * 62 | * @param id 63 | * @param targetVClass 64 | * @param 65 | * @return 66 | */ 67 | public static V findVById(IdV id, Class targetVClass) { 68 | return findVById(id.obtainId(), targetVClass); 69 | } 70 | 71 | /** 72 | * 获取值对象 73 | * 74 | * @param id 75 | * @param targetVClass 76 | * @param 77 | * @return 78 | */ 79 | public static V findVById(Long id, Class targetVClass) { 80 | return dataFillStrategy.findById(id, targetVClass); 81 | } 82 | 83 | /** 84 | * 获取值类型对于的仓库获取器 85 | * 86 | * @param targetVClass 87 | * @param 88 | * @return 89 | */ 90 | static RepositoryWrapper getRepository(Class targetVClass) { 91 | return vTypeToDataWrapperMap.get(targetVClass); 92 | } 93 | } 94 | -------------------------------------------------------------------------------- /ice-cola-components/component-dictionary/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | cn.stephen12.icecola 7 | ice-cola-components 8 | 1.0.6-SNAPSHOT 9 | 10 | 4.0.0 11 | 12 | component-dictionary 13 | 14 | 15 | 16 | org.projectlombok 17 | lombok 18 | 19 | 20 | org.springframework.boot 21 | spring-boot-starter-web 22 | 23 | 24 | io.swagger 25 | swagger-annotations 26 | true 27 | 28 | 29 | 30 | io.springfox 31 | springfox-swagger2 32 | true 33 | 34 | 35 | 36 | io.springfox 37 | springfox-bean-validators 38 | 39 | 40 | com.alibaba 41 | fastjson 42 | true 43 | 44 | 45 | org.mybatis 46 | mybatis 47 | true 48 | 49 | 50 | com.google.guava 51 | guava 52 | 53 | 54 | cn.hutool 55 | hutool-all 56 | 57 | 58 | jakarta.persistence 59 | jakarta.persistence-api 60 | true 61 | 62 | 63 | org.hibernate 64 | hibernate-core 65 | true 66 | 67 | 68 | com.alibaba.cola 69 | cola-component-exception 70 | 71 | 72 | 73 | cn.stephen12.icecola 74 | component-utils 75 | 76 | 77 | 78 | -------------------------------------------------------------------------------- /ice-cola-framework/framework-core-domain/src/main/java/cn/stephen12/icecola/framework/core/domain/model/BaseAggregateRoot.java: -------------------------------------------------------------------------------- 1 | package cn.stephen12.icecola.framework.core.domain.model; 2 | 3 | import com.alibaba.cola.domain.ApplicationContextHelper; 4 | import com.alibaba.cola.domain.Entity; 5 | import cn.stephen12.icecola.framework.core.domain.BaseGatewayI; 6 | import cn.stephen12.icecola.framework.core.domain.GatewayManager; 7 | import lombok.AccessLevel; 8 | import lombok.Data; 9 | import lombok.NoArgsConstructor; 10 | import lombok.Setter; 11 | import lombok.ToString; 12 | import lombok.experimental.SuperBuilder; 13 | import org.springframework.beans.factory.annotation.Autowired; 14 | 15 | import java.util.Optional; 16 | 17 | /** 18 | * 基本模型基类 19 | * 20 | * @author ouyangsheng 21 | * @since 2022-05-13 22 | */ 23 | @ToString 24 | @NoArgsConstructor 25 | @SuperBuilder 26 | @Data 27 | @Entity 28 | public abstract class BaseAggregateRoot> extends BaseE { 29 | @SuppressWarnings("SpringJavaInjectionPointsAutowiringInspection") 30 | @Autowired(required = false) 31 | @Setter(AccessLevel.MODULE) 32 | protected BaseGatewayI basicGateway; 33 | 34 | /** 35 | * 分公司ID 36 | */ 37 | protected Long storeId; 38 | 39 | /** 40 | * 持久化 41 | */ 42 | public void save() { 43 | basicGateway.save((E) this); 44 | } 45 | 46 | /** 47 | * 推送事件 48 | * 49 | * @param eventObj 50 | */ 51 | public void publishEvent(DE eventObj) { 52 | basicGateway.publishEvent(eventObj); 53 | } 54 | 55 | 56 | /** 57 | * 获取工厂Bean 58 | * 59 | * @param fClass 60 | * @param 61 | * @return 62 | */ 63 | protected static T getFactoryBean(Class fClass) { 64 | return ApplicationContextHelper.getBean(fClass); 65 | } 66 | 67 | /** 68 | * 通过ID获取 69 | * 70 | * @param domainClass 71 | * @param id 72 | * @param 73 | * @return 74 | */ 75 | protected static > Optional findDomainById(Class domainClass, Long id) { 76 | return getBasicGateway(domainClass).flatMap(gateway -> gateway.findDomainById(id)); 77 | } 78 | 79 | /** 80 | * 获取值对象 81 | * 82 | * @param domainClass 83 | * @param id 84 | * @param vajObjClass 85 | * @param 86 | * @param 87 | * @return 88 | */ 89 | protected static , V> Optional findValObjById(Class domainClass, Long id, Class vajObjClass) { 90 | return getBasicGateway(domainClass).flatMap(gateway -> gateway.findValObjById(id, vajObjClass)); 91 | } 92 | 93 | /** 94 | * 获取Gateway 95 | * 96 | * @param clazz 97 | * @param 98 | * @return 99 | */ 100 | public static > Optional getBasicGateway(Class clazz) { 101 | return GatewayManager.findGatewayByDomainClass(clazz); 102 | } 103 | } 104 | -------------------------------------------------------------------------------- /ice-cola-framework/framework-core-exception/src/main/java/cn/stephen12/icecola/framework/exception/CoreExceptionHandler.java: -------------------------------------------------------------------------------- 1 | package cn.stephen12.icecola.framework.exception; 2 | 3 | import cn.stephen12.icecola.framework.model.vo.RestResult; 4 | import com.alibaba.cola.exception.BizException; 5 | import com.alibaba.cola.exception.SysException; 6 | import lombok.extern.slf4j.Slf4j; 7 | import org.springframework.core.Ordered; 8 | import org.springframework.core.annotation.Order; 9 | import org.springframework.web.bind.annotation.ControllerAdvice; 10 | import org.springframework.web.bind.annotation.ExceptionHandler; 11 | import org.springframework.web.bind.annotation.ResponseBody; 12 | 13 | /** 14 | * 核心异常处理 15 | * 16 | * @author ouyangsheng 17 | * @date 2022-05-26 18 | **/ 19 | @Slf4j 20 | @ControllerAdvice 21 | @Order(Ordered.LOWEST_PRECEDENCE - 10) 22 | public class CoreExceptionHandler { 23 | private static final Integer DEFAULT_CLIENT_ERROR_CODE = 400; 24 | private static final Integer DEFAULT_SERVER_ERROR_CODE = 500; 25 | 26 | /** 27 | * 业务异常,抛给用户看到,不需要打堆栈 28 | * 29 | * @param e 30 | * @return 31 | */ 32 | @ExceptionHandler(value = ErrorCodeBizException.class) 33 | @ResponseBody 34 | public RestResult handleErrorCodeBizException(ErrorCodeBizException e) { 35 | log.info("ErrorCodeBizException( code: {}, message: {})", e.getCode(), e.getMessage()); 36 | return RestResult.fail(e.getCode(), e.getMessage()); 37 | } 38 | 39 | /** 40 | * 业务异常,抛给用户看到,不需要打堆栈 41 | * 42 | * @param e 43 | * @return 44 | */ 45 | @ExceptionHandler(value = BizException.class) 46 | @ResponseBody 47 | public RestResult handleBizException(BizException e) { 48 | log.info("BizException( code: {}, message: {})", e.getErrCode(), e.getMessage()); 49 | return RestResult.fail(DEFAULT_CLIENT_ERROR_CODE, e.getMessage()); 50 | } 51 | 52 | /** 53 | * 参数错误,要打堆栈 54 | * 55 | * @param e 56 | * @return 57 | */ 58 | @ExceptionHandler(value = IllegalArgumentException.class) 59 | @ResponseBody 60 | public RestResult handleIllegalArgumentException(IllegalArgumentException e) { 61 | log.info("IllegalArgumentException( message: {}), cause: {}", e.getMessage(), e); 62 | return RestResult.fail(DEFAULT_CLIENT_ERROR_CODE 63 | , e.getMessage()); 64 | } 65 | 66 | /** 67 | * 状态错误,需要打堆栈 68 | * 69 | * @param e 70 | * @return 71 | */ 72 | @ExceptionHandler(value = IllegalStateException.class) 73 | @ResponseBody 74 | public RestResult handleIllegalStateException(IllegalStateException e) { 75 | log.warn("IllegalStateException( message: {}), cause: {}", e.getMessage(), e); 76 | return RestResult.fail(DEFAULT_CLIENT_ERROR_CODE 77 | , e.getMessage()); 78 | } 79 | 80 | /** 81 | * 系统异常,抛给程序员看的,要打堆栈 82 | * 83 | * @param e 84 | * @return 85 | */ 86 | @ExceptionHandler(value = SysException.class) 87 | @ResponseBody 88 | public RestResult handleSysException(SysException e) { 89 | log.error("SysException( code: {}, message: {}), cause: {}", e.getErrCode(), e.getMessage(), e); 90 | return RestResult.fail(DEFAULT_SERVER_ERROR_CODE 91 | , "内部系统错误"); 92 | } 93 | 94 | 95 | } 96 | -------------------------------------------------------------------------------- /ice-cola-framework/framework-core-model/src/main/java/cn/stephen12/icecola/framework/model/vo/RestResult.java: -------------------------------------------------------------------------------- 1 | package cn.stephen12.icecola.framework.model.vo; 2 | 3 | import cn.stephen12.icecola.framework.model.dto.ErrorCodeEnumI; 4 | import com.alibaba.cola.exception.BizException; 5 | import lombok.Builder; 6 | import lombok.Data; 7 | 8 | import java.io.Serializable; 9 | import java.util.function.Supplier; 10 | 11 | /** 12 | * 参考 Optional 对响应结果进行包装 13 | * 14 | * @author ouyangsheng 15 | * @date 2022-05-26 16 | **/ 17 | @Data 18 | @Builder 19 | public class RestResult implements Serializable { 20 | /** 21 | * 成功的状态码 22 | */ 23 | private final static Integer SUCCESS_CODE_0 = 0; 24 | private final static Integer SUCCESS_CODE_200 = 200; 25 | private final static String DEFAULT_SUCCESS_MESSAGE = "OK"; 26 | 27 | private static final long serialVersionUID = 6095433538316185017L; 28 | private int code; 29 | private String message; 30 | private T data; 31 | 32 | public RestResult() { 33 | } 34 | 35 | public RestResult(int code, String message, T data) { 36 | this.code = code; 37 | this.setMessage(message); 38 | this.data = data; 39 | } 40 | 41 | public RestResult(int code, T data) { 42 | this.code = code; 43 | this.data = data; 44 | } 45 | 46 | public RestResult(int code, String message) { 47 | this.code = code; 48 | this.setMessage(message); 49 | } 50 | 51 | public boolean isOk() { 52 | return this.code == SUCCESS_CODE_0 || this.code == SUCCESS_CODE_200; 53 | } 54 | 55 | @Override 56 | public String toString() { 57 | return "RestResult{code=" + this.code + ", message='" + this.message + '\'' + ", data=" + this.data + '}'; 58 | } 59 | 60 | public static RestResult fail(int code, String message) { 61 | return new RestResult(code, message); 62 | } 63 | 64 | public static RestResult success() { 65 | return new RestResult(SUCCESS_CODE_0, DEFAULT_SUCCESS_MESSAGE); 66 | } 67 | 68 | public static RestResult success(T data) { 69 | return new RestResult(SUCCESS_CODE_0, DEFAULT_SUCCESS_MESSAGE, data); 70 | } 71 | 72 | public static RestResult success(String message, T data) { 73 | return new RestResult(SUCCESS_CODE_0, message, data); 74 | } 75 | 76 | /** 77 | * 如果未成功,则抛异常 78 | * 79 | * @param ex 80 | * @return 81 | */ 82 | public T elseThrow(Supplier ex) { 83 | if (this.isOk()) { 84 | return this.getData(); 85 | } 86 | throw ex.get(); 87 | } 88 | 89 | /** 90 | * 如果失败,抛出异常 91 | * 92 | * @param codeEnum 93 | * @param errorMsgTemplate 94 | * @param params 95 | * @return 96 | */ 97 | public T elseThrow(ErrorCodeEnumI codeEnum, String errorMsgTemplate, Object... params) { 98 | return elseThrow(() -> { 99 | String message = String.format(errorMsgTemplate, params); 100 | return new BizException(String.valueOf(codeEnum.getCode()), message); 101 | }); 102 | } 103 | 104 | /** 105 | * 如果失败,抛出异常 106 | * 107 | * @return 108 | */ 109 | public T elseThrow() { 110 | return elseThrow(() -> new BizException(String.valueOf(this.getCode()), this.getMessage()) 111 | ); 112 | } 113 | } 114 | -------------------------------------------------------------------------------- /ice-cola-components/component-distributed/src/main/java/cn/stephen12/icecola/component/distributed/DistributedLockUtil.java: -------------------------------------------------------------------------------- 1 | package cn.stephen12.icecola.component.distributed; 2 | 3 | import com.alibaba.cola.exception.BizException; 4 | import lombok.Getter; 5 | import lombok.extern.slf4j.Slf4j; 6 | import org.redisson.Redisson; 7 | import org.redisson.api.RLock; 8 | import org.springframework.beans.factory.annotation.Autowired; 9 | import org.springframework.stereotype.Component; 10 | 11 | import java.util.concurrent.TimeUnit; 12 | import java.util.function.Supplier; 13 | 14 | /** 15 | *

16 | * 分布式锁工具类 Redisson 实现。 17 | *

18 | * 19 | * @author ouyangsheng 20 | * @date 2022-03-14 21 | */ 22 | @Slf4j 23 | @Component 24 | public class DistributedLockUtil { 25 | @SuppressWarnings("SpringJavaInjectionPointsAutowiringInspection") 26 | @Autowired 27 | private Redisson redisson; 28 | 29 | /** 30 | * 获取锁,带返回结果 31 | * 32 | * @param processFunction 操作代码函数 ()-> { return obj; } 33 | * @param waitTime 超时时间 34 | * @param lockName 锁名称函数 ()-> str 35 | * @return 36 | */ 37 | public T lock(Supplier processFunction, Integer waitTime, Supplier lockName) { 38 | AbstractLockTemplateWithResult lockTemplateWithResult = new AbstractLockTemplateWithResult() { 39 | @Override 40 | public T processWithResult() { 41 | return processFunction.get(); 42 | } 43 | }; 44 | getLock(lockTemplateWithResult, waitTime, lockName.get()); 45 | return lockTemplateWithResult.getResult(); 46 | } 47 | 48 | /** 49 | * 获取锁 50 | * 51 | * @param processFunction 操作代码函数 ()-> { } 52 | * @param waitTime 等待时间 53 | * @param lockName 锁名称函数 ()-> str 54 | */ 55 | public void lock(LockTemplate processFunction, Integer waitTime, Supplier lockName) { 56 | getLock(processFunction, waitTime, lockName.get()); 57 | } 58 | 59 | /** 60 | * 获取锁,默认无返回结果 61 | * 62 | * @param lockTemplate 63 | * @param time 64 | */ 65 | private void getLock(LockTemplate lockTemplate, Integer time, String lockName) { 66 | RLock lock = null; 67 | try { 68 | //上锁 69 | lock = redisson.getLock(lockName); 70 | try { 71 | if (!lock.tryLock(time, TimeUnit.SECONDS)) { 72 | log.error("无法获取锁{}", lockName); 73 | throw new BizException("无法获取锁" + lockName); 74 | } 75 | } catch (InterruptedException e) { 76 | throw new BizException("无法获取锁" + lockName, e); 77 | } 78 | lockTemplate.process(); 79 | } finally { 80 | if (lock != null) { 81 | lock.unlock(); 82 | } 83 | } 84 | } 85 | 86 | @Getter 87 | private abstract class AbstractLockTemplateWithResult implements LockTemplate { 88 | private T result; 89 | 90 | /** 91 | * 业务代码 92 | * 93 | * @return 94 | */ 95 | public abstract T processWithResult(); 96 | 97 | @Override 98 | public void process() { 99 | this.result = processWithResult(); 100 | } 101 | } 102 | 103 | @FunctionalInterface 104 | public interface LockTemplate { 105 | /** 106 | * 业务代码 107 | */ 108 | void process(); 109 | } 110 | 111 | 112 | } -------------------------------------------------------------------------------- /ice-cola-components/component-utils/src/main/java/cn/stephen12/icecola/component/utils/ClassUtil.java: -------------------------------------------------------------------------------- 1 | package cn.stephen12.icecola.component.utils; 2 | 3 | 4 | import cn.hutool.core.lang.Assert; 5 | import org.springframework.core.GenericTypeResolver; 6 | 7 | import java.lang.reflect.Field; 8 | import java.util.Arrays; 9 | import java.util.LinkedHashMap; 10 | import java.util.List; 11 | import java.util.Map; 12 | import java.util.stream.Stream; 13 | 14 | import static java.util.function.Function.identity; 15 | import static java.util.stream.Collectors.toMap; 16 | 17 | /** 18 | * 反射工具类,提供反射相关的快捷操作 19 | * 20 | * @author Caratacus 21 | * @author hcl 22 | * @since 2016-09-22 23 | */ 24 | public class ClassUtil extends cn.hutool.core.util.ClassUtil { 25 | 26 | private static final char PACKAGE_SEPARATOR = '.'; 27 | 28 | /** 29 | * 代理 class 的名称 30 | */ 31 | private static final List PROXY_CLASS_NAMES = Arrays.asList("net.sf.cglib.proxy.Factory" 32 | // cglib 33 | , "org.springframework.cglib.proxy.Factory" 34 | , "javassist.util.proxy.ProxyObject" 35 | // javassist 36 | , "org.apache.ibatis.javassist.util.proxy.ProxyObject"); 37 | 38 | /** 39 | *

40 | * 反射对象获取泛型 41 | *

42 | * 43 | * @param clazz 对象 44 | * @param genericIfc 所属泛型父类 45 | * @param index 泛型所在位置 46 | * @return Class 47 | */ 48 | public static Class getSuperClassGenericType(final Class clazz, final Class genericIfc, final int index) { 49 | Class[] typeArguments = GenericTypeResolver.resolveTypeArguments(getUserClass(clazz), genericIfc); 50 | return null == typeArguments ? null : typeArguments[index]; 51 | } 52 | 53 | /** 54 | * 判断是否为代理对象 55 | * 56 | * @param clazz 传入 class 对象 57 | * @return 如果对象class是代理 class,返回 true 58 | */ 59 | public static boolean isProxy(Class clazz) { 60 | if (clazz != null) { 61 | for (Class cls : clazz.getInterfaces()) { 62 | if (PROXY_CLASS_NAMES.contains(cls.getName())) { 63 | return true; 64 | } 65 | } 66 | } 67 | return false; 68 | } 69 | 70 | /** 71 | *

72 | * 获取当前对象的 class 73 | *

74 | * 75 | * @param clazz 传入 76 | * @return 如果是代理的class,返回父 class,否则返回自身 77 | */ 78 | public static Class getUserClass(Class clazz) { 79 | Assert.notNull(clazz, "Class must not be null"); 80 | return isProxy(clazz) ? clazz.getSuperclass() : clazz; 81 | } 82 | 83 | /** 84 | *

85 | * 获取当前对象的class 86 | *

87 | * 88 | * @param object 对象 89 | * @return 返回对象的 user class 90 | */ 91 | public static Class getUserClass(Object object) { 92 | Assert.notNull(object, "Instance must not be null"); 93 | return getUserClass(object.getClass()); 94 | } 95 | 96 | 97 | /** 98 | *

99 | * 排序重置父类属性 100 | *

101 | * 102 | * @param fields 子类属性 103 | * @param superFieldList 父类属性 104 | */ 105 | public static Map excludeOverrideSuperField(Field[] fields, List superFieldList) { 106 | // 子类属性 107 | Map fieldMap = Stream.of(fields).collect(toMap(Field::getName, identity(), 108 | (u, v) -> { 109 | throw new IllegalStateException(String.format("Duplicate key %s", u)); 110 | }, 111 | LinkedHashMap::new)); 112 | superFieldList.stream().filter(field -> !fieldMap.containsKey(field.getName())) 113 | .forEach(f -> fieldMap.put(f.getName(), f)); 114 | return fieldMap; 115 | } 116 | 117 | 118 | } 119 | -------------------------------------------------------------------------------- /ice-cola-components/component-dictionary/src/main/java/cn/stephen12/icecola/component/dictionary/mybatis/MybatisEnumTypeHandler.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2011-2021, baomidou (jobob@qq.com). 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package cn.stephen12.icecola.component.dictionary.mybatis; 17 | 18 | import cn.hutool.core.util.StrUtil; 19 | import cn.stephen12.icecola.component.dictionary.model.Dict; 20 | import cn.stephen12.icecola.component.dictionary.model.Dictionary; 21 | import org.apache.ibatis.type.BaseTypeHandler; 22 | import org.apache.ibatis.type.JdbcType; 23 | 24 | import java.math.BigDecimal; 25 | import java.sql.CallableStatement; 26 | import java.sql.PreparedStatement; 27 | import java.sql.ResultSet; 28 | import java.sql.SQLException; 29 | import java.util.Arrays; 30 | import java.util.Objects; 31 | 32 | /** 33 | * 自定义枚举属性转换器 34 | * 35 | * @author ouyangsheng 36 | * @since 2022-09-07 37 | */ 38 | public class MybatisEnumTypeHandler extends BaseTypeHandler { 39 | 40 | private final Class enumClassType; 41 | private final Class propertyType; 42 | 43 | public MybatisEnumTypeHandler(Class enumClassType) { 44 | if (enumClassType == null) { 45 | throw new IllegalArgumentException("Type argument cannot be null"); 46 | } 47 | this.enumClassType = enumClassType; 48 | this.propertyType = (Class) Dict.getCodeType(enumClassType); 49 | } 50 | 51 | @SuppressWarnings("Duplicates") 52 | @Override 53 | public void setNonNullParameter(PreparedStatement ps, int i, E parameter, JdbcType jdbcType) 54 | throws SQLException { 55 | if (jdbcType == null) { 56 | ps.setObject(i, parameter.getCode()); 57 | } else { 58 | // see r3589 59 | ps.setObject(i, parameter.getCode(), jdbcType.TYPE_CODE); 60 | } 61 | } 62 | 63 | @Override 64 | public E getNullableResult(ResultSet rs, String columnName) throws SQLException { 65 | Object value = rs.getObject(columnName, this.propertyType); 66 | if (null == value && rs.wasNull()) { 67 | return null; 68 | } 69 | return this.valueOf(value); 70 | } 71 | 72 | @Override 73 | public E getNullableResult(ResultSet rs, int columnIndex) throws SQLException { 74 | Object value = rs.getObject(columnIndex, this.propertyType); 75 | if (null == value && rs.wasNull()) { 76 | return null; 77 | } 78 | return this.valueOf(value); 79 | } 80 | 81 | @Override 82 | public E getNullableResult(CallableStatement cs, int columnIndex) throws SQLException { 83 | Object value = cs.getObject(columnIndex, this.propertyType); 84 | if (null == value && cs.wasNull()) { 85 | return null; 86 | } 87 | return this.valueOf(value); 88 | } 89 | 90 | private E valueOf(Object value) { 91 | E[] es = this.enumClassType.getEnumConstants(); 92 | return Arrays.stream(es).filter((e) -> equalsValue(value, e.getCode())).findAny().orElse(null); 93 | } 94 | 95 | /** 96 | * 值比较 97 | * 98 | * @param sourceValue 数据库字段值 99 | * @param targetValue 当前枚举属性值 100 | * @return 是否匹配 101 | * @since 3.3.0 102 | */ 103 | protected boolean equalsValue(Object sourceValue, Object targetValue) { 104 | String sValue = StrUtil.toString(sourceValue).trim(); 105 | String tValue = StrUtil.toString(targetValue).trim(); 106 | if (sourceValue instanceof Number && targetValue instanceof Number 107 | && new BigDecimal(sValue).compareTo(new BigDecimal(tValue)) == 0) { 108 | return true; 109 | } 110 | return Objects.equals(sValue, tValue); 111 | } 112 | 113 | } 114 | -------------------------------------------------------------------------------- /ice-cola-components/component-dictionary/src/main/java/cn/stephen12/icecola/component/dictionary/DictionaryRegistry.java: -------------------------------------------------------------------------------- 1 | package cn.stephen12.icecola.component.dictionary; 2 | 3 | import cn.hutool.core.util.StrUtil; 4 | import cn.stephen12.icecola.component.dictionary.model.DefaultDictWrapper; 5 | import cn.stephen12.icecola.component.dictionary.model.DictWrapper; 6 | import cn.stephen12.icecola.component.dictionary.model.Dictionary; 7 | import com.alibaba.cola.exception.SysException; 8 | import lombok.extern.slf4j.Slf4j; 9 | import org.springframework.core.annotation.AnnotationUtils; 10 | import org.springframework.util.StringUtils; 11 | 12 | import java.lang.reflect.Constructor; 13 | import java.util.Arrays; 14 | import java.util.List; 15 | import java.util.Map; 16 | import java.util.concurrent.ConcurrentHashMap; 17 | 18 | import static org.springframework.util.StringUtils.hasLength; 19 | 20 | /** 21 | * 枚举字典字典注册中心 22 | * 23 | * @author ouyangsheng 24 | * @date 2022-03-16 25 | **/ 26 | @Slf4j 27 | public class DictionaryRegistry { 28 | /** 29 | * 原始包装类型、不能被注册的 30 | */ 31 | private final static List> ORIGIN_DICT_WRAPPER_CLASSES = Arrays.asList(DictWrapper.class, DefaultDictWrapper.class); 32 | private final static String DEFAULT_SUFFIX = "Enum"; 33 | 34 | static final Map dictionaryMap = new ConcurrentHashMap(16); 35 | static final Map> wrapperToPrototypeMap = new ConcurrentHashMap(16); 36 | 37 | public static void registerDictWrapper(Class wrapperClazz) { 38 | String key = getDictionaryKey(wrapperClazz); 39 | registerDictWrapper(key, wrapperClazz); 40 | } 41 | 42 | public static void registerDictWrapper(String key, Class wrapperClazz) { 43 | if (isDictWrapper(wrapperClazz)) { 44 | try { 45 | Constructor constructor = wrapperClazz.getConstructor(); 46 | DictWrapper wrapper = (DictWrapper) constructor.newInstance(); 47 | 48 | register0(key, wrapper); 49 | } catch (Exception e) { 50 | throw new SysException("Error occurred when register dictWrapper[" + wrapperClazz + "]: ", e); 51 | } 52 | } else { 53 | throw new SysException("wrapperClazz(" + wrapperClazz + ") must implement DictWrapper"); 54 | } 55 | } 56 | 57 | public static void registerDict(Class enumClazz) { 58 | String key = getDictionaryKey(enumClazz); 59 | registerDict(key, enumClazz); 60 | } 61 | 62 | public static void registerDict(String key, Class enumClazz) { 63 | if (isDictionary(enumClazz)) { 64 | DefaultDictWrapper dictWrapper = new DefaultDictWrapper(); 65 | dictWrapper.setPrototypeClass(enumClazz); 66 | 67 | register0(key, dictWrapper); 68 | } else { 69 | throw new SysException("enumClazz(" + enumClazz + ") must implement Dictionary and be a enum"); 70 | } 71 | } 72 | 73 | 74 | public static boolean isDictionary(Class clazz) { 75 | return Dictionary.class.isAssignableFrom(clazz) && clazz.isEnum(); 76 | } 77 | 78 | public static boolean isDictWrapper(Class clazz) { 79 | if (ORIGIN_DICT_WRAPPER_CLASSES.contains(clazz)) { 80 | return false; 81 | } 82 | return DictWrapper.class.isAssignableFrom(clazz); 83 | } 84 | 85 | public static String getDictionaryKey(Class cls) { 86 | String key; 87 | DictionaryKey annotation = AnnotationUtils.findAnnotation(cls, DictionaryKey.class); 88 | if (annotation != null && hasLength(annotation.value())) { 89 | key = annotation.value(); 90 | } else { 91 | key = StringUtils.uncapitalize(cls.getSimpleName()); 92 | 93 | //如果有 Enum后缀,则移除Enum 94 | int indexOfSuffix = key.indexOf(DEFAULT_SUFFIX); 95 | if (indexOfSuffix > 0) { 96 | key = key.substring(0, indexOfSuffix); 97 | } 98 | } 99 | 100 | // 前端要求字典key 统一下划线格式 101 | return StrUtil.toUnderlineCase(key); 102 | } 103 | 104 | private static void register0(String key, DictWrapper wrapper) { 105 | dictionaryMap.put(key, wrapper); 106 | wrapperToPrototypeMap.put(wrapper, wrapper.getPrototypeClass()); 107 | } 108 | } 109 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Ice Cola DDD架构文档 2 | 3 | ## Overview 4 | 在实践过程中逐渐沉淀的 DDD 开发框架,延用了Alibaba Cola 的设计理念, 5 | 集成 Spring Data( 主要是 JPA 和 Mongodb) 实现了主动充血和持久化能力,并封装了DDD的一些核心概念。 6 | 借鉴了Cola的命名,起名叫 Ice Cola, 意为:”冰可乐“,加倍的快乐! 7 | 8 | ![Ice Cola 结构图](doc/img/ice_cola_framework.png) 9 | 10 | 项目分成三部分: 11 | 1. Ice Cola Framework 12 | 2. Ice Cola Components 13 | 3. 业务系统的架构及规范 14 | ## Ice-Cola Framework 15 | 1. core-adapter 16 | 未实现 17 | 1. core-app 18 | 对AppService、CmdExecutor、CmdProcessor概念进行封装 19 | 2. core-domain 20 | 对 BaseAggregateRoot、BaseE、Gateway等盖帘进行封装 21 | 3. core-infrastructure 22 | 对 BaseGatewayImpl进行实现,实现了自动转换、自动充血、自动持久化等功能 23 | 24 | ![Ice Cola 持久化逻辑](doc/img/ice_cola_persistence.png) 25 | 4. core-exception 26 | 27 | 对 业务异常进行了封装,实现了基本异常的处理器。 28 | ## Ice-Cola Components 29 | - dictionary 30 | 打通了 MyBatis、Hibernate、FastJson、HuTool 等常用框架, 31 | 让你摆脱枚举转换的烦恼;提供统一的枚举接口;未来可支持动态枚举。 32 | 33 | - mock 34 | 在接口完成开发之前,提供mock数据给前端 35 | 36 | - office 37 | 优雅地进行导入导出 38 | 39 | - distributed 40 | 分布式锁、限流、防重、幂等等工具能力 41 | 42 | - utils 43 | 在 HuTool 的基础上,拓展了如数学集合运算,数轴运算,校验规则集, 44 | ClassUtil 等工具。 45 | 46 | - Op Log 47 | 操作日志组件,支持采集当前操作(事务型)前后数据变化及行为描述, 48 | 并整理成半格式化数据同步指日志服务。 49 | 50 | ## 业务系统结构及规范 51 | 52 | ![ice cola framework.png](doc/img/ice_cola_framework.png) 53 | 54 | ### Adapter 层 55 | 1. Adapter 层要维护Application所需的登录、权限等信息。 56 | 2. Adapter 层原则上使用 Form、VO与外部交互,不要为了重用而调整Cmd或Qry对象。 57 | 58 | 3. Controller 命名为 XxControllerForApp、XxControllerForOpenApi 59 | 4. 请求适配器命名为 XxRequestAdapter 如 PlaceOrderRequestAdapter 60 | 61 | ![ice cola framework.png](doc/img/CQRS_and_concepts.png) 62 | 上图为CQRS模式对应 各层的逻辑关系 63 | 64 | ### Query 层 65 | 目的是将查询从Domain中分割出来 66 | 67 | ### Application 层 68 | 1. Application目的是做编排、控制及应用层面内聚。 69 | 2. 不能直接依赖Infrastructure。 70 | 3. 追求无状态,避免利用TreadLocal或RequestAttributes传递值,这样会导致控制耦合。 71 | 4. 不要使用Context对象,公共耦合。 72 | 73 | 5. AppService 命名为 XxAppService 74 | 6. Executor、Processor 统一命名为 XxCmdExecutor,并实现 ICmdExecutor或 ICmdProcessor, 且加上@CmdExecutor注解 75 | 7. 事务统一加载 AppService 方法上。 76 | 8. 请注意,CmdExecutor 会自动对 Cmd 做校验。 77 | 9. EventListener 统一命名为XxEventListener 78 | 79 | ### Domain 层 80 | 1. Domain 层的目的是知识内聚,要屏蔽实现细节,聚焦于核心概念的表述。 81 | 2. Domain 层不能直接依赖Infrastructure。 82 | 3. Domain 层需要确保领域知识的完整性:非同一聚合的不能相互调用,同一聚合的不能分开;核心知识必须封装到Domain层。 83 | 4. 聚合根默认作为单例Bean存在,可以注入Gateway进行操作,但禁止在本聚合内直接操作其他聚合的数据。 84 | 5. 创建聚合根的逻辑建议使用DomainFactory封装,DomainFactory本身是一种DomainService。 85 | 6. 需要操作、查询、校验多个聚合跟(而非明确的某一个)时,使用DomainService。 86 | 7. 属于本聚合固有行为,且该行为可能引发其他聚合改变的,可以用DomainEvent。 87 | 8. 发布事件需要在调用聚合根的Save方法后。 88 | 9. 领域事件必须在Domain层内发布,不能在Application层发布。 89 | 90 | 10. AggregateRoot、DomainEntity 统一命名为 XxE 91 | 11. 领域事件统一命名为 XxEvent。 92 | 93 | ### Infrastructure 层 94 | 1. Infrastructure层的目的是技术实现、资源调配,对上层透明,通过Gateway与Domain、Application交互。 95 | 2. Gateway只设计于服务相应的聚合,Gateway实现不宜有太多业务逻辑。 96 | 3. 出SpringDataRepository 外,建议把外部服务(FeiClient等) 通过RepositoryWrapper包装为一个整体。 缓存也建议加在Repository上。 97 | 4. MyBatis Mapper 命名空间 优先按逻辑概念聚合。 98 | 5. DO( Data Object) 及 Entity只宜出现在本层。 99 | 6. 事件、消息的实现在本层,但处理通常在App层。 100 | 7. 事务型操作建议使用Jpa、查询操作建议使用MyBatis,且禁止同一事务中用Jpa和MyBatis同时写,会导致很多缓存失效,进而导致数据不一致。 101 | 102 | 8. Gateway 命名为 XxGateway 103 | 9. Mapper 命名为 XxAggregationMapper 104 | 10. 对实体转换的 Converter 统一命名为 XxEntityConverter 105 | 11. 利用 MapperConfig封装共用的Convert逻辑 106 | 107 | 108 | ## 版本说明 109 | ### 1.0.3 110 | 1. 自动装配 DataFiller 111 | 2. 领域实体 Payload 112 | 3. Excel 导出优化 113 | .... 114 | 115 | ### 1.0.5 116 | 1. 执行器CmdExecutor 统一参数校验 @Valid 117 | 2. Dictionary 默认扫包路径 118 | 3. 反射处理DomainPayloadCopy 119 | 4. 优化及修复CoreExceptionHandler 120 | 5. 请求级别缓存实现 RequestContextCacheManager 121 | 122 | ### 1.0.6 123 | 1. Gateway增加remove方法; 124 | 2. Gateway增加发布事件忽略异常方法 125 | 3. LocalDateTimeToLongConverter、LocalDateToLongConverter 126 | 4. 优化统一异常处理; 127 | 5. SetUtil (Hutool的 CollUtil是基于Collection进行交集、并集、差集运算,不能满足侠义上的集合运算) 128 | 6. WithEntityPayloadConverter 隐藏Payload概念,降低使用成本。 129 | 7. RequestScopeCacheSweeper 自动配置 130 | 8. EntityConverter 基于IJpaEntity转换,IJpaEntity移除非必要参数(仅保留Id) 131 | 9. Dictionary 去除对MyBatis-Plus、Hibernate强依赖;只需要配置Dictionary扫包路径,不需再配置MyBatis-plus枚举扫包路径。 132 | 133 | ### 1.1 (孵化中) 134 | 1. 去掉Payload 从 EntityManager 中获取JpaEntity对象 135 | 2. Fix: Dictionary MyBatisTypeHandler注册 bug. 136 | 3. 干掉非通用性工具。 137 | 138 | ### TODO LIST 139 | - enhanced-auditing 组件封装 140 | - archetype 141 | - Excel 导入导出 142 | - PDF 处理 143 | - MQ 整合Event 144 | - repository 大量数据异步请求 145 | - 业务日志框架 146 | - 多租户组件 -------------------------------------------------------------------------------- /ice-cola-framework/framework-core-infr/src/main/java/cn/stephen12/icecola/framework/core/infr/IEntityConverter.java: -------------------------------------------------------------------------------- 1 | package cn.stephen12.icecola.framework.core.infr; 2 | 3 | 4 | import cn.hutool.core.bean.BeanUtil; 5 | import cn.hutool.core.bean.copier.CopyOptions; 6 | import cn.hutool.core.util.ReflectUtil; 7 | import cn.stephen12.icecola.framework.core.domain.model.AfterDataInitializing; 8 | import cn.stephen12.icecola.framework.core.domain.model.BaseAggregateRoot; 9 | import cn.stephen12.icecola.framework.core.domain.model.BaseE; 10 | import cn.stephen12.icecola.framework.core.domain.model.BaseV; 11 | import cn.stephen12.icecola.framework.core.infr.datafiller.DataFiller; 12 | import cn.stephen12.icecola.framework.core.infr.model.IJpaEntity; 13 | import cn.stephen12.icecola.framework.core.infr.model.IdV; 14 | import com.alibaba.cola.domain.ApplicationContextHelper; 15 | import org.mapstruct.AfterMapping; 16 | import org.mapstruct.MappingTarget; 17 | import org.mapstruct.ObjectFactory; 18 | import org.mapstruct.TargetType; 19 | 20 | import javax.persistence.EntityManager; 21 | 22 | /** 23 | * 基础 Convertor 24 | * 25 | * @author ouyangsheng 26 | * @date 2022-04-01 27 | **/ 28 | public interface IEntityConverter, E extends IJpaEntity> { 29 | /** 30 | * 转换 Domain为 Entity 31 | * 32 | * @param domain 33 | * @return 34 | */ 35 | E convertDomainToEntity(D domain); 36 | 37 | /** 38 | * 复制领域模型到实体 39 | * 40 | * @param domain 41 | * @param entity 42 | */ 43 | void copyFromDomainToEntity(D domain, @MappingTarget E entity); 44 | 45 | /** 46 | * 转换 Entity 为 Domain 47 | * 48 | * @param entity 49 | * @return 50 | */ 51 | D convertEntityToDomain(E entity); 52 | 53 | /** 54 | * 复制实体到领域模型 55 | * 56 | * @param domain 57 | * @param entity 58 | */ 59 | void copyFromEntityToDomain(E entity, @MappingTarget D domain); 60 | 61 | /** 62 | * 多态生成聚合对象 63 | * 64 | * @param idv 65 | * @param vType 66 | * @return 67 | */ 68 | @ObjectFactory 69 | default V generateV(IDV idv, @TargetType Class vType) { 70 | return DataFiller.findVById(idv, vType); 71 | } 72 | 73 | /** 74 | * 调用目标对象方法 75 | * @param target 76 | */ 77 | @AfterMapping 78 | default void defaultAfterMapping(@MappingTarget AfterDataInitializing target){ 79 | target.afterDataInitializing(); 80 | } 81 | 82 | /** 83 | * 从EntityManager中获取Entity,而非直接new 84 | * 85 | * @param 86 | */ 87 | interface WithEm, E extends IJpaEntity> extends IEntityConverter { 88 | 89 | /** 90 | * 从BaseE 转换为JpaEntity的时候,从EntityManager 获取 JpaEntity 91 | * 92 | * @param domainE 93 | * @param jpaEntityType 94 | * @param BaseE子类 95 | * @param 96 | * @return 97 | */ 98 | @ObjectFactory 99 | default JE generateJpaEntity(BE domainE, @TargetType Class jpaEntityType) { 100 | EntityManager em = ApplicationContextHelper.getBean(EntityManager.class); 101 | JE jpaEntity = em.find(jpaEntityType, domainE.getId()); 102 | if (jpaEntity != null) { 103 | // 不能传递原引用,因为Copy过程中Collection类型无法保证引用不变 104 | return BeanUtil.toBean(jpaEntity,jpaEntityType); 105 | } 106 | 107 | return ReflectUtil.newInstance(jpaEntityType); 108 | } 109 | 110 | /** 111 | * 从BaseV 转换为JpaEntity的时候,从EntityManager 获取 112 | * 113 | * @param valueObj 114 | * @param jpaEntityType 115 | * @param BaseV子类 116 | * @param 117 | * @return 118 | */ 119 | @ObjectFactory 120 | default JE generateJpaEntity(BV valueObj, @TargetType Class jpaEntityType) { 121 | EntityManager em = ApplicationContextHelper.getBean(EntityManager.class); 122 | JE jpaEntity = em.find(jpaEntityType, valueObj.getId()); 123 | if (jpaEntity != null) { 124 | // 不能传递原引用,因为Copy过程中Collection类型无法保证引用不变 125 | return BeanUtil.toBean(jpaEntity,jpaEntityType); 126 | } 127 | 128 | return ReflectUtil.newInstance(jpaEntityType); 129 | } 130 | 131 | } 132 | } 133 | -------------------------------------------------------------------------------- /ice-cola-components/component-dictionary/src/main/java/cn/stephen12/icecola/component/dictionary/apidoc/EnumModelPropertyPlugin.java: -------------------------------------------------------------------------------- 1 | package cn.stephen12.icecola.component.dictionary.apidoc; 2 | 3 | import com.google.common.base.Optional; 4 | import cn.stephen12.icecola.component.dictionary.DictionaryFiled; 5 | import cn.stephen12.icecola.component.dictionary.DictionaryManager; 6 | import cn.stephen12.icecola.component.dictionary.DictionaryRegistry; 7 | import cn.stephen12.icecola.component.dictionary.model.DictionaryVO; 8 | import io.swagger.annotations.ApiModelProperty; 9 | import lombok.extern.slf4j.Slf4j; 10 | import org.springframework.beans.factory.annotation.Autowired; 11 | import org.springframework.stereotype.Component; 12 | import springfox.documentation.schema.Annotations; 13 | import springfox.documentation.service.AllowableListValues; 14 | import springfox.documentation.spi.DocumentationType; 15 | import springfox.documentation.spi.schema.ModelPropertyBuilderPlugin; 16 | import springfox.documentation.spi.schema.contexts.ModelPropertyContext; 17 | import springfox.documentation.swagger.schema.ApiModelProperties; 18 | 19 | import java.lang.annotation.Annotation; 20 | import java.util.Collection; 21 | import java.util.List; 22 | import java.util.stream.Collectors; 23 | 24 | /** 25 | *

26 | * Swagger 插件,对枚举属性的支持 27 | *

28 | * 29 | * @author ouyangsheng 30 | * @date 2021-03-25 31 | */ 32 | @Slf4j 33 | @Component 34 | public class EnumModelPropertyPlugin implements ModelPropertyBuilderPlugin { 35 | @Autowired 36 | private DictionaryManager dictionaryManager; 37 | 38 | @Override 39 | public void apply(ModelPropertyContext context) { 40 | buildDictionaryTypeProperty(context); 41 | buildEnumModelProperty(context); 42 | } 43 | 44 | @Override 45 | public boolean supports(DocumentationType documentationType) { 46 | return true; 47 | } 48 | 49 | 50 | /** 51 | * 枚举类型的属性文档 52 | * 53 | * @param context 54 | */ 55 | private void buildEnumModelProperty(ModelPropertyContext context) { 56 | Optional annotation = findApiModelProperty(context); 57 | final Class rawPrimaryType = context.getBeanPropertyDefinition().get().getRawPrimaryType(); 58 | //过滤得到目标类型 实现Dictionary 的枚举 59 | if (annotation.isPresent() && DictionaryRegistry.isDictionary(rawPrimaryType)) { 60 | 61 | //获取指定包装器 62 | Optional dictionaryFiled = findAnnotation(context, DictionaryFiled.class); 63 | 64 | //获取字典Key 65 | String dictKey = dictionaryFiled.isPresent() ? DictionaryRegistry.getDictionaryKey(dictionaryFiled.get().wrapperClass()) 66 | : DictionaryRegistry.getDictionaryKey(rawPrimaryType); 67 | 68 | //获取Enum的code值 69 | Collection dictionaryVos = dictionaryManager.listDictByType(dictKey); 70 | final List displayValues = dictionaryVos.stream().map(dict -> " " + dict.getCode() + " - " + dict.getName()).collect(Collectors.toList()); 71 | final AllowableListValues allowableListValues = new AllowableListValues(displayValues, rawPrimaryType.getTypeName()); 72 | 73 | context.getBuilder() 74 | .description(annotation.get().value() + " [枚举 key: " + dictKey + "] ") 75 | .allowableValues(allowableListValues) 76 | .type(context.getResolver().resolve(String.class)); 77 | } 78 | } 79 | 80 | private void buildDictionaryTypeProperty(ModelPropertyContext context) { 81 | Optional apiDictionaryType = findAnnotation(context, ApiDictionaryType.class); 82 | if (apiDictionaryType.isPresent()) { 83 | log.debug("@ApiDictionaryType present"); 84 | context.getBuilder().description(DictionaryParamDescriptor.buildDescription(dictionaryManager)); 85 | } 86 | } 87 | 88 | private Optional findApiModelProperty(ModelPropertyContext context) { 89 | Optional annotation = Optional.absent(); 90 | 91 | if (context.getAnnotatedElement().isPresent()) { 92 | annotation = annotation.or(Optional.fromJavaUtil(ApiModelProperties.findApiModePropertyAnnotation(context.getAnnotatedElement().get()))); 93 | } 94 | if (context.getBeanPropertyDefinition().isPresent()) { 95 | annotation = annotation.or(findAnnotation(context, ApiModelProperty.class)); 96 | } 97 | return annotation; 98 | } 99 | 100 | private Optional findAnnotation(ModelPropertyContext context, Class clazz) { 101 | if (context.getBeanPropertyDefinition().isPresent()) { 102 | return Optional.fromJavaUtil(Annotations.findPropertyAnnotation( 103 | context.getBeanPropertyDefinition().get(), 104 | clazz)); 105 | } 106 | return Optional.absent(); 107 | } 108 | } -------------------------------------------------------------------------------- /ice-cola-components/component-office/src/main/java/cn/stephen12/icecola/component/office/excel/ExportExcelAspect.java: -------------------------------------------------------------------------------- 1 | package cn.stephen12.icecola.component.office.excel; 2 | 3 | import cn.afterturn.easypoi.excel.ExcelExportUtil; 4 | import cn.afterturn.easypoi.excel.entity.ExportParams; 5 | import cn.hutool.core.lang.Assert; 6 | import cn.hutool.core.util.StrUtil; 7 | import cn.stephen12.icecola.component.office.excel.annotation.ExportExcel; 8 | import cn.stephen12.icecola.component.office.excel.handler.ExcelDataHandleDispatcher; 9 | import cn.stephen12.icecola.component.office.excel.model.ExcelVO; 10 | import cn.stephen12.icecola.framework.model.unpacker.Unpacker; 11 | import com.alibaba.cola.domain.ApplicationContextHelper; 12 | import com.alibaba.cola.exception.SysException; 13 | import org.apache.poi.ss.usermodel.Workbook; 14 | import org.aspectj.lang.annotation.AfterReturning; 15 | import org.aspectj.lang.annotation.Aspect; 16 | import org.springframework.beans.factory.annotation.Autowired; 17 | import org.springframework.stereotype.Component; 18 | import org.springframework.util.CollectionUtils; 19 | 20 | import javax.servlet.http.HttpServletResponse; 21 | import java.net.URLEncoder; 22 | import java.util.List; 23 | 24 | /** 25 | * 导出Excel注解 26 | * 27 | * @author ouyangsheng 28 | * @date 2022-03-31 29 | **/ 30 | @Aspect 31 | @Component 32 | public class ExportExcelAspect { 33 | 34 | @Autowired 35 | private HttpServletResponse response; 36 | @Autowired 37 | private ExcelDataHandleDispatcher excelDataHandleDispatcher; 38 | 39 | @AfterReturning(returning = "resultObj", pointcut = "@annotation(exportExcel)") 40 | public void exportExcel(ExportExcel exportExcel, Object resultObj) { 41 | String fileName = getFileName(exportExcel, resultObj); 42 | String sheetName = getSheetName(exportExcel, resultObj); 43 | 44 | if (StrUtil.isBlank(fileName) || StrUtil.isBlank(sheetName)) { 45 | throw new SysException("Please correctly set the annotation @ExportExcel."); 46 | } 47 | 48 | //拆包 49 | Unpacker unpacker = getUnpacker(exportExcel.unpacker()); 50 | List data = unpacker.unpack(resultObj); 51 | 52 | //TODO 按理说可以把这里去掉,为空的情况,直接返回空excel 53 | Assert.state(!CollectionUtils.isEmpty(data), "没有数据可导出"); 54 | 55 | Class modelType = data.get(0).getClass(); 56 | try { 57 | response.setHeader("Access-Control-Expose-Headers", "content-disposition"); 58 | response.addHeader("content-disposition", "attachment;filename=" + URLEncoder.encode(fileName, "UTF-8") + ".xls"); 59 | 60 | ExportParams exportParams = new ExportParams(); 61 | exportParams.setDataHandler(this.excelDataHandleDispatcher); 62 | exportParams.setExclusions(getExclusions()); 63 | 64 | Workbook workbook = ExcelExportUtil.exportExcel(exportParams, modelType, data); 65 | workbook.write(response.getOutputStream()); 66 | workbook.close(); 67 | } catch (Exception e) { 68 | throw new SysException("Error occurred when export data to excel.", e); 69 | } finally { 70 | //清理上下文 71 | ExcelContext.clear(); 72 | } 73 | } 74 | 75 | 76 | /** 77 | * 拆包器 78 | * 79 | * @param unpackerClass 80 | * @return 81 | */ 82 | private Unpacker getUnpacker(Class unpackerClass) { 83 | //尝试从容器中获取实例 84 | Unpacker unpacker = ApplicationContextHelper.getBean(unpackerClass); 85 | if (unpacker == null) { 86 | try { 87 | unpacker = unpackerClass.getConstructor().newInstance(); 88 | } catch (Exception e) { 89 | throw new SysException("Instancing " + unpackerClass.getName() + " fail. Please ensure your unpacker class is instantiatable", e); 90 | } 91 | } 92 | 93 | return unpacker; 94 | } 95 | 96 | /** 97 | * 获取文件名 98 | * 99 | * @param exportExcel 100 | * @param resultObj 101 | * @return 102 | */ 103 | private String getFileName(ExportExcel exportExcel, Object resultObj) { 104 | if (resultObj != null && resultObj instanceof ExcelVO) { 105 | return ((ExcelVO) resultObj).getFileName(); 106 | } 107 | return exportExcel.fileName(); 108 | } 109 | 110 | /** 111 | * 获取Sheet 名称 112 | * 113 | * @param exportExcel 114 | * @param resultObj 115 | * @return 116 | */ 117 | private String getSheetName(ExportExcel exportExcel, Object resultObj) { 118 | if (resultObj != null && resultObj instanceof ExcelVO) { 119 | return ((ExcelVO) resultObj).getSheetName(); 120 | } 121 | return exportExcel.shellName(); 122 | } 123 | 124 | /** 125 | * 获取需要排除的列 126 | * 127 | * @return 128 | */ 129 | private String[] getExclusions() { 130 | int exclusionNum = ExcelContext.getExcludedFields().size(); 131 | String[] exclusions = new String[exclusionNum]; 132 | return ExcelContext.getExcludedFields().toArray(exclusions); 133 | } 134 | 135 | 136 | } 137 | -------------------------------------------------------------------------------- /ice-cola-components/component-dictionary/src/main/java/cn/stephen12/icecola/component/dictionary/jpa/DictUserType.java: -------------------------------------------------------------------------------- 1 | package cn.stephen12.icecola.component.dictionary.jpa; 2 | 3 | import cn.stephen12.icecola.component.dictionary.model.Dict; 4 | import cn.stephen12.icecola.component.dictionary.model.Dictionary; 5 | import org.hibernate.HibernateException; 6 | import org.hibernate.engine.spi.SharedSessionContractImplementor; 7 | import org.hibernate.usertype.DynamicParameterizedType; 8 | import org.hibernate.usertype.UserType; 9 | 10 | import java.io.Serializable; 11 | import java.lang.reflect.Type; 12 | import java.sql.PreparedStatement; 13 | import java.sql.ResultSet; 14 | import java.sql.SQLException; 15 | import java.sql.Types; 16 | import java.util.*; 17 | import java.util.concurrent.ConcurrentHashMap; 18 | 19 | /** 20 | * 字典Hibernate 类型定义 21 | * 22 | * @author ouyangsheng 23 | * @date 2022-03-08 24 | **/ 25 | public class DictUserType implements UserType, DynamicParameterizedType { 26 | /** 27 | * 全类名 28 | */ 29 | public static final String DICT_TYPE_NAME = "cn.stephen12.icecola.component.dictionary.jpa.DictUserType"; 30 | private static final String SQL_TYPE_PROPERTY_NAME = "SqlType"; 31 | 32 | /** 33 | * 默认Java 类型-Sql 类型的映射 34 | */ 35 | private static final Map DEFAULT_TYPE_TO_SQL_TYPE_MAP = new ConcurrentHashMap<>(16); 36 | 37 | static { 38 | /** 39 | * 默认JAVA 类型 到SQL 类型映射关系 40 | */ 41 | DEFAULT_TYPE_TO_SQL_TYPE_MAP.put(Long.TYPE, Types.BIGINT); 42 | DEFAULT_TYPE_TO_SQL_TYPE_MAP.put(Integer.TYPE, Types.INTEGER); 43 | DEFAULT_TYPE_TO_SQL_TYPE_MAP.put(Short.TYPE, Types.SMALLINT); 44 | DEFAULT_TYPE_TO_SQL_TYPE_MAP.put(Byte.TYPE, Types.TINYINT); 45 | DEFAULT_TYPE_TO_SQL_TYPE_MAP.put(String.class, Types.VARCHAR); 46 | DEFAULT_TYPE_TO_SQL_TYPE_MAP.put(Boolean.TYPE, Types.BOOLEAN); 47 | DEFAULT_TYPE_TO_SQL_TYPE_MAP.put(Character.TYPE, Types.CHAR); 48 | } 49 | 50 | private Class enumClass; 51 | private int sqlType; 52 | 53 | @Override 54 | public void setParameterValues(Properties parameters) { 55 | //设置枚举类 56 | setEnumClass(parameters); 57 | 58 | //设置 SqlType 59 | setSqlType(parameters); 60 | } 61 | 62 | @Override 63 | public int[] sqlTypes() { 64 | return new int[]{this.sqlType}; 65 | } 66 | 67 | @Override 68 | public Class returnedClass() { 69 | return this.enumClass; 70 | } 71 | 72 | @Override 73 | public boolean equals(Object x, Object y) throws HibernateException { 74 | return Objects.equals(x, y); 75 | } 76 | 77 | @Override 78 | public int hashCode(Object x) throws HibernateException { 79 | return x.hashCode(); 80 | } 81 | 82 | @Override 83 | public Object nullSafeGet(ResultSet rs, String[] names, SharedSessionContractImplementor session, Object owner) throws HibernateException, SQLException { 84 | String code = rs.getString(names[0]); 85 | return Arrays.stream(enumClass.getEnumConstants()) 86 | .filter(dict -> dict.codeToStr().equals(code)) 87 | .findFirst().orElse(null); 88 | } 89 | 90 | @Override 91 | public void nullSafeSet(PreparedStatement st, Object value, int index, SharedSessionContractImplementor session) throws HibernateException, SQLException { 92 | if (value != null) { 93 | Object code = ((Dictionary) value).getCode(); 94 | st.setObject(index, code, this.sqlType); 95 | } else { 96 | st.setNull(index, this.sqlType); 97 | } 98 | } 99 | 100 | @Override 101 | public Object deepCopy(Object value) throws HibernateException { 102 | return value; 103 | } 104 | 105 | @Override 106 | public boolean isMutable() { 107 | return false; 108 | } 109 | 110 | @Override 111 | public Serializable disassemble(Object value) throws HibernateException { 112 | return (Serializable) value; 113 | } 114 | 115 | @Override 116 | public Object assemble(Serializable cached, Object owner) throws HibernateException { 117 | return cached; 118 | } 119 | 120 | @Override 121 | public Object replace(Object original, Object target, Object owner) throws HibernateException { 122 | return original; 123 | } 124 | 125 | private void setEnumClass(Properties parameters) { 126 | final ParameterType parameterType = (ParameterType) parameters.get(PARAMETER_TYPE); 127 | if (parameterType != null) { 128 | enumClass = parameterType.getReturnedClass().asSubclass(Enum.class); 129 | } 130 | } 131 | 132 | private void setSqlType(Properties parameters) { 133 | Integer sqlType = Optional.ofNullable(getSqlTypeFromParameter(parameters)) 134 | .orElseGet(() -> getSqlTypeFromDefaultMap()); 135 | 136 | if (sqlType != null) { 137 | this.sqlType = sqlType; 138 | } else { 139 | this.sqlType = Types.INTEGER; 140 | } 141 | } 142 | 143 | private Integer getSqlTypeFromParameter(Properties parameters) { 144 | final String val = (String) parameters.get(SQL_TYPE_PROPERTY_NAME); 145 | if (val != null) { 146 | return Integer.parseInt(val); 147 | } 148 | return null; 149 | } 150 | 151 | private Integer getSqlTypeFromDefaultMap() { 152 | if (this.enumClass != null) { 153 | Type codeType = Dict.getCodeType(enumClass); 154 | return DictUserType.DEFAULT_TYPE_TO_SQL_TYPE_MAP.get(codeType); 155 | } 156 | return null; 157 | } 158 | } 159 | -------------------------------------------------------------------------------- /ice-cola-components/component-dictionary/src/main/java/cn/stephen12/icecola/component/dictionary/autoconfig/DictionaryScanner.java: -------------------------------------------------------------------------------- 1 | package cn.stephen12.icecola.component.dictionary.autoconfig; 2 | 3 | import cn.stephen12.icecola.component.dictionary.DictionaryRegistry; 4 | import lombok.extern.slf4j.Slf4j; 5 | import org.springframework.beans.factory.InitializingBean; 6 | import org.springframework.context.ConfigurableApplicationContext; 7 | import org.springframework.core.io.Resource; 8 | import org.springframework.core.io.support.PathMatchingResourcePatternResolver; 9 | import org.springframework.core.io.support.ResourcePatternResolver; 10 | import org.springframework.core.type.ClassMetadata; 11 | import org.springframework.core.type.classreading.CachingMetadataReaderFactory; 12 | import org.springframework.core.type.classreading.MetadataReaderFactory; 13 | import org.springframework.stereotype.Component; 14 | import org.springframework.util.Assert; 15 | import org.springframework.util.ClassUtils; 16 | import org.springframework.util.StringUtils; 17 | 18 | import java.io.IOException; 19 | import java.util.HashSet; 20 | import java.util.Set; 21 | import java.util.stream.Stream; 22 | 23 | import static org.springframework.util.StringUtils.hasLength; 24 | import static org.springframework.util.StringUtils.tokenizeToStringArray; 25 | 26 | /** 27 | * 字典扫描器 28 | * 29 | * @author ouyangsheng 30 | * @date 2022-03-16 31 | **/ 32 | @Slf4j 33 | @Component 34 | public class DictionaryScanner implements InitializingBean { 35 | private static final String STAR = "*"; 36 | private static final String SEMICOLON = ";"; 37 | public static final String COMMA = ","; 38 | 39 | 40 | private static final ResourcePatternResolver RESOURCE_PATTERN_RESOLVER = new PathMatchingResourcePatternResolver(); 41 | private static final MetadataReaderFactory METADATA_READER_FACTORY = new CachingMetadataReaderFactory(); 42 | 43 | private String typeEnumsPackage; 44 | 45 | public DictionaryScanner(DictionaryProperties properties){ 46 | this.typeEnumsPackage = properties.getTypeEnumsPackage(); 47 | } 48 | 49 | public void registerDictionaries() throws IOException { 50 | // TODO 自定义枚举类扫描处理 51 | if (hasLength(this.typeEnumsPackage)) { 52 | Set> classes; 53 | if (typeEnumsPackage.contains(STAR) && !typeEnumsPackage.contains(COMMA) 54 | && !typeEnumsPackage.contains(SEMICOLON)) { 55 | classes = scanClasses(typeEnumsPackage, null); 56 | if (classes.isEmpty()) { 57 | log.warn("Can't find class in '[" + typeEnumsPackage + "]' package. Please check your configuration."); 58 | } 59 | } else { 60 | classes = new HashSet<>(); 61 | String[] typeEnumsPackageArray = tokenizeToStringArray(this.typeEnumsPackage, 62 | ConfigurableApplicationContext.CONFIG_LOCATION_DELIMITERS); 63 | Assert.notNull(typeEnumsPackageArray, "not find typeEnumsPackage:" + typeEnumsPackage); 64 | Stream.of(typeEnumsPackageArray).forEach(typePackage -> { 65 | try { 66 | Set> scanTypePackage = scanClasses(typePackage, null); 67 | if (scanTypePackage.isEmpty()) { 68 | log.warn("Can't find class in '[" + typePackage + "]' package. Please check your configuration."); 69 | } else { 70 | classes.addAll(scanTypePackage); 71 | } 72 | } catch (IOException e) { 73 | throw new IllegalStateException("Cannot scan class in '[" + typePackage + "]' package", e); 74 | } 75 | }); 76 | } 77 | 78 | // 注册枚举 79 | classes.stream() 80 | .filter(DictionaryRegistry::isDictionary) 81 | .forEach(DictionaryRegistry::registerDict); 82 | 83 | 84 | // 注册枚举包装器 85 | classes.stream() 86 | .filter(DictionaryRegistry::isDictWrapper) 87 | .forEach(DictionaryRegistry::registerDictWrapper); 88 | } 89 | } 90 | 91 | private Set> scanClasses(String packagePatterns, Class assignableType) throws IOException { 92 | Set> classes = new HashSet(); 93 | String[] packagePatternArray = StringUtils.tokenizeToStringArray(packagePatterns, ",; \t\n"); 94 | String[] var5 = packagePatternArray; 95 | int var6 = packagePatternArray.length; 96 | 97 | for(int var7 = 0; var7 < var6; ++var7) { 98 | String packagePattern = var5[var7]; 99 | Resource[] resources = RESOURCE_PATTERN_RESOLVER.getResources("classpath*:" + ClassUtils.convertClassNameToResourcePath(packagePattern) + "/**/*.class"); 100 | Resource[] var10 = resources; 101 | int var11 = resources.length; 102 | 103 | for(int var12 = 0; var12 < var11; ++var12) { 104 | Resource resource = var10[var12]; 105 | 106 | try { 107 | ClassMetadata classMetadata = METADATA_READER_FACTORY.getMetadataReader(resource).getClassMetadata(); 108 | Class clazz = Class.forName(classMetadata.getClassName()); 109 | if (assignableType == null || assignableType.isAssignableFrom(clazz)) { 110 | classes.add(clazz); 111 | } 112 | } catch (Throwable var16) { 113 | log.warn("Cannot load the '" + resource + "'. Cause by " + var16.toString()); 114 | } 115 | } 116 | } 117 | 118 | return classes; 119 | } 120 | 121 | @Override 122 | public void afterPropertiesSet() throws Exception { 123 | this.registerDictionaries(); 124 | } 125 | } 126 | -------------------------------------------------------------------------------- /ice-cola-framework/framework-core-infr/src/main/java/cn/stephen12/icecola/framework/core/infr/datafiller/MergedDataFillStrategy.java: -------------------------------------------------------------------------------- 1 | package cn.stephen12.icecola.framework.core.infr.datafiller; 2 | 3 | import cn.hutool.core.bean.BeanUtil; 4 | import cn.hutool.core.bean.copier.CopyOptions; 5 | import cn.hutool.core.date.StopWatch; 6 | import cn.stephen12.icecola.framework.core.infr.api.FindAggregateRootInterceptor; 7 | import cn.stephen12.icecola.framework.core.domain.model.BaseV; 8 | import cn.stephen12.icecola.framework.core.infr.context.RequestContext; 9 | import cn.stephen12.icecola.framework.core.infr.model.IdV; 10 | import cn.stephen12.icecola.framework.core.infr.repository.RepositoryWrapper; 11 | import org.springframework.context.annotation.Primary; 12 | import org.springframework.stereotype.Component; 13 | import org.springframework.util.LinkedMultiValueMap; 14 | import org.springframework.util.MultiValueMap; 15 | 16 | import java.util.List; 17 | import java.util.Map; 18 | import java.util.Set; 19 | import java.util.function.Function; 20 | import java.util.stream.Collectors; 21 | 22 | /** 23 | * 合并数据填充策略 24 | *
25 | * 通过收集所有同类型值对象的ID,调用批量查询的接口,减少I/O 26 | * 27 | * @author ouyangsheng 28 | * @date 2022-05-25 29 | **/ 30 | @Primary 31 | @Component 32 | public class MergedDataFillStrategy implements DataFillStrategy, FindAggregateRootInterceptor { 33 | 34 | /** 35 | * 缓存Key 36 | */ 37 | private final static String MERGE_CACHE_KEY = "MERGE_CACHE"; 38 | 39 | /** 40 | * 数据填充策略 41 | * 42 | * @param id 43 | * @param targetVType 44 | * @param 45 | * @return 46 | */ 47 | @Override 48 | public V findById(Long id, Class targetVType) { 49 | //从上下文中获取缓存对象 50 | MergeCache mergeCache = getMergeCache(); 51 | 52 | //新建对象、并缓存 53 | return mergeCache.newAndCache(targetVType, id); 54 | } 55 | 56 | /** 57 | * 虽然一个RequestContext 范围内,会有多个聚合跟 充血的过程,但只需要保证每次充血后把数据清空,即可保证数据正确性。 58 | * 59 | * @param aggregateRoot 60 | */ 61 | @Override 62 | public void postHandle(Object aggregateRoot) { 63 | StopWatch stopWatch = new StopWatch(); 64 | stopWatch.start("Start filling outer data!"); 65 | 66 | //从上下文中获取缓存对象 67 | MergeCache mergeCache = getMergeCache(); 68 | 69 | //拿到所有被缓存的类型,统一调接口 70 | Set cachedVTypes = mergeCache.getCachedVTypes(); 71 | for (Class vType : cachedVTypes) { 72 | 73 | //拿到所有Id去调 findByIds 方法 74 | Set instanceIdSet = mergeCache.getInstanceIdSet(vType); 75 | List instances = mergeCache.getInstances(vType); 76 | 77 | //查询结果 78 | RepositoryWrapper repository = DataFiller.getRepository(vType); 79 | Map results = (Map) repository.findByIds(instanceIdSet).stream() 80 | .collect(Collectors.toMap(this::getId, Function.identity(), (pre, curr) -> pre)); 81 | 82 | //将结果反Copy 回实例 83 | for (Object inst : instances) { 84 | Object source = results.get(getId(inst)); 85 | BeanUtil.copyProperties(source, inst, CopyOptions.create().ignoreNullValue().ignoreError()); 86 | } 87 | } 88 | 89 | //清理MergeCache 避免其他同线程聚合根数据错乱 90 | mergeCache.clear(); 91 | 92 | //Finished filling outer data 93 | stopWatch.stop(); 94 | stopWatch.prettyPrint(); 95 | } 96 | 97 | /** 98 | * 获取任意Bean的Id 99 | * 100 | * @param obj 101 | * @return 102 | */ 103 | private Long getId(Object obj) { 104 | if (obj instanceof IdV) { 105 | return ((IdV) obj).obtainId(); 106 | } else if (obj instanceof BaseV) { 107 | return ((BaseV) obj).getId(); 108 | } else { 109 | return BeanUtil.getProperty(obj, "id"); 110 | } 111 | } 112 | 113 | private MergeCache getMergeCache() { 114 | //获取该类型的缓存 115 | return RequestContext.computeIfAbsent(MERGE_CACHE_KEY, key -> new MergeCache()); 116 | } 117 | 118 | 119 | /** 120 | * 服务于请求合并,每一种值对象,对应一个 MergeCache 121 | */ 122 | class MergeCache { 123 | /** 124 | * 一对多的Map 125 | */ 126 | MultiValueMap vTypeToInstancesMap; 127 | 128 | /** 129 | * 初始化 130 | */ 131 | MergeCache() { 132 | this.vTypeToInstancesMap = new LinkedMultiValueMap<>(16); 133 | } 134 | 135 | /** 136 | * 往缓存里添加实例 137 | * 138 | * @param vType 139 | * @param id 140 | * @param 141 | * @return 142 | */ 143 | V newAndCache(Class vType, Long id) { 144 | V vObj = null; 145 | try { 146 | vObj = vType.newInstance(); 147 | vObj.setId(id); 148 | } catch (Exception e) { 149 | throw new IllegalStateException("targetVType (" + vType.toString() + ") is not implementable"); 150 | } 151 | this.vTypeToInstancesMap.add(vType, vObj); 152 | 153 | return vObj; 154 | } 155 | 156 | /** 157 | * 获取所有被缓存管理的值对象类型 158 | * 159 | * @return 160 | */ 161 | Set getCachedVTypes() { 162 | return this.vTypeToInstancesMap.keySet(); 163 | } 164 | 165 | 166 | /** 167 | * 获取指定类型 的 Instances 168 | * 169 | * @param vType 170 | * @return 171 | */ 172 | List getInstances(Class vType) { 173 | return this.vTypeToInstancesMap.get(vType); 174 | } 175 | 176 | /** 177 | * 获取指定类型 的 Id集合 178 | * 179 | * @param vType 180 | * @return 181 | */ 182 | Set getInstanceIdSet(Class vType) { 183 | return this.vTypeToInstancesMap.get(vType).stream().map(v -> getId(v)).collect(Collectors.toSet()); 184 | } 185 | 186 | /** 187 | * 清理掉全部缓存 188 | */ 189 | void clear() { 190 | this.vTypeToInstancesMap.clear(); 191 | } 192 | } 193 | } 194 | --------------------------------------------------------------------------------