├── .mvn
└── wrapper
│ ├── maven-wrapper.jar
│ └── maven-wrapper.properties
├── scs-main
├── src
│ └── main
│ │ ├── resources
│ │ ├── application.properties
│ │ └── logback-spring.xml
│ │ └── java
│ │ └── com
│ │ └── smart
│ │ └── classroom
│ │ └── subscription
│ │ ├── config
│ │ └── BootstrapConfiguration.java
│ │ └── SubscriptionApplication.java
└── pom.xml
├── scs-facade
├── src
│ └── main
│ │ └── java
│ │ └── com
│ │ └── smart
│ │ └── classroom
│ │ └── subscription
│ │ └── facade
│ │ ├── healthy
│ │ └── HealthyFacade.java
│ │ ├── biz
│ │ ├── subscription
│ │ │ ├── request
│ │ │ │ ├── ReaderColumnQueryRequest.java
│ │ │ │ ├── PrepareSubscribeRequest.java
│ │ │ │ └── SubscriptionPageRequest.java
│ │ │ ├── SubscriptionWriteFacade.java
│ │ │ ├── response
│ │ │ │ ├── PrepareSubscribeDTO.java
│ │ │ │ └── SubscriptionDTO.java
│ │ │ └── SubscriptionReadFacade.java
│ │ └── order
│ │ │ ├── OrderReadFacade.java
│ │ │ └── response
│ │ │ └── OrderDTO.java
│ │ └── common
│ │ └── resposne
│ │ └── PagerResponse.java
└── pom.xml
├── docs
└── start
│ ├── nacos.md
│ ├── zookeeper.md
│ └── rocketmq.md
├── scs-repository
├── src
│ └── main
│ │ ├── resources
│ │ ├── application-repository.properties
│ │ └── mybatis
│ │ │ ├── mapper
│ │ │ ├── subscription
│ │ │ │ ├── SubscriptionMapper.xml
│ │ │ │ └── SubscriptionBaseMapper.xml
│ │ │ └── order
│ │ │ │ └── OrderMapper.xml
│ │ │ └── mybatis-config.xml
│ │ └── java
│ │ └── com
│ │ └── smart
│ │ └── classroom
│ │ └── subscription
│ │ └── repository
│ │ ├── orm
│ │ ├── base
│ │ │ └── BaseEntityDO.java
│ │ ├── subscription
│ │ │ └── SubscriptionDO.java
│ │ └── order
│ │ │ └── OrderDO.java
│ │ ├── mapper
│ │ ├── subscription
│ │ │ ├── SubscriptionMapper.java
│ │ │ └── SubscriptionBaseMapper.java
│ │ ├── base
│ │ │ └── BaseMapper.java
│ │ └── order
│ │ │ ├── OrderMapper.java
│ │ │ └── OrderBaseMapper.java
│ │ ├── impl
│ │ ├── subscription
│ │ │ ├── converter
│ │ │ │ ├── SubscriptionDO2ModelConverter.java
│ │ │ │ └── SubscriptionModel2DOConverter.java
│ │ │ └── SubscriptionRepositoryImpl.java
│ │ └── order
│ │ │ ├── converter
│ │ │ ├── OrderDO2ModelConverter.java
│ │ │ └── OrderModel2DOConverter.java
│ │ │ └── OrderRepositoryImpl.java
│ │ ├── transaction
│ │ └── TransactionService.java
│ │ └── config
│ │ └── DataSourceConfiguration.java
└── pom.xml
├── scs-domain
├── src
│ └── main
│ │ └── java
│ │ └── com
│ │ └── smart
│ │ └── classroom
│ │ └── subscription
│ │ └── domain
│ │ ├── rpc
│ │ ├── reader
│ │ │ ├── ReaderFacadeClient.java
│ │ │ └── vo
│ │ │ │ └── ReaderVO.java
│ │ ├── column
│ │ │ ├── ColumnFacadeClient.java
│ │ │ └── vo
│ │ │ │ └── ColumnVO.java
│ │ ├── quote
│ │ │ ├── ColumnQuoteFacadeClient.java
│ │ │ └── vo
│ │ │ │ └── ColumnQuoteVO.java
│ │ └── payment
│ │ │ ├── info
│ │ │ ├── PaymentCreateInfo.java
│ │ │ └── PreparePaymentInfo.java
│ │ │ ├── PaymentFacadeClient.java
│ │ │ └── vo
│ │ │ └── PaymentVO.java
│ │ ├── middleware
│ │ └── mq
│ │ │ ├── MqConsumer.java
│ │ │ ├── info
│ │ │ ├── MqMessagePayloadInfo.java
│ │ │ ├── MqSendResultInfo.java
│ │ │ └── MqConsumeResultInfo.java
│ │ │ ├── MqConsumerListener.java
│ │ │ └── MqProducer.java
│ │ ├── base
│ │ └── member
│ │ │ └── Member.java
│ │ └── biz
│ │ ├── order
│ │ ├── info
│ │ │ └── PrepareSubscribeInfo.java
│ │ ├── enums
│ │ │ └── OrderStatus.java
│ │ ├── repository
│ │ │ ├── query
│ │ │ │ └── OrderPageQuery.java
│ │ │ └── OrderRepository.java
│ │ ├── model
│ │ │ └── OrderModel.java
│ │ └── service
│ │ │ ├── OrderPaidDomainService.java
│ │ │ └── OrderPrepareDomainService.java
│ │ └── subscription
│ │ ├── repository
│ │ ├── query
│ │ │ └── SubscriptionPageQuery.java
│ │ └── SubscriptionRepository.java
│ │ ├── enums
│ │ └── SubscriptionStatus.java
│ │ ├── event
│ │ └── SubscriptionDomainEvent.java
│ │ ├── info
│ │ └── SubscriptionEventPayload.java
│ │ ├── model
│ │ └── SubscriptionModel.java
│ │ └── service
│ │ └── SubscriptionCreateDomainService.java
└── pom.xml
├── scs-testsuit
├── src
│ ├── test
│ │ └── java
│ │ │ └── com
│ │ │ └── ddd
│ │ │ └── practise
│ │ │ └── testsuit
│ │ │ └── DddPractiseApplication.java
│ └── main
│ │ ├── resources
│ │ └── saber
│ │ │ ├── TemplateMapperXml.vm
│ │ │ ├── TemplateMapperJava.vm
│ │ │ ├── TemplateDOJava.vm
│ │ │ ├── TemplateBaseMapperJava.vm
│ │ │ └── TemplateBaseMapperXml.vm
│ │ └── java
│ │ └── com
│ │ └── smart
│ │ └── classroom
│ │ └── subscription
│ │ └── tool
│ │ └── saber
│ │ ├── config
│ │ └── SaberConfig.java
│ │ ├── artwork
│ │ ├── base
│ │ │ └── Artwork.java
│ │ ├── MapperJavaArtwork.java
│ │ ├── MapperXmlArtwork.java
│ │ └── DOArtwork.java
│ │ ├── x
│ │ ├── order
│ │ │ └── OrderCommand.java
│ │ └── subscription
│ │ │ └── SubscriptionCommand.java
│ │ ├── meta
│ │ └── SaberTable.java
│ │ ├── command
│ │ └── SaberCommand.java
│ │ └── contrast
│ │ └── TypeContrast.java
└── pom.xml
├── scs-utility
├── src
│ └── main
│ │ └── java
│ │ └── com
│ │ └── smart
│ │ └── classroom
│ │ └── subscription
│ │ └── utility
│ │ ├── exception
│ │ ├── ExceptionCode.java
│ │ ├── UnauthorizedException.java
│ │ ├── SystemException.java
│ │ └── UtilException.java
│ │ ├── enums
│ │ └── SortDirection.java
│ │ ├── model
│ │ ├── Triplet.java
│ │ └── Pair.java
│ │ ├── util
│ │ ├── TemplateUtil.java
│ │ ├── NumberUtil.java
│ │ ├── PathUtil.java
│ │ └── JsonUtil.java
│ │ └── result
│ │ └── Pager.java
└── pom.xml
├── .gitignore
├── scs-infrastructure
├── src
│ └── main
│ │ ├── resources
│ │ └── application-infrastructure.properties
│ │ └── java
│ │ └── com
│ │ └── smart
│ │ └── classroom
│ │ └── subscription
│ │ └── infrastructure
│ │ ├── rpc
│ │ ├── reader
│ │ │ ├── converter
│ │ │ │ └── ReaderDTO2VOConverter.java
│ │ │ └── ReaderFacadeClientImpl.java
│ │ ├── column
│ │ │ ├── converter
│ │ │ │ └── ColumnDTO2VOConverter.java
│ │ │ └── ColumnFacadeClientImpl.java
│ │ ├── payment
│ │ │ ├── converter
│ │ │ │ ├── PreparePaymentDTO2InfoConverter.java
│ │ │ │ └── PaymentDTO2VOConverter.java
│ │ │ └── PaymentFacadeClientImpl.java
│ │ └── quote
│ │ │ ├── converter
│ │ │ └── ColumnQuoteDTO2VOConverter.java
│ │ │ └── ColumnQuoteFacadeClientImpl.java
│ │ └── middleware
│ │ └── rocketmq
│ │ ├── RocketMqProducerImpl.java
│ │ └── RocketMqConsumerImpl.java
└── pom.xml
├── scs-facade-impl
├── src
│ └── main
│ │ └── java
│ │ └── com
│ │ └── smart
│ │ └── classroom
│ │ └── subscription
│ │ └── facade
│ │ └── impl
│ │ ├── healthy
│ │ └── HealthyFacadeImpl.java
│ │ └── biz
│ │ ├── order
│ │ ├── OrderReadFacadeImpl.java
│ │ └── converter
│ │ │ └── OrderModel2DTOConverter.java
│ │ └── subscription
│ │ ├── converter
│ │ └── SubscriptionModel2DTOConverter.java
│ │ ├── SubscriptionWriteFacadeImpl.java
│ │ └── SubscriptionReadFacadeImpl.java
└── pom.xml
├── scs-application
├── src
│ └── main
│ │ └── java
│ │ └── com
│ │ └── smart
│ │ └── classroom
│ │ └── subscription
│ │ └── application
│ │ └── rpc
│ │ └── payment
│ │ ├── event
│ │ └── PaymentDomainEvent.java
│ │ └── info
│ │ └── PaymentEventPayload.java
└── pom.xml
└── README.md
/.mvn/wrapper/maven-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/eyebluecn/smart-classroom-subscription/HEAD/.mvn/wrapper/maven-wrapper.jar
--------------------------------------------------------------------------------
/scs-main/src/main/resources/application.properties:
--------------------------------------------------------------------------------
1 | server.port=6500
2 |
3 | # include repository profiles
4 | spring.profiles.include=repository,infrastructure
5 |
--------------------------------------------------------------------------------
/scs-facade/src/main/java/com/smart/classroom/subscription/facade/healthy/HealthyFacade.java:
--------------------------------------------------------------------------------
1 | package com.smart.classroom.subscription.facade.healthy;
2 |
3 | /**
4 | * @author lishuang
5 | * @date 2023-05-11
6 | */
7 | public interface HealthyFacade {
8 | String check();
9 | }
10 |
--------------------------------------------------------------------------------
/docs/start/nacos.md:
--------------------------------------------------------------------------------
1 | # Nacos使用方法
2 | ## 下载
3 | 从 [官网](https://nacos.io/zh-cn/index.html) 下载,比如下载nacos-server-2.1.2.zip
4 |
5 | ## 解压
6 | unzip nacos-server-2.1.2.zip
7 | cd nacos/bin
8 |
9 | ## 启动
10 | ```shell
11 | sh startup.sh -m standalone
12 | ```
13 |
14 | window下使用
15 | ```shell
16 | startup.cmd -m standalone
17 | ```
18 |
19 | # 控制台
20 | 访问 http://localhost:8848/nacos/ 即可看到自己注册的服务。
--------------------------------------------------------------------------------
/scs-repository/src/main/resources/application-repository.properties:
--------------------------------------------------------------------------------
1 | spring.datasource.primary.jdbc-url=jdbc:mysql://127.0.0.1:3306/smart_classroom?useUnicode=true&useSSL=false&characterEncoding=UTF-8&serverTimezone=GMT%2B8&useInformationSchema=true
2 | spring.datasource.primary.username=smart_classroom
3 | spring.datasource.primary.password=Smart_classroom123
4 |
5 | logging.level.com.zaxxer.hikari=INFO
6 |
7 |
--------------------------------------------------------------------------------
/scs-domain/src/main/java/com/smart/classroom/subscription/domain/rpc/reader/ReaderFacadeClient.java:
--------------------------------------------------------------------------------
1 | package com.smart.classroom.subscription.domain.rpc.reader;
2 |
3 | import com.smart.classroom.subscription.domain.rpc.reader.vo.ReaderVO;
4 |
5 | /**
6 | * @author lishuang
7 | * @date 2023-05-15
8 | */
9 | public interface ReaderFacadeClient {
10 |
11 | ReaderVO queryById(long readerId);
12 |
13 | }
14 |
--------------------------------------------------------------------------------
/scs-domain/src/main/java/com/smart/classroom/subscription/domain/rpc/column/ColumnFacadeClient.java:
--------------------------------------------------------------------------------
1 | package com.smart.classroom.subscription.domain.rpc.column;
2 |
3 | import com.smart.classroom.subscription.domain.rpc.column.vo.ColumnVO;
4 | import com.smart.classroom.subscription.domain.rpc.reader.vo.ReaderVO;
5 |
6 | /**
7 | * @author lishuang
8 | * @date 2023-05-15
9 | */
10 | public interface ColumnFacadeClient {
11 |
12 | ColumnVO queryById(long columnId);
13 |
14 | }
15 |
--------------------------------------------------------------------------------
/scs-domain/src/main/java/com/smart/classroom/subscription/domain/middleware/mq/MqConsumer.java:
--------------------------------------------------------------------------------
1 | package com.smart.classroom.subscription.domain.middleware.mq;
2 |
3 | /**
4 | * @author lishuang
5 | * @date 2023-05-17
6 | * MQ消息订阅
7 | */
8 | public interface MqConsumer {
9 |
10 | /**
11 | * 监听某个"领域"下的某个"事件"消息。
12 | *
13 | * @param eventName 事件由 领域名前缀+事件构成. 需要上下游约定产出。
14 | */
15 | void listen(String eventName, MqConsumerListener mqConsumerListener);
16 |
17 | }
18 |
--------------------------------------------------------------------------------
/scs-domain/src/main/java/com/smart/classroom/subscription/domain/rpc/quote/ColumnQuoteFacadeClient.java:
--------------------------------------------------------------------------------
1 | package com.smart.classroom.subscription.domain.rpc.quote;
2 |
3 | import com.smart.classroom.subscription.domain.rpc.quote.vo.ColumnQuoteVO;
4 |
5 | /**
6 | * @author lishuang
7 | * @date 2023-05-15
8 | */
9 | public interface ColumnQuoteFacadeClient {
10 |
11 | ColumnQuoteVO queryById(long columnQuoteId);
12 |
13 |
14 | ColumnQuoteVO queryByColumnId(long columnId);
15 |
16 |
17 | }
18 |
--------------------------------------------------------------------------------
/scs-testsuit/src/test/java/com/ddd/practise/testsuit/DddPractiseApplication.java:
--------------------------------------------------------------------------------
1 | package com.smart.classroom.subscription.testsuit;
2 | import org.springframework.boot.SpringApplication;
3 | import org.springframework.boot.autoconfigure.SpringBootApplication;
4 |
5 | /**
6 | * @author fusu
7 | * @date 2023-04-14
8 | */
9 | @SpringBootApplication
10 | public class DddPractiseApplication {
11 |
12 | public static void main(String[] args) {
13 | SpringApplication.run(DddPractiseApplication.class, args);
14 | }
15 |
16 | }
17 |
--------------------------------------------------------------------------------
/scs-utility/src/main/java/com/smart/classroom/subscription/utility/exception/ExceptionCode.java:
--------------------------------------------------------------------------------
1 | package com.smart.classroom.subscription.utility.exception;
2 |
3 | import lombok.Getter;
4 |
5 |
6 | /**
7 | * 所有定义的错误码
8 | */
9 | public enum ExceptionCode {
10 |
11 | OK("成功"),
12 | UNAUTHORIZED("没有权限"),
13 | SYSTEM_ERROR("系统异常"),
14 | UNKNOWN("服务器未知错误"),
15 | ;
16 |
17 | @Getter
18 | private String message;
19 |
20 | ExceptionCode(String message) {
21 | this.message = message;
22 | }
23 |
24 | }
25 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | HELP.md
2 | target/
3 | !.mvn/wrapper/maven-wrapper.jar
4 | !**/src/main/**/target/
5 | !**/src/test/**/target/
6 |
7 | ### STS ###
8 | .apt_generated
9 | .classpath
10 | .factorypath
11 | .project
12 | .settings
13 | .springBeans
14 | .sts4-cache
15 |
16 | ### IntelliJ IDEA ###
17 | .idea
18 | *.iws
19 | *.iml
20 | *.ipr
21 |
22 | ### NetBeans ###
23 | /nbproject/private/
24 | /nbbuild/
25 | /dist/
26 | /nbdist/
27 | /.nb-gradle/
28 | build/
29 | !**/src/main/**/build/
30 | !**/src/test/**/build/
31 |
32 | ### VS Code ###
33 | .vscode/
34 |
35 | update.sh
36 | production/
--------------------------------------------------------------------------------
/scs-domain/src/main/java/com/smart/classroom/subscription/domain/base/member/Member.java:
--------------------------------------------------------------------------------
1 | package com.smart.classroom.subscription.domain.base.member;
2 |
3 | import lombok.AllArgsConstructor;
4 | import lombok.Data;
5 | import lombok.NoArgsConstructor;
6 |
7 | /**
8 | * 员工成员
9 | * @author fusu
10 | * @date 2023-04-14
11 | */
12 | @Data
13 | @NoArgsConstructor
14 | @AllArgsConstructor
15 | public class Member {
16 |
17 | /**
18 | * 工号
19 | */
20 | private String workNo;
21 |
22 | /**
23 | * 花名
24 | */
25 | private String nickname;
26 |
27 | }
28 |
--------------------------------------------------------------------------------
/scs-testsuit/src/main/resources/saber/TemplateMapperXml.vm:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/scs-infrastructure/src/main/resources/application-infrastructure.properties:
--------------------------------------------------------------------------------
1 | dubbo.application.name=smart-classroom-subscription
2 | dubbo.application.qos-port=22222
3 |
4 | # Enable token verification for each invocation
5 | dubbo.provider.token=false
6 | # do not check provider status when start.
7 | dubbo.consumer.check=false
8 |
9 | # Specify the registry address
10 | # dubbo.registry.address=nacos://localhost:8848?username=nacos&password=nacos
11 | dubbo.registry.address=nacos://${nacos.address:localhost}:8848?username=nacos&password=nacos
12 |
13 | dubbo.protocol.name=dubbo
14 | dubbo.protocol.port=20882
--------------------------------------------------------------------------------
/scs-domain/src/main/java/com/smart/classroom/subscription/domain/middleware/mq/info/MqMessagePayloadInfo.java:
--------------------------------------------------------------------------------
1 | package com.smart.classroom.subscription.domain.middleware.mq.info;
2 |
3 | import lombok.AllArgsConstructor;
4 | import lombok.Builder;
5 | import lombok.Data;
6 | import lombok.NoArgsConstructor;
7 |
8 | /**
9 | * @author lishuang
10 | * @date 2023-05-17
11 | */
12 | @Data
13 | @Builder
14 | @NoArgsConstructor
15 | @AllArgsConstructor
16 | public class MqMessagePayloadInfo {
17 |
18 | String messageId;
19 |
20 | String content;
21 |
22 | String tag;
23 |
24 | String keys;
25 |
26 | }
27 |
--------------------------------------------------------------------------------
/scs-testsuit/src/main/resources/saber/TemplateMapperJava.vm:
--------------------------------------------------------------------------------
1 | /**
2 | * smart-classroom.com Inc. Copyright (c) 2015-present All Rights Reserved.
3 | * generated by SaberGenerator
4 | */
5 | package ${artwork.mapperPackage};
6 |
7 | #foreach($item in $artwork.mapperImportNones)
8 | import ${item};
9 | #if(!$foreach.hasNext)
10 |
11 | #end
12 | #end
13 | #foreach($item in $artwork.mapperImportJavas)
14 | import ${item};
15 | #if(!$foreach.hasNext)
16 |
17 | #end
18 | #end
19 | @Mapper
20 | @Repository
21 | public interface ${artwork.entityUpperBodyName}Mapper extends ${artwork.entityUpperBodyName}BaseMapper {
22 |
23 | }
--------------------------------------------------------------------------------
/scs-domain/src/main/java/com/smart/classroom/subscription/domain/middleware/mq/MqConsumerListener.java:
--------------------------------------------------------------------------------
1 | package com.smart.classroom.subscription.domain.middleware.mq;
2 |
3 | import com.smart.classroom.subscription.domain.middleware.mq.info.MqMessagePayloadInfo;
4 |
5 | /**
6 | * @author lishuang
7 | * @date 2023-05-17
8 | * MQ消息订阅
9 | */
10 | public interface MqConsumerListener {
11 |
12 | /**
13 | * 订阅这。
14 | *
15 | * @param mqMessagePayloadInfo Mq投递过来的内容
16 | * @return true:表示消费成功,消息不再重新投递。 false:表示消费失败,消息会继续投递。
17 | */
18 | boolean consume(MqMessagePayloadInfo mqMessagePayloadInfo);
19 |
20 | }
21 |
--------------------------------------------------------------------------------
/scs-utility/src/main/java/com/smart/classroom/subscription/utility/exception/UnauthorizedException.java:
--------------------------------------------------------------------------------
1 | package com.smart.classroom.subscription.utility.exception;
2 |
3 |
4 | import lombok.Data;
5 | import lombok.EqualsAndHashCode;
6 |
7 |
8 | /**
9 | * 用户没有权限,不能访问
10 | */
11 | @EqualsAndHashCode(callSuper = false)
12 | @Data
13 | public class UnauthorizedException extends UtilException {
14 |
15 | public UnauthorizedException() {
16 | super(ExceptionCode.UNAUTHORIZED);
17 | }
18 |
19 | public UnauthorizedException(String messagePattern, Object... arguments) {
20 | super(ExceptionCode.UNAUTHORIZED, messagePattern, arguments);
21 | }
22 |
23 | }
--------------------------------------------------------------------------------
/scs-main/src/main/java/com/smart/classroom/subscription/config/BootstrapConfiguration.java:
--------------------------------------------------------------------------------
1 | package com.smart.classroom.subscription.config;
2 |
3 |
4 | import com.smart.classroom.subscription.utility.util.StringUtil;
5 |
6 | /**
7 | * @author lishuang
8 | * @date 2023-05-16
9 | *
10 | * 启动配置
11 | */
12 | public class BootstrapConfiguration {
13 |
14 | public static void start() {
15 |
16 | //配置日志路径。
17 | String logPath = StringUtil.format("{}/logs/smart-classroom-subscription",
18 | System.getProperty("user.home"));
19 | System.setProperty("log.path", logPath);
20 | System.out.println("日志地址:" + logPath);
21 |
22 | }
23 |
24 | }
25 |
--------------------------------------------------------------------------------
/docs/start/zookeeper.md:
--------------------------------------------------------------------------------
1 | # zookeeper使用方法
2 | ## 下载
3 | 从 [官网](https://zookeeper.apache.org/) 下载,比如下载apache-zookeeper-3.8.1-bin.tar.gz
4 |
5 | ## 修改配置
6 | 解压后,将 apache-zookeeper-3.8.1-bin/conf/zoo_sample.cfg 重命名为 zoo.cfg,修改日志和数据存放位置:
7 | ```shell
8 | # dataDir表示保存数据的目录,修改成你希望的位置。
9 | dataDir=/tmp/zookeeper
10 | ```
11 |
12 | ## 运行
13 | ```shell
14 | cd apache-zookeeper-3.8.1-bin/bin/
15 | ./zkServer.sh start
16 | ```
17 |
18 | 看到以下提示表示启动成功
19 | ```text
20 | Using config: .../conf/zoo.cfg
21 | Starting zookeeper ... STARTED
22 | ```
23 |
24 | windows平台下,双击运行 apache-zookeeper-3.8.1-bin/zkServer.cmd
25 |
26 | ## 验证
27 |
28 | 方法1:
29 | 使用jvm命令jps
30 | ```shell
31 | jps
32 | ```
33 | 看到"QuorumPeerMain"表示启动成功
34 |
35 |
--------------------------------------------------------------------------------
/scs-domain/src/main/java/com/smart/classroom/subscription/domain/middleware/mq/MqProducer.java:
--------------------------------------------------------------------------------
1 | package com.smart.classroom.subscription.domain.middleware.mq;
2 |
3 | import com.smart.classroom.subscription.domain.middleware.mq.info.MqSendResultInfo;
4 |
5 | /**
6 | * @author lishuang
7 | * @date 2023-05-17
8 | * MQ消息生产
9 | */
10 | public interface MqProducer {
11 |
12 | /**
13 | * 发送MQ消息
14 | *
15 | * 消息的topic统一采用"SmartClassroomTopic"
16 | *
17 | * @param tags 消息的tags
18 | * @param keys 消息的Key字段是为了唯一标识消息的,方便运维排查问题。如果不设置Key,则无法定位消息丢失原因。
19 | * @param body 发送的消息体,在智慧课堂中只发送文本消息。
20 | */
21 | MqSendResultInfo send(String tags, String keys, String body);
22 |
23 |
24 | }
25 |
--------------------------------------------------------------------------------
/scs-domain/src/main/java/com/smart/classroom/subscription/domain/middleware/mq/info/MqSendResultInfo.java:
--------------------------------------------------------------------------------
1 | package com.smart.classroom.subscription.domain.middleware.mq.info;
2 |
3 | import lombok.AllArgsConstructor;
4 | import lombok.Builder;
5 | import lombok.Data;
6 | import lombok.NoArgsConstructor;
7 |
8 | /**
9 | * @author lishuang
10 | * @date 2023-05-17
11 | */
12 | @Data
13 | @Builder
14 | @NoArgsConstructor
15 | @AllArgsConstructor
16 | public class MqSendResultInfo {
17 | /**
18 | * mq发送是否成功
19 | */
20 | private boolean success;
21 |
22 | /**
23 | * 发送的消息id
24 | */
25 | private String messageId;
26 |
27 | /**
28 | * 如果发送失败,错误消息是什么
29 | */
30 | private String msg;
31 | }
32 |
--------------------------------------------------------------------------------
/scs-repository/src/main/java/com/smart/classroom/subscription/repository/orm/base/BaseEntityDO.java:
--------------------------------------------------------------------------------
1 | package com.smart.classroom.subscription.repository.orm.base;
2 |
3 |
4 | import lombok.Data;
5 |
6 | import java.util.Date;
7 |
8 | /**
9 | * @author fusu
10 | * @date 2023-04-14
11 | */
12 | @Data
13 | public class BaseEntityDO {
14 |
15 | public final static String EMPTY_JSON_ARRAY = "[]";
16 | public final static String EMPTY_JSON_OBJECT = "{}";
17 |
18 | /**
19 | * 主键
20 | */
21 | private Long id;
22 |
23 | /**
24 | * 创建时间
25 | */
26 | private Date createTime = new Date();
27 |
28 | /**
29 | * 修改时间
30 | */
31 | private Date updateTime = new Date();
32 |
33 | }
34 |
--------------------------------------------------------------------------------
/scs-facade-impl/src/main/java/com/smart/classroom/subscription/facade/impl/healthy/HealthyFacadeImpl.java:
--------------------------------------------------------------------------------
1 | package com.smart.classroom.subscription.facade.impl.healthy;
2 |
3 | import com.smart.classroom.subscription.facade.healthy.HealthyFacade;
4 | import com.smart.classroom.subscription.utility.util.DateUtil;
5 | import org.apache.dubbo.config.annotation.DubboService;
6 |
7 | import java.util.Date;
8 |
9 | /**
10 | * @author lishuang
11 | * @date 2023-05-11
12 | */
13 | @DubboService
14 | public class HealthyFacadeImpl implements HealthyFacade {
15 |
16 | @Override
17 | public String check() {
18 | return "Hello,你好. 我是smart-classroom-subscription,状态正常 现在时间:" + DateUtil.convertDateToString(new Date());
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/scs-domain/src/main/java/com/smart/classroom/subscription/domain/middleware/mq/info/MqConsumeResultInfo.java:
--------------------------------------------------------------------------------
1 | package com.smart.classroom.subscription.domain.middleware.mq.info;
2 |
3 | import lombok.AllArgsConstructor;
4 | import lombok.Builder;
5 | import lombok.Data;
6 | import lombok.NoArgsConstructor;
7 |
8 | /**
9 | * @author lishuang
10 | * @date 2023-05-17
11 | */
12 | @Data
13 | @Builder
14 | @NoArgsConstructor
15 | @AllArgsConstructor
16 | public class MqConsumeResultInfo {
17 | /**
18 | * mq发送是否成功
19 | */
20 | private boolean success;
21 |
22 | /**
23 | * 发送的消息id
24 | */
25 | private String messageId;
26 |
27 | /**
28 | * 如果发送失败,错误消息是什么
29 | */
30 | private String msg;
31 | }
32 |
--------------------------------------------------------------------------------
/scs-facade/src/main/java/com/smart/classroom/subscription/facade/biz/subscription/request/ReaderColumnQueryRequest.java:
--------------------------------------------------------------------------------
1 | package com.smart.classroom.subscription.facade.biz.subscription.request;
2 |
3 | import lombok.AllArgsConstructor;
4 | import lombok.Builder;
5 | import lombok.Data;
6 | import lombok.NoArgsConstructor;
7 |
8 | import java.io.Serializable;
9 |
10 | /**
11 | * @author lishuang
12 | * @date 2023-05-15
13 | */
14 | @Data
15 | @Builder
16 | @NoArgsConstructor
17 | @AllArgsConstructor
18 | public class ReaderColumnQueryRequest implements Serializable {
19 |
20 | /**
21 | * 当前读者id
22 | */
23 | private long readerId;
24 |
25 | /**
26 | * 希望订阅的专栏
27 | */
28 | private long columnId;
29 |
30 | }
31 |
--------------------------------------------------------------------------------
/scs-main/src/main/java/com/smart/classroom/subscription/SubscriptionApplication.java:
--------------------------------------------------------------------------------
1 | package com.smart.classroom.subscription;
2 |
3 | import com.smart.classroom.subscription.config.BootstrapConfiguration;
4 | import org.apache.dubbo.config.spring.context.annotation.EnableDubbo;
5 | import org.springframework.boot.SpringApplication;
6 | import org.springframework.boot.autoconfigure.SpringBootApplication;
7 |
8 | @EnableDubbo
9 | @SpringBootApplication
10 | public class SubscriptionApplication {
11 |
12 | public static void main(String[] args) {
13 | //应用定义的启动配置
14 | BootstrapConfiguration.start();
15 |
16 | //spring-boot的启动入口
17 | SpringApplication.run(SubscriptionApplication.class, args);
18 | }
19 |
20 | }
21 |
--------------------------------------------------------------------------------
/scs-domain/src/main/java/com/smart/classroom/subscription/domain/rpc/payment/info/PaymentCreateInfo.java:
--------------------------------------------------------------------------------
1 | package com.smart.classroom.subscription.domain.rpc.payment.info;
2 |
3 | import lombok.AllArgsConstructor;
4 | import lombok.Builder;
5 | import lombok.Data;
6 | import lombok.NoArgsConstructor;
7 |
8 | /**
9 | * @author lishuang
10 | * @date 2023-05-17
11 | */
12 | @Data
13 | @Builder
14 | @NoArgsConstructor
15 | @AllArgsConstructor
16 | public class PaymentCreateInfo {
17 |
18 | /**
19 | * 订单编号
20 | */
21 | private String orderNo = null;
22 |
23 | /**
24 | * 支付方式 ALIPAY/WEIXIN 支付宝/微信
25 | */
26 | private String method = null;
27 |
28 | /**
29 | * 金额(单位:分)
30 | */
31 | private Long amount = null;
32 |
33 | }
34 |
--------------------------------------------------------------------------------
/scs-repository/src/main/java/com/smart/classroom/subscription/repository/mapper/subscription/SubscriptionMapper.java:
--------------------------------------------------------------------------------
1 | /**
2 | * smart-classroom.com Inc. Copyright (c) 2015-present All Rights Reserved.
3 | * generated by SaberGenerator
4 | */
5 | package com.smart.classroom.subscription.repository.mapper.subscription;
6 |
7 | import com.smart.classroom.subscription.repository.orm.subscription.SubscriptionDO;
8 | import org.apache.ibatis.annotations.Mapper;
9 | import org.apache.ibatis.annotations.Param;
10 | import org.springframework.stereotype.Repository;
11 |
12 | @Mapper
13 | @Repository
14 | public interface SubscriptionMapper extends SubscriptionBaseMapper {
15 | SubscriptionDO queryByReaderIdAndColumnId(@Param("readerId") Long readerId, @Param("columnId") Long columnId);
16 | }
--------------------------------------------------------------------------------
/scs-domain/src/main/java/com/smart/classroom/subscription/domain/biz/order/info/PrepareSubscribeInfo.java:
--------------------------------------------------------------------------------
1 | package com.smart.classroom.subscription.domain.biz.order.info;
2 |
3 | import com.smart.classroom.subscription.domain.biz.order.model.OrderModel;
4 | import lombok.AllArgsConstructor;
5 | import lombok.Builder;
6 | import lombok.Data;
7 | import lombok.NoArgsConstructor;
8 |
9 | /**
10 | * @author lishuang
11 | * @date 2023-05-15
12 | */
13 | @Data
14 | @Builder
15 | @NoArgsConstructor
16 | @AllArgsConstructor
17 | public class PrepareSubscribeInfo {
18 |
19 | /**
20 | * 相关的订单。
21 | */
22 | OrderModel orderModel;
23 |
24 | /**
25 | * 支付的一些token及信息
26 | */
27 | String thirdTransactionNo;
28 |
29 | /**
30 | * 支付时候的验证信息等。
31 | */
32 | String nonceStr;
33 |
34 | }
35 |
--------------------------------------------------------------------------------
/scs-facade/src/main/java/com/smart/classroom/subscription/facade/biz/order/OrderReadFacade.java:
--------------------------------------------------------------------------------
1 | package com.smart.classroom.subscription.facade.biz.order;
2 |
3 | import com.smart.classroom.subscription.facade.biz.order.response.OrderDTO;
4 | import com.smart.classroom.subscription.facade.biz.subscription.request.ReaderColumnQueryRequest;
5 | import com.smart.classroom.subscription.facade.biz.subscription.request.SubscriptionPageRequest;
6 | import com.smart.classroom.subscription.facade.biz.subscription.response.SubscriptionDTO;
7 | import com.smart.classroom.subscription.facade.common.resposne.PagerResponse;
8 |
9 | /**
10 | * @author lishuang
11 | * @date 2023-05-15
12 | */
13 | public interface OrderReadFacade {
14 |
15 | /**
16 | * 按照id查询
17 | */
18 | OrderDTO queryById(Long orderId);
19 |
20 | }
21 |
--------------------------------------------------------------------------------
/scs-domain/src/main/java/com/smart/classroom/subscription/domain/rpc/payment/PaymentFacadeClient.java:
--------------------------------------------------------------------------------
1 | package com.smart.classroom.subscription.domain.rpc.payment;
2 |
3 | import com.smart.classroom.subscription.domain.rpc.payment.info.PaymentCreateInfo;
4 | import com.smart.classroom.subscription.domain.rpc.payment.info.PreparePaymentInfo;
5 | import com.smart.classroom.subscription.domain.rpc.payment.vo.PaymentVO;
6 |
7 | /**
8 | * @author lishuang
9 | * @date 2023-05-15
10 | */
11 | public interface PaymentFacadeClient {
12 |
13 | PaymentVO queryById(long paymentId);
14 |
15 | /**
16 | * 创建支付单
17 | * 同时返回可用于支付的物流
18 | */
19 | PreparePaymentInfo create(PaymentCreateInfo paymentCreateInfo);
20 |
21 | /**
22 | * 获取一个支付单对应的支付准备物料等信息。
23 | */
24 | PreparePaymentInfo prepare(long paymentId);
25 |
26 | }
27 |
--------------------------------------------------------------------------------
/scs-domain/src/main/java/com/smart/classroom/subscription/domain/rpc/reader/vo/ReaderVO.java:
--------------------------------------------------------------------------------
1 | package com.smart.classroom.subscription.domain.rpc.reader.vo;
2 |
3 | import lombok.AllArgsConstructor;
4 | import lombok.Builder;
5 | import lombok.Data;
6 | import lombok.NoArgsConstructor;
7 |
8 | import java.util.Date;
9 |
10 | /**
11 | * @author lishuang
12 | * @date 2023-05-15
13 | */
14 | @Data
15 | @Builder
16 | @NoArgsConstructor
17 | @AllArgsConstructor
18 | public class ReaderVO {
19 |
20 |
21 | /**
22 | * 主键
23 | */
24 | private Long id = null;
25 |
26 | /**
27 | * 创建时间
28 | */
29 | private Date createTime = null;
30 |
31 | /**
32 | * 修改时间
33 | */
34 | private Date updateTime = null;
35 |
36 | /**
37 | * 用户名
38 | */
39 | private String username = null;
40 |
41 | }
42 |
--------------------------------------------------------------------------------
/scs-facade/src/main/java/com/smart/classroom/subscription/facade/biz/subscription/request/PrepareSubscribeRequest.java:
--------------------------------------------------------------------------------
1 | package com.smart.classroom.subscription.facade.biz.subscription.request;
2 |
3 | import lombok.AllArgsConstructor;
4 | import lombok.Builder;
5 | import lombok.Data;
6 | import lombok.NoArgsConstructor;
7 |
8 | import java.io.Serializable;
9 |
10 | /**
11 | * @author lishuang
12 | * @date 2023-05-15
13 | */
14 | @Data
15 | @Builder
16 | @NoArgsConstructor
17 | @AllArgsConstructor
18 | public class PrepareSubscribeRequest implements Serializable {
19 |
20 | /**
21 | * 当前读者id
22 | */
23 | private long readerId;
24 |
25 | /**
26 | * 希望订阅的专栏
27 | */
28 | private long columnId;
29 |
30 | /**
31 | * 支付方式 支持 ALIPAY/WEIXIN
32 | */
33 | private String payMethod;
34 |
35 |
36 | }
37 |
--------------------------------------------------------------------------------
/scs-facade/src/main/java/com/smart/classroom/subscription/facade/biz/subscription/SubscriptionWriteFacade.java:
--------------------------------------------------------------------------------
1 | package com.smart.classroom.subscription.facade.biz.subscription;
2 |
3 | import com.smart.classroom.subscription.facade.biz.subscription.request.PrepareSubscribeRequest;
4 | import com.smart.classroom.subscription.facade.biz.subscription.response.PrepareSubscribeDTO;
5 | import com.smart.classroom.subscription.facade.biz.subscription.response.SubscriptionDTO;
6 |
7 | /**
8 | * @author lishuang
9 | * @date 2023-05-15
10 | */
11 | public interface SubscriptionWriteFacade {
12 |
13 |
14 | /**
15 | * 发起订阅请求
16 | */
17 | PrepareSubscribeDTO prepareSubscribe(PrepareSubscribeRequest request);
18 |
19 |
20 | /**
21 | * 支付成功消息补偿。
22 | */
23 | SubscriptionDTO compensatePaymentPaid(long paymentId);
24 |
25 |
26 | }
27 |
--------------------------------------------------------------------------------
/scs-facade/src/main/java/com/smart/classroom/subscription/facade/biz/subscription/request/SubscriptionPageRequest.java:
--------------------------------------------------------------------------------
1 | package com.smart.classroom.subscription.facade.biz.subscription.request;
2 |
3 | import lombok.AllArgsConstructor;
4 | import lombok.Builder;
5 | import lombok.Data;
6 | import lombok.NoArgsConstructor;
7 |
8 | import java.io.Serializable;
9 |
10 | /**
11 | * @author lishuang
12 | * @date 2023-05-12
13 | */
14 | @Data
15 | @Builder
16 | @NoArgsConstructor
17 | @AllArgsConstructor
18 | public class SubscriptionPageRequest implements Serializable {
19 | int pageNum = 1;
20 | int pageSize = 20;
21 | //参考 SortDirection枚举
22 | String orderCreateTime = null;
23 | //参考 SortDirection枚举
24 | String orderUpdateTime = null;
25 |
26 | Long readerId = null;
27 | Long columnId = null;
28 | Long orderId = null;
29 | String status = null;
30 | }
31 |
--------------------------------------------------------------------------------
/scs-testsuit/src/main/java/com/smart/classroom/subscription/tool/saber/config/SaberConfig.java:
--------------------------------------------------------------------------------
1 | package com.smart.classroom.subscription.tool.saber.config;
2 |
3 | /**
4 | * Saber工具中用到的一些配置项
5 | *
6 | * @author lishuang
7 | * @date 2023-05-11
8 | */
9 | public interface SaberConfig {
10 |
11 | //仓储层的模块名
12 | String REPOSITORY_MODULE_NAME = "scs-repository";
13 |
14 | //基础包名,即所有类共同的包名前缀。
15 | String BASE_PACKAGE_NAME = "com.smart.classroom.subscription";
16 |
17 | //数据库表前缀
18 | String DATABASE_TABLE_PREFIX = "scs_";
19 |
20 | //数据库连接串 useInformationSchema=true应该加上,否则获取不到表名注释。
21 | String JDBC_URL = "jdbc:mysql://127.0.0.1:3306/smart_classroom?useUnicode=true&useSSL=false&characterEncoding=UTF-8&serverTimezone=GMT%2B8&useInformationSchema=true";
22 | String JDBC_USERNAME = "smart_classroom";
23 | String JDBC_PASSWORD = "Smart_classroom123";
24 |
25 | }
26 |
--------------------------------------------------------------------------------
/scs-utility/src/main/java/com/smart/classroom/subscription/utility/enums/SortDirection.java:
--------------------------------------------------------------------------------
1 | package com.smart.classroom.subscription.utility.enums;
2 |
3 | /**
4 | * @author fusu
5 | * @date 2023-04-14
6 | */
7 |
8 | import lombok.Getter;
9 |
10 | public enum SortDirection {
11 | ASC("升序"),
12 | DESC("降序");;
13 |
14 | @Getter
15 | private final String description;
16 |
17 | SortDirection(String description) {
18 | this.description = description;
19 | }
20 |
21 |
22 | public static String toString(SortDirection orderStatus) {
23 | if (orderStatus == null) {
24 | return null;
25 | }
26 | return orderStatus.name();
27 | }
28 |
29 | public static SortDirection toEnum(String s) {
30 | if (s == null) {
31 | return null;
32 | }
33 | return SortDirection.valueOf(s);
34 | }
35 |
36 | }
--------------------------------------------------------------------------------
/scs-utility/src/main/java/com/smart/classroom/subscription/utility/model/Triplet.java:
--------------------------------------------------------------------------------
1 | package com.smart.classroom.subscription.utility.model;
2 |
3 | /**
4 | * 将三个值封装在一个类中
5 | * 从而方便多值返回使用
6 | *
7 | * @author lishuang
8 | * @version 2023-05-11
9 | */
10 | public class Triplet {
11 |
12 | private X x;
13 | private Y y;
14 | private Z z;
15 |
16 | public X getX() {
17 | return x;
18 | }
19 |
20 | public void setX(X x) {
21 | this.x = x;
22 | }
23 |
24 | public Y getY() {
25 | return y;
26 | }
27 |
28 | public void setY(Y y) {
29 | this.y = y;
30 | }
31 |
32 | public Z getZ() {
33 | return z;
34 | }
35 |
36 | public void setZ(Z z) {
37 | this.z = z;
38 | }
39 |
40 | public Triplet(X x, Y y, Z z) {
41 | this.x = x;
42 | this.y = y;
43 | this.z = z;
44 | }
45 | }
--------------------------------------------------------------------------------
/scs-facade/src/main/java/com/smart/classroom/subscription/facade/biz/subscription/response/PrepareSubscribeDTO.java:
--------------------------------------------------------------------------------
1 | package com.smart.classroom.subscription.facade.biz.subscription.response;
2 |
3 | import com.smart.classroom.subscription.facade.biz.order.response.OrderDTO;
4 | import lombok.AllArgsConstructor;
5 | import lombok.Builder;
6 | import lombok.Data;
7 | import lombok.NoArgsConstructor;
8 |
9 | import java.io.Serializable;
10 |
11 | /**
12 | * @author lishuang
13 | * @date 2023-05-15
14 | */
15 | @Data
16 | @Builder
17 | @NoArgsConstructor
18 | @AllArgsConstructor
19 | public class PrepareSubscribeDTO implements Serializable {
20 |
21 | /**
22 | * 相关的订单。
23 | */
24 | OrderDTO orderDTO;
25 |
26 | /**
27 | * 支付的一些token及信息
28 | */
29 | String thirdTransactionNo;
30 |
31 | /**
32 | * 支付时候的验证信息等。
33 | */
34 | String nonceStr;
35 |
36 |
37 |
38 | }
39 |
--------------------------------------------------------------------------------
/scs-testsuit/src/main/resources/saber/TemplateDOJava.vm:
--------------------------------------------------------------------------------
1 | /**
2 | * smart-classroom.com Inc. Copyright (c) 2015-present All Rights Reserved.
3 | * generated by SaberGenerator
4 | */
5 | package ${artwork.entityPackage};
6 |
7 | #foreach($item in $artwork.entityImportNones)
8 | import ${item};
9 | #if(!$foreach.hasNext)
10 |
11 | #end
12 | #end
13 | #foreach($item in $artwork.entityImportJavas)
14 | import ${item};
15 | #if(!$foreach.hasNext)
16 |
17 | #end
18 | #end
19 | /**
20 | * ${artwork.tableRemark}
21 | */
22 | @Data
23 | @Builder
24 | @NoArgsConstructor
25 | @AllArgsConstructor
26 | @EqualsAndHashCode(callSuper = true)
27 | public class ${artwork.entityUpperClassName} extends BaseEntityDO {
28 |
29 | #foreach($column in $artwork.selfColumns)
30 | /**
31 | * ${column.remark}
32 | */
33 | private ${column.javaSimpleName} ${column.lowerCamelName} = ${column.defaultValue};
34 |
35 | #end
36 |
37 | }
--------------------------------------------------------------------------------
/scs-domain/src/main/java/com/smart/classroom/subscription/domain/biz/order/enums/OrderStatus.java:
--------------------------------------------------------------------------------
1 | package com.smart.classroom.subscription.domain.biz.order.enums;
2 |
3 | import lombok.Getter;
4 |
5 | public enum OrderStatus {
6 |
7 | CREATED("已创建"),
8 | PAID("已支付"),
9 | SUBSCRIBED("已订阅"),
10 | CLOSED("已关闭"),
11 | CANCELED("已取消");
12 |
13 | @Getter
14 | private final String description;
15 |
16 | OrderStatus(String description) {
17 | this.description = description;
18 | }
19 |
20 |
21 | public static String toString(OrderStatus orderStatus) {
22 | if (orderStatus == null) {
23 | return null;
24 | }
25 | return orderStatus.name();
26 | }
27 |
28 | public static OrderStatus toEnum(String s) {
29 | if (s == null) {
30 | return null;
31 | }
32 | return OrderStatus.valueOf(s);
33 | }
34 |
35 | }
36 |
--------------------------------------------------------------------------------
/scs-application/src/main/java/com/smart/classroom/subscription/application/rpc/payment/event/PaymentDomainEvent.java:
--------------------------------------------------------------------------------
1 | package com.smart.classroom.subscription.application.rpc.payment.event;
2 |
3 | import lombok.Getter;
4 |
5 | /**
6 | * 定义领域事件类型。
7 | */
8 | public enum PaymentDomainEvent {
9 |
10 | PAYMENT_DOMAIN_EVENT_PAID("已支付");
11 |
12 | @Getter
13 | private final String description;
14 |
15 | PaymentDomainEvent(String description) {
16 | this.description = description;
17 | }
18 |
19 |
20 | public static String toString(PaymentDomainEvent status) {
21 | if (status == null) {
22 | return null;
23 | }
24 | return status.name();
25 | }
26 |
27 | public static PaymentDomainEvent toEnum(String s) {
28 | if (s == null) {
29 | return null;
30 | }
31 | return PaymentDomainEvent.valueOf(s);
32 | }
33 |
34 |
35 | }
36 |
--------------------------------------------------------------------------------
/scs-domain/src/main/java/com/smart/classroom/subscription/domain/biz/subscription/repository/query/SubscriptionPageQuery.java:
--------------------------------------------------------------------------------
1 | package com.smart.classroom.subscription.domain.biz.subscription.repository.query;
2 |
3 | import com.smart.classroom.subscription.domain.biz.subscription.enums.SubscriptionStatus;
4 | import com.smart.classroom.subscription.utility.enums.SortDirection;
5 | import lombok.AllArgsConstructor;
6 | import lombok.Builder;
7 | import lombok.Data;
8 | import lombok.NoArgsConstructor;
9 |
10 | /**
11 | * @author lishuang
12 | * @date 2023-05-15
13 | */
14 | @Data
15 | @Builder
16 | @NoArgsConstructor
17 | @AllArgsConstructor
18 | public class SubscriptionPageQuery {
19 |
20 | int pageNum = 1;
21 | int pageSize = 20;
22 |
23 | SortDirection orderCreateTime;
24 | SortDirection orderUpdateTime;
25 | Long readerId;
26 | Long columnId;
27 | Long orderId;
28 | SubscriptionStatus status;
29 |
30 | }
31 |
--------------------------------------------------------------------------------
/scs-domain/src/main/java/com/smart/classroom/subscription/domain/biz/subscription/enums/SubscriptionStatus.java:
--------------------------------------------------------------------------------
1 | package com.smart.classroom.subscription.domain.biz.subscription.enums;
2 |
3 | import lombok.Getter;
4 |
5 | public enum SubscriptionStatus {
6 |
7 | CREATED("已创建"),
8 | OK("已生效"),
9 | DISABLED("已失效");
10 |
11 | @Getter
12 | private final String description;
13 |
14 | SubscriptionStatus(String description) {
15 | this.description = description;
16 | }
17 |
18 |
19 | public static String toString(SubscriptionStatus subscriptionStatus) {
20 | if (subscriptionStatus == null) {
21 | return null;
22 | }
23 | return subscriptionStatus.name();
24 | }
25 |
26 | public static SubscriptionStatus toEnum(String s) {
27 | if (s == null) {
28 | return null;
29 | }
30 | return SubscriptionStatus.valueOf(s);
31 | }
32 |
33 | }
34 |
--------------------------------------------------------------------------------
/scs-domain/src/main/java/com/smart/classroom/subscription/domain/biz/order/repository/query/OrderPageQuery.java:
--------------------------------------------------------------------------------
1 | package com.smart.classroom.subscription.domain.biz.order.repository.query;
2 |
3 | import com.smart.classroom.subscription.domain.biz.order.enums.OrderStatus;
4 | import com.smart.classroom.subscription.utility.enums.SortDirection;
5 | import lombok.AllArgsConstructor;
6 | import lombok.Builder;
7 | import lombok.Data;
8 | import lombok.NoArgsConstructor;
9 |
10 | /**
11 | * @author lishuang
12 | * @date 2023-05-15
13 | */
14 | @Data
15 | @Builder
16 | @NoArgsConstructor
17 | @AllArgsConstructor
18 | public class OrderPageQuery {
19 |
20 | int pageNum = 1;
21 | int pageSize = 20;
22 | SortDirection orderCreateTime;
23 | SortDirection orderUpdateTime;
24 | Long readerId = null;
25 | Long columnId = null;
26 | Long columnQuoteId = null;
27 | Long paymentId = null;
28 | OrderStatus status = null;
29 |
30 | }
31 |
--------------------------------------------------------------------------------
/scs-domain/src/main/java/com/smart/classroom/subscription/domain/biz/subscription/event/SubscriptionDomainEvent.java:
--------------------------------------------------------------------------------
1 | package com.smart.classroom.subscription.domain.biz.subscription.event;
2 |
3 | import lombok.Getter;
4 |
5 | /**
6 | * 定义领域事件类型。
7 | */
8 | public enum SubscriptionDomainEvent {
9 |
10 | SUBSCRIPTION_DOMAIN_EVENT_CREATED("订阅成功");
11 |
12 | @Getter
13 | private final String description;
14 |
15 | SubscriptionDomainEvent(String description) {
16 | this.description = description;
17 | }
18 |
19 |
20 | public static String toString(SubscriptionDomainEvent status) {
21 | if (status == null) {
22 | return null;
23 | }
24 | return status.name();
25 | }
26 |
27 | public static SubscriptionDomainEvent toEnum(String s) {
28 | if (s == null) {
29 | return null;
30 | }
31 | return SubscriptionDomainEvent.valueOf(s);
32 | }
33 |
34 |
35 | }
36 |
--------------------------------------------------------------------------------
/scs-domain/src/main/java/com/smart/classroom/subscription/domain/rpc/payment/info/PreparePaymentInfo.java:
--------------------------------------------------------------------------------
1 | package com.smart.classroom.subscription.domain.rpc.payment.info;
2 |
3 | import com.smart.classroom.subscription.domain.biz.order.model.OrderModel;
4 | import com.smart.classroom.subscription.domain.rpc.payment.vo.PaymentVO;
5 | import lombok.AllArgsConstructor;
6 | import lombok.Builder;
7 | import lombok.Data;
8 | import lombok.NoArgsConstructor;
9 |
10 | /**
11 | * @author lishuang
12 | * @date 2023-05-16
13 | */
14 | @Data
15 | @Builder
16 | @NoArgsConstructor
17 | @AllArgsConstructor
18 | public class PreparePaymentInfo {
19 |
20 | /**
21 | * 支付单
22 | */
23 | PaymentVO paymentVO;
24 |
25 | /**
26 | * 订单号
27 | */
28 | String orderNo;
29 |
30 | /**
31 | * 支付的一些token及信息
32 | */
33 | String thirdTransactionNo;
34 |
35 | /**
36 | * 支付时候的验证信息等。
37 | */
38 | String nonceStr;
39 |
40 | }
41 |
--------------------------------------------------------------------------------
/scs-infrastructure/src/main/java/com/smart/classroom/subscription/infrastructure/rpc/reader/converter/ReaderDTO2VOConverter.java:
--------------------------------------------------------------------------------
1 | package com.smart.classroom.subscription.infrastructure.rpc.reader.converter;
2 |
3 |
4 | import com.smart.classroom.misc.facade.biz.reader.response.ReaderDTO;
5 | import com.smart.classroom.subscription.domain.rpc.reader.vo.ReaderVO;
6 |
7 | /**
8 | * @author lishuang
9 | * @date 2023-05-12
10 | * 转换器
11 | */
12 | public class ReaderDTO2VOConverter {
13 |
14 | /**
15 | * 将DO转换成模型
16 | */
17 | public static ReaderVO convert(ReaderDTO readerDTO) {
18 | if (readerDTO == null) {
19 | return null;
20 | }
21 |
22 | return ReaderVO.builder()
23 | .id(readerDTO.getId())
24 | .createTime(readerDTO.getCreateTime())
25 | .updateTime(readerDTO.getUpdateTime())
26 | .username(readerDTO.getUsername())
27 | .build();
28 | }
29 |
30 |
31 | }
32 |
--------------------------------------------------------------------------------
/scs-domain/src/main/java/com/smart/classroom/subscription/domain/biz/subscription/repository/SubscriptionRepository.java:
--------------------------------------------------------------------------------
1 | package com.smart.classroom.subscription.domain.biz.subscription.repository;
2 |
3 | import com.smart.classroom.subscription.domain.biz.subscription.model.SubscriptionModel;
4 | import com.smart.classroom.subscription.domain.biz.subscription.repository.query.SubscriptionPageQuery;
5 | import com.smart.classroom.subscription.domain.rpc.column.vo.ColumnVO;
6 | import com.smart.classroom.subscription.domain.rpc.reader.vo.ReaderVO;
7 | import com.smart.classroom.subscription.utility.result.Pager;
8 |
9 | /**
10 | * @author lishuang
11 | * @date 2023-05-12
12 | */
13 | public interface SubscriptionRepository {
14 |
15 | SubscriptionModel queryByReaderAndColumn(ReaderVO readerVO, ColumnVO columnVO);
16 |
17 | //分页查询
18 | Pager page(SubscriptionPageQuery subscriptionPageQuery);
19 |
20 | SubscriptionModel insert(SubscriptionModel order);
21 |
22 | }
23 |
--------------------------------------------------------------------------------
/scs-repository/src/main/java/com/smart/classroom/subscription/repository/mapper/base/BaseMapper.java:
--------------------------------------------------------------------------------
1 | package com.smart.classroom.subscription.repository.mapper.base;
2 |
3 | import org.apache.ibatis.annotations.Param;
4 |
5 | import java.util.List;
6 |
7 | public interface BaseMapper {
8 |
9 | /**
10 | * 插入一个对象 返回影响的条数。要获取id使用 fsEvent.getId()
11 | */
12 | int insert(T t);
13 |
14 | /**
15 | * 批量插入对象
16 | */
17 | int insertBatch(@Param("list") List list);
18 |
19 | /**
20 | * 按id删除
21 | */
22 | int deleteById(Long id);
23 |
24 | /**
25 | * 根据一系列id来删除对应的条目
26 | */
27 | int deleteByIds(@Param("list") List list);
28 |
29 | /**
30 | * 更新 返回影响的条数
31 | */
32 | int update(T fsEvent);
33 |
34 | /**
35 | * 按id查询
36 | */
37 | T queryById(Long id);
38 |
39 | /**
40 | * 根据一系列id来获取到对应的条目
41 | */
42 | List queryByIds(@Param("list") List list);
43 |
44 |
45 | }
46 |
--------------------------------------------------------------------------------
/scs-facade/src/main/java/com/smart/classroom/subscription/facade/biz/subscription/SubscriptionReadFacade.java:
--------------------------------------------------------------------------------
1 | package com.smart.classroom.subscription.facade.biz.subscription;
2 |
3 | import com.smart.classroom.subscription.facade.biz.subscription.request.ReaderColumnQueryRequest;
4 | import com.smart.classroom.subscription.facade.biz.subscription.request.SubscriptionPageRequest;
5 | import com.smart.classroom.subscription.facade.biz.subscription.response.SubscriptionDTO;
6 | import com.smart.classroom.subscription.facade.common.resposne.PagerResponse;
7 |
8 | /**
9 | * @author lishuang
10 | * @date 2023-05-15
11 | */
12 | public interface SubscriptionReadFacade {
13 |
14 |
15 | /**
16 | * 查找某个读者关于某个专栏的订阅情况
17 | */
18 | SubscriptionDTO queryByColumnIdAndReaderId(ReaderColumnQueryRequest readerColumnQueryRequest);
19 |
20 |
21 | /**
22 | * 查找订阅情况分页
23 | */
24 | PagerResponse page(SubscriptionPageRequest subscriptionPageRequest);
25 |
26 |
27 | }
28 |
--------------------------------------------------------------------------------
/scs-domain/src/main/java/com/smart/classroom/subscription/domain/rpc/column/vo/ColumnVO.java:
--------------------------------------------------------------------------------
1 | package com.smart.classroom.subscription.domain.rpc.column.vo;
2 |
3 | import lombok.AllArgsConstructor;
4 | import lombok.Builder;
5 | import lombok.Data;
6 | import lombok.NoArgsConstructor;
7 |
8 | import java.util.Date;
9 |
10 | /**
11 | * @author lishuang
12 | * @date 2023-05-15
13 | */
14 | @Data
15 | @Builder
16 | @NoArgsConstructor
17 | @AllArgsConstructor
18 | public class ColumnVO {
19 |
20 | /**
21 | * 主键
22 | */
23 | private Long id = null;
24 |
25 | /**
26 | * 创建时间
27 | */
28 | private Date createTime = null;
29 |
30 | /**
31 | * 修改时间
32 | */
33 | private Date updateTime = null;
34 |
35 | /**
36 | * 专栏名称
37 | */
38 | private String name = null;
39 |
40 | /**
41 | * 作者id
42 | */
43 | private Long authorId = null;
44 |
45 | /**
46 | * 参考:ColumnStatus
47 | * 状态 NEW/OK/DISABLED 未发布/已生效/已禁用
48 | */
49 | private String status = null;
50 | }
51 |
--------------------------------------------------------------------------------
/scs-utility/src/main/java/com/smart/classroom/subscription/utility/util/TemplateUtil.java:
--------------------------------------------------------------------------------
1 | package com.smart.classroom.subscription.utility.util;
2 |
3 |
4 | import lombok.NonNull;
5 | import org.apache.velocity.VelocityContext;
6 | import org.apache.velocity.app.Velocity;
7 |
8 | import java.io.StringWriter;
9 | import java.util.Map;
10 |
11 |
12 | /**
13 | * Velocity语法
14 | * 专门用来渲染模板的。
15 | */
16 | public class TemplateUtil {
17 |
18 |
19 | //传入模板字符串,和参数,自动填写完成!
20 | public static String render(@NonNull String template, @NonNull Map map) {
21 |
22 | VelocityContext context = new VelocityContext();
23 |
24 | for (Map.Entry entry : map.entrySet()) {
25 | if (entry.getValue() != null) {
26 | context.put(entry.getKey(), entry.getValue());
27 | }
28 | }
29 |
30 | StringWriter writer = new StringWriter();
31 |
32 | Velocity.evaluate(context, writer, "", template);
33 |
34 | return writer.toString();
35 | }
36 |
37 |
38 | }
39 |
--------------------------------------------------------------------------------
/scs-domain/src/main/java/com/smart/classroom/subscription/domain/biz/subscription/info/SubscriptionEventPayload.java:
--------------------------------------------------------------------------------
1 | package com.smart.classroom.subscription.domain.biz.subscription.info;
2 |
3 | import com.smart.classroom.subscription.domain.biz.subscription.enums.SubscriptionStatus;
4 | import lombok.AllArgsConstructor;
5 | import lombok.Builder;
6 | import lombok.Data;
7 | import lombok.NoArgsConstructor;
8 |
9 | import java.util.Date;
10 |
11 | /**
12 | * @author lishuang
13 | * @date 2023-05-16
14 | */
15 | @Data
16 | @Builder
17 | @NoArgsConstructor
18 | @AllArgsConstructor
19 | public class SubscriptionEventPayload {
20 |
21 | /**
22 | * 读者id
23 | */
24 | private Long readerId = null;
25 |
26 | /**
27 | * 专栏id
28 | */
29 | private Long columnId = null;
30 |
31 | /**
32 | * 订单id
33 | */
34 | private Long orderId = null;
35 |
36 | /**
37 | * 状态 CREATED/OK/DISABLED
38 | */
39 | private String status = null;
40 |
41 | /**
42 | * 时间
43 | */
44 | private Date occurTime = null;
45 |
46 | }
47 |
--------------------------------------------------------------------------------
/scs-utility/src/main/java/com/smart/classroom/subscription/utility/exception/SystemException.java:
--------------------------------------------------------------------------------
1 | package com.smart.classroom.subscription.utility.exception;
2 |
3 | import lombok.Data;
4 | import lombok.EqualsAndHashCode;
5 |
6 | /**
7 | * 系统异常
8 | *
9 | * 应用中所有的非业务异常——也就是系统异常,都抛这个异常
10 | *
11 | * @author lishuang
12 | * @date 2023/2/16
13 | */
14 | @EqualsAndHashCode(callSuper = true)
15 | @Data
16 | public class SystemException extends UtilException {
17 |
18 | public SystemException() {
19 | super(ExceptionCode.SYSTEM_ERROR);
20 | }
21 |
22 | public SystemException(String messagePattern, Object... arguments) {
23 | super(messagePattern, arguments);
24 | }
25 |
26 | public SystemException(ExceptionCode resultCode) {
27 | super(resultCode);
28 | }
29 |
30 | public SystemException(Throwable throwable) {
31 | super(throwable);
32 | }
33 |
34 | public SystemException(ExceptionCode resultCode, String messagePattern, Object... arguments) {
35 | super(resultCode, messagePattern, arguments);
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/scs-infrastructure/src/main/java/com/smart/classroom/subscription/infrastructure/rpc/column/converter/ColumnDTO2VOConverter.java:
--------------------------------------------------------------------------------
1 | package com.smart.classroom.subscription.infrastructure.rpc.column.converter;
2 |
3 |
4 | import com.smart.classroom.misc.facade.biz.column.response.ColumnDTO;
5 | import com.smart.classroom.subscription.domain.rpc.column.vo.ColumnVO;
6 |
7 | /**
8 | * @author lishuang
9 | * @date 2023-05-12
10 | * 转换器
11 | */
12 | public class ColumnDTO2VOConverter {
13 |
14 | /**
15 | * 将DO转换成模型
16 | */
17 | public static ColumnVO convert(ColumnDTO columnDTO) {
18 | if (columnDTO == null) {
19 | return null;
20 | }
21 |
22 | return ColumnVO.builder()
23 | .id(columnDTO.getId())
24 | .createTime(columnDTO.getCreateTime())
25 | .updateTime(columnDTO.getUpdateTime())
26 | .name(columnDTO.getName())
27 | .authorId(columnDTO.getAuthorId())
28 | .status(columnDTO.getStatus())
29 |
30 | .build();
31 | }
32 |
33 |
34 | }
35 |
--------------------------------------------------------------------------------
/scs-application/src/main/java/com/smart/classroom/subscription/application/rpc/payment/info/PaymentEventPayload.java:
--------------------------------------------------------------------------------
1 | package com.smart.classroom.subscription.application.rpc.payment.info;
2 |
3 | import lombok.AllArgsConstructor;
4 | import lombok.Builder;
5 | import lombok.Data;
6 | import lombok.NoArgsConstructor;
7 |
8 | import java.util.Date;
9 |
10 | /**
11 | * @author lishuang
12 | * @date 2023-05-16
13 | */
14 | @Data
15 | @Builder
16 | @NoArgsConstructor
17 | @AllArgsConstructor
18 | public class PaymentEventPayload {
19 |
20 | /**
21 | * 支付单
22 | */
23 | private Long paymentId;
24 |
25 | /**
26 | * 订单编号
27 | */
28 | private String orderNo = null;
29 |
30 | /**
31 | * 支付方式 ALIPAY/WEIXIN 支付宝/微信
32 | */
33 | private String method = null;
34 |
35 | /**
36 | * 金额(单位:分)
37 | */
38 | private Long amount = null;
39 |
40 | /**
41 | * 支付状态 UNPAID/PAID/CLOSED 未支付/已支付/已关闭
42 | */
43 | private String status = null;
44 |
45 | /**
46 | * 时间
47 | */
48 | private Date occurTime = null;
49 |
50 | }
51 |
--------------------------------------------------------------------------------
/scs-infrastructure/src/main/java/com/smart/classroom/subscription/infrastructure/rpc/payment/converter/PreparePaymentDTO2InfoConverter.java:
--------------------------------------------------------------------------------
1 | package com.smart.classroom.subscription.infrastructure.rpc.payment.converter;
2 |
3 |
4 | import com.smart.classroom.misc.facade.biz.payment.response.PreparePaymentDTO;
5 | import com.smart.classroom.subscription.domain.rpc.payment.info.PreparePaymentInfo;
6 |
7 | /**
8 | * @author lishuang
9 | * @date 2023-05-12
10 | * 转换器
11 | */
12 | public class PreparePaymentDTO2InfoConverter {
13 |
14 | /**
15 | * 将DO转换成模型
16 | */
17 | public static PreparePaymentInfo convert(PreparePaymentDTO preparePaymentDTO) {
18 | if (preparePaymentDTO == null) {
19 | return null;
20 | }
21 |
22 | return PreparePaymentInfo.builder()
23 | .paymentVO(PaymentDTO2VOConverter.convert(preparePaymentDTO.getPaymentDTO()))
24 | .thirdTransactionNo(preparePaymentDTO.getThirdTransactionNo())
25 | .nonceStr(preparePaymentDTO.getNonceStr())
26 | .build();
27 | }
28 |
29 |
30 | }
31 |
--------------------------------------------------------------------------------
/.mvn/wrapper/maven-wrapper.properties:
--------------------------------------------------------------------------------
1 | # Licensed to the Apache Software Foundation (ASF) under one
2 | # or more contributor license agreements. See the NOTICE file
3 | # distributed with this work for additional information
4 | # regarding copyright ownership. The ASF licenses this file
5 | # to you under the Apache License, Version 2.0 (the
6 | # "License"); you may not use this file except in compliance
7 | # with the License. You may obtain a copy of the License at
8 | #
9 | # https://www.apache.org/licenses/LICENSE-2.0
10 | #
11 | # Unless required by applicable law or agreed to in writing,
12 | # software distributed under the License is distributed on an
13 | # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14 | # KIND, either express or implied. See the License for the
15 | # specific language governing permissions and limitations
16 | # under the License.
17 | distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.8.7/apache-maven-3.8.7-bin.zip
18 | wrapperUrl=https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.1.1/maven-wrapper-3.1.1.jar
19 |
--------------------------------------------------------------------------------
/scs-repository/src/main/resources/mybatis/mapper/subscription/SubscriptionMapper.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
22 |
23 |
--------------------------------------------------------------------------------
/scs-domain/src/main/java/com/smart/classroom/subscription/domain/rpc/quote/vo/ColumnQuoteVO.java:
--------------------------------------------------------------------------------
1 | package com.smart.classroom.subscription.domain.rpc.quote.vo;
2 |
3 | import lombok.AllArgsConstructor;
4 | import lombok.Builder;
5 | import lombok.Data;
6 | import lombok.NoArgsConstructor;
7 |
8 | import java.util.Date;
9 |
10 | /**
11 | * @author lishuang
12 | * @date 2023-05-15
13 | */
14 | @Data
15 | @Builder
16 | @NoArgsConstructor
17 | @AllArgsConstructor
18 | public class ColumnQuoteVO {
19 |
20 | /**
21 | * 主键
22 | */
23 | private Long id = null;
24 |
25 | /**
26 | * 创建时间
27 | */
28 | private Date createTime = null;
29 |
30 | /**
31 | * 修改时间
32 | */
33 | private Date updateTime = null;
34 |
35 | /**
36 | * 专栏id
37 | */
38 | private Long columnId = null;
39 |
40 | /**
41 | * 编辑id
42 | */
43 | private Long editorId = null;
44 |
45 | /**
46 | * 价格(单位:分)
47 | */
48 | private Long price = null;
49 |
50 | /**
51 | * 报价状态 DISABLED/OK 未生效/已生效
52 | */
53 | private String status = null;
54 | }
55 |
--------------------------------------------------------------------------------
/scs-testsuit/src/main/java/com/smart/classroom/subscription/tool/saber/artwork/base/Artwork.java:
--------------------------------------------------------------------------------
1 | package com.smart.classroom.subscription.tool.saber.artwork.base;
2 |
3 | import com.smart.classroom.subscription.tool.saber.command.SaberCommand;
4 | import com.smart.classroom.subscription.tool.saber.meta.SaberTable;
5 | import lombok.Data;
6 | import lombok.NonNull;
7 |
8 | /**
9 | * 一个产出物,一件艺术品。
10 | * 比如 TemplateMapperJava.vm 是模板,对应的产出物是 XXMapper.java
11 | */
12 | @Data
13 | public abstract class Artwork {
14 |
15 | //模板的文件名称。
16 | private String templateFileName;
17 |
18 | //该作品是 可覆盖型的
19 | //true: 表示直接用最新的去覆盖。 false: 表示文件不存在就生成,存在了就不改动了。
20 | private boolean overwrite = false;
21 |
22 | public Artwork() {
23 |
24 | }
25 |
26 | public Artwork(String templateFileName, boolean overwrite) {
27 | this.templateFileName = templateFileName;
28 | this.overwrite = overwrite;
29 | }
30 |
31 | //目标文件的路径。
32 | public abstract String destAbsolutePath();
33 |
34 | public abstract void init(@NonNull SaberTable saberTable, @NonNull SaberCommand saberCommand);
35 | }
36 |
--------------------------------------------------------------------------------
/scs-facade/src/main/java/com/smart/classroom/subscription/facade/common/resposne/PagerResponse.java:
--------------------------------------------------------------------------------
1 | package com.smart.classroom.subscription.facade.common.resposne;
2 |
3 | import lombok.Data;
4 | import lombok.NoArgsConstructor;
5 |
6 | import java.io.Serializable;
7 | import java.util.List;
8 |
9 |
10 | @Data
11 | @NoArgsConstructor
12 | public class PagerResponse implements Serializable {
13 |
14 | //当前页码。 1基
15 | private long pageNum;
16 |
17 | //每页的大小。
18 | private long pageSize;
19 |
20 | //总条目数
21 | private long totalItems;
22 |
23 | //总页数
24 | private long totalPages;
25 |
26 | private List data;
27 |
28 |
29 | public PagerResponse(long pageNum, long pageSize, long totalItems, List data) {
30 |
31 | if (pageSize <= 0) {
32 | pageSize = 10;
33 | }
34 |
35 | this.pageNum = pageNum;
36 |
37 | this.pageSize = pageSize;
38 |
39 | this.totalItems = totalItems;
40 |
41 | this.totalPages = (long) Math.ceil(this.totalItems * 1.0 / this.pageSize);
42 |
43 | this.data = data;
44 |
45 | }
46 |
47 |
48 | }
49 |
--------------------------------------------------------------------------------
/scs-domain/src/main/java/com/smart/classroom/subscription/domain/biz/order/repository/OrderRepository.java:
--------------------------------------------------------------------------------
1 | package com.smart.classroom.subscription.domain.biz.order.repository;
2 |
3 | import com.smart.classroom.subscription.domain.biz.order.model.OrderModel;
4 | import com.smart.classroom.subscription.domain.biz.order.repository.query.OrderPageQuery;
5 | import com.smart.classroom.subscription.domain.rpc.column.vo.ColumnVO;
6 | import com.smart.classroom.subscription.domain.rpc.reader.vo.ReaderVO;
7 | import com.smart.classroom.subscription.utility.result.Pager;
8 |
9 | /**
10 | * @author lishuang
11 | * @date 2023-05-12
12 | */
13 | public interface OrderRepository {
14 |
15 |
16 | OrderModel queryById(long orderId);
17 |
18 | OrderModel queryByNo(String orderNo);
19 |
20 | //分页查询
21 | Pager page(OrderPageQuery orderPageQuery);
22 |
23 | OrderModel insert(OrderModel order);
24 |
25 | OrderModel updatePaymentId(OrderModel order);
26 |
27 | //查找某人关于某个专栏的非终态订单。
28 | OrderModel queryNonFinalState(ReaderVO readerVO, ColumnVO columnVO);
29 |
30 | OrderModel updateStatus(OrderModel orderModel);
31 | }
32 |
--------------------------------------------------------------------------------
/scs-infrastructure/src/main/java/com/smart/classroom/subscription/infrastructure/rpc/column/ColumnFacadeClientImpl.java:
--------------------------------------------------------------------------------
1 | package com.smart.classroom.subscription.infrastructure.rpc.column;
2 |
3 | import com.smart.classroom.misc.facade.biz.column.ColumnReadFacade;
4 | import com.smart.classroom.misc.facade.biz.column.response.ColumnDTO;
5 | import com.smart.classroom.subscription.domain.rpc.column.ColumnFacadeClient;
6 | import com.smart.classroom.subscription.domain.rpc.column.vo.ColumnVO;
7 | import com.smart.classroom.subscription.infrastructure.rpc.column.converter.ColumnDTO2VOConverter;
8 | import org.apache.dubbo.config.annotation.DubboReference;
9 | import org.springframework.stereotype.Service;
10 |
11 | /**
12 | * @author lishuang
13 | * @date 2023-05-15
14 | */
15 | @Service
16 | public class ColumnFacadeClientImpl implements ColumnFacadeClient {
17 |
18 | @DubboReference
19 | ColumnReadFacade columnReadFacade;
20 |
21 | @Override
22 | public ColumnVO queryById(long columnId) {
23 |
24 | ColumnDTO columnDTO = columnReadFacade.queryById(columnId);
25 |
26 | return ColumnDTO2VOConverter.convert(columnDTO);
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/scs-infrastructure/src/main/java/com/smart/classroom/subscription/infrastructure/rpc/reader/ReaderFacadeClientImpl.java:
--------------------------------------------------------------------------------
1 | package com.smart.classroom.subscription.infrastructure.rpc.reader;
2 |
3 | import com.smart.classroom.misc.facade.biz.reader.ReaderReadFacade;
4 | import com.smart.classroom.misc.facade.biz.reader.response.ReaderDTO;
5 | import com.smart.classroom.subscription.domain.rpc.reader.ReaderFacadeClient;
6 | import com.smart.classroom.subscription.domain.rpc.reader.vo.ReaderVO;
7 | import com.smart.classroom.subscription.infrastructure.rpc.reader.converter.ReaderDTO2VOConverter;
8 | import org.apache.dubbo.config.annotation.DubboReference;
9 | import org.springframework.stereotype.Service;
10 |
11 | /**
12 | * @author lishuang
13 | * @date 2023-05-15
14 | */
15 | @Service
16 | public class ReaderFacadeClientImpl implements ReaderFacadeClient {
17 |
18 | @DubboReference
19 | ReaderReadFacade readerReadFacade;
20 |
21 | @Override
22 | public ReaderVO queryById(long readerId) {
23 |
24 | ReaderDTO readerDTO = readerReadFacade.queryById(readerId);
25 |
26 | return ReaderDTO2VOConverter.convert(readerDTO);
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/scs-utility/src/main/java/com/smart/classroom/subscription/utility/result/Pager.java:
--------------------------------------------------------------------------------
1 | package com.smart.classroom.subscription.utility.result;
2 |
3 | import lombok.Data;
4 | import lombok.NoArgsConstructor;
5 |
6 | import java.util.List;
7 |
8 |
9 | @Data
10 | @NoArgsConstructor
11 | public class Pager {
12 |
13 | //允许的最大页数
14 | public static int MAX_PAGE_SIZE = 1000;
15 |
16 | //批处理时每次页数
17 | public static int HANDLE_PAGE_SIZE = 500;
18 |
19 | //当前页码。 1基
20 | private long pageNum;
21 |
22 | //每页的大小。
23 | private long pageSize;
24 |
25 | //总条目数
26 | private long totalItems;
27 |
28 | //总页数
29 | private long totalPages;
30 |
31 | private List data;
32 |
33 |
34 | public Pager(long pageNum, long pageSize, long totalItems, List data) {
35 |
36 | if (pageSize <= 0) {
37 | pageSize = 10;
38 | }
39 |
40 | this.pageNum = pageNum;
41 |
42 | this.pageSize = pageSize;
43 |
44 | this.totalItems = totalItems;
45 |
46 | this.totalPages = (long) Math.ceil(this.totalItems * 1.0 / this.pageSize);
47 |
48 | this.data = data;
49 |
50 | }
51 |
52 |
53 | }
54 |
--------------------------------------------------------------------------------
/scs-facade-impl/src/main/java/com/smart/classroom/subscription/facade/impl/biz/order/OrderReadFacadeImpl.java:
--------------------------------------------------------------------------------
1 | package com.smart.classroom.subscription.facade.impl.biz.order;
2 |
3 | import com.smart.classroom.subscription.domain.biz.order.model.OrderModel;
4 | import com.smart.classroom.subscription.domain.biz.order.repository.OrderRepository;
5 | import com.smart.classroom.subscription.facade.biz.order.OrderReadFacade;
6 | import com.smart.classroom.subscription.facade.biz.order.response.OrderDTO;
7 | import com.smart.classroom.subscription.facade.impl.biz.order.converter.OrderModel2DTOConverter;
8 | import org.apache.dubbo.config.annotation.DubboService;
9 | import org.springframework.beans.factory.annotation.Autowired;
10 |
11 | import javax.annotation.Resource;
12 |
13 | /**
14 | * @author lishuang
15 | * @date 2023-05-19
16 | */
17 | @DubboService
18 | public class OrderReadFacadeImpl implements OrderReadFacade {
19 |
20 | @Resource
21 | OrderRepository orderRepository;
22 |
23 | @Override
24 | public OrderDTO queryById(Long orderId) {
25 | OrderModel orderModel = orderRepository.queryById(orderId);
26 | return OrderModel2DTOConverter.convert(orderModel);
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/scs-facade/src/main/java/com/smart/classroom/subscription/facade/biz/subscription/response/SubscriptionDTO.java:
--------------------------------------------------------------------------------
1 | package com.smart.classroom.subscription.facade.biz.subscription.response;
2 |
3 | import lombok.AllArgsConstructor;
4 | import lombok.Builder;
5 | import lombok.Data;
6 | import lombok.NoArgsConstructor;
7 |
8 | import java.io.Serializable;
9 | import java.util.Date;
10 |
11 | /**
12 | * @author lishuang
13 | * @date 2023-05-15
14 | */
15 | @Data
16 | @Builder
17 | @NoArgsConstructor
18 | @AllArgsConstructor
19 | public class SubscriptionDTO implements Serializable {
20 |
21 |
22 | /**
23 | * 主键
24 | */
25 | private Long id;
26 |
27 | /**
28 | * 创建时间
29 | */
30 | private Date createTime = null;
31 |
32 | /**
33 | * 修改时间
34 | */
35 | private Date updateTime = null;
36 |
37 | /**
38 | * 读者id
39 | */
40 | private Long readerId = null;
41 |
42 | /**
43 | * 专栏id
44 | */
45 | private Long columnId = null;
46 |
47 | /**
48 | * 订单id
49 | */
50 | private Long orderId = null;
51 |
52 | /**
53 | * 状态 CREATED/OK/DISABLED
54 | */
55 | private String status = null;
56 |
57 |
58 |
59 |
60 | }
61 |
--------------------------------------------------------------------------------
/scs-repository/src/main/java/com/smart/classroom/subscription/repository/mapper/order/OrderMapper.java:
--------------------------------------------------------------------------------
1 | /**
2 | * smart-classroom.com Inc. Copyright (c) 2015-present All Rights Reserved.
3 | * generated by SaberGenerator
4 | */
5 | package com.smart.classroom.subscription.repository.mapper.order;
6 |
7 | import com.smart.classroom.subscription.domain.biz.order.enums.OrderStatus;
8 | import com.smart.classroom.subscription.repository.orm.order.OrderDO;
9 | import com.smart.classroom.subscription.repository.orm.subscription.SubscriptionDO;
10 | import org.apache.ibatis.annotations.Mapper;
11 | import org.apache.ibatis.annotations.Param;
12 | import org.springframework.stereotype.Repository;
13 |
14 | import java.util.List;
15 |
16 | @Mapper
17 | @Repository
18 | public interface OrderMapper extends OrderBaseMapper {
19 |
20 | List queryByReaderIdAndColumnIdAndStatuses(
21 | @Param("readerId") Long readerId,
22 | @Param("columnId") Long columnId,
23 | @Param("statuses") List statuses
24 | );
25 |
26 | OrderDO queryByNo(@Param("orderNo") String orderNo);
27 |
28 | int updateStatus(@Param("orderId") Long orderId, @Param("status") OrderStatus status);
29 | }
--------------------------------------------------------------------------------
/scs-testsuit/src/main/resources/saber/TemplateBaseMapperJava.vm:
--------------------------------------------------------------------------------
1 | /**
2 | * smart-classroom.com Inc. Copyright (c) 2015-present All Rights Reserved.
3 | * generated by SaberGenerator
4 | */
5 | package ${artwork.mapperPackage};
6 |
7 | #foreach($item in $artwork.mapperImportNones)
8 | import ${item};
9 | #if(!$foreach.hasNext)
10 |
11 | #end
12 | #end
13 | #foreach($item in $artwork.mapperImportJavas)
14 | import ${item};
15 | #if(!$foreach.hasNext)
16 |
17 | #end
18 | #end
19 | @Mapper
20 | @Repository
21 | public interface ${artwork.entityUpperBodyName}BaseMapper extends BaseMapper<${artwork.entityUpperBodyName}DO> {
22 |
23 | /**
24 | * 当入参中含有PageNum和pageSize时,会自动分页。
25 | */
26 | Page<${artwork.entityUpperBodyName}DO> page(
27 | @Param("pageNum") int pageNum,
28 | @Param("pageSize") int pageSize,
29 | #foreach($item in $artwork.filterSummaryColumns)
30 | #if($item.canSort)
31 | @Param("order${item.upperCamelName}") SortDirection order${item.upperCamelName}#if($foreach.hasNext),
32 | #end
33 | #else
34 | @Param("${item.lowerCamelName}") ${item.javaSimpleName} ${item.lowerCamelName}#if($foreach.hasNext),
35 | #end
36 | #end
37 | #end
38 |
39 | );
40 |
41 | }
--------------------------------------------------------------------------------
/docs/start/rocketmq.md:
--------------------------------------------------------------------------------
1 | # Nacos使用方法
2 | ## 下载
3 | 从 [官网](https://rocketmq.apache.org/zh/docs/quickStart/01quickstart/) 下载,比如下载rocketmq-all-5.1.0-bin-release.zip
4 |
5 | ## 启动NameServer
6 | ```shell
7 | $ nohup sh bin/mqnamesrv &
8 |
9 | ### 验证namesrv是否启动成功
10 | $ tail -f ~/logs/rocketmqlogs/namesrv.log
11 | The Name Server boot success...
12 | ```
13 |
14 |
15 | ## 启动Broker+Proxy
16 | ```shell
17 | ### 先启动broker
18 | $ nohup sh bin/mqbroker -n localhost:9876 --enable-proxy &
19 |
20 | ### 验证broker是否启动成功, 比如, broker的ip是192.168.1.2 然后名字是broker-a
21 | $ tail -f ~/logs/rocketmqlogs/proxy.log
22 | The broker[broker-a,192.169.1.2:10911] boot success...
23 | ```
24 |
25 | 首次启动的时候需要创建一个Topic.
26 | ```shell
27 | sh bin/mqadmin updatetopic -n localhost:9876 -t SmartClassroomTopic -c DefaultCluster
28 | ```
29 |
30 | ## 关闭
31 | ```shell
32 | $ sh bin/mqshutdown broker
33 | $ sh bin/mqshutdown namesrv
34 | ```
35 |
36 |
37 | ## 常见问题
38 | ### 有可能rocket-mq会因为磁盘不足而报错:
39 | ```text
40 | the broker's disk is full
41 | ```
42 | 这个时候将磁盘阈值调大:
43 | ```text
44 | vi bin/runbroker.sh
45 | ```
46 | 增加一行java启动参数
47 | ```shell
48 | JAVA_OPT="${JAVA_OPT} -Drocketmq.broker.diskSpaceWarningLevelRatio=0.99"
49 | ```
50 | 然后重启rocketmq即可。
51 |
52 |
53 |
54 |
--------------------------------------------------------------------------------
/scs-repository/src/main/java/com/smart/classroom/subscription/repository/orm/subscription/SubscriptionDO.java:
--------------------------------------------------------------------------------
1 | /**
2 | * smart-classroom.com Inc. Copyright (c) 2015-present All Rights Reserved.
3 | * generated by SaberGenerator
4 | */
5 | package com.smart.classroom.subscription.repository.orm.subscription;
6 |
7 | import com.smart.classroom.subscription.domain.biz.subscription.enums.SubscriptionStatus;
8 | import com.smart.classroom.subscription.repository.orm.base.BaseEntityDO;
9 | import lombok.AllArgsConstructor;
10 | import lombok.Builder;
11 | import lombok.Data;
12 | import lombok.EqualsAndHashCode;
13 | import lombok.NoArgsConstructor;
14 |
15 | /**
16 | * 订阅表
17 | */
18 | @Data
19 | @Builder
20 | @NoArgsConstructor
21 | @AllArgsConstructor
22 | @EqualsAndHashCode(callSuper = true)
23 | public class SubscriptionDO extends BaseEntityDO {
24 |
25 | /**
26 | * 读者id
27 | */
28 | private Long readerId = null;
29 |
30 | /**
31 | * 专栏id
32 | */
33 | private Long columnId = null;
34 |
35 | /**
36 | * 订单id
37 | */
38 | private Long orderId = null;
39 |
40 | /**
41 | * 状态 CREATED/OK/DISABLED
42 | */
43 | private SubscriptionStatus status = SubscriptionStatus.CREATED;
44 |
45 |
46 | }
--------------------------------------------------------------------------------
/scs-domain/src/main/java/com/smart/classroom/subscription/domain/rpc/payment/vo/PaymentVO.java:
--------------------------------------------------------------------------------
1 | package com.smart.classroom.subscription.domain.rpc.payment.vo;
2 |
3 | import lombok.AllArgsConstructor;
4 | import lombok.Builder;
5 | import lombok.Data;
6 | import lombok.NoArgsConstructor;
7 |
8 | import java.util.Date;
9 |
10 | /**
11 | * @author lishuang
12 | * @date 2023-05-15
13 | */
14 | @Data
15 | @Builder
16 | @NoArgsConstructor
17 | @AllArgsConstructor
18 | public class PaymentVO {
19 |
20 | /**
21 | * 主键
22 | */
23 | private Long id = null;
24 |
25 | /**
26 | * 创建时间
27 | */
28 | private Date createTime = null;
29 |
30 | /**
31 | * 修改时间
32 | */
33 | private Date updateTime = null;
34 |
35 |
36 | /**
37 | * 订单编号
38 | */
39 | private String orderNo = null;
40 |
41 | /**
42 | * 支付方式 ALIPAY/WEIXIN 支付宝/微信
43 | */
44 | private String method = null;
45 |
46 | /**
47 | * 支付平台订单号
48 | */
49 | private String thirdTransactionNo = null;
50 |
51 | /**
52 | * 金额(单位:分)
53 | */
54 | private Long amount = null;
55 |
56 | /**
57 | * 支付状态 UNPAID/PAID/CLOSED 未支付/已支付/已关闭
58 | */
59 | private String status = null;
60 | }
61 |
--------------------------------------------------------------------------------
/scs-infrastructure/src/main/java/com/smart/classroom/subscription/infrastructure/rpc/payment/converter/PaymentDTO2VOConverter.java:
--------------------------------------------------------------------------------
1 | package com.smart.classroom.subscription.infrastructure.rpc.payment.converter;
2 |
3 |
4 | import com.smart.classroom.misc.facade.biz.payment.response.PaymentDTO;
5 | import com.smart.classroom.subscription.domain.rpc.payment.vo.PaymentVO;
6 |
7 | /**
8 | * @author lishuang
9 | * @date 2023-05-12
10 | * 转换器
11 | */
12 | public class PaymentDTO2VOConverter {
13 |
14 | /**
15 | * 将DO转换成模型
16 | */
17 | public static PaymentVO convert(PaymentDTO paymentDTO) {
18 | if (paymentDTO == null) {
19 | return null;
20 | }
21 |
22 | return PaymentVO.builder()
23 | .id(paymentDTO.getId())
24 | .createTime(paymentDTO.getCreateTime())
25 | .updateTime(paymentDTO.getUpdateTime())
26 |
27 | .orderNo(paymentDTO.getOrderNo())
28 | .method(paymentDTO.getMethod())
29 | .thirdTransactionNo(paymentDTO.getThirdTransactionNo())
30 | .amount(paymentDTO.getAmount())
31 |
32 | .status(paymentDTO.getStatus())
33 |
34 | .build();
35 | }
36 |
37 |
38 | }
39 |
--------------------------------------------------------------------------------
/scs-repository/src/main/java/com/smart/classroom/subscription/repository/impl/subscription/converter/SubscriptionDO2ModelConverter.java:
--------------------------------------------------------------------------------
1 | package com.smart.classroom.subscription.repository.impl.subscription.converter;
2 |
3 |
4 | import com.smart.classroom.subscription.domain.biz.subscription.model.SubscriptionModel;
5 | import com.smart.classroom.subscription.repository.orm.subscription.SubscriptionDO;
6 |
7 | /**
8 | * @author lishuang
9 | * @date 2023-05-12
10 | * 转换器
11 | */
12 | public class SubscriptionDO2ModelConverter {
13 |
14 | /**
15 | * 将DO转换成模型
16 | */
17 | public static SubscriptionModel convert(SubscriptionDO subscriptionDO) {
18 | if (subscriptionDO == null) {
19 | return null;
20 | }
21 |
22 | return SubscriptionModel.builder()
23 | .id(subscriptionDO.getId())
24 | .createTime(subscriptionDO.getCreateTime())
25 | .updateTime(subscriptionDO.getUpdateTime())
26 | .readerId(subscriptionDO.getReaderId())
27 | .columnId(subscriptionDO.getColumnId())
28 | .orderId(subscriptionDO.getOrderId())
29 | .status(subscriptionDO.getStatus())
30 | .build();
31 | }
32 |
33 |
34 | }
35 |
--------------------------------------------------------------------------------
/scs-domain/src/main/java/com/smart/classroom/subscription/domain/biz/subscription/model/SubscriptionModel.java:
--------------------------------------------------------------------------------
1 | package com.smart.classroom.subscription.domain.biz.subscription.model;
2 |
3 | import com.smart.classroom.subscription.domain.biz.subscription.enums.SubscriptionStatus;
4 | import lombok.AllArgsConstructor;
5 | import lombok.Builder;
6 | import lombok.Data;
7 | import lombok.NoArgsConstructor;
8 |
9 | import java.util.Date;
10 |
11 | /**
12 | * @author lishuang
13 | * @date 2023-05-12
14 | */
15 | @Data
16 | @Builder
17 | @NoArgsConstructor
18 | @AllArgsConstructor
19 | public class SubscriptionModel {
20 |
21 | /**
22 | * 主键
23 | */
24 | private Long id;
25 |
26 | /**
27 | * 创建时间
28 | */
29 | private Date createTime = null;
30 |
31 | /**
32 | * 修改时间
33 | */
34 | private Date updateTime = null;
35 |
36 | /**
37 | * 读者id
38 | */
39 | private Long readerId = null;
40 |
41 | /**
42 | * 专栏id
43 | */
44 | private Long columnId = null;
45 |
46 | /**
47 | * 订单id
48 | */
49 | private Long orderId = null;
50 |
51 | /**
52 | * 状态 CREATED/OK/DISABLED
53 | */
54 | private SubscriptionStatus status = SubscriptionStatus.CREATED;
55 |
56 |
57 | }
58 |
--------------------------------------------------------------------------------
/scs-repository/src/main/java/com/smart/classroom/subscription/repository/impl/order/converter/OrderDO2ModelConverter.java:
--------------------------------------------------------------------------------
1 | package com.smart.classroom.subscription.repository.impl.order.converter;
2 |
3 |
4 | import com.smart.classroom.subscription.domain.biz.order.model.OrderModel;
5 | import com.smart.classroom.subscription.repository.orm.order.OrderDO;
6 |
7 | /**
8 | * @author lishuang
9 | * @date 2023-05-12
10 | * 转换器
11 | */
12 | public class OrderDO2ModelConverter {
13 |
14 | /**
15 | * 将DO转换成模型
16 | */
17 | public static OrderModel convert(OrderDO orderDO) {
18 | if (orderDO == null) {
19 | return null;
20 | }
21 |
22 | return OrderModel.builder()
23 | .id(orderDO.getId())
24 | .createTime(orderDO.getCreateTime())
25 | .updateTime(orderDO.getUpdateTime())
26 | .no(orderDO.getNo())
27 | .readerId(orderDO.getReaderId())
28 | .columnId(orderDO.getColumnId())
29 | .columnQuoteId(orderDO.getColumnQuoteId())
30 | .paymentId(orderDO.getPaymentId())
31 | .price(orderDO.getPrice())
32 | .status(orderDO.getStatus())
33 | .build();
34 | }
35 |
36 |
37 | }
38 |
--------------------------------------------------------------------------------
/scs-facade-impl/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 | smart-classroom-subscription
7 | com.smart.classroom
8 | 1.0.0
9 |
10 | 4.0.0
11 |
12 | scs-facade-impl
13 |
14 |
15 | 8
16 | 8
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 | com.smart.classroom
26 | scs-application
27 |
28 |
29 |
30 | com.smart.classroom
31 | scs-facade
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
--------------------------------------------------------------------------------
/scs-domain/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 | smart-classroom-subscription
7 | com.smart.classroom
8 | 1.0.0
9 |
10 | 4.0.0
11 |
12 | scs-domain
13 |
14 |
15 | 8
16 | 8
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 | com.smart.classroom
26 | scs-utility
27 |
28 |
29 |
30 |
31 |
32 |
33 | org.springframework.boot
34 | spring-boot-starter
35 |
36 |
37 |
38 |
39 |
40 |
41 |
--------------------------------------------------------------------------------
/scs-testsuit/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 | smart-classroom-subscription
7 | com.smart.classroom
8 | 1.0.0
9 |
10 | 4.0.0
11 |
12 | scs-testsuit
13 |
14 |
15 | 8
16 | 8
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 | com.smart.classroom
25 | scs-main
26 |
27 |
28 |
29 |
30 |
31 |
32 | org.springframework.boot
33 | spring-boot-starter-test
34 | test
35 |
36 |
37 |
38 |
39 |
--------------------------------------------------------------------------------
/scs-infrastructure/src/main/java/com/smart/classroom/subscription/infrastructure/rpc/quote/converter/ColumnQuoteDTO2VOConverter.java:
--------------------------------------------------------------------------------
1 | package com.smart.classroom.subscription.infrastructure.rpc.quote.converter;
2 |
3 |
4 | import com.smart.classroom.misc.facade.biz.column.response.ColumnDTO;
5 | import com.smart.classroom.misc.facade.biz.quote.response.ColumnQuoteDTO;
6 | import com.smart.classroom.subscription.domain.rpc.column.vo.ColumnVO;
7 | import com.smart.classroom.subscription.domain.rpc.quote.vo.ColumnQuoteVO;
8 |
9 | /**
10 | * @author lishuang
11 | * @date 2023-05-12
12 | * 转换器
13 | */
14 | public class ColumnQuoteDTO2VOConverter {
15 |
16 | /**
17 | * 将DO转换成模型
18 | */
19 | public static ColumnQuoteVO convert(ColumnQuoteDTO columnQuoteDTO) {
20 | if (columnQuoteDTO == null) {
21 | return null;
22 | }
23 |
24 | return ColumnQuoteVO.builder()
25 | .id(columnQuoteDTO.getId())
26 | .createTime(columnQuoteDTO.getCreateTime())
27 | .updateTime(columnQuoteDTO.getUpdateTime())
28 | .columnId(columnQuoteDTO.getColumnId())
29 | .editorId(columnQuoteDTO.getEditorId())
30 | .price(columnQuoteDTO.getPrice())
31 | .status(columnQuoteDTO.getStatus())
32 |
33 | .build();
34 | }
35 |
36 |
37 | }
38 |
--------------------------------------------------------------------------------
/scs-repository/src/main/java/com/smart/classroom/subscription/repository/impl/order/converter/OrderModel2DOConverter.java:
--------------------------------------------------------------------------------
1 | package com.smart.classroom.subscription.repository.impl.order.converter;
2 |
3 | import com.smart.classroom.subscription.domain.biz.order.model.OrderModel;
4 | import com.smart.classroom.subscription.repository.orm.order.OrderDO;
5 |
6 | /**
7 | * @author lishuang
8 | * @date 2023-05-12
9 | * 转换器
10 | */
11 | public class OrderModel2DOConverter {
12 |
13 | /**
14 | * 将模型转换成DO
15 | */
16 | public static OrderDO convert(OrderModel orderModel) {
17 | if (orderModel == null) {
18 | return null;
19 | }
20 |
21 | OrderDO orderDO = OrderDO.builder()
22 | .no(orderModel.getNo())
23 | .readerId(orderModel.getReaderId())
24 | .columnId(orderModel.getColumnId())
25 | .columnQuoteId(orderModel.getColumnQuoteId())
26 | .paymentId(orderModel.getPaymentId())
27 | .price(orderModel.getPrice())
28 | .status(orderModel.getStatus())
29 | .build();
30 |
31 | orderDO.setId(orderModel.getId());
32 | orderDO.setCreateTime(orderModel.getCreateTime());
33 | orderDO.setUpdateTime(orderModel.getUpdateTime());
34 |
35 | return orderDO;
36 |
37 | }
38 |
39 |
40 | }
41 |
--------------------------------------------------------------------------------
/scs-repository/src/main/java/com/smart/classroom/subscription/repository/impl/subscription/converter/SubscriptionModel2DOConverter.java:
--------------------------------------------------------------------------------
1 | package com.smart.classroom.subscription.repository.impl.subscription.converter;
2 |
3 | import com.smart.classroom.subscription.domain.biz.subscription.model.SubscriptionModel;
4 | import com.smart.classroom.subscription.repository.orm.subscription.SubscriptionDO;
5 |
6 | /**
7 | * @author lishuang
8 | * @date 2023-05-12
9 | * 转换器
10 | */
11 | public class SubscriptionModel2DOConverter {
12 |
13 | /**
14 | * 将模型转换成DO
15 | */
16 | public static SubscriptionDO convert(SubscriptionModel subscriptionModel) {
17 | if (subscriptionModel == null) {
18 | return null;
19 | }
20 |
21 | SubscriptionDO subscriptionDO = SubscriptionDO.builder()
22 | .readerId(subscriptionModel.getReaderId())
23 | .columnId(subscriptionModel.getColumnId())
24 | .orderId(subscriptionModel.getOrderId())
25 | .status(subscriptionModel.getStatus())
26 | .build();
27 |
28 | subscriptionDO.setId(subscriptionModel.getId());
29 | subscriptionDO.setCreateTime(subscriptionModel.getCreateTime());
30 | subscriptionDO.setUpdateTime(subscriptionModel.getUpdateTime());
31 |
32 | return subscriptionDO;
33 |
34 | }
35 |
36 |
37 | }
38 |
--------------------------------------------------------------------------------
/scs-facade-impl/src/main/java/com/smart/classroom/subscription/facade/impl/biz/order/converter/OrderModel2DTOConverter.java:
--------------------------------------------------------------------------------
1 | package com.smart.classroom.subscription.facade.impl.biz.order.converter;
2 |
3 | import com.smart.classroom.subscription.domain.biz.order.enums.OrderStatus;
4 | import com.smart.classroom.subscription.domain.biz.order.model.OrderModel;
5 | import com.smart.classroom.subscription.facade.biz.order.response.OrderDTO;
6 |
7 | /**
8 | * @author lishuang
9 | * @date 2023-05-12
10 | * 转换器
11 | */
12 | public class OrderModel2DTOConverter {
13 |
14 | /**
15 | * 将DO转换成模型
16 | */
17 | public static OrderDTO convert(OrderModel orderModel) {
18 | if (orderModel == null) {
19 | return null;
20 | }
21 |
22 | OrderDTO orderDTO = OrderDTO.builder()
23 | .id(orderModel.getId())
24 | .createTime(orderModel.getCreateTime())
25 | .updateTime(orderModel.getUpdateTime())
26 | .no(orderModel.getNo())
27 | .readerId(orderModel.getReaderId())
28 | .columnId(orderModel.getColumnId())
29 | .columnQuoteId(orderModel.getColumnQuoteId())
30 | .paymentId(orderModel.getPaymentId())
31 | .price(orderModel.getPrice())
32 | .status(OrderStatus.toString(orderModel.getStatus()))
33 | .build();
34 |
35 | return orderDTO;
36 | }
37 |
38 |
39 | }
40 |
--------------------------------------------------------------------------------
/scs-application/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 | smart-classroom-subscription
7 | com.smart.classroom
8 | 1.0.0
9 |
10 | 4.0.0
11 |
12 | scs-application
13 |
14 |
15 | 8
16 | 8
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 | com.smart.classroom
25 | scs-domain
26 |
27 |
28 |
29 | com.smart.classroom
30 | scs-infrastructure
31 |
32 |
33 |
34 | com.smart.classroom
35 | scs-repository
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
--------------------------------------------------------------------------------
/scs-facade-impl/src/main/java/com/smart/classroom/subscription/facade/impl/biz/subscription/converter/SubscriptionModel2DTOConverter.java:
--------------------------------------------------------------------------------
1 | package com.smart.classroom.subscription.facade.impl.biz.subscription.converter;
2 |
3 | import com.smart.classroom.subscription.domain.biz.subscription.enums.SubscriptionStatus;
4 | import com.smart.classroom.subscription.domain.biz.subscription.model.SubscriptionModel;
5 | import com.smart.classroom.subscription.facade.biz.subscription.response.SubscriptionDTO;
6 |
7 | /**
8 | * @author lishuang
9 | * @date 2023-05-12
10 | * 转换器
11 | */
12 | public class SubscriptionModel2DTOConverter {
13 |
14 | /**
15 | * 将DO转换成模型
16 | */
17 | public static SubscriptionDTO convert(SubscriptionModel subscriptionModel) {
18 | if (subscriptionModel == null) {
19 | return null;
20 | }
21 |
22 | SubscriptionDTO subscriptionDTO = SubscriptionDTO.builder()
23 | .id(subscriptionModel.getId())
24 | .createTime(subscriptionModel.getCreateTime())
25 | .updateTime(subscriptionModel.getUpdateTime())
26 |
27 | .readerId(subscriptionModel.getReaderId())
28 | .columnId(subscriptionModel.getColumnId())
29 | .orderId(subscriptionModel.getOrderId())
30 | .status(SubscriptionStatus.toString(subscriptionModel.getStatus()))
31 | .build();
32 |
33 | return subscriptionDTO;
34 | }
35 |
36 |
37 | }
38 |
--------------------------------------------------------------------------------
/scs-facade/src/main/java/com/smart/classroom/subscription/facade/biz/order/response/OrderDTO.java:
--------------------------------------------------------------------------------
1 | package com.smart.classroom.subscription.facade.biz.order.response;
2 |
3 | import lombok.AllArgsConstructor;
4 | import lombok.Builder;
5 | import lombok.Data;
6 | import lombok.NoArgsConstructor;
7 |
8 | import java.io.Serializable;
9 | import java.util.Date;
10 |
11 | /**
12 | * @author lishuang
13 | * @date 2023-05-15
14 | */
15 | @Data
16 | @Builder
17 | @NoArgsConstructor
18 | @AllArgsConstructor
19 | public class OrderDTO implements Serializable {
20 |
21 |
22 | /**
23 | * 主键
24 | */
25 | private Long id;
26 |
27 | /**
28 | * 创建时间
29 | */
30 | private Date createTime = null;
31 |
32 | /**
33 | * 修改时间
34 | */
35 | private Date updateTime = null;
36 |
37 | /**
38 | * 订单唯一编号,整个系统唯一,带有前缀
39 | */
40 | private String no = null;
41 |
42 | /**
43 | * 读者id
44 | */
45 | private Long readerId = null;
46 |
47 | /**
48 | * 专栏id
49 | */
50 | private Long columnId = null;
51 |
52 | /**
53 | * 专栏报价id
54 | */
55 | private Long columnQuoteId = null;
56 |
57 | /**
58 | * 支付单id
59 | */
60 | private Long paymentId = null;
61 |
62 | /**
63 | * 价格(单位:分)
64 | */
65 | private Long price = null;
66 |
67 | /**
68 | * 状态 CREATED/PAID/SUBSCRIBED/CLOSED/CANCELED
69 | */
70 | private String status = null;
71 |
72 |
73 |
74 | }
75 |
--------------------------------------------------------------------------------
/scs-repository/src/main/java/com/smart/classroom/subscription/repository/orm/order/OrderDO.java:
--------------------------------------------------------------------------------
1 | /**
2 | * smart-classroom.com Inc. Copyright (c) 2015-present All Rights Reserved.
3 | * generated by SaberGenerator
4 | */
5 | package com.smart.classroom.subscription.repository.orm.order;
6 |
7 | import com.smart.classroom.subscription.domain.biz.order.enums.OrderStatus;
8 | import com.smart.classroom.subscription.repository.orm.base.BaseEntityDO;
9 | import lombok.AllArgsConstructor;
10 | import lombok.Builder;
11 | import lombok.Data;
12 | import lombok.EqualsAndHashCode;
13 | import lombok.NoArgsConstructor;
14 |
15 | /**
16 | * 订单表
17 | */
18 | @Data
19 | @Builder
20 | @NoArgsConstructor
21 | @AllArgsConstructor
22 | @EqualsAndHashCode(callSuper = true)
23 | public class OrderDO extends BaseEntityDO {
24 |
25 | /**
26 | * 订单唯一编号,整个系统唯一,带有前缀
27 | */
28 | private String no = null;
29 |
30 | /**
31 | * 读者id
32 | */
33 | private Long readerId = null;
34 |
35 | /**
36 | * 专栏id
37 | */
38 | private Long columnId = null;
39 |
40 | /**
41 | * 专栏报价id
42 | */
43 | private Long columnQuoteId = null;
44 |
45 | /**
46 | * 支付单id
47 | */
48 | private Long paymentId = null;
49 |
50 | /**
51 | * 价格(单位:分)
52 | */
53 | private Long price = null;
54 |
55 | /**
56 | * 状态 CREATED/PAID/SUBSCRIBED/CLOSED/CANCELED
57 | */
58 | private OrderStatus status = OrderStatus.CREATED;
59 |
60 |
61 | }
--------------------------------------------------------------------------------
/scs-domain/src/main/java/com/smart/classroom/subscription/domain/biz/order/model/OrderModel.java:
--------------------------------------------------------------------------------
1 | package com.smart.classroom.subscription.domain.biz.order.model;
2 |
3 | import com.smart.classroom.subscription.domain.biz.order.enums.OrderStatus;
4 | import lombok.AllArgsConstructor;
5 | import lombok.Builder;
6 | import lombok.Data;
7 | import lombok.NoArgsConstructor;
8 |
9 | import java.util.Date;
10 |
11 | /**
12 | * @author lishuang
13 | * @date 2023-05-12
14 | */
15 | @Data
16 | @Builder
17 | @NoArgsConstructor
18 | @AllArgsConstructor
19 | public class OrderModel {
20 |
21 | /**
22 | * 主键
23 | */
24 | private Long id;
25 |
26 | /**
27 | * 创建时间
28 | */
29 | private Date createTime = null;
30 |
31 | /**
32 | * 修改时间
33 | */
34 | private Date updateTime = null;
35 |
36 | /**
37 | * 订单唯一编号,整个系统唯一,带有前缀
38 | */
39 | private String no = null;
40 |
41 | /**
42 | * 读者id
43 | */
44 | private Long readerId = null;
45 |
46 | /**
47 | * 专栏id
48 | */
49 | private Long columnId = null;
50 |
51 | /**
52 | * 专栏报价id
53 | */
54 | private Long columnQuoteId = null;
55 |
56 | /**
57 | * 支付单id
58 | */
59 | private Long paymentId = null;
60 |
61 | /**
62 | * 价格(单位:分)
63 | */
64 | private Long price = null;
65 |
66 | /**
67 | * 状态 CREATED/PAID/SUBSCRIBED/CLOSED/CANCELED
68 | */
69 | private OrderStatus status = OrderStatus.CREATED;
70 |
71 |
72 | }
73 |
--------------------------------------------------------------------------------
/scs-repository/src/main/java/com/smart/classroom/subscription/repository/mapper/order/OrderBaseMapper.java:
--------------------------------------------------------------------------------
1 | /**
2 | * smart-classroom.com Inc. Copyright (c) 2015-present All Rights Reserved.
3 | * generated by SaberGenerator
4 | */
5 | package com.smart.classroom.subscription.repository.mapper.order;
6 |
7 | import com.github.pagehelper.Page;
8 | import com.smart.classroom.subscription.domain.biz.order.enums.OrderStatus;
9 | import com.smart.classroom.subscription.repository.mapper.base.BaseMapper;
10 | import com.smart.classroom.subscription.repository.orm.order.OrderDO;
11 | import com.smart.classroom.subscription.utility.enums.SortDirection;
12 | import org.apache.ibatis.annotations.Mapper;
13 | import org.apache.ibatis.annotations.Param;
14 | import org.springframework.stereotype.Repository;
15 |
16 | @Mapper
17 | @Repository
18 | public interface OrderBaseMapper extends BaseMapper {
19 |
20 | /**
21 | * 当入参中含有PageNum和pageSize时,会自动分页。
22 | */
23 | Page page(
24 | @Param("pageNum") int pageNum,
25 | @Param("pageSize") int pageSize,
26 | @Param("orderCreateTime") SortDirection orderCreateTime,
27 | @Param("orderUpdateTime") SortDirection orderUpdateTime,
28 | @Param("readerId") Long readerId,
29 | @Param("columnId") Long columnId,
30 | @Param("columnQuoteId") Long columnQuoteId,
31 | @Param("paymentId") Long paymentId,
32 | @Param("status") OrderStatus status
33 | );
34 |
35 |
36 | }
--------------------------------------------------------------------------------
/scs-repository/src/main/java/com/smart/classroom/subscription/repository/mapper/subscription/SubscriptionBaseMapper.java:
--------------------------------------------------------------------------------
1 | /**
2 | * smart-classroom.com Inc. Copyright (c) 2015-present All Rights Reserved.
3 | * generated by SaberGenerator
4 | */
5 | package com.smart.classroom.subscription.repository.mapper.subscription;
6 |
7 | import com.github.pagehelper.Page;
8 | import com.smart.classroom.subscription.domain.biz.subscription.enums.SubscriptionStatus;
9 | import com.smart.classroom.subscription.repository.mapper.base.BaseMapper;
10 | import com.smart.classroom.subscription.repository.orm.subscription.SubscriptionDO;
11 | import com.smart.classroom.subscription.utility.enums.SortDirection;
12 | import org.apache.ibatis.annotations.Mapper;
13 | import org.apache.ibatis.annotations.Param;
14 | import org.springframework.stereotype.Repository;
15 |
16 | @Mapper
17 | @Repository
18 | public interface SubscriptionBaseMapper extends BaseMapper {
19 |
20 | /**
21 | * 当入参中含有PageNum和pageSize时,会自动分页。
22 | */
23 | Page page(
24 | @Param("pageNum") int pageNum,
25 | @Param("pageSize") int pageSize,
26 | @Param("orderCreateTime") SortDirection orderCreateTime,
27 | @Param("orderUpdateTime") SortDirection orderUpdateTime,
28 | @Param("readerId") Long readerId,
29 | @Param("columnId") Long columnId,
30 | @Param("orderId") Long orderId,
31 | @Param("status") SubscriptionStatus status
32 | );
33 |
34 | }
--------------------------------------------------------------------------------
/scs-domain/src/main/java/com/smart/classroom/subscription/domain/biz/order/service/OrderPaidDomainService.java:
--------------------------------------------------------------------------------
1 | package com.smart.classroom.subscription.domain.biz.order.service;
2 |
3 | import com.smart.classroom.subscription.domain.biz.order.enums.OrderStatus;
4 | import com.smart.classroom.subscription.domain.biz.order.model.OrderModel;
5 | import com.smart.classroom.subscription.domain.biz.order.repository.OrderRepository;
6 | import com.smart.classroom.subscription.domain.rpc.payment.PaymentFacadeClient;
7 | import com.smart.classroom.subscription.domain.rpc.quote.ColumnQuoteFacadeClient;
8 | import lombok.extern.slf4j.Slf4j;
9 | import org.springframework.beans.factory.annotation.Autowired;
10 | import org.springframework.stereotype.Service;
11 |
12 | /**
13 | * 准备订单 领域服务
14 | *
15 | * @author lishuang
16 | * @date 2023-05-12
17 | */
18 | @Slf4j
19 | @Service
20 | public class OrderPaidDomainService {
21 |
22 |
23 | @Autowired
24 | OrderRepository orderRepository;
25 |
26 | @Autowired
27 | ColumnQuoteFacadeClient columnQuoteFacadeClient;
28 |
29 | @Autowired
30 | PaymentFacadeClient paymentFacadeClient;
31 |
32 |
33 | /**
34 | * 更新订单状态至已支付。
35 | */
36 | public OrderModel orderPaid(OrderModel orderModel) {
37 |
38 | //更新状态
39 | orderModel.setStatus(OrderStatus.PAID);
40 | orderModel = orderRepository.updateStatus(orderModel);
41 |
42 | log.info("订单id={} no={}状态已更新成PAID", orderModel.getId(), orderModel.getNo());
43 |
44 |
45 | return orderModel;
46 |
47 | }
48 |
49 | }
50 |
--------------------------------------------------------------------------------
/scs-utility/src/main/java/com/smart/classroom/subscription/utility/model/Pair.java:
--------------------------------------------------------------------------------
1 | package com.smart.classroom.subscription.utility.model;
2 |
3 | import java.util.Objects;
4 |
5 | /**
6 | * 将两个值封装在一个类中
7 | * 从而方便多值返回使用
8 | *
9 | * @author lishuang
10 | * @version 2023-05-11
11 | */
12 | public class Pair {
13 |
14 | /**
15 | * 键
16 | */
17 | private K key;
18 |
19 | public K getKey() {
20 | return key;
21 | }
22 |
23 | /**
24 | * 值
25 | */
26 | private V value;
27 |
28 | public V getValue() {
29 | return value;
30 | }
31 |
32 | public Pair(K key, V value) {
33 | this.key = key;
34 | this.value = value;
35 | }
36 |
37 | @Override
38 | public String toString() {
39 | return key + "=" + value;
40 | }
41 |
42 | @Override
43 | public int hashCode() {
44 | // name's hashCode is multiplied by an arbitrary prime number (13)
45 | // in order to make sure there is a difference in the hashCode between
46 | // these two parameters:
47 | // name: a value: aa
48 | // name: aa value: a
49 | return key.hashCode() * 13 + (value == null ? 0 : value.hashCode());
50 | }
51 |
52 | @Override
53 | public boolean equals(Object o) {
54 | if (this == o) {
55 | return true;
56 | }
57 | if (o instanceof Pair) {
58 | Pair pair = (Pair) o;
59 | if (!Objects.equals(key, pair.key)) {
60 | return false;
61 | }
62 | return Objects.equals(value, pair.value);
63 | }
64 | return false;
65 | }
66 | }
--------------------------------------------------------------------------------
/scs-testsuit/src/main/java/com/smart/classroom/subscription/tool/saber/x/order/OrderCommand.java:
--------------------------------------------------------------------------------
1 | package com.smart.classroom.subscription.tool.saber.x.order;
2 |
3 |
4 | import com.smart.classroom.subscription.domain.biz.order.enums.OrderStatus;
5 | import com.smart.classroom.subscription.tool.saber.command.SaberCommand;
6 | import com.smart.classroom.subscription.tool.saber.support.SaberHelper;
7 | import com.smart.classroom.subscription.utility.model.Pair;
8 |
9 | import java.util.ArrayList;
10 | import java.util.HashMap;
11 |
12 | /**
13 | * 直接运行该文件,会生成对应的DO,Mapper文件。
14 | */
15 | public class OrderCommand {
16 | public static void main(String[] args) {
17 |
18 | /*
19 | * scs_order
20 | */
21 | SaberCommand saberCommand = new SaberCommand("scs_order");
22 |
23 | //模糊筛选
24 | saberCommand.setFilterLikeFields(new ArrayList() {{
25 | //下划线风格,驼峰均可以
26 |
27 |
28 | }});
29 |
30 | //等号筛选
31 | saberCommand.setFilterEqualFields(new ArrayList() {{
32 | //下划线风格,驼峰均可以
33 |
34 | add("reader_id");
35 | add("column_id");
36 | add("column_quote_id");
37 | add("payment_id");
38 | add("status");
39 | }});
40 |
41 | //排序
42 | saberCommand.setFilterOrderFields(new ArrayList() {{
43 | //下划线风格,驼峰均可以
44 |
45 | }});
46 |
47 | //枚举定义
48 | saberCommand.setEnumFieldMap(new HashMap>, String>>() {{
49 | put("status", new Pair<>(OrderStatus.class, OrderStatus.CREATED.name()));
50 | }});
51 |
52 | SaberHelper.run(saberCommand);
53 | }
54 | }
55 |
--------------------------------------------------------------------------------
/scs-testsuit/src/main/java/com/smart/classroom/subscription/tool/saber/x/subscription/SubscriptionCommand.java:
--------------------------------------------------------------------------------
1 | package com.smart.classroom.subscription.tool.saber.x.subscription;
2 |
3 |
4 | import com.smart.classroom.subscription.domain.biz.subscription.enums.SubscriptionStatus;
5 | import com.smart.classroom.subscription.tool.saber.command.SaberCommand;
6 | import com.smart.classroom.subscription.tool.saber.support.SaberHelper;
7 | import com.smart.classroom.subscription.utility.model.Pair;
8 |
9 | import java.util.ArrayList;
10 | import java.util.HashMap;
11 |
12 | /**
13 | * 直接运行该文件,会生成对应的DO,Mapper文件。
14 | */
15 | public class SubscriptionCommand {
16 | public static void main(String[] args) {
17 |
18 | /*
19 | * scs_subscription
20 | */
21 | SaberCommand saberCommand = new SaberCommand("scs_subscription");
22 |
23 | //模糊筛选
24 | saberCommand.setFilterLikeFields(new ArrayList() {{
25 | //下划线风格,驼峰均可以
26 |
27 |
28 | }});
29 |
30 | //等号筛选
31 | saberCommand.setFilterEqualFields(new ArrayList() {{
32 | //下划线风格,驼峰均可以
33 |
34 | add("reader_id");
35 | add("column_id");
36 | add("order_id");
37 | add("status");
38 | }});
39 |
40 | //排序
41 | saberCommand.setFilterOrderFields(new ArrayList() {{
42 | //下划线风格,驼峰均可以
43 |
44 | }});
45 |
46 | //枚举定义
47 | saberCommand.setEnumFieldMap(new HashMap>, String>>() {{
48 | put("status", new Pair<>(SubscriptionStatus.class, SubscriptionStatus.CREATED.name()));
49 | }});
50 |
51 | SaberHelper.run(saberCommand);
52 | }
53 | }
54 |
--------------------------------------------------------------------------------
/scs-repository/src/main/resources/mybatis/mapper/order/OrderMapper.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
29 |
30 |
37 |
38 |
39 |
40 | UPDATE scs_order
41 | SET
42 | update_time = current_timestamp() ,
43 | status = #{status}
44 | WHERE id = #{orderId}
45 |
46 |
47 |
--------------------------------------------------------------------------------
/scs-repository/src/main/resources/mybatis/mybatis-config.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
--------------------------------------------------------------------------------
/scs-utility/src/main/java/com/smart/classroom/subscription/utility/exception/UtilException.java:
--------------------------------------------------------------------------------
1 | package com.smart.classroom.subscription.utility.exception;
2 |
3 |
4 | import com.smart.classroom.subscription.utility.util.StringUtil;
5 | import lombok.Data;
6 | import lombok.EqualsAndHashCode;
7 |
8 | /**
9 | * 作为我们自定义异常的父类
10 | */
11 | @EqualsAndHashCode(callSuper = false)
12 | @Data
13 | public class UtilException extends RuntimeException {
14 |
15 | protected ExceptionCode code;
16 | protected String message;
17 |
18 | public UtilException() {
19 | this(ExceptionCode.UNKNOWN);
20 | }
21 |
22 | public UtilException(String messagePattern, Object... arguments) {
23 |
24 | super(StringUtil.format(messagePattern, arguments));
25 |
26 | this.code = ExceptionCode.UNKNOWN;
27 | this.message = StringUtil.format(messagePattern, arguments);
28 | }
29 |
30 | public UtilException(ExceptionCode resultCode) {
31 | super(resultCode.getMessage());
32 |
33 | this.code = resultCode;
34 | this.message = resultCode.getMessage();
35 | }
36 |
37 | public UtilException(Throwable throwable) {
38 | super(throwable);
39 |
40 | this.code = ExceptionCode.UNKNOWN;
41 | this.message = throwable.getMessage();
42 | }
43 |
44 |
45 | public UtilException(ExceptionCode resultCode, String messagePattern, Object... arguments) {
46 | super(StringUtil.format(messagePattern, arguments));
47 |
48 | this.code = resultCode;
49 | this.message = StringUtil.format(messagePattern, arguments);
50 | }
51 |
52 | @Override
53 | public String getMessage() {
54 | return this.message;
55 | }
56 |
57 | @Override
58 | public String toString() {
59 | return StringUtil.format("{} code={} message={}", this.getClass().getSimpleName(), this.code, this.message);
60 | }
61 |
62 | }
--------------------------------------------------------------------------------
/scs-utility/src/main/java/com/smart/classroom/subscription/utility/util/NumberUtil.java:
--------------------------------------------------------------------------------
1 | package com.smart.classroom.subscription.utility.util;
2 |
3 | import java.math.BigDecimal;
4 | import java.util.Objects;
5 | import java.util.Random;
6 |
7 | public class NumberUtil {
8 |
9 |
10 | /**
11 | * 判断一个字符串是否为整数
12 | *
13 | * @param value 待检测的字符串
14 | * @return true=>是整数 false=>不是整数
15 | */
16 | public static boolean isInteger(String value) {
17 | try {
18 | Integer.parseInt(value);
19 | return true;
20 | } catch (Throwable throwable) {
21 | return false;
22 | }
23 | }
24 |
25 |
26 | /**
27 | * 判断一个BigDecimal是否为整数
28 | *
29 | * @param bigDecimal 待检测的字符串
30 | * @return true=>是整数 false=>不是整数
31 | */
32 | public static boolean isInteger(BigDecimal bigDecimal) {
33 | return bigDecimal.stripTrailingZeros().scale() <= 0;
34 | }
35 |
36 |
37 | /**
38 | * [a,b)的一个随机整数
39 | */
40 | public static int random(int start, int end) {
41 |
42 | if (start > end) {
43 | int temp = start;
44 | start = end;
45 | end = temp;
46 | }
47 |
48 | Random r = new Random();
49 |
50 | return r.nextInt(end - start) + start;
51 | }
52 |
53 |
54 | /**
55 | * 比较两个泛型Number的大小
56 | */
57 | public static int numberCompare(Number number1, Number number2) {
58 |
59 | return new BigDecimal(number1.toString()).compareTo(new BigDecimal(number2.toString()));
60 |
61 | }
62 |
63 | public static int min(int a, int b) {
64 | return Math.min(a, b);
65 |
66 | }
67 |
68 |
69 | /**
70 | * 都为null 为true ,相等为true
71 | */
72 | public static Boolean equals(Number number1,Number number2) {
73 |
74 | if (Objects.isNull(number1) && Objects.isNull(number2)) {
75 | return true;
76 | } else if (Objects.nonNull(number1) && number1.equals(number2)) {
77 | return true;
78 | } else{
79 | return false;
80 | }
81 | }
82 |
83 | }
84 |
--------------------------------------------------------------------------------
/scs-infrastructure/src/main/java/com/smart/classroom/subscription/infrastructure/rpc/quote/ColumnQuoteFacadeClientImpl.java:
--------------------------------------------------------------------------------
1 | package com.smart.classroom.subscription.infrastructure.rpc.quote;
2 |
3 | import com.smart.classroom.misc.facade.biz.payment.PaymentReadFacade;
4 | import com.smart.classroom.misc.facade.biz.payment.response.PaymentDTO;
5 | import com.smart.classroom.misc.facade.biz.payment.response.PreparePaymentDTO;
6 | import com.smart.classroom.misc.facade.biz.quote.ColumnQuoteReadFacade;
7 | import com.smart.classroom.misc.facade.biz.quote.response.ColumnQuoteDTO;
8 | import com.smart.classroom.subscription.domain.rpc.payment.PaymentFacadeClient;
9 | import com.smart.classroom.subscription.domain.rpc.payment.info.PreparePaymentInfo;
10 | import com.smart.classroom.subscription.domain.rpc.payment.vo.PaymentVO;
11 | import com.smart.classroom.subscription.domain.rpc.quote.ColumnQuoteFacadeClient;
12 | import com.smart.classroom.subscription.domain.rpc.quote.vo.ColumnQuoteVO;
13 | import com.smart.classroom.subscription.infrastructure.rpc.payment.converter.PaymentDTO2VOConverter;
14 | import com.smart.classroom.subscription.infrastructure.rpc.payment.converter.PreparePaymentDTO2InfoConverter;
15 | import com.smart.classroom.subscription.infrastructure.rpc.quote.converter.ColumnQuoteDTO2VOConverter;
16 | import org.apache.dubbo.config.annotation.DubboReference;
17 | import org.springframework.stereotype.Service;
18 |
19 | /**
20 | * @author lishuang
21 | * @date 2023-05-15
22 | */
23 | @Service
24 | public class ColumnQuoteFacadeClientImpl implements ColumnQuoteFacadeClient {
25 |
26 | @DubboReference
27 | ColumnQuoteReadFacade columnQuoteReadFacade;
28 |
29 | @Override
30 | public ColumnQuoteVO queryById(long columnQuoteId) {
31 |
32 | ColumnQuoteDTO columnQuoteDTO = columnQuoteReadFacade.queryById(columnQuoteId);
33 |
34 | return ColumnQuoteDTO2VOConverter.convert(columnQuoteDTO);
35 | }
36 |
37 | @Override
38 | public ColumnQuoteVO queryByColumnId(long columnId) {
39 |
40 | ColumnQuoteDTO columnQuoteDTO = columnQuoteReadFacade.queryByColumnId(columnId);
41 |
42 | return ColumnQuoteDTO2VOConverter.convert(columnQuoteDTO);
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/scs-facade/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 | smart-classroom-subscription
7 | com.smart.classroom
8 | 1.0.0
9 |
10 | 4.0.0
11 |
12 | scs-facade
13 |
14 |
15 | 8
16 | 8
17 |
18 |
19 |
20 |
21 |
22 | org.projectlombok
23 | lombok
24 | provided
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 | org.apache.maven.plugins
35 | maven-compiler-plugin
36 | 3.5.1
37 |
38 | 1.8
39 | 1.8
40 | UTF-8
41 |
42 |
43 |
44 |
45 |
46 | org.apache.maven.plugins
47 | maven-source-plugin
48 | 3.0.1
49 |
50 |
51 | package
52 |
53 | jar-no-fork
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
--------------------------------------------------------------------------------
/scs-main/src/main/resources/logback-spring.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | 1000
7 |
8 |
9 |
10 |
11 |
12 |
13 |
15 |
16 |
17 |
18 |
19 |
20 | ${APPLICATION_FILE}
21 |
22 |
23 | ${APPLICATION_FILE}.%d{yyyy-MM-dd}.%i
24 |
25 | 7
26 | 50MB
27 | 2GB
28 |
29 |
30 |
31 | ${PATTERN}
32 |
33 |
34 |
35 |
36 | INFO
37 |
38 |
39 |
40 |
41 |
42 |
43 | ${PATTERN}
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
--------------------------------------------------------------------------------
/scs-main/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 | smart-classroom-subscription
7 | com.smart.classroom
8 | 1.0.0
9 |
10 | 4.0.0
11 |
12 | scs-main
13 |
14 |
15 | 8
16 | 8
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 | com.smart.classroom
25 | scs-facade-impl
26 |
27 |
28 |
29 |
30 |
31 |
32 | org.springframework.boot
33 | spring-boot-devtools
34 | runtime
35 | true
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 | org.springframework.boot
49 | spring-boot-maven-plugin
50 |
51 | com.smart.classroom.subscription.SubscriptionApplication
52 |
53 | true
54 |
55 |
56 |
57 |
58 | repackage
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
--------------------------------------------------------------------------------
/scs-repository/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 | smart-classroom-subscription
7 | com.smart.classroom
8 | 1.0.0
9 |
10 | 4.0.0
11 |
12 | scs-repository
13 |
14 |
15 | 8
16 | 8
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 | com.smart.classroom
26 | scs-domain
27 |
28 |
29 |
30 | com.smart.classroom
31 | scs-utility
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 | org.mybatis.spring.boot
43 | mybatis-spring-boot-starter
44 |
45 |
46 |
47 |
48 | com.zaxxer
49 | HikariCP
50 |
51 |
52 |
53 |
54 | org.mybatis
55 | mybatis
56 |
57 |
58 |
59 |
60 | com.github.pagehelper
61 | pagehelper
62 |
63 |
64 |
65 | mysql
66 | mysql-connector-java
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
--------------------------------------------------------------------------------
/scs-infrastructure/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 | smart-classroom-subscription
7 | com.smart.classroom
8 | 1.0.0
9 |
10 | 4.0.0
11 |
12 | scs-infrastructure
13 |
14 |
15 | 8
16 | 8
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 | com.smart.classroom
25 | scs-domain
26 |
27 |
28 |
29 | com.smart.classroom
30 | scs-utility
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 | com.alibaba.nacos
42 | nacos-client
43 |
44 |
45 |
46 |
47 | org.apache.dubbo
48 | dubbo-spring-boot-starter
49 |
50 |
51 |
52 |
53 |
54 | org.apache.rocketmq
55 | rocketmq-client-java
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 | com.smart.classroom
66 | scm-facade
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
--------------------------------------------------------------------------------
/scs-repository/src/main/java/com/smart/classroom/subscription/repository/transaction/TransactionService.java:
--------------------------------------------------------------------------------
1 | package com.smart.classroom.subscription.repository.transaction;
2 |
3 | import org.springframework.beans.factory.annotation.Autowired;
4 | import org.springframework.jdbc.datasource.DataSourceTransactionManager;
5 | import org.springframework.lang.Nullable;
6 | import org.springframework.stereotype.Component;
7 | import org.springframework.transaction.TransactionDefinition;
8 | import org.springframework.transaction.TransactionException;
9 | import org.springframework.transaction.TransactionStatus;
10 | import org.springframework.transaction.support.DefaultTransactionDefinition;
11 | import org.springframework.transaction.support.TransactionCallback;
12 | import org.springframework.transaction.support.TransactionTemplate;
13 |
14 | /**
15 | * 事务,手动挡。
16 | *
17 | * @author lishuang
18 | * @date 2023-05-12
19 | */
20 | @Component
21 | public class TransactionService {
22 |
23 | @Autowired
24 | private DataSourceTransactionManager transactionManager;
25 |
26 | @Autowired
27 | private TransactionTemplate transactionTemplate;
28 |
29 | //*************************** 精细手动控制 开始 ***************************//
30 |
31 | //开启事务, 默认使用RR隔离级别,REQUIRED传播级别
32 | public TransactionStatus begin() {
33 | DefaultTransactionDefinition def = new DefaultTransactionDefinition();
34 | // 事物隔离级别,开启新事务
35 | def.setIsolationLevel(TransactionDefinition.ISOLATION_REPEATABLE_READ);
36 | // 事务传播行为
37 | def.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
38 | //将拿到的事务返回进去,才能提交。
39 | return transactionManager.getTransaction(def);
40 | }
41 |
42 | //提交事务
43 | public void commit(TransactionStatus transaction) {
44 | //提交事务
45 | transactionManager.commit(transaction);
46 | }
47 |
48 | //回滚事务
49 | public void rollback(TransactionStatus transaction) {
50 | transactionManager.rollback(transaction);
51 | }
52 |
53 | //*************************** 精细手动控制 结束 ***************************//
54 |
55 |
56 |
57 | //*************************** 粗粒度手动控制 开始 ***************************//
58 | //直接执行方法方法体。
59 | @Nullable
60 | public T execute(TransactionCallback action) throws TransactionException {
61 | return transactionTemplate.execute(action);
62 | }
63 | //*************************** 粗粒度手动控制 结束 ***************************//
64 |
65 | }
--------------------------------------------------------------------------------
/scs-utility/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 | smart-classroom-subscription
7 | com.smart.classroom
8 | 1.0.0
9 |
10 | 4.0.0
11 |
12 | scs-utility
13 |
14 |
15 | 8
16 | 8
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 | org.projectlombok
25 | lombok
26 |
27 |
28 |
29 |
30 | org.apache.commons
31 | commons-lang3
32 |
33 |
34 |
35 | commons-io
36 | commons-io
37 |
38 |
39 |
40 | commons-codec
41 | commons-codec
42 |
43 |
44 |
45 | commons-collections
46 | commons-collections
47 |
48 |
49 |
50 |
51 | com.google.guava
52 | guava
53 |
54 |
55 |
56 | org.slf4j
57 | slf4j-api
58 |
59 |
60 |
61 |
62 |
63 | org.apache.velocity
64 | velocity
65 |
66 |
67 |
68 |
69 | org.springframework.boot
70 | spring-boot-starter-json
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
--------------------------------------------------------------------------------
/scs-facade-impl/src/main/java/com/smart/classroom/subscription/facade/impl/biz/subscription/SubscriptionWriteFacadeImpl.java:
--------------------------------------------------------------------------------
1 | package com.smart.classroom.subscription.facade.impl.biz.subscription;
2 |
3 | import com.smart.classroom.subscription.application.biz.subscription.SubscriptionCommandAppService;
4 | import com.smart.classroom.subscription.domain.biz.order.info.PrepareSubscribeInfo;
5 | import com.smart.classroom.subscription.domain.biz.subscription.model.SubscriptionModel;
6 | import com.smart.classroom.subscription.facade.biz.order.response.OrderDTO;
7 | import com.smart.classroom.subscription.facade.biz.subscription.SubscriptionWriteFacade;
8 | import com.smart.classroom.subscription.facade.biz.subscription.request.PrepareSubscribeRequest;
9 | import com.smart.classroom.subscription.facade.biz.subscription.response.PrepareSubscribeDTO;
10 | import com.smart.classroom.subscription.facade.biz.subscription.response.SubscriptionDTO;
11 | import com.smart.classroom.subscription.facade.impl.biz.order.converter.OrderModel2DTOConverter;
12 | import com.smart.classroom.subscription.facade.impl.biz.subscription.converter.SubscriptionModel2DTOConverter;
13 | import org.apache.dubbo.config.annotation.DubboService;
14 |
15 | import javax.annotation.Resource;
16 |
17 | /**
18 | * @author lishuang
19 | * @date 2023-05-15
20 | */
21 | @DubboService
22 | public class SubscriptionWriteFacadeImpl implements SubscriptionWriteFacade {
23 |
24 | @Resource
25 | SubscriptionCommandAppService subscriptionCommandAppService;
26 |
27 | /**
28 | * 发起订阅请求
29 | */
30 | public PrepareSubscribeDTO prepareSubscribe(PrepareSubscribeRequest request) {
31 |
32 | PrepareSubscribeInfo prepareSubscribeInfo = subscriptionCommandAppService.prepareSubscribe(request.getReaderId(), request.getColumnId(), request.getPayMethod());
33 |
34 | OrderDTO orderDTO = OrderModel2DTOConverter.convert(prepareSubscribeInfo.getOrderModel());
35 |
36 | PrepareSubscribeDTO prepareSubscribeDTO = new PrepareSubscribeDTO(
37 | orderDTO,
38 | prepareSubscribeInfo.getThirdTransactionNo(),
39 | prepareSubscribeInfo.getNonceStr()
40 | );
41 |
42 | return prepareSubscribeDTO;
43 |
44 |
45 | }
46 |
47 |
48 | /**
49 | * 支付成功消息补偿。
50 | */
51 | @Override
52 | public SubscriptionDTO compensatePaymentPaid(long paymentId) {
53 |
54 | SubscriptionModel subscriptionModel = subscriptionCommandAppService.paymentPaid(paymentId);
55 |
56 | return SubscriptionModel2DTOConverter.convert(subscriptionModel);
57 | }
58 |
59 |
60 | }
61 |
--------------------------------------------------------------------------------
/scs-infrastructure/src/main/java/com/smart/classroom/subscription/infrastructure/rpc/payment/PaymentFacadeClientImpl.java:
--------------------------------------------------------------------------------
1 | package com.smart.classroom.subscription.infrastructure.rpc.payment;
2 |
3 | import com.smart.classroom.misc.facade.biz.payment.PaymentReadFacade;
4 | import com.smart.classroom.misc.facade.biz.payment.PaymentWriteFacade;
5 | import com.smart.classroom.misc.facade.biz.payment.request.PaymentCreateRequest;
6 | import com.smart.classroom.misc.facade.biz.payment.response.PaymentDTO;
7 | import com.smart.classroom.misc.facade.biz.payment.response.PreparePaymentDTO;
8 | import com.smart.classroom.subscription.domain.rpc.payment.PaymentFacadeClient;
9 | import com.smart.classroom.subscription.domain.rpc.payment.info.PaymentCreateInfo;
10 | import com.smart.classroom.subscription.domain.rpc.payment.info.PreparePaymentInfo;
11 | import com.smart.classroom.subscription.domain.rpc.payment.vo.PaymentVO;
12 | import com.smart.classroom.subscription.infrastructure.rpc.payment.converter.PaymentDTO2VOConverter;
13 | import com.smart.classroom.subscription.infrastructure.rpc.payment.converter.PreparePaymentDTO2InfoConverter;
14 | import org.apache.dubbo.config.annotation.DubboReference;
15 | import org.springframework.stereotype.Service;
16 |
17 | /**
18 | * @author lishuang
19 | * @date 2023-05-15
20 | */
21 | @Service
22 | public class PaymentFacadeClientImpl implements PaymentFacadeClient {
23 |
24 | @DubboReference
25 | PaymentReadFacade paymentReadFacade;
26 |
27 | @DubboReference
28 | PaymentWriteFacade paymentWriteFacade;
29 |
30 | @Override
31 | public PaymentVO queryById(long paymentId) {
32 |
33 | PaymentDTO paymentDTO = paymentReadFacade.queryById(paymentId);
34 |
35 | return PaymentDTO2VOConverter.convert(paymentDTO);
36 | }
37 |
38 | @Override
39 | public PreparePaymentInfo create(PaymentCreateInfo paymentCreateInfo) {
40 | PaymentCreateRequest paymentCreateRequest =
41 | PaymentCreateRequest.builder()
42 | .orderNo(paymentCreateInfo.getOrderNo())
43 | .amount(paymentCreateInfo.getAmount())
44 | .method(paymentCreateInfo.getMethod())
45 | .build();
46 | PreparePaymentDTO preparePaymentDTO = paymentWriteFacade.create(paymentCreateRequest);
47 |
48 | return PreparePaymentDTO2InfoConverter.convert(preparePaymentDTO);
49 | }
50 |
51 | @Override
52 | public PreparePaymentInfo prepare(long paymentId) {
53 | PreparePaymentDTO preparePaymentDTO = paymentReadFacade.prepare(paymentId);
54 |
55 | return PreparePaymentDTO2InfoConverter.convert(preparePaymentDTO);
56 | }
57 | }
58 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # smart-classroom-subscription
2 |
3 | 本项目对应文章[《领域驱动设计DDD|从入门到代码实践》](https://mp.weixin.qq.com/s/HMLpjcE0UENUTfMK0Z9n8A)
4 |
5 | ## 首次启动
6 |
7 | ### 安装并启动Nacos
8 | 项目使用Nacos作为注册中心,安装和启动方法见 [这里](./docs/start/nacos.md)
9 | ```shell
10 | sh startup.sh -m standalone
11 | ```
12 |
13 | ### 安装并启动RocketMQ
14 | 项目的消息队列使用RocketMQ,安装和启动方法见 [这里](./docs/start/rocketmq.md)
15 | ```shell
16 | nohup sh bin/mqnamesrv &
17 | nohup sh bin/mqbroker -n localhost:9876 --enable-proxy &
18 | ```
19 |
20 | 首次启动的时候需要创建一个Topic.
21 | ```shell
22 | sh bin/mqadmin updatetopic -n localhost:9876 -t SmartClassroomTopic -c DefaultCluster
23 | ```
24 |
25 | ### 导入数据库
26 | 数据库文件位于 docs/db 完全导入到自己的数据库中。
27 |
28 | 修改配置文件中的jdbc配置
29 | src/main/resources/application-repository.properties
30 | ```properties
31 | spring.datasource.primary.jdbc-url=
32 | spring.datasource.primary.username=
33 | spring.datasource.primary.password=
34 | ```
35 |
36 | 如果需要做二次开发,也需要修改saber工具中的jdbc配置:
37 | src/main/java/com/smart/classroom/misc/tool/saber/config/SaberConfig.java
38 |
39 | ### 打包facade.
40 | 因为smart-classroom-misc和smart-classroom-subscription两个项目的facade包相互依赖,而我们又没有将其上传至中央仓库。
41 |
42 | 因此在启动前,需要先到这两个项目下各自打包facade,安装到本地仓库中。
43 |
44 | ```shell
45 | cd smart-classroom-misc
46 | ./mvnw install -pl scm-facade -DskipTests
47 |
48 | cd smart-classroom-subscription
49 | ./mvnw install -pl scs-facade -DskipTests
50 | ```
51 |
52 |
53 | ### 启动应用.
54 | 分别运行两个项目的main文件即可:
55 | ```shell
56 | cd smart-classroom-misc
57 | src/main/java/com/smart/classroom/misc/MiscApplication.java
58 |
59 | cd smart-classroom-subscription
60 | src/main/java/com/smart/classroom/subscription/SubscriptionApplication.java
61 | ```
62 |
63 |
64 | ### 验证
65 | ```shell
66 | # 健康检查接口有内容返回表示成功
67 | curl http://localhost:6500/api/index/healthy
68 | ```
69 | ```text
70 | {"code":"OK","data":"服务健康, 现在时间:2023-05-22 16:36:00 远程调用结果:Hello,你好. 我是smart-classroom-subscription,状态正常 现在时间:2023-05-22 16:36:00","msg":"成功"}
71 | ```
72 |
73 | 如果你也将前端项目 smart-classroom-front 启动了,那么就能够看到对应的页面了。
74 |
75 | ## 日常启动
76 |
77 | ### 启动Nacos
78 | 项目使用Nacos作为注册中心,安装和启动方法见 [这里](./docs/start/nacos.md)
79 | ```shell
80 | sh startup.sh -m standalone
81 | ```
82 |
83 | ### 启动RocketMQ
84 | 项目的消息队列使用RocketMQ,安装和启动方法见 [这里](./docs/start/rocketmq.md)
85 | ```shell
86 | nohup sh bin/mqnamesrv &
87 | nohup sh bin/mqbroker -n localhost:9876 --enable-proxy &
88 | ```
89 |
90 | ### 启动应用.
91 | 分别运行两个项目的main文件即可:
92 | ```shell
93 | cd smart-classroom-misc
94 | src/main/java/com/smart/classroom/misc/MiscApplication.java
95 |
96 | cd smart-classroom-subscription
97 | src/main/java/com/smart/classroom/subscription/SubscriptionApplication.java
98 | ```
99 |
100 | 如果你也将前端项目 smart-classroom-front 启动了,那么就能够看到对应的页面了。
101 |
--------------------------------------------------------------------------------
/scs-testsuit/src/main/java/com/smart/classroom/subscription/tool/saber/artwork/MapperJavaArtwork.java:
--------------------------------------------------------------------------------
1 | package com.smart.classroom.subscription.tool.saber.artwork;
2 |
3 | import com.smart.classroom.subscription.tool.saber.artwork.base.Artwork;
4 | import com.smart.classroom.subscription.tool.saber.command.SaberCommand;
5 | import com.smart.classroom.subscription.tool.saber.config.SaberConfig;
6 | import com.smart.classroom.subscription.tool.saber.meta.SaberTable;
7 | import com.smart.classroom.subscription.utility.util.PathUtil;
8 | import com.smart.classroom.subscription.utility.util.StringUtil;
9 | import lombok.Data;
10 | import lombok.EqualsAndHashCode;
11 | import lombok.NonNull;
12 | import org.apache.ibatis.annotations.Mapper;
13 | import org.springframework.stereotype.Repository;
14 |
15 | import java.util.ArrayList;
16 | import java.util.List;
17 |
18 | /**
19 | * XXMapper.java
20 | * 负责生产模型Mapper的
21 | */
22 | @EqualsAndHashCode(callSuper = true)
23 | @Data
24 | public class MapperJavaArtwork extends Artwork {
25 | /**
26 | * 表的主体名称,例如 scm_application_member 主体为application,主体会作为一层包名。
27 | * 默认:scm_后的第一个单词
28 | */
29 | private String bodyName;
30 |
31 | //表注释。
32 | private String tableRemark;
33 |
34 | //包名路径
35 | private String mapperPackage;
36 |
37 | //类名大写。
38 | private String entityUpperBodyName;
39 |
40 | /**
41 | * Mapper类名
42 | * 默认会使用表名的首字母大写驼峰写法+Mapper
43 | */
44 | private String mapperUpperClassName;
45 |
46 |
47 |
48 | //依赖的包。
49 | private List mapperImportNones;
50 |
51 | //依赖的包。
52 | private List mapperImportJavas;
53 |
54 |
55 | public MapperJavaArtwork() {
56 | super("TemplateMapperJava.vm", false);
57 | }
58 |
59 | @Override
60 | public String destAbsolutePath() {
61 |
62 | String directoryPath = PathUtil.getAppHomePath() + "/"+ SaberConfig.REPOSITORY_MODULE_NAME +"/src/main/java/" + this.mapperPackage.replaceAll("\\.", "/");
63 |
64 | //获取到所在文件夹的路径,如果没有自动创建。
65 | directoryPath = PathUtil.getSafeDirectoryPath(directoryPath);
66 |
67 | return directoryPath + "/" + this.entityUpperBodyName + "Mapper.java";
68 | }
69 |
70 | @Override
71 | public void init(@NonNull SaberTable saberTable, @NonNull SaberCommand saberCommand) {
72 | this.bodyName = saberCommand.getDirectFolderName();
73 | this.tableRemark = saberTable.getRemark();
74 | this.mapperPackage = SaberConfig.BASE_PACKAGE_NAME+".repository.mapper." + this.bodyName;
75 | this.entityUpperBodyName = saberCommand.getEntityUpperBodyName();
76 |
77 | //处理Mapper类需要引入的包
78 | this.mapperImportNones = new ArrayList<>();
79 | this.mapperImportNones.add(Mapper.class.getName());
80 | this.mapperImportNones.add(Repository.class.getName());
81 |
82 | this.mapperImportJavas = new ArrayList() {{
83 |
84 | }};
85 |
86 |
87 |
88 | //进行排序
89 | this.mapperImportJavas.sort(StringUtil::compare);
90 | this.mapperImportNones.sort(StringUtil::compare);
91 |
92 | }
93 | }
94 |
--------------------------------------------------------------------------------
/scs-repository/src/main/java/com/smart/classroom/subscription/repository/impl/subscription/SubscriptionRepositoryImpl.java:
--------------------------------------------------------------------------------
1 | package com.smart.classroom.subscription.repository.impl.subscription;
2 |
3 |
4 | import com.github.pagehelper.Page;
5 | import com.smart.classroom.subscription.domain.biz.subscription.model.SubscriptionModel;
6 | import com.smart.classroom.subscription.domain.biz.subscription.repository.SubscriptionRepository;
7 | import com.smart.classroom.subscription.domain.biz.subscription.repository.query.SubscriptionPageQuery;
8 | import com.smart.classroom.subscription.domain.rpc.column.vo.ColumnVO;
9 | import com.smart.classroom.subscription.domain.rpc.reader.vo.ReaderVO;
10 | import com.smart.classroom.subscription.repository.impl.subscription.converter.SubscriptionDO2ModelConverter;
11 | import com.smart.classroom.subscription.repository.impl.subscription.converter.SubscriptionModel2DOConverter;
12 | import com.smart.classroom.subscription.repository.mapper.subscription.SubscriptionMapper;
13 | import com.smart.classroom.subscription.repository.orm.subscription.SubscriptionDO;
14 | import com.smart.classroom.subscription.utility.result.Pager;
15 | import org.springframework.beans.factory.annotation.Autowired;
16 | import org.springframework.stereotype.Service;
17 |
18 | import java.util.List;
19 | import java.util.stream.Collectors;
20 |
21 | /**
22 | * @author lishuang
23 | * @date 2023-05-12
24 | */
25 | @Service
26 | public class SubscriptionRepositoryImpl implements SubscriptionRepository {
27 |
28 |
29 | @Autowired
30 | SubscriptionMapper subscriptionMapper;
31 |
32 |
33 | @Override
34 | public SubscriptionModel insert(SubscriptionModel subscriptionModel) {
35 |
36 | SubscriptionDO subscriptionDO = SubscriptionModel2DOConverter.convert(subscriptionModel);
37 |
38 | subscriptionMapper.insert(subscriptionDO);
39 |
40 | //查询一次。
41 | subscriptionDO = subscriptionMapper.queryById(subscriptionDO.getId());
42 |
43 | return SubscriptionDO2ModelConverter.convert(subscriptionDO);
44 | }
45 |
46 | @Override
47 | public SubscriptionModel queryByReaderAndColumn(ReaderVO readerVO, ColumnVO columnVO) {
48 |
49 | SubscriptionDO subscriptionDO = subscriptionMapper.queryByReaderIdAndColumnId(readerVO.getId(), columnVO.getId());
50 |
51 | return SubscriptionDO2ModelConverter.convert(subscriptionDO);
52 | }
53 |
54 | @Override
55 | public Pager page(SubscriptionPageQuery subscriptionPageQuery) {
56 | Page page = subscriptionMapper.page(
57 | subscriptionPageQuery.getPageNum(),
58 | subscriptionPageQuery.getPageSize(),
59 | subscriptionPageQuery.getOrderCreateTime(),
60 | subscriptionPageQuery.getOrderUpdateTime(),
61 | subscriptionPageQuery.getReaderId(),
62 | subscriptionPageQuery.getColumnId(),
63 | subscriptionPageQuery.getOrderId(),
64 | subscriptionPageQuery.getStatus()
65 | );
66 |
67 | List subscriptionModelList = page.stream().map(SubscriptionDO2ModelConverter::convert).collect(Collectors.toList());
68 |
69 | return new Pager<>(page.getPageNum(), page.getPageSize(), page.getTotal(), subscriptionModelList);
70 | }
71 | }
72 |
--------------------------------------------------------------------------------
/scs-testsuit/src/main/java/com/smart/classroom/subscription/tool/saber/artwork/MapperXmlArtwork.java:
--------------------------------------------------------------------------------
1 | package com.smart.classroom.subscription.tool.saber.artwork;
2 |
3 | import com.smart.classroom.subscription.tool.saber.artwork.base.Artwork;
4 | import com.smart.classroom.subscription.tool.saber.command.SaberCommand;
5 | import com.smart.classroom.subscription.tool.saber.config.SaberConfig;
6 | import com.smart.classroom.subscription.tool.saber.meta.SaberTable;
7 | import com.smart.classroom.subscription.utility.util.PathUtil;
8 | import lombok.Data;
9 | import lombok.EqualsAndHashCode;
10 | import lombok.NonNull;
11 |
12 | /**
13 | * XXMapper.xml
14 | * 负责生产模型Mapper的
15 | */
16 | @EqualsAndHashCode(callSuper = true)
17 | @Data
18 | public class MapperXmlArtwork extends Artwork {
19 | /**
20 | * 表的主体名称,例如 scm_application_member 主体为application,主体会作为一层包名。
21 | * 默认:scm_后的第一个单词
22 | */
23 | private String bodyName;
24 |
25 |
26 | /**
27 | * 数据库表名
28 | */
29 | private String tableName;
30 |
31 |
32 | //表注释。
33 | private String tableRemark;
34 |
35 | //包名路径
36 | private String mapperPackage;
37 |
38 | //类名大写。
39 | private String entityUpperBodyName;
40 |
41 | /**
42 | * 类所在的包
43 | * 默认 SaberConfig.BASE_PACKAGE_NAME
44 | */
45 | private String entityPackage;
46 |
47 | /**
48 | * 实体全名
49 | * 包名+类名
50 | */
51 | private String entityFullName;
52 |
53 | /**
54 | * baseMapper全名
55 | */
56 | private String baseMapperClassFullName;
57 |
58 |
59 | /**
60 | * Mapper类名
61 | * 默认会使用表名的首字母大写驼峰写法+Mapper
62 | */
63 | private String mapperUpperClassName;
64 | /**
65 | * 实体全名
66 | * 包名+类名
67 | */
68 | private String mapperFullName;
69 |
70 |
71 | public MapperXmlArtwork() {
72 | super("TemplateMapperXml.vm", false);
73 | }
74 |
75 | @Override
76 | public String destAbsolutePath() {
77 |
78 | String directoryPath = PathUtil.getAppHomePath() + "/"+ SaberConfig.REPOSITORY_MODULE_NAME +"/src/main/resources/mybatis/mapper/" + this.bodyName;
79 |
80 | //获取到所在文件夹的路径,如果没有自动创建。
81 | directoryPath = PathUtil.getSafeDirectoryPath(directoryPath);
82 |
83 | return directoryPath + "/" + this.entityUpperBodyName + "Mapper.xml";
84 | }
85 |
86 | @Override
87 | public void init(@NonNull SaberTable saberTable, @NonNull SaberCommand saberCommand) {
88 | this.bodyName = saberCommand.getDirectFolderName();
89 | this.tableName = saberCommand.getTableName();
90 | this.tableRemark = saberTable.getRemark();
91 | this.mapperPackage = SaberConfig.BASE_PACKAGE_NAME+".repository.mapper." + this.bodyName;
92 | this.entityPackage = SaberConfig.BASE_PACKAGE_NAME + ".repository.orm."+ this.bodyName;
93 | this.entityUpperBodyName = saberCommand.getEntityUpperBodyName();
94 | this.entityFullName = this.entityPackage + "." + this.entityUpperBodyName+"DO";
95 | this.baseMapperClassFullName = this.mapperPackage + "." + this.entityUpperBodyName+"BaseMapper";
96 |
97 | this.mapperUpperClassName = this.entityUpperBodyName + "Mapper";
98 | this.mapperFullName = this.mapperPackage + "." + this.mapperUpperClassName;
99 |
100 | }
101 | }
102 |
--------------------------------------------------------------------------------
/scs-utility/src/main/java/com/smart/classroom/subscription/utility/util/PathUtil.java:
--------------------------------------------------------------------------------
1 | package com.smart.classroom.subscription.utility.util;
2 |
3 |
4 | import com.smart.classroom.subscription.utility.exception.UtilException;
5 | import lombok.SneakyThrows;
6 | import lombok.extern.slf4j.Slf4j;
7 | import org.apache.commons.io.IOUtils;
8 |
9 | import java.io.InputStream;
10 | import java.net.URL;
11 | import java.nio.charset.StandardCharsets;
12 | import java.nio.file.Files;
13 | import java.nio.file.Path;
14 | import java.nio.file.Paths;
15 |
16 | /**
17 | * 路径通用类
18 | */
19 | @Slf4j
20 | public class PathUtil {
21 |
22 | /**
23 | * 获取应用的home目录。
24 | * 例如:/d/smart-classroom-misc
25 | */
26 | public static String getAppHomePath() {
27 | return Paths.get("").toAbsolutePath().toString();
28 |
29 | }
30 |
31 |
32 | /**
33 | * 获取当前模块名,需要传入一个resources下面的文件作为指南针文件
34 | * 例如:传入 doc.md
35 | * 获取到:/d/smart-classroom-misc/scm-utility
36 | */
37 | public static String getModuleHomePath(String compassFile) {
38 |
39 |
40 | URL url = PathUtil.class.getClassLoader().getResource(compassFile);
41 |
42 | if (url == null) {
43 | throw new UtilException("No " + compassFile + ", please fix it!");
44 | }
45 |
46 |
47 | String inputFilePath = url.getPath();
48 |
49 | //windows环境和其他环境路径有差异
50 | String osName = System.getProperties().getProperty("os.name");
51 | if (osName.toLowerCase().startsWith("win")) {
52 | //win环境下去掉file:/
53 | inputFilePath = inputFilePath.substring(inputFilePath.indexOf("/") + 1);
54 | }
55 |
56 | //如果是jar包,那么要求Jar包旁边有个jar直接解压的文件夹。
57 | int index = inputFilePath.indexOf(".jar!");
58 | if (index == -1) {
59 | index = inputFilePath.indexOf("/target/classes");
60 | if (index == -1) {
61 | index = inputFilePath.indexOf("/target/test-classes");
62 |
63 | }
64 | }
65 |
66 | return inputFilePath.substring(0, index);
67 |
68 |
69 | }
70 |
71 | /**
72 | * 获取一个安全的文件夹路径
73 | * 如果中间某个文件夹不存在,那么就创建文件夹
74 | */
75 | @SneakyThrows
76 | public static String getSafeDirectoryPath(String directoryPath) {
77 |
78 | Path path = Paths.get(directoryPath);
79 |
80 | if (!Files.exists(path)) {
81 |
82 | Files.createDirectories(path);
83 | }
84 |
85 | return directoryPath;
86 |
87 | }
88 |
89 |
90 | /**
91 | * 判断一个文件是否存在
92 | */
93 | public static boolean isExist(String filePath) {
94 |
95 | Path path = Paths.get(filePath);
96 |
97 | return Files.exists(path);
98 |
99 | }
100 |
101 | /**
102 | * 获取resources下面的某个文件内容
103 | *
104 | * @param resourceRelativeName 资源相对路径,相对于resources文件夹,eg: scm-utility/script/XX.java
105 | * @return 返回资源文件的内容,如果没有找到或者出错,那么就返回 null
106 | */
107 | public static String getResourceContent(String resourceRelativeName) {
108 |
109 | ClassLoader classLoader = PathUtil.class.getClassLoader();
110 | InputStream inputStream = classLoader.getResourceAsStream(resourceRelativeName);
111 |
112 | if (inputStream == null) {
113 | log.error("{} 对应的文件内容为空", resourceRelativeName);
114 | return null;
115 | }
116 |
117 | //Read File Content
118 | try {
119 | return IOUtils.toString(inputStream, StandardCharsets.UTF_8);
120 | } catch (Throwable throwable) {
121 | log.error("对应的文件内容为空" + resourceRelativeName, throwable);
122 | return null;
123 | }
124 | }
125 |
126 |
127 | }
128 |
--------------------------------------------------------------------------------
/scs-testsuit/src/main/java/com/smart/classroom/subscription/tool/saber/meta/SaberTable.java:
--------------------------------------------------------------------------------
1 | package com.smart.classroom.subscription.tool.saber.meta;
2 |
3 |
4 | import com.smart.classroom.subscription.tool.saber.command.SaberCommand;
5 | import com.smart.classroom.subscription.tool.saber.contrast.TypeContrast;
6 | import com.smart.classroom.subscription.utility.exception.UtilException;
7 | import com.smart.classroom.subscription.utility.model.Pair;
8 | import lombok.AllArgsConstructor;
9 | import lombok.Data;
10 | import lombok.NoArgsConstructor;
11 | import lombok.NonNull;
12 | import lombok.extern.slf4j.Slf4j;
13 |
14 | import java.util.ArrayList;
15 | import java.util.Iterator;
16 | import java.util.List;
17 | import java.util.Map;
18 |
19 | /**
20 | * 数据库表,元信息
21 | *
22 | * @author lishuang 2023-05-11
23 | */
24 | @Data
25 | @AllArgsConstructor
26 | @NoArgsConstructor
27 | @Slf4j
28 | public class SaberTable {
29 |
30 | private String name;
31 | private String remark;
32 |
33 | private List columns = new ArrayList<>();
34 |
35 |
36 | //根据给定的数据库字段,获取到对应的SaberColumn.
37 | public List fetchSaberColumns(@NonNull List fields) {
38 |
39 | List columnList = new ArrayList<>();
40 |
41 | fields.forEach(field -> {
42 |
43 | SaberColumn targetColumn = null;
44 | for (SaberColumn column : columns) {
45 | //用户输入create_time 或者 createTime 都可以
46 | if (column.sameField(field)) {
47 |
48 | targetColumn = column;
49 |
50 | }
51 | }
52 |
53 | if (targetColumn == null) {
54 | throw new UtilException("{} 中不存在字段 {}", name, field);
55 |
56 | } else {
57 |
58 | columnList.add(targetColumn);
59 | }
60 |
61 | });
62 |
63 | return columnList;
64 |
65 | }
66 |
67 |
68 | //根据saberCommand中的自定义设置,来调整一下saberTable中的内容
69 | public void prepare(SaberCommand saberCommand) {
70 |
71 |
72 | for (Map.Entry entry : saberCommand.getCustomFieldTypes().entrySet()) {
73 |
74 | //调整自定义的字段
75 | for (SaberColumn column : this.columns) {
76 |
77 | //用户输入create_time 或者 createTime 都可以
78 | if (column.sameField(entry.getKey())) {
79 |
80 | column.updateTypeContrast(entry.getValue(), column.getDefaultValue());
81 |
82 | }
83 |
84 |
85 | }
86 |
87 |
88 | }
89 |
90 |
91 | //一些枚举字段,我们希望直接使用枚举。。
92 | for (Map.Entry>, String>> entry : saberCommand.getEnumFieldMap().entrySet()) {
93 |
94 | //调整自定义的字段
95 | for (SaberColumn column : this.columns) {
96 |
97 | //用户输入gmt_create 或者 gmtCreate 都可以
98 | if (column.sameField(entry.getKey())) {
99 |
100 | column.updateEnumField(entry.getValue().getKey(), entry.getValue().getValue());
101 |
102 | }
103 |
104 |
105 | }
106 |
107 |
108 | }
109 |
110 |
111 | //有个别废弃掉的字段不予考虑。(小心删除陷阱,必须使用迭代器删除)
112 | Iterator it = columns.iterator();
113 | while (it.hasNext()) {
114 | SaberColumn column = it.next();
115 | //调整自定义的字段
116 | for (String ignoreField : saberCommand.getIgnoreFields()) {
117 |
118 | //用户输入create_time 或者 createTime 都可以
119 | if (column.sameField(ignoreField)) {
120 | it.remove();
121 | break;
122 | }
123 |
124 |
125 | }
126 |
127 | }
128 |
129 |
130 | }
131 |
132 |
133 | }
134 |
--------------------------------------------------------------------------------
/scs-domain/src/main/java/com/smart/classroom/subscription/domain/biz/subscription/service/SubscriptionCreateDomainService.java:
--------------------------------------------------------------------------------
1 | package com.smart.classroom.subscription.domain.biz.subscription.service;
2 |
3 | import com.smart.classroom.subscription.domain.biz.order.enums.OrderStatus;
4 | import com.smart.classroom.subscription.domain.biz.order.model.OrderModel;
5 | import com.smart.classroom.subscription.domain.biz.order.repository.OrderRepository;
6 | import com.smart.classroom.subscription.domain.biz.subscription.enums.SubscriptionStatus;
7 | import com.smart.classroom.subscription.domain.biz.subscription.event.SubscriptionDomainEvent;
8 | import com.smart.classroom.subscription.domain.biz.subscription.info.SubscriptionEventPayload;
9 | import com.smart.classroom.subscription.domain.biz.subscription.model.SubscriptionModel;
10 | import com.smart.classroom.subscription.domain.biz.subscription.repository.SubscriptionRepository;
11 | import com.smart.classroom.subscription.domain.middleware.mq.MqProducer;
12 | import com.smart.classroom.subscription.domain.middleware.mq.info.MqSendResultInfo;
13 | import com.smart.classroom.subscription.domain.rpc.column.ColumnFacadeClient;
14 | import com.smart.classroom.subscription.domain.rpc.column.vo.ColumnVO;
15 | import com.smart.classroom.subscription.domain.rpc.payment.vo.PaymentVO;
16 | import com.smart.classroom.subscription.domain.rpc.reader.ReaderFacadeClient;
17 | import com.smart.classroom.subscription.domain.rpc.reader.vo.ReaderVO;
18 | import com.smart.classroom.subscription.utility.exception.UtilException;
19 | import com.smart.classroom.subscription.utility.util.JsonUtil;
20 | import com.smart.classroom.subscription.utility.util.StringUtil;
21 | import lombok.extern.slf4j.Slf4j;
22 | import org.springframework.beans.factory.annotation.Autowired;
23 | import org.springframework.stereotype.Service;
24 |
25 | import java.util.Date;
26 |
27 | /**
28 | * 创建专栏领域服务
29 | *
30 | * @author lishuang
31 | * @date 2023-05-12
32 | */
33 | @Slf4j
34 | @Service
35 | public class SubscriptionCreateDomainService {
36 |
37 | @Autowired
38 | OrderRepository orderRepository;
39 |
40 | @Autowired
41 | ReaderFacadeClient readerFacadeClient;
42 |
43 | @Autowired
44 | ColumnFacadeClient columnFacadeClient;
45 |
46 | @Autowired
47 | SubscriptionRepository subscriptionRepository;
48 |
49 | @Autowired
50 | MqProducer mqProducer;
51 |
52 |
53 | /**
54 | * 创建专栏
55 | */
56 | public SubscriptionModel create(OrderModel orderModel) {
57 |
58 | //创建一个新的订阅关系。
59 | SubscriptionModel subscriptionModel = new SubscriptionModel(
60 | null,
61 | new Date(),
62 | new Date(),
63 | orderModel.getReaderId(),
64 | orderModel.getColumnId(),
65 | orderModel.getId(),
66 | SubscriptionStatus.CREATED
67 | );
68 |
69 | //持久化 数据库做了唯一联合索引。
70 | subscriptionModel = subscriptionRepository.insert(subscriptionModel);
71 |
72 | log.info("专栏订阅成功,readerId={} columnId={}", subscriptionModel.getReaderId(), subscriptionModel.getColumnId());
73 |
74 | //发送专栏创建成功的领域事件。
75 | String uuid = StringUtil.uuid();
76 | SubscriptionEventPayload subscriptionEventPayload = new SubscriptionEventPayload(
77 | subscriptionModel.getReaderId(),
78 | subscriptionModel.getColumnId(),
79 | subscriptionModel.getOrderId(),
80 | subscriptionModel.getStatus().name(),
81 | subscriptionModel.getCreateTime()
82 | );
83 | String content = JsonUtil.toJson(subscriptionEventPayload);
84 | MqSendResultInfo mqSendResultInfo = mqProducer.send(SubscriptionDomainEvent.SUBSCRIPTION_DOMAIN_EVENT_CREATED.name(), uuid, content);
85 | if (mqSendResultInfo.isSuccess()) {
86 | log.info("领域事件{}发布成功", SubscriptionDomainEvent.SUBSCRIPTION_DOMAIN_EVENT_CREATED);
87 | } else {
88 | log.error("领域事件{}发布失败", SubscriptionDomainEvent.SUBSCRIPTION_DOMAIN_EVENT_CREATED);
89 | }
90 |
91 | return subscriptionModel;
92 | }
93 |
94 | }
95 |
--------------------------------------------------------------------------------
/scs-domain/src/main/java/com/smart/classroom/subscription/domain/biz/order/service/OrderPrepareDomainService.java:
--------------------------------------------------------------------------------
1 | package com.smart.classroom.subscription.domain.biz.order.service;
2 |
3 | import com.smart.classroom.subscription.domain.biz.order.enums.OrderStatus;
4 | import com.smart.classroom.subscription.domain.biz.order.info.PrepareSubscribeInfo;
5 | import com.smart.classroom.subscription.domain.biz.order.model.OrderModel;
6 | import com.smart.classroom.subscription.domain.biz.order.repository.OrderRepository;
7 | import com.smart.classroom.subscription.domain.rpc.column.vo.ColumnVO;
8 | import com.smart.classroom.subscription.domain.rpc.payment.PaymentFacadeClient;
9 | import com.smart.classroom.subscription.domain.rpc.payment.info.PaymentCreateInfo;
10 | import com.smart.classroom.subscription.domain.rpc.payment.info.PreparePaymentInfo;
11 | import com.smart.classroom.subscription.domain.rpc.payment.vo.PaymentVO;
12 | import com.smart.classroom.subscription.domain.rpc.quote.ColumnQuoteFacadeClient;
13 | import com.smart.classroom.subscription.domain.rpc.quote.vo.ColumnQuoteVO;
14 | import com.smart.classroom.subscription.domain.rpc.reader.vo.ReaderVO;
15 | import com.smart.classroom.subscription.utility.exception.UtilException;
16 | import com.smart.classroom.subscription.utility.util.NumberUtil;
17 | import org.springframework.beans.factory.annotation.Autowired;
18 | import org.springframework.stereotype.Service;
19 |
20 | import java.util.Date;
21 |
22 | /**
23 | * 准备订单 领域服务
24 | *
25 | * @author lishuang
26 | * @date 2023-05-12
27 | */
28 | @Service
29 | public class OrderPrepareDomainService {
30 |
31 |
32 | @Autowired
33 | OrderRepository orderRepository;
34 |
35 | @Autowired
36 | ColumnQuoteFacadeClient columnQuoteFacadeClient;
37 |
38 | @Autowired
39 | PaymentFacadeClient paymentFacadeClient;
40 |
41 |
42 | /**
43 | * 订单编号生成规则
44 | */
45 | private String generateOrderNo() {
46 | //订单编号简单使用时间戳
47 | return "SCO" + System.currentTimeMillis() + NumberUtil.random(1000, 10000);
48 | }
49 |
50 | /**
51 | * 创建专栏
52 | */
53 | public PrepareSubscribeInfo createAndPrepare(ColumnVO columnVO, ReaderVO readerVO, String payMethod) {
54 |
55 | PreparePaymentInfo preparePaymentInfo = null;
56 | //2. 查找当前订单是否已经存在了。
57 | OrderModel orderModel = orderRepository.queryNonFinalState(readerVO, columnVO);
58 | if (orderModel != null) {
59 |
60 | //根据订单,获取支付的信息。
61 | preparePaymentInfo = paymentFacadeClient.prepare(orderModel.getPaymentId());
62 |
63 | } else {
64 |
65 | //获取专栏报价。
66 | ColumnQuoteVO columnQuoteVO = columnQuoteFacadeClient.queryByColumnId(columnVO.getId());
67 | if (columnQuoteVO == null) {
68 | throw new UtilException("专栏{}(id={})尚无报价,无法订阅", columnVO.getName(), columnVO.getId());
69 | }
70 |
71 | String orderNo = this.generateOrderNo();
72 | Long price = columnQuoteVO.getPrice();
73 |
74 | PaymentCreateInfo paymentCreateInfo = new PaymentCreateInfo(
75 | orderNo,
76 | payMethod,
77 | price
78 | );
79 |
80 | //创建对应的支付单。
81 | preparePaymentInfo = paymentFacadeClient.create(paymentCreateInfo);
82 |
83 | PaymentVO paymentVO = preparePaymentInfo.getPaymentVO();
84 |
85 | //创建订单。
86 | orderModel = new OrderModel(
87 | null,
88 | new Date(),
89 | new Date(),
90 | orderNo,
91 | readerVO.getId(),
92 | columnVO.getId(),
93 | columnQuoteVO.getId(),
94 | paymentVO.getId(),
95 | price,
96 | OrderStatus.CREATED
97 | );
98 |
99 | //持久化订单。
100 | orderRepository.insert(orderModel);
101 | }
102 |
103 | return new PrepareSubscribeInfo(
104 | orderModel,
105 | preparePaymentInfo.getThirdTransactionNo(),
106 | preparePaymentInfo.getNonceStr()
107 | );
108 |
109 | }
110 |
111 | }
112 |
--------------------------------------------------------------------------------
/scs-repository/src/main/java/com/smart/classroom/subscription/repository/impl/order/OrderRepositoryImpl.java:
--------------------------------------------------------------------------------
1 | package com.smart.classroom.subscription.repository.impl.order;
2 |
3 |
4 | import com.github.pagehelper.Page;
5 | import com.smart.classroom.subscription.domain.biz.order.enums.OrderStatus;
6 | import com.smart.classroom.subscription.domain.biz.order.model.OrderModel;
7 | import com.smart.classroom.subscription.domain.biz.order.repository.OrderRepository;
8 | import com.smart.classroom.subscription.domain.biz.order.repository.query.OrderPageQuery;
9 | import com.smart.classroom.subscription.domain.rpc.column.vo.ColumnVO;
10 | import com.smart.classroom.subscription.domain.rpc.reader.vo.ReaderVO;
11 | import com.smart.classroom.subscription.repository.impl.order.converter.OrderDO2ModelConverter;
12 | import com.smart.classroom.subscription.repository.impl.order.converter.OrderModel2DOConverter;
13 | import com.smart.classroom.subscription.repository.mapper.order.OrderMapper;
14 | import com.smart.classroom.subscription.repository.orm.order.OrderDO;
15 | import com.smart.classroom.subscription.utility.result.Pager;
16 | import org.apache.commons.collections.CollectionUtils;
17 | import org.springframework.beans.factory.annotation.Autowired;
18 | import org.springframework.stereotype.Service;
19 |
20 | import java.util.Collections;
21 | import java.util.List;
22 | import java.util.stream.Collectors;
23 |
24 | /**
25 | * @author lishuang
26 | * @date 2023-05-12
27 | */
28 | @Service
29 | public class OrderRepositoryImpl implements OrderRepository {
30 |
31 |
32 | @Autowired
33 | OrderMapper orderMapper;
34 |
35 |
36 | @Override
37 | public OrderModel insert(OrderModel orderModel) {
38 |
39 | OrderDO orderDO = OrderModel2DOConverter.convert(orderModel);
40 |
41 | orderMapper.insert(orderDO);
42 |
43 | //查询一次。
44 | orderDO = orderMapper.queryById(orderDO.getId());
45 |
46 | return OrderDO2ModelConverter.convert(orderDO);
47 | }
48 |
49 | @Override
50 | public OrderModel updatePaymentId(OrderModel orderModel) {
51 |
52 |
53 |
54 |
55 | return null;
56 | }
57 |
58 | @Override
59 | public OrderModel queryNonFinalState(ReaderVO readerVO, ColumnVO columnVO) {
60 |
61 | List list = Collections.singletonList(OrderStatus.CREATED);
62 | List orderDOList = orderMapper.queryByReaderIdAndColumnIdAndStatuses(readerVO.getId(), columnVO.getId(), list);
63 | if (CollectionUtils.isEmpty(orderDOList)) {
64 | return null;
65 | } else {
66 | return OrderDO2ModelConverter.convert(orderDOList.get(0));
67 | }
68 | }
69 |
70 | @Override
71 | public OrderModel updateStatus(OrderModel orderModel) {
72 |
73 | orderMapper.updateStatus(orderModel.getId(),orderModel.getStatus());
74 | OrderDO orderDO = orderMapper.queryById(orderModel.getId());
75 |
76 | return OrderDO2ModelConverter.convert(orderDO);
77 | }
78 |
79 | @Override
80 | public OrderModel queryById(long orderId) {
81 | OrderDO orderDO = orderMapper.queryById(orderId);
82 |
83 | return OrderDO2ModelConverter.convert(orderDO);
84 | }
85 |
86 | @Override
87 | public OrderModel queryByNo(String orderNo) {
88 |
89 | OrderDO orderDO = orderMapper.queryByNo(orderNo);
90 |
91 | return OrderDO2ModelConverter.convert(orderDO);
92 | }
93 |
94 | @Override
95 | public Pager page(OrderPageQuery orderPageQuery) {
96 | Page page = orderMapper.page(
97 | orderPageQuery.getPageNum(),
98 | orderPageQuery.getPageSize(),
99 | orderPageQuery.getOrderCreateTime(),
100 | orderPageQuery.getOrderUpdateTime(),
101 | orderPageQuery.getReaderId(),
102 | orderPageQuery.getColumnId(),
103 | orderPageQuery.getColumnQuoteId(),
104 | orderPageQuery.getPaymentId(),
105 | orderPageQuery.getStatus()
106 | );
107 |
108 | List orderModelList = page.stream().map(OrderDO2ModelConverter::convert).collect(Collectors.toList());
109 |
110 | return new Pager<>(page.getPageNum(), page.getPageSize(), page.getTotal(), orderModelList);
111 | }
112 | }
113 |
--------------------------------------------------------------------------------
/scs-infrastructure/src/main/java/com/smart/classroom/subscription/infrastructure/middleware/rocketmq/RocketMqProducerImpl.java:
--------------------------------------------------------------------------------
1 | package com.smart.classroom.subscription.infrastructure.middleware.rocketmq;
2 |
3 | import com.smart.classroom.subscription.domain.middleware.mq.MqProducer;
4 | import com.smart.classroom.subscription.domain.middleware.mq.info.MqSendResultInfo;
5 | import lombok.extern.slf4j.Slf4j;
6 | import org.apache.rocketmq.client.apis.ClientConfiguration;
7 | import org.apache.rocketmq.client.apis.ClientConfigurationBuilder;
8 | import org.apache.rocketmq.client.apis.ClientServiceProvider;
9 | import org.apache.rocketmq.client.apis.message.Message;
10 | import org.apache.rocketmq.client.apis.producer.Producer;
11 | import org.apache.rocketmq.client.apis.producer.SendReceipt;
12 | import org.springframework.context.event.ContextRefreshedEvent;
13 | import org.springframework.context.event.ContextStoppedEvent;
14 | import org.springframework.context.event.EventListener;
15 | import org.springframework.stereotype.Component;
16 |
17 | /**
18 | * @author lishuang
19 | * @date 2023-05-17
20 | *
21 | * 实现代码参考:https://rocketmq.apache.org/zh/docs/quickStart/01quickstart
22 | */
23 | @Slf4j
24 | @Component
25 | public class RocketMqProducerImpl implements MqProducer {
26 | // 接入点地址,需要设置成Proxy的地址和端口列表,一般是xxx:8081;xxx:8081。
27 | public static String ENDPOINT = "localhost:8081";
28 |
29 | // 消息发送的目标Topic名称,需要提前在RocketMQ中创建。
30 | // 一般一个应用对应一个TOPIC.
31 | public static String TOPIC = "SmartClassroomTopic";
32 |
33 | //标识是否已完成启动,防止多次启动
34 | private boolean initialized = false;
35 |
36 | private ClientServiceProvider provider;
37 |
38 | //消费者,发送消息的物件。
39 | private Producer producer = null;
40 |
41 | /**
42 | * 这个方法只在系统启动的时候调用,系统可能调多次。
43 | */
44 | @EventListener(ContextRefreshedEvent.class)
45 | public void applicationRefreshed() {
46 |
47 | log.info("准备启动RocketMQProducer");
48 |
49 | if (initialized) {
50 | return;
51 | } else {
52 | initialized = true;
53 | }
54 |
55 | /*
56 | * Producer对象在使用之前必须要调用start初始化,初始化一次即可
57 | * 注意:切记不可以在每次发送消息时,都调用start方法
58 | */
59 | try {
60 | this.provider = ClientServiceProvider.loadService();
61 | ClientConfigurationBuilder builder = ClientConfiguration.newBuilder().setEndpoints(ENDPOINT);
62 | ClientConfiguration configuration = builder.build();
63 | // 初始化Producer时需要设置通信配置以及预绑定的Topic。
64 | this.producer = provider.newProducerBuilder()
65 | .setTopics(TOPIC)
66 | .setClientConfiguration(configuration)
67 | .build();
68 |
69 | } catch (Throwable throwable) {
70 | log.error("RocketMQ启动失败,请检查RocketMQ是否已经启动", throwable);
71 | }
72 | }
73 |
74 |
75 | /**
76 | * 这个方法只在系统停止的时候调用
77 | */
78 | @EventListener(ContextStoppedEvent.class)
79 | public void applicationStop() {
80 | log.info("RocketMQProducer 系统停止钩子函数");
81 |
82 | //应用退出时,要调用shutdown来清理资源,关闭网络连接,从RocketMQ服务器上注销自己
83 | if (producer == null) {
84 | log.warn("在尝试关闭RocketMQProducer时发现producer已经不存在了");
85 | } else {
86 | try {
87 | producer.close();
88 | } catch (Throwable e) {
89 | log.error("在关闭RocketMQProducer的过程中遭遇错误", e);
90 | }
91 | }
92 | }
93 |
94 |
95 | @Override
96 | public MqSendResultInfo send(String tags, String keys, String body) {
97 |
98 | // 普通消息发送。
99 | Message message = this.provider.newMessageBuilder()
100 | .setTopic(TOPIC)
101 | // 设置消息索引键,可根据关键字精确查找某条消息。
102 | .setKeys(keys)
103 | // 设置消息Tag,用于消费端根据指定Tag过滤消息。
104 | .setTag(tags)
105 | // 消息体。
106 | .setBody(body.getBytes())
107 | .build();
108 |
109 | try {
110 | // 发送消息,需要关注发送结果,并捕获失败等异常。
111 | SendReceipt sendReceipt = producer.send(message);
112 | String messageId = sendReceipt.getMessageId().toString();
113 | log.info("消息发送成功 keys={} tags={} messageId={} version={}", keys, tags, messageId, sendReceipt.getMessageId().getVersion());
114 | return new MqSendResultInfo(true, messageId, null);
115 | } catch (Throwable e) {
116 | String errorMessage = e.getMessage();
117 | log.error("消息发送失败 keys={} tags={} error={}", keys, tags, errorMessage);
118 | return new MqSendResultInfo(false, null, errorMessage);
119 | }
120 | }
121 | }
122 |
--------------------------------------------------------------------------------
/scs-utility/src/main/java/com/smart/classroom/subscription/utility/util/JsonUtil.java:
--------------------------------------------------------------------------------
1 | package com.smart.classroom.subscription.utility.util;
2 |
3 | import com.fasterxml.jackson.core.JsonProcessingException;
4 | import com.fasterxml.jackson.core.type.TypeReference;
5 | import com.fasterxml.jackson.databind.DeserializationFeature;
6 | import com.fasterxml.jackson.databind.JavaType;
7 | import com.fasterxml.jackson.databind.ObjectMapper;
8 | import com.smart.classroom.subscription.utility.exception.UtilException;
9 | import org.apache.commons.lang3.StringUtils;
10 | import org.apache.commons.lang3.exception.ExceptionUtils;
11 |
12 | import java.io.IOException;
13 | import java.text.SimpleDateFormat;
14 | import java.util.ArrayList;
15 | import java.util.List;
16 | import java.util.Map;
17 |
18 | public class JsonUtil {
19 |
20 | public final static String EMPTY_JSON_ARRAY = "[]";
21 | public final static String EMPTY_JSON_OBJECT = "{}";
22 |
23 | public final static ObjectMapper objectMapper;
24 |
25 | static {
26 | objectMapper = new ObjectMapper();
27 | //遇到没有定义的字段,反序列化不要报错。
28 | objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
29 |
30 | // 时间格式化
31 | objectMapper.setDateFormat(new SimpleDateFormat(DateUtil.DEFAULT_FORMAT));
32 | }
33 |
34 | public static T toObject(String content, Class clazz) {
35 |
36 | try {
37 | return objectMapper.readValue(content, clazz);
38 | } catch (IOException e) {
39 | throw new UtilException("JSON信息有误:{} {}", content, ExceptionUtils.getRootCauseMessage(e));
40 | }
41 | }
42 |
43 |
44 | //从一个jsonString中去获取对应类型的对象
45 | public static T toGenericObject(TypeReference typeReference, String jsonString) {
46 |
47 | if (jsonString == null) {
48 | throw new UtilException("jsonString必须指定");
49 | }
50 |
51 |
52 | try {
53 | return objectMapper.readValue(jsonString, typeReference);
54 | } catch (IOException e) {
55 | throw new UtilException("JSON信息有误:{} {}", jsonString, ExceptionUtils.getRootCauseMessage(e));
56 | }
57 |
58 | }
59 |
60 | /**
61 | * 从一个jsonString中去获取对应含有泛型的对象。
62 | * eg.
63 | * final TxyResponse o1 = JsonUtil.toGenericObject(TxyResponse.class, AesKeyData.class, content);
64 | */
65 | public static T toGenericObject(Class> baseClass, Class> parameterClass, String jsonString) {
66 |
67 | if (jsonString == null) {
68 | throw new UtilException("jsonString必须指定");
69 | }
70 |
71 | JavaType concreteType = objectMapper.getTypeFactory().constructParametricType(
72 | baseClass,
73 | parameterClass
74 | );
75 |
76 | try {
77 | return objectMapper.readValue(jsonString, concreteType);
78 | } catch (IOException e) {
79 | throw new UtilException("JSON信息有误:{} {}", jsonString, ExceptionUtils.getRootCauseMessage(e));
80 | }
81 |
82 | }
83 |
84 | //从一个jsonString中去获取List
85 | public static List toLongList(String jsonString) {
86 |
87 |
88 | if (jsonString == null) {
89 | return new ArrayList<>();
90 | }
91 |
92 | return toGenericObject(new TypeReference>() {
93 | }, jsonString);
94 | }
95 |
96 | //从一个jsonString中去获取List
97 | public static List toStringList(String jsonString) {
98 | if (StringUtils.isEmpty(jsonString)) {
99 | return new ArrayList<>();
100 | }
101 |
102 | return toGenericObject(new TypeReference>() {
103 | }, jsonString);
104 | }
105 |
106 |
107 | //将对象转换成json字符串。
108 | public static String toJson(Object obj) {
109 |
110 |
111 | try {
112 |
113 | return objectMapper.writeValueAsString(obj);
114 |
115 | } catch (JsonProcessingException e) {
116 | throw new UtilException("转成JSON时出错:{}", ExceptionUtils.getRootCauseMessage(e));
117 | }
118 | }
119 |
120 | //将一个对象转换成 Map
121 | public static Map toMap(String jsonString, Class clazz) {
122 |
123 | TypeReference