# infrastructure **Repository Path**: Dreamer1024_admin/infrastructure ## Basic Information - **Project Name**: infrastructure - **Description**: Java开发基础架构: 1. 国际化处理(SPI) 2.通用异常捕获 3.多数据源连接(MyBatis- Plus) 4.Shrio权鉴验证 5.DDD框架(可选, 基于AXON) - **Primary Language**: Java - **License**: Not specified - **Default Branch**: main - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 1 - **Created**: 2023-04-20 - **Last Updated**: 2023-04-20 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # infrastructure #### 介绍 Java开发基础架构: 1. 国际化处理 2. 通用异常捕获 3. 多数据源连接(MyBatis- Plus) 4. Shiro权鉴验证 5. DDD框架(可选, 基于AXON) 6. Partner(DDD示例应用) #### Axon * 框架文档: [点击访问](https://docs.axoniq.io/reference-guide/) * [关于TEP, SEP 的说明](https://docs.axoniq.io/reference-guide/axon-framework/events/event-processors/streaming#spring-boot-autoconfiguration-4) * [关于AxonServer的说明](https://developer.axoniq.io/axon-server/overview) * [关于拦截器的说胆](https://docs.axoniq.io/reference-guide/axon-framework/messaging-concepts/message-intercepting) #### mdb * [Spring boot Starter](https://reflectoring.io/spring-boot-starter/) * [Configuration Properties](https://docs.spring.io/spring-boot/docs/current/reference/html/features.html) * [Bean 容器](https://docs.spring.io/spring-framework/docs/current/reference/html/core.html) * [MyBatis/Mybatis-Plus](https://baomidou.com/) #### mvc * [Servlet Listener/Filter/Interceptor](https://cloud.tencent.com/developer/article/1342503), 应用于全局异常处理 * [ResponseBodyAdvice](https://www.cnblogs.com/dissipate/p/16335792.html), 统一返回值 * [i18n(ResourceBundleMessage)](https://www.baeldung.com/spring-boot-internationalization) 国际化 * [SPI-Java Service Provider Interface](https://docs.oracle.com/javase/tutorial/sound/SPI-intro.html), 动态加载国际化本地文件 * [Validation-(spring-boot-starter-validation)](https://www.baeldung.com/spring-boot-bean-validation), 注解验证,国际化后返回, #### 软件架构 软件架构说明 #### 安装教程 1. mvn clean install -Pdelombok -DskipTests #### 使用说明 ##### mdb -multiple datasource 1.需要配置多数据库源,示例如下: ``` mdb: databases: - item: password: password user: user url: jdbc:mysql://server:13306/databaseName type: com.mysql.cj.jdbc.MysqlDataSource driver: com.mysql.cj.jdbc.Driver max: 100 idle: 100 mapper: '' name: partner desc: partner ``` MyBatisPlus 配置 ```java @Slf4j @Configuration @EnableTransactionManagement @MapperScan(basePackages = "com.yp.apps.partner.domain.mapper", sqlSessionTemplateRef = "partnerSqlSessionTemplate") public class PartnerDataSource { } ``` ##### 国际化 1. 实现```IMessageSourceManager``` 2. 在```META-INF/services```目录下创建SPI文件 ```com.yp.infrastructure.mvc.i18n.IMessageSourceProvider```, 内容为接口的实现类 #### Shiro 1. 配置JWT签名与默认过期时间(分钟) ``` security: secret: juxj.net expired: 10 ``` ##### DDD 1. 聚合 ```kotlin @Aggregate class PartnerAggregate constructor() : BaseAggregate() { val log: Logger = LoggerFactory.getLogger(PartnerAggregate::class.java) lateinit var code: String lateinit var name: String @AggregateMember var customers: MutableSet = mutableSetOf() @AggregateMember var vendors: MutableSet = mutableSetOf() @CommandHandler constructor(cmd: CreatePartnerCommand) : this() { val e = CreatePartnerEvent(cmd.code, cmd.name, cmd.owner, cmd.type) e.id = cmd.id AggregateLifecycle.apply(e) } @EventHandler fun on(e: CreatePartnerEvent) { log.debug("....") this.id = e.id this.code = e.code this.name = e.name when (e.type) { EnumPartnerType.CUSTOMER -> { if (customers.contains(e.owner)) throw PartnerException(EnumErrorMessage.CUSTOMER_EXISTS) customers.add(e.owner) } EnumPartnerType.VENDOR -> { if (customers.contains(e.owner)) throw PartnerException(EnumErrorMessage.VENDOR_EXISTS) vendors.add(e.owner) } else -> { throw PartnerException(EnumErrorMessage.UNKNOWN_PARTNER_TYPE) } } } } abstract class AbstractAxonHandler : AbstractHandler() { /** * 查询聚合实体 * @param repository 聚合仓库 * @param id 聚合id * @param e 空值是否异常, 默认(true),空值抛异常 */ @Throws(AggregateNotFoundException::class) protected inline fun getAxonAggregate( repository: EventSourcingRepository, id: String, e: Boolean = true ): T { val aggregate = repository.load(id).wrappedAggregate.aggregateRoot if (null == aggregate && e) { logger.warn("聚合未找到: {}, type:{}", id, T::class.simpleName) throw AggregateNotFoundException("Aggregate Not found", id) } return aggregate } } ``` 2. 命令 ```kotlin /** * 命令责职抽象类 */ abstract class AbstractPartnerCommand(open val owner: String) : BaseAxonCommand() { constructor(id: String, owner: String) : this(owner) { this.id = id } } /** * 创建命令 */ data class CreatePartnerCommand( val code: String, val name: String, override val owner: String, val type: EnumPartnerType ) : AbstractPartnerCommand(owner) /** * 更改状态 */ data class ChangePartnerStatusCommand( val partnerId: String, override val owner: String, val status: EnumAvailable, val type: EnumPartnerType ) : AbstractPartnerCommand(partnerId, owner) ``` 3. 事件 ```kotlin /** * Partner事件抽象类 */ abstract class AbstractPartnerEvent(open val owner: String) : BaseAxonEvent() { constructor(id: String, owner: String) : this(owner) { this.id = id } } /** * 创建Partner */ data class CreatePartnerEvent( val code: String, val name: String, override val owner: String, val type: EnumPartnerType ) : AbstractPartnerEvent(owner) /** * 更改Partner状态 */ data class ChangePartnerStatusEvent( val partnerId: String, override val owner: String, val status: EnumAvailable, val type: EnumPartnerType ) : AbstractPartnerEvent(partnerId, owner) ``` 4. 查询 ```kotlin /** * 模糊查询 */ data class QueryPartnerByName(val name: String, val type: EnumPartnerType) : BaseAxonQuery() ``` 5. EventHandler ```kotlin @LazyAutowired lateinit var partnerMapper: PartnerMapper @LazyAutowired lateinit var partnerTypeMapper: PartnerTypeMapper @LazyAutowired lateinit var partnerShipMapper: PartnerShipMapper /** * 处理创建Partner创建事件, 如写数据, 或进行其他发布新的事件, 供后续处理 */ @EventHandler fun on(e: CreatePartnerEvent) { log.debug("event handler.") } ``` 7. QueryHandler ```kotlin /** * 事件库 */ @LazyAutowired lateinit var repository : EventSourcingRepository; /** * Mapper */ @LazyAutowired lateinit var partnerMapper: PartnerMapper @LazyAutowired lateinit var partnerTypeMapper: PartnerTypeMapper @LazyAutowired lateinit var partnerShipMapper: PartnerShipMapper /** * 可以通过Mybatis+到数据库查(MySql), 也可以通过EventSourcing到事件库(Mongodb)查询 */ @QueryHandler fun on(q: QueryPartnerByName): List? { return emptyList() } ```