├── demo.png
├── order-charge-gateway-notify
├── src
│ ├── main
│ │ ├── resources
│ │ │ ├── application.properties
│ │ │ ├── mybatis-config.xml
│ │ │ ├── META-INF
│ │ │ │ ├── applicationContext-mapper.xml
│ │ │ │ └── applicationContext-bean.xml
│ │ │ └── mapper
│ │ │ │ └── WalletMapper.xml
│ │ └── java
│ │ │ └── com
│ │ │ └── snowalker
│ │ │ └── notify
│ │ │ ├── NotifyApplication.java
│ │ │ ├── common
│ │ │ ├── constant
│ │ │ │ └── NotifyConstant.java
│ │ │ ├── util
│ │ │ │ ├── LogExceptionWapper.java
│ │ │ │ └── DateUtil.java
│ │ │ ├── service
│ │ │ │ ├── WalletService.java
│ │ │ │ └── impl
│ │ │ │ │ └── WalletServiceImpl.java
│ │ │ ├── dao
│ │ │ │ ├── WalletMapper.java
│ │ │ │ └── dataobject
│ │ │ │ │ ├── ChargeRecordEntity.java
│ │ │ │ │ ├── WalletEntity.java
│ │ │ │ │ └── OrderEntity.java
│ │ │ └── config
│ │ │ │ └── RestTemplateConfig.java
│ │ │ └── mq
│ │ │ ├── notify
│ │ │ └── NotifySendConsumer.java
│ │ │ └── payment
│ │ │ ├── consumer
│ │ │ ├── WalletPaymentConsumer.java
│ │ │ └── listener
│ │ │ │ └── WalletPaymentMsgListenerImpl.java
│ │ │ └── producer
│ │ │ ├── OrderStatusUpdateProducer.java
│ │ │ └── listener
│ │ │ └── LocalTranListenerImpl.java
│ └── test
│ │ └── java
│ │ └── com
│ │ └── snowalker
│ │ └── notify
│ │ └── OrderChargeNotifyApplicationTests.java
├── .gitignore
├── pom.xml
└── mvnw.cmd
├── order-charge-gateway-server
├── src
│ ├── main
│ │ ├── resources
│ │ │ ├── application.properties
│ │ │ ├── mybatis-config.xml
│ │ │ ├── mapper
│ │ │ │ ├── MerchantInfoMapper.xml
│ │ │ │ └── OrderChargeMapper.xml
│ │ │ └── META-INF
│ │ │ │ ├── applicationContext-mapper.xml
│ │ │ │ └── applicationContext-bean.xml
│ │ └── java
│ │ │ └── com
│ │ │ └── snowalker
│ │ │ └── order
│ │ │ ├── common
│ │ │ ├── dao
│ │ │ │ ├── MerchantInfoMapper.java
│ │ │ │ ├── OrderChargeMapper.java
│ │ │ │ └── dataobject
│ │ │ │ │ ├── MerchantInfoDO.java
│ │ │ │ │ ├── OrderInfoDobj.java
│ │ │ │ │ └── OrderInfoDO.java
│ │ │ ├── service
│ │ │ │ ├── MerchantInfoService.java
│ │ │ │ ├── impl
│ │ │ │ │ └── MerchantInfoServiceImpl.java
│ │ │ │ └── OrderChargeService.java
│ │ │ ├── util
│ │ │ │ └── LogExceptionWapper.java
│ │ │ ├── config
│ │ │ │ ├── ProductVO.java
│ │ │ │ ├── ProductConfig.java
│ │ │ │ └── MerchantInfoConfig.java
│ │ │ └── dto
│ │ │ │ ├── Result.java
│ │ │ │ └── CodeMsg.java
│ │ │ ├── ServerApplication.java
│ │ │ ├── mq
│ │ │ ├── notify
│ │ │ │ └── producer
│ │ │ │ │ └── OrderNotifySendProducer.java
│ │ │ └── payment
│ │ │ │ └── producer
│ │ │ │ ├── ChargeOrderPaymentTranProducer.java
│ │ │ │ └── listener
│ │ │ │ └── ChargeOrderTranListenerImpl.java
│ │ │ └── portal
│ │ │ └── OrderChargeController.java
│ └── test
│ │ └── java
│ │ └── com
│ │ └── snowalker
│ │ └── order
│ │ └── OrderChargeGatewayApplicationTests.java
├── .gitignore
└── pom.xml
├── order-charge-gateway-merchant
├── src
│ ├── main
│ │ ├── resources
│ │ │ ├── application.properties
│ │ │ ├── mybatis-config.xml
│ │ │ ├── META-INF
│ │ │ │ ├── applicationContext-mapper.xml
│ │ │ │ └── applicationContext-bean.xml
│ │ │ └── mapper
│ │ │ │ └── OrderInfoMapper.xml
│ │ └── java
│ │ │ └── com
│ │ │ └── snowalker
│ │ │ └── gateway
│ │ │ └── merchant
│ │ │ ├── order
│ │ │ ├── manager
│ │ │ │ ├── package-info.java
│ │ │ │ └── OrderChargeManager.java
│ │ │ ├── constant
│ │ │ │ ├── NotifyConstant.java
│ │ │ │ └── OrderStatusEnum.java
│ │ │ ├── exception
│ │ │ │ └── ApiException.java
│ │ │ ├── util
│ │ │ │ └── LogExceptionWapper.java
│ │ │ ├── mapper
│ │ │ │ └── OrderInfoMapper.java
│ │ │ ├── config
│ │ │ │ └── RestTemplateConfig.java
│ │ │ ├── handler
│ │ │ │ ├── GlobalExceptionHandler.java
│ │ │ │ └── RequestParamValidateHandler.java
│ │ │ ├── dto
│ │ │ │ ├── Result.java
│ │ │ │ ├── CodeMsg.java
│ │ │ │ └── ChargeOrderDto.java
│ │ │ ├── service
│ │ │ │ └── OrderService.java
│ │ │ ├── OrderChargeController.java
│ │ │ ├── OrderNotifyController.java
│ │ │ └── dataobject
│ │ │ │ └── ChargeOrderDO.java
│ │ │ ├── MerchantApplication.java
│ │ │ └── goods
│ │ │ ├── ProductConfig.java
│ │ │ └── ProductVO.java
│ └── test
│ │ └── java
│ │ └── com
│ │ └── snowalker
│ │ └── gateway
│ │ └── merchant
│ │ └── OrderChargeGatewayMerchantApplicationTests.java
├── .gitignore
└── pom.xml
├── order-charge-sdk
├── src
│ ├── main
│ │ └── java
│ │ │ └── com
│ │ │ └── snowalker
│ │ │ ├── App.java
│ │ │ └── order
│ │ │ └── charge
│ │ │ ├── constant
│ │ │ └── ResponseCodeEnum.java
│ │ │ ├── response
│ │ │ └── ChargeOrderResponse.java
│ │ │ └── request
│ │ │ ├── ChargeNotifyRequest.java
│ │ │ └── ChargeOrderRequest.java
│ └── test
│ │ └── java
│ │ └── com
│ │ └── snowalker
│ │ └── AppTest.java
├── .gitignore
├── order-charge-sdk.iml
└── pom.xml
├── order-charge-message-protocol
├── src
│ ├── test
│ │ └── java
│ │ │ └── com
│ │ │ └── snowalker
│ │ │ └── AppTest.java
│ └── main
│ │ └── java
│ │ └── com
│ │ └── snowalker
│ │ └── order
│ │ └── charge
│ │ └── message
│ │ ├── constant
│ │ ├── UpdateEventTypeConst.java
│ │ └── MessageProtocolConst.java
│ │ └── protocol
│ │ ├── BaseMsg.java
│ │ ├── OrderStatusUpdateProtocol.java
│ │ └── WalletPaymentProtocol.java
├── .gitignore
├── order-charge-message-protocol.iml
└── pom.xml
├── .gitignore
├── pom.xml
├── readme.md
└── script
└── demo.sql
/demo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TaXueWWL/order-charge-notify/HEAD/demo.png
--------------------------------------------------------------------------------
/order-charge-gateway-notify/src/main/resources/application.properties:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TaXueWWL/order-charge-notify/HEAD/order-charge-gateway-notify/src/main/resources/application.properties
--------------------------------------------------------------------------------
/order-charge-gateway-server/src/main/resources/application.properties:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TaXueWWL/order-charge-notify/HEAD/order-charge-gateway-server/src/main/resources/application.properties
--------------------------------------------------------------------------------
/order-charge-gateway-merchant/src/main/resources/application.properties:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TaXueWWL/order-charge-notify/HEAD/order-charge-gateway-merchant/src/main/resources/application.properties
--------------------------------------------------------------------------------
/order-charge-gateway-merchant/src/main/java/com/snowalker/gateway/merchant/order/manager/package-info.java:
--------------------------------------------------------------------------------
1 | /**
2 | * @author snowalker
3 | * 防腐层
4 | */
5 | package com.snowalker.gateway.merchant.order.manager;
--------------------------------------------------------------------------------
/order-charge-sdk/src/main/java/com/snowalker/App.java:
--------------------------------------------------------------------------------
1 | package com.snowalker;
2 |
3 | /**
4 | * Hello world!
5 | *
6 | */
7 | public class App
8 | {
9 | public static void main( String[] args )
10 | {
11 | System.out.println( "Hello World!" );
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/order-charge-message-protocol/src/test/java/com/snowalker/AppTest.java:
--------------------------------------------------------------------------------
1 | package com.snowalker;
2 |
3 | import static org.junit.Assert.assertTrue;
4 |
5 | import org.junit.Test;
6 |
7 | /**
8 | * Unit test for simple App.
9 | */
10 | public class AppTest
11 | {
12 | /**
13 | * Rigorous Test :-)
14 | */
15 | @Test
16 | public void shouldAnswerWithTrue()
17 | {
18 | assertTrue( true );
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/order-charge-gateway-notify/.gitignore:
--------------------------------------------------------------------------------
1 | HELP.md
2 | /target/
3 | !.mvn/wrapper/maven-wrapper.jar
4 |
5 | ### STS ###
6 | .apt_generated
7 | .classpath
8 | .factorypath
9 | .project
10 | .settings
11 | .springBeans
12 | .sts4-cache
13 |
14 | ### IntelliJ IDEA ###
15 | .idea
16 | *.iws
17 | *.iml
18 | *.ipr
19 |
20 | ### NetBeans ###
21 | /nbproject/private/
22 | /nbbuild/
23 | /dist/
24 | /nbdist/
25 | /.nb-gradle/
26 | /build/
27 |
28 | ### VS Code ###
29 | .vscode/
30 |
--------------------------------------------------------------------------------
/order-charge-gateway-server/.gitignore:
--------------------------------------------------------------------------------
1 | HELP.md
2 | /target/
3 | !.mvn/wrapper/maven-wrapper.jar
4 |
5 | ### STS ###
6 | .apt_generated
7 | .classpath
8 | .factorypath
9 | .project
10 | .settings
11 | .springBeans
12 | .sts4-cache
13 |
14 | ### IntelliJ IDEA ###
15 | .idea
16 | *.iws
17 | *.iml
18 | *.ipr
19 |
20 | ### NetBeans ###
21 | /nbproject/private/
22 | /nbbuild/
23 | /dist/
24 | /nbdist/
25 | /.nb-gradle/
26 | /build/
27 |
28 | ### VS Code ###
29 | .vscode/
30 |
--------------------------------------------------------------------------------
/order-charge-gateway-merchant/.gitignore:
--------------------------------------------------------------------------------
1 | HELP.md
2 | /target/
3 | !.mvn/wrapper/maven-wrapper.jar
4 |
5 | ### STS ###
6 | .apt_generated
7 | .classpath
8 | .factorypath
9 | .project
10 | .settings
11 | .springBeans
12 | .sts4-cache
13 |
14 | ### IntelliJ IDEA ###
15 | .idea
16 | *.iws
17 | *.iml
18 | *.ipr
19 |
20 | ### NetBeans ###
21 | /nbproject/private/
22 | /nbbuild/
23 | /dist/
24 | /nbdist/
25 | /.nb-gradle/
26 | /build/
27 |
28 | ### VS Code ###
29 | .vscode/
30 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Created by .ignore support plugin (hsz.mobi)
2 | ### Java template
3 | # Compiled class file
4 | *.class
5 |
6 | # Log file
7 | *.log
8 |
9 | # BlueJ files
10 | *.ctxt
11 |
12 | # Mobile Tools for Java (J2ME)
13 | .mtj.tmp/
14 |
15 | # Package Files #
16 | *.jar
17 | *.war
18 | *.nar
19 | *.ear
20 | *.zip
21 | *.tar.gz
22 | *.rar
23 | .idea
24 |
25 | # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
26 | hs_err_pid*
27 |
28 |
--------------------------------------------------------------------------------
/order-charge-sdk/.gitignore:
--------------------------------------------------------------------------------
1 | # Created by .ignore support plugin (hsz.mobi)
2 | ### Java template
3 | # Compiled class file
4 | *.class
5 |
6 | # Log file
7 | *.log
8 |
9 | # BlueJ files
10 | *.ctxt
11 |
12 | # Mobile Tools for Java (J2ME)
13 | .mtj.tmp/
14 |
15 | # Package Files #
16 | *.jar
17 | *.war
18 | *.nar
19 | *.ear
20 | *.zip
21 | *.tar.gz
22 | *.rar
23 | .idea
24 |
25 | # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
26 | hs_err_pid*
27 |
28 |
--------------------------------------------------------------------------------
/order-charge-message-protocol/.gitignore:
--------------------------------------------------------------------------------
1 | # Created by .ignore support plugin (hsz.mobi)
2 | ### Java template
3 | # Compiled class file
4 | *.class
5 |
6 | # Log file
7 | *.log
8 |
9 | # BlueJ files
10 | *.ctxt
11 |
12 | # Mobile Tools for Java (J2ME)
13 | .mtj.tmp/
14 |
15 | # Package Files #
16 | *.jar
17 | *.war
18 | *.nar
19 | *.ear
20 | *.zip
21 | *.tar.gz
22 | *.rar
23 | .idea
24 |
25 | # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
26 | hs_err_pid*
27 |
28 |
--------------------------------------------------------------------------------
/order-charge-gateway-notify/src/test/java/com/snowalker/notify/OrderChargeNotifyApplicationTests.java:
--------------------------------------------------------------------------------
1 | package com.snowalker.notify;
2 |
3 | import org.junit.Test;
4 | import org.junit.runner.RunWith;
5 | import org.springframework.boot.test.context.SpringBootTest;
6 | import org.springframework.test.context.junit4.SpringRunner;
7 |
8 | @RunWith(SpringRunner.class)
9 | @SpringBootTest
10 | public class OrderChargeNotifyApplicationTests {
11 |
12 | @Test
13 | public void contextLoads() {
14 | }
15 |
16 | }
17 |
--------------------------------------------------------------------------------
/order-charge-gateway-notify/src/main/resources/mybatis-config.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/order-charge-gateway-server/src/main/resources/mybatis-config.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/order-charge-gateway-merchant/src/main/resources/mybatis-config.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/order-charge-gateway-merchant/src/test/java/com/snowalker/gateway/merchant/OrderChargeGatewayMerchantApplicationTests.java:
--------------------------------------------------------------------------------
1 | package com.snowalker.gateway.merchant;
2 |
3 | import org.junit.Test;
4 | import org.junit.runner.RunWith;
5 | import org.springframework.boot.test.context.SpringBootTest;
6 | import org.springframework.test.context.junit4.SpringRunner;
7 |
8 | @RunWith(SpringRunner.class)
9 | @SpringBootTest
10 | public class OrderChargeGatewayMerchantApplicationTests {
11 |
12 | @Test
13 | public void contextLoads() {
14 | }
15 |
16 | }
17 |
--------------------------------------------------------------------------------
/order-charge-gateway-server/src/main/java/com/snowalker/order/common/dao/MerchantInfoMapper.java:
--------------------------------------------------------------------------------
1 | package com.snowalker.order.common.dao;
2 |
3 | import com.snowalker.order.common.dao.dataobject.MerchantInfoDO;
4 |
5 | import java.util.List;
6 |
7 | /**
8 | * @author snowalker
9 | * @version 1.0
10 | * @date 2019/6/11 14:06
11 | * @className MerchantInfoMapper
12 | * @desc 商户基本信息Mapper
13 | */
14 | public interface MerchantInfoMapper {
15 |
16 | /**
17 | * 查询商户信息列表
18 | * @return
19 | */
20 | List queryMerchantList();
21 | }
22 |
--------------------------------------------------------------------------------
/order-charge-gateway-server/src/main/java/com/snowalker/order/common/service/MerchantInfoService.java:
--------------------------------------------------------------------------------
1 | package com.snowalker.order.common.service;
2 |
3 | import com.snowalker.order.common.dao.dataobject.MerchantInfoDO;
4 |
5 | import java.util.List;
6 |
7 | /**
8 | * @author snowalker
9 | * @version 1.0
10 | * @date 2019/6/11 14:13
11 | * @className MerchantInfoService
12 | * @desc 商户服务接口
13 | */
14 | public interface MerchantInfoService {
15 |
16 | /**
17 | * 查询商户列表
18 | * @return
19 | */
20 | List queryMerchantList();
21 | }
22 |
--------------------------------------------------------------------------------
/order-charge-gateway-notify/src/main/java/com/snowalker/notify/NotifyApplication.java:
--------------------------------------------------------------------------------
1 | package com.snowalker.notify;
2 |
3 | import org.springframework.boot.SpringApplication;
4 | import org.springframework.boot.autoconfigure.SpringBootApplication;
5 | import org.springframework.context.annotation.ImportResource;
6 |
7 | /**
8 | * 通知服务启动器
9 | * @author snowalker
10 | */
11 | @SpringBootApplication
12 | @ImportResource({"classpath*:META-INF/applicationContext-bean.xml"})
13 | public class NotifyApplication {
14 |
15 | public static void main(String[] args) {
16 | SpringApplication.run(NotifyApplication.class, args);
17 | }
18 |
19 | }
20 |
--------------------------------------------------------------------------------
/order-charge-gateway-server/src/main/java/com/snowalker/order/ServerApplication.java:
--------------------------------------------------------------------------------
1 | package com.snowalker.order;
2 |
3 | import org.springframework.boot.SpringApplication;
4 | import org.springframework.boot.autoconfigure.SpringBootApplication;
5 | import org.springframework.context.annotation.ImportResource;
6 |
7 | /**
8 | * 上游收单网关启动器
9 | * @author snowalker
10 | */
11 | @SpringBootApplication
12 | @ImportResource({"classpath*:META-INF/applicationContext-bean.xml"})
13 | public class ServerApplication {
14 |
15 | public static void main(String[] args) {
16 | SpringApplication.run(ServerApplication.class, args);
17 | }
18 |
19 | }
20 |
--------------------------------------------------------------------------------
/order-charge-gateway-notify/src/main/java/com/snowalker/notify/common/constant/NotifyConstant.java:
--------------------------------------------------------------------------------
1 | package com.snowalker.notify.common.constant;
2 |
3 | /**
4 | * @author snowalker
5 | * @version 1.0
6 | * @date 2019/6/11 12:54
7 | * @className NotifyConstant
8 | * @desc 通知常量
9 | */
10 | public abstract class NotifyConstant {
11 |
12 | private NotifyConstant() {}
13 |
14 | /**通知结果返回*/
15 | public static final String NOTIFY_RETURN_SUCC = "T";
16 | public static final String NOTIFY_RETURN_FAIL = "F";
17 | /**订单结果通知状态*/
18 | public static final String NOTIFY_SUCCESS = "SUCCESS";
19 | public static final String NOTIFY_FAIL = "FAIL";
20 | }
21 |
--------------------------------------------------------------------------------
/order-charge-gateway-merchant/src/main/java/com/snowalker/gateway/merchant/MerchantApplication.java:
--------------------------------------------------------------------------------
1 | package com.snowalker.gateway.merchant;
2 |
3 | import org.springframework.boot.SpringApplication;
4 | import org.springframework.boot.autoconfigure.SpringBootApplication;
5 | import org.springframework.context.annotation.ImportResource;
6 |
7 | /**
8 | * 渠道收单网关启动器
9 | * @author snowalker
10 | */
11 | @SpringBootApplication
12 | @ImportResource({"classpath*:META-INF/applicationContext-bean.xml"})
13 | public class MerchantApplication {
14 |
15 | public static void main(String[] args) {
16 | SpringApplication.run(MerchantApplication.class, args);
17 | }
18 |
19 | }
20 |
--------------------------------------------------------------------------------
/order-charge-gateway-merchant/src/main/java/com/snowalker/gateway/merchant/order/constant/NotifyConstant.java:
--------------------------------------------------------------------------------
1 | package com.snowalker.gateway.merchant.order.constant;
2 |
3 | /**
4 | * @author snowalker
5 | * @version 1.0
6 | * @date 2019/6/11 12:54
7 | * @className NotifyConstant
8 | * @desc
9 | */
10 | public abstract class NotifyConstant {
11 |
12 | private NotifyConstant() {}
13 |
14 | /**通知结果返回*/
15 | public static final String NOTIFY_RETURN_SUCC = "T";
16 | public static final String NOTIFY_RETURN_FAIL = "F";
17 | /**订单结果通知状态*/
18 | public static final String NOTIFY_SUCCESS = "SUCCESS";
19 | public static final String NOTIFY_FAIL = "FAIL";
20 | }
21 |
--------------------------------------------------------------------------------
/order-charge-gateway-server/src/main/resources/mapper/MerchantInfoMapper.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
16 |
17 |
--------------------------------------------------------------------------------
/order-charge-sdk/src/main/java/com/snowalker/order/charge/constant/ResponseCodeEnum.java:
--------------------------------------------------------------------------------
1 | package com.snowalker.order.charge.constant;
2 |
3 | /**
4 | * @author snowalker
5 | * @version 1.0
6 | * @date 2019/6/10 11:49
7 | * @className OrderStatusEnum
8 | * @desc 同步下单及异步回调状态码枚举
9 | */
10 | public enum ResponseCodeEnum {
11 |
12 | SUCCESS("10000", "成功"),
13 | FAIL("20000", "失败"),
14 | UNKNOWN("40004", "未知");
15 |
16 | private String code;
17 | private String desc;
18 |
19 | ResponseCodeEnum(String code, String desc) {
20 | this.code = code;
21 | this.desc = desc;
22 | }
23 |
24 | public String getCode() {
25 | return code;
26 | }
27 |
28 | public String getDesc() {
29 | return desc;
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/order-charge-gateway-notify/src/main/resources/META-INF/applicationContext-mapper.xml:
--------------------------------------------------------------------------------
1 |
2 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/order-charge-gateway-server/src/main/resources/META-INF/applicationContext-mapper.xml:
--------------------------------------------------------------------------------
1 |
2 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/order-charge-gateway-merchant/src/main/resources/META-INF/applicationContext-mapper.xml:
--------------------------------------------------------------------------------
1 |
2 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/order-charge-gateway-merchant/src/main/java/com/snowalker/gateway/merchant/order/exception/ApiException.java:
--------------------------------------------------------------------------------
1 | package com.snowalker.gateway.merchant.order.exception;
2 |
3 | import com.snowalker.gateway.merchant.order.dto.CodeMsg;
4 |
5 | /**
6 | * @author snowalker
7 | * @version 1.0
8 | * @date 2019/6/10 10:15
9 | * @className ApiException
10 | * @desc 自定义接口异常
11 | */
12 | public class ApiException extends RuntimeException {
13 |
14 | private static final long serialVersionUID = 1L;
15 |
16 | private CodeMsg codeMsg;
17 |
18 | public ApiException(CodeMsg codeMsg) {
19 | super(codeMsg.toString());
20 | this.codeMsg = codeMsg;
21 | }
22 |
23 | public ApiException() {}
24 |
25 | public CodeMsg getCodeMsg() {
26 | return codeMsg;
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/order-charge-gateway-merchant/src/main/java/com/snowalker/gateway/merchant/order/constant/OrderStatusEnum.java:
--------------------------------------------------------------------------------
1 | package com.snowalker.gateway.merchant.order.constant;
2 |
3 | /**
4 | * @author snowalker
5 | * @version 1.0
6 | * @date 2019/6/10 11:49
7 | * @className OrderStatusEnum
8 | * @desc 订单状态枚举
9 | */
10 | public enum OrderStatusEnum {
11 |
12 | SUCCESS(0, "成功"),
13 | INIT(1, "初始化"),
14 | DEALING(2, "处理中"),
15 | FAIL(3, "失败");
16 |
17 | private Integer code;
18 | private String desc;
19 |
20 | OrderStatusEnum(Integer code, String desc) {
21 | this.code = code;
22 | this.desc = desc;
23 | }
24 |
25 | public Integer getCode() {
26 | return code;
27 | }
28 |
29 | public String getDesc() {
30 | return desc;
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/order-charge-gateway-server/src/main/java/com/snowalker/order/common/util/LogExceptionWapper.java:
--------------------------------------------------------------------------------
1 | package com.snowalker.order.common.util;
2 |
3 | import java.io.PrintWriter;
4 | import java.io.StringWriter;
5 | import java.io.Writer;
6 |
7 | /**
8 | * @author snowalker
9 | * @date 2018/9/20
10 | * @desc 日志工具
11 | */
12 | public class LogExceptionWapper {
13 |
14 | private LogExceptionWapper() {}
15 |
16 | /**
17 | * 获取完整栈轨迹
18 | *
19 | * @param aThrowable
20 | * @return
21 | */
22 | public static String getStackTrace(Throwable aThrowable) {
23 | final Writer result = new StringWriter();
24 | final PrintWriter printWriter = new PrintWriter(result);
25 | aThrowable.printStackTrace(printWriter);
26 | return result.toString();
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/order-charge-gateway-notify/src/main/java/com/snowalker/notify/common/util/LogExceptionWapper.java:
--------------------------------------------------------------------------------
1 | package com.snowalker.notify.common.util;
2 |
3 | import java.io.PrintWriter;
4 | import java.io.StringWriter;
5 | import java.io.Writer;
6 |
7 | /**
8 | * @author snowalker
9 | * @date 2018/9/20
10 | * @desc 日志工具
11 | */
12 | public class LogExceptionWapper {
13 |
14 | private LogExceptionWapper() {}
15 |
16 | /**
17 | * 获取完整栈轨迹
18 | *
19 | * @param aThrowable
20 | * @return
21 | */
22 | public static String getStackTrace(Throwable aThrowable) {
23 | final Writer result = new StringWriter();
24 | final PrintWriter printWriter = new PrintWriter(result);
25 | aThrowable.printStackTrace(printWriter);
26 | return result.toString();
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/order-charge-gateway-merchant/src/main/java/com/snowalker/gateway/merchant/order/util/LogExceptionWapper.java:
--------------------------------------------------------------------------------
1 | package com.snowalker.gateway.merchant.order.util;
2 |
3 | import java.io.PrintWriter;
4 | import java.io.StringWriter;
5 | import java.io.Writer;
6 |
7 | /**
8 | * @author snowalker
9 | * @date 2018/9/20
10 | * @desc 日志工具
11 | */
12 | public class LogExceptionWapper {
13 |
14 | private LogExceptionWapper() {}
15 |
16 | /**
17 | * 获取完整栈轨迹
18 | *
19 | * @param aThrowable
20 | * @return
21 | */
22 | public static String getStackTrace(Throwable aThrowable) {
23 | final Writer result = new StringWriter();
24 | final PrintWriter printWriter = new PrintWriter(result);
25 | aThrowable.printStackTrace(printWriter);
26 | return result.toString();
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/order-charge-gateway-notify/src/main/resources/META-INF/applicationContext-bean.xml:
--------------------------------------------------------------------------------
1 |
2 |
11 |
12 |
13 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/order-charge-gateway-server/src/main/resources/META-INF/applicationContext-bean.xml:
--------------------------------------------------------------------------------
1 |
2 |
11 |
12 |
13 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/order-charge-gateway-merchant/src/main/resources/META-INF/applicationContext-bean.xml:
--------------------------------------------------------------------------------
1 |
2 |
11 |
12 |
13 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/order-charge-gateway-merchant/src/main/java/com/snowalker/gateway/merchant/order/mapper/OrderInfoMapper.java:
--------------------------------------------------------------------------------
1 | package com.snowalker.gateway.merchant.order.mapper;
2 |
3 | import com.snowalker.gateway.merchant.order.dataobject.ChargeOrderDO;
4 | import com.snowalker.gateway.merchant.order.dto.ChargeOrderDto;
5 |
6 | /**
7 | * @author snowalker
8 | * @version 1.0
9 | * @date 2019/6/10 13:46
10 | * @className OrderMapper
11 | * @desc 订单本地Mapper
12 | */
13 | public interface OrderInfoMapper {
14 |
15 | /**
16 | * 订单入库
17 | * @param chargeOrderDto
18 | * @return
19 | */
20 | int insertOrderInfo(ChargeOrderDto chargeOrderDto);
21 |
22 | /**
23 | * 订单状态更新
24 | * @param chargeOrderDto
25 | * @return
26 | */
27 | int updateOrderStatus(ChargeOrderDto chargeOrderDto);
28 |
29 | /**
30 | * 查询订单信息
31 | * @param chargeOrderDto
32 | * @return
33 | */
34 | ChargeOrderDO queryOrderByOrderId(ChargeOrderDto chargeOrderDto);
35 | }
36 |
--------------------------------------------------------------------------------
/order-charge-message-protocol/src/main/java/com/snowalker/order/charge/message/constant/UpdateEventTypeConst.java:
--------------------------------------------------------------------------------
1 | package com.snowalker.order.charge.message.constant;
2 |
3 | /**
4 | * @author snowalker
5 | * @version 1.0
6 | * @date 2019/6/11 14:45
7 | * @className MessageProtocolConst
8 | * @desc 消息协议常量
9 | */
10 | public enum UpdateEventTypeConst {
11 |
12 | /**支付状态更新事件*/
13 | EVENT_UPDATE_PAY_STATUS("EVENT_UPDATE_PAY_STATUS", "EVENT_UPDATE_PAY_STATUS"),
14 | /**通知状态及订单状态更新事件*/
15 | EVENT_UPDATE_NOTIFY_OD_STATUS("EVENT_UPDATE_NOTIFY_OD_STATUS", "EVENT_UPDATE_NOTIFY_OD_STATUS")
16 | ;
17 |
18 | /**更新事件*/
19 | private String eventType;
20 | /**事件描述*/
21 | private String eventDesc;
22 |
23 | UpdateEventTypeConst(String eventType, String eventDesc) {
24 | this.eventType = eventType;
25 | this.eventDesc = eventDesc;
26 | }
27 |
28 | public String getEventType() {
29 | return eventType;
30 | }
31 |
32 | public String getEventDesc() {
33 | return eventDesc;
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/order-charge-gateway-server/src/test/java/com/snowalker/order/OrderChargeGatewayApplicationTests.java:
--------------------------------------------------------------------------------
1 | package com.snowalker.order;
2 |
3 | import com.snowalker.order.common.dao.dataobject.OrderInfoDO;
4 | import com.snowalker.order.common.dao.dataobject.OrderInfoDobj;
5 | import com.snowalker.order.common.service.OrderChargeService;
6 | import org.junit.Test;
7 | import org.junit.runner.RunWith;
8 | import org.springframework.beans.factory.annotation.Autowired;
9 | import org.springframework.boot.test.context.SpringBootTest;
10 | import org.springframework.test.context.junit4.SpringRunner;
11 |
12 | @RunWith(SpringRunner.class)
13 | @SpringBootTest
14 | public class OrderChargeGatewayApplicationTests {
15 |
16 | @Autowired
17 | OrderChargeService orderChargeService;
18 |
19 | @Test
20 | public void contextLoads() {
21 | OrderInfoDO orderInfoDO = new OrderInfoDO().setOrderId("00001");
22 | OrderInfoDobj orderInfoDobj = orderChargeService.queryOrderInfo(orderInfoDO);
23 | System.out.println(orderInfoDobj.toString());
24 | }
25 |
26 | }
27 |
--------------------------------------------------------------------------------
/order-charge-gateway-server/src/main/java/com/snowalker/order/common/service/impl/MerchantInfoServiceImpl.java:
--------------------------------------------------------------------------------
1 | package com.snowalker.order.common.service.impl;
2 |
3 | import com.snowalker.order.common.dao.MerchantInfoMapper;
4 | import com.snowalker.order.common.dao.dataobject.MerchantInfoDO;
5 | import com.snowalker.order.common.service.MerchantInfoService;
6 | import org.springframework.beans.factory.annotation.Autowired;
7 | import org.springframework.stereotype.Service;
8 |
9 | import java.util.List;
10 |
11 | /**
12 | * @author snowalker
13 | * @version 1.0
14 | * @date 2019/6/11 14:21
15 | * @className MerchantInfoServiceImpl
16 | * @desc 商户信息服务实现
17 | */
18 | @Service(value = "merchantInfoService")
19 | public class MerchantInfoServiceImpl implements MerchantInfoService {
20 |
21 | @Autowired
22 | MerchantInfoMapper merchantInfoMapper;
23 |
24 | /**
25 | * 商户列表查询
26 | * @return
27 | */
28 | @Override
29 | public List queryMerchantList() {
30 | return merchantInfoMapper.queryMerchantList();
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/order-charge-gateway-notify/src/main/java/com/snowalker/notify/common/service/WalletService.java:
--------------------------------------------------------------------------------
1 | package com.snowalker.notify.common.service;
2 |
3 | import com.snowalker.notify.common.dao.dataobject.ChargeRecordEntity;
4 | import com.snowalker.notify.common.dao.dataobject.WalletEntity;
5 |
6 | /**
7 | * @author snowalker
8 | * @version 1.0
9 | * @date 2019/6/12 9:15
10 | * @className WalletService
11 | * @desc 钱包相关接口定义
12 | */
13 | public interface WalletService {
14 |
15 | /**
16 | * 新增用户钱包
17 | * @param walletEntity
18 | */
19 | void insertWallet(WalletEntity walletEntity);
20 |
21 | /**
22 | * 修改用户钱包数据
23 | * @param walletEntity
24 | * @return
25 | */
26 | boolean updateWallet(WalletEntity walletEntity, String orderId);
27 |
28 | /**
29 | * 查询扣款流水
30 | * @param orderId
31 | * @return
32 | */
33 | ChargeRecordEntity queryChargeRecordByOrderId(String orderId);
34 |
35 | /**
36 | * 查询钱包信息
37 | * @param purseId
38 | * @return
39 | */
40 | WalletEntity queryWalletInfoByPurseId(String purseId);
41 | }
42 |
--------------------------------------------------------------------------------
/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
5 | 4.0.0
6 |
7 | com.snowalker
8 | order-charge-notify
9 | 1.0-SNAPSHOT
10 | pom
11 |
12 | order-charge-notify
13 |
14 |
15 | 1.8
16 | 1.8
17 | UTF-8
18 | UTF-8
19 |
20 |
21 |
22 | order-charge-gateway-server
23 | order-charge-gateway-notify
24 | order-charge-gateway-merchant
25 | order-charge-sdk
26 | order-charge-message-protocol
27 |
28 |
29 |
30 |
--------------------------------------------------------------------------------
/order-charge-gateway-server/src/main/java/com/snowalker/order/common/dao/OrderChargeMapper.java:
--------------------------------------------------------------------------------
1 | package com.snowalker.order.common.dao;
2 |
3 | import com.snowalker.order.common.dao.dataobject.OrderInfoDO;
4 | import com.snowalker.order.common.dao.dataobject.OrderInfoDobj;
5 |
6 | /**
7 | * @author snowalker
8 | * @version 1.0
9 | * @date 2019/6/11 20:01
10 | * @className OrderChargeMapper
11 | * @desc 订单交易Mapper
12 | */
13 | public interface OrderChargeMapper {
14 |
15 | /**
16 | * 订单入库
17 | * @param orderInfoDO
18 | * @return
19 | */
20 | int insertOrder(OrderInfoDO orderInfoDO);
21 |
22 | /**
23 | * 订单查询
24 | * @param orderInfoDO
25 | * @return
26 | */
27 | OrderInfoDobj queryOrderInfoByOrderId(OrderInfoDO orderInfoDO);
28 |
29 | /**
30 | * 订单状态修改为处理中
31 | * @param orderInfoDO
32 | * @return
33 | */
34 | int updateOrderDealing(OrderInfoDO orderInfoDO);
35 |
36 | /**
37 | * 支付状态修改为成功
38 | * @param orderInfoDO
39 | * @return
40 | */
41 | int updateOrderPayStatusSucc(OrderInfoDO orderInfoDO);
42 |
43 | /**
44 | * 通知状态改成功
45 | * @param orderInfoDO
46 | * @return
47 | */
48 | int updateOrderNotifyStatusSucc(OrderInfoDO orderInfoDO);
49 | }
50 |
--------------------------------------------------------------------------------
/order-charge-message-protocol/src/main/java/com/snowalker/order/charge/message/protocol/BaseMsg.java:
--------------------------------------------------------------------------------
1 | package com.snowalker.order.charge.message.protocol;
2 |
3 | import org.slf4j.Logger;
4 | import org.slf4j.LoggerFactory;
5 |
6 | /**
7 | * @author snowalker
8 | * @date 2018/9/16
9 | * @desc 基础协议类
10 | */
11 | public abstract class BaseMsg {
12 |
13 | public Logger LOGGER = LoggerFactory.getLogger(this.getClass());
14 |
15 | /**版本号,默认1.0*/
16 | private String version = "1.0";
17 | /**主题名*/
18 | private String topicName;
19 |
20 | public abstract String encode();
21 |
22 | public abstract void decode(String msg);
23 |
24 | public String getVersion() {
25 | return version;
26 | }
27 |
28 | public void setVersion(String version) {
29 | this.version = version;
30 | }
31 |
32 | public String getTopicName() {
33 | return topicName;
34 | }
35 |
36 | public void setTopicName(String topicName) {
37 | this.topicName = topicName;
38 | }
39 |
40 | @Override
41 | public String toString() {
42 | return "BaseMsg{" +
43 | "version='" + version + '\'' +
44 | ", topicName='" + topicName + '\'' +
45 | '}';
46 | }
47 | }
48 |
49 |
50 |
--------------------------------------------------------------------------------
/order-charge-gateway-notify/src/main/java/com/snowalker/notify/common/dao/WalletMapper.java:
--------------------------------------------------------------------------------
1 | package com.snowalker.notify.common.dao;
2 |
3 | import com.snowalker.notify.common.dao.dataobject.ChargeRecordEntity;
4 | import com.snowalker.notify.common.dao.dataobject.OrderEntity;
5 | import com.snowalker.notify.common.dao.dataobject.WalletEntity;
6 | import java.util.Map;
7 |
8 | /**
9 | * @author snowalker
10 | * @version 1.0
11 | * @date 2019/2/18 9:30
12 | * @className WalletMapper
13 | * @desc 钱包Mapper
14 | */
15 | public interface WalletMapper {
16 |
17 | /**
18 | * 新增用户钱包
19 | * @param walletEntity
20 | */
21 | void insertWallet(WalletEntity walletEntity);
22 |
23 | /**
24 | * 更新用户钱包
25 | * @param params
26 | * @return
27 | */
28 | int updateWallet(Map params);
29 |
30 | /**
31 | * 插入扣款流水
32 | */
33 | void insertChargeRecord(Map params);
34 |
35 | /**
36 | * 查询扣款流水
37 | * @param orderEntity
38 | * @return
39 | */
40 | ChargeRecordEntity queryChargeRecordByOrderId(OrderEntity orderEntity);
41 |
42 | /**
43 | * 查询钱包信息
44 | * @param params
45 | * @return
46 | */
47 | WalletEntity queryWalletInfoByPurseId(Map params);
48 | }
49 |
--------------------------------------------------------------------------------
/order-charge-sdk/src/test/java/com/snowalker/AppTest.java:
--------------------------------------------------------------------------------
1 | package com.snowalker;
2 |
3 | import static org.junit.Assert.assertTrue;
4 |
5 | import com.alibaba.fastjson.JSON;
6 | import com.snowalker.order.charge.request.ChargeOrderRequest;
7 | import org.junit.Test;
8 |
9 | import java.text.SimpleDateFormat;
10 | import java.util.Date;
11 | import java.util.UUID;
12 |
13 | /**
14 | * Unit test for simple App.
15 | */
16 | public class AppTest {
17 | /**
18 | * Rigorous Test :-)
19 | */
20 | @Test
21 | public void shouldAnswerWithTrue() {
22 | assertTrue( true );
23 | }
24 |
25 | @Test
26 | public void generateChargeOrderRequestJson() {
27 | ChargeOrderRequest chargeOrderRequest = new ChargeOrderRequest();
28 | chargeOrderRequest.setChannelOrderId(UUID.randomUUID().toString())
29 | .setChargePrice("123.14")
30 | .setMerchantName("SNOWALKER")
31 | .setPurseId("NO00000001")
32 | .setUserPhoneNum("13912312343")
33 | .setTimestamp(new SimpleDateFormat("yyyyMMddHHmmss").format(new Date(System.currentTimeMillis())));
34 | chargeOrderRequest.setSign(chargeOrderRequest.sign("asdaseasdaddada"));
35 | String json = JSON.toJSONString(chargeOrderRequest);
36 | System.out.println(json);
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/order-charge-gateway-notify/src/main/java/com/snowalker/notify/common/config/RestTemplateConfig.java:
--------------------------------------------------------------------------------
1 | package com.snowalker.notify.common.config;
2 |
3 | import org.springframework.context.annotation.Bean;
4 | import org.springframework.context.annotation.Configuration;
5 | import org.springframework.http.client.ClientHttpRequestFactory;
6 | import org.springframework.http.client.SimpleClientHttpRequestFactory;
7 | import org.springframework.web.client.RestTemplate;
8 |
9 | /**
10 | * @author snowalker
11 | * @version 1.0
12 | * @date 2019/6/10 13:37
13 | * @className RestTemplateConfig
14 | * @desc RestTemplate配置
15 | */
16 | @Configuration
17 | public class RestTemplateConfig {
18 |
19 | @Bean
20 | public RestTemplate restTemplate(ClientHttpRequestFactory factory){
21 | return new RestTemplate(factory);
22 | }
23 |
24 | @Bean
25 | public RestTemplate restTemplateNew(ClientHttpRequestFactory factory){
26 | return new RestTemplate(factory);
27 | }
28 |
29 | @Bean
30 | public ClientHttpRequestFactory simpleClientHttpRequestFactory(){
31 | SimpleClientHttpRequestFactory factory = new SimpleClientHttpRequestFactory();
32 | /**读超时单位为ms*/
33 | factory.setReadTimeout(10000);
34 | /**连接超时单位为ms*/
35 | factory.setConnectTimeout(10000);
36 | return factory;
37 | }
38 |
39 | }
40 |
--------------------------------------------------------------------------------
/order-charge-gateway-merchant/src/main/java/com/snowalker/gateway/merchant/order/config/RestTemplateConfig.java:
--------------------------------------------------------------------------------
1 | package com.snowalker.gateway.merchant.order.config;
2 |
3 | import org.springframework.context.annotation.Bean;
4 | import org.springframework.context.annotation.Configuration;
5 | import org.springframework.http.client.ClientHttpRequestFactory;
6 | import org.springframework.http.client.SimpleClientHttpRequestFactory;
7 | import org.springframework.web.client.RestTemplate;
8 |
9 | /**
10 | * @author snowalker
11 | * @version 1.0
12 | * @date 2019/6/10 13:37
13 | * @className RestTemplateConfig
14 | * @desc RestTemplate配置
15 | */
16 | @Configuration
17 | public class RestTemplateConfig {
18 |
19 | @Bean
20 | public RestTemplate restTemplate(ClientHttpRequestFactory factory){
21 | return new RestTemplate(factory);
22 | }
23 |
24 | @Bean
25 | public RestTemplate restTemplateNew(ClientHttpRequestFactory factory){
26 | return new RestTemplate(factory);
27 | }
28 |
29 | @Bean
30 | public ClientHttpRequestFactory simpleClientHttpRequestFactory(){
31 | SimpleClientHttpRequestFactory factory = new SimpleClientHttpRequestFactory();
32 | /**读超时单位为ms*/
33 | factory.setReadTimeout(10000);
34 | /**连接超时单位为ms*/
35 | factory.setConnectTimeout(10000);
36 | return factory;
37 | }
38 |
39 | }
40 |
--------------------------------------------------------------------------------
/order-charge-gateway-server/src/main/java/com/snowalker/order/common/config/ProductVO.java:
--------------------------------------------------------------------------------
1 | package com.snowalker.order.common.config;
2 |
3 | /**
4 | * @author snowalker
5 | * @version 1.0
6 | * @date 2019/6/10 9:45
7 | * @className ProductBean
8 | * @desc 商品配置领域
9 | */
10 | public class ProductVO {
11 |
12 | /**商品id*/
13 | private String productId;
14 | /**商品名*/
15 | private String productName;
16 | /**商品库存*/
17 | private Integer productStock;
18 |
19 | public String getProductId() {
20 | return productId;
21 | }
22 |
23 | public ProductVO setProductId(String productId) {
24 | this.productId = productId;
25 | return this;
26 | }
27 |
28 | public String getProductName() {
29 | return productName;
30 | }
31 |
32 | public ProductVO setProductName(String productName) {
33 | this.productName = productName;
34 | return this;
35 | }
36 |
37 | public Integer getProductStock() {
38 | return productStock;
39 | }
40 |
41 | public ProductVO setProductStock(Integer productStock) {
42 | this.productStock = productStock;
43 | return this;
44 | }
45 |
46 | @Override
47 | public String toString() {
48 | return "ProductVO{" +
49 | "productId='" + productId + '\'' +
50 | ", productName='" + productName + '\'' +
51 | ", productStock=" + productStock +
52 | '}';
53 | }
54 | }
55 |
--------------------------------------------------------------------------------
/order-charge-gateway-server/src/main/java/com/snowalker/order/common/config/ProductConfig.java:
--------------------------------------------------------------------------------
1 | package com.snowalker.order.common.config;
2 |
3 | import com.alibaba.fastjson.JSON;
4 | import org.slf4j.Logger;
5 | import org.slf4j.LoggerFactory;
6 | import org.springframework.context.annotation.Configuration;
7 |
8 | import javax.annotation.PostConstruct;
9 | import java.util.Map;
10 | import java.util.concurrent.ConcurrentHashMap;
11 |
12 | /**
13 | * @author snowalker
14 | * @version 1.0
15 | * @date 2019/6/10 9:41
16 | * @className GoodsConfig
17 | * @desc 商品配置
18 | * prod_id:BJ_SY_JJC_01
19 | * prod_name:南航北京-三亚经济舱
20 | * prod_stock:999
21 | */
22 | @Configuration
23 | public class ProductConfig {
24 |
25 | private static final Logger LOGGER = LoggerFactory.getLogger(ProductConfig.class);
26 |
27 | private static final Map PRODUCTS_MAP = new ConcurrentHashMap<>(16);
28 |
29 | @PostConstruct
30 | public void init() {
31 | ProductVO productVO = new ProductVO();
32 | String productId = "BJ_SY_JJC_01";
33 | productVO.setProductId(productId)
34 | .setProductName("南航北京-三亚经济舱")
35 | .setProductStock(200);
36 | PRODUCTS_MAP.put(productId, productVO);
37 | LOGGER.info("平台商品配置加载完毕,productConfig={}", JSON.toJSONString(PRODUCTS_MAP));
38 | }
39 |
40 | public static Map getProductsMap() {
41 | return PRODUCTS_MAP;
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/readme.md:
--------------------------------------------------------------------------------
1 | # Readme
2 |
3 | > 场景为:示例项目以客户端模拟下单成功,下单成功后服务端回调客户端修改订单状态场景进行讲解。
4 | 即:模拟下单并处理异步通知
5 |
6 | ## 主要技术
7 |
8 | 消息队列(RocketMQ): 作用,长流程异步化,提升吞吐量,削峰填谷
9 | |-普通消息的发布及订阅
10 | |-事务消息的发布及订阅
11 | 线程池
12 | |-事务消息回查
13 | SpringBoot
14 | |-配置资源预加载
15 | RestTemplate
16 | |-application/json格式数据的发送
17 | |-application/x-www-form-urlencoded格式数据的发送
18 |
19 | ## 思路
20 |
21 | 业务流程图如下
22 |
23 | 
24 |
25 |
26 | ## 模块描述
27 |
28 | | 模块 | 说明 |
29 | | :------ | :------ |
30 | | order-charge-gateway-merchant | 商户收单网关,2C业务,对用户提供下单接口;提供对下单平台的充值回调接口 |
31 | | order-charge-gateway-server | 核心收单平台,2B业务,进行业务正式下单,下单完成后投递通知消息到MQ |
32 | | order-charge-gateway-notify | 核心通知平台,消费通知消息发送通知到order-charge-gateway-merchant的回调接口 |
33 | | order-charge-message-protocol | 消息协议封装 |
34 | | order-charge-sdk | HTTP下单接口sdk及通知sdk |
35 | | script | 数据库初始化脚本 |
36 |
37 | ## 业务描述
38 | 1. 用户访问第三方售票网关,进行购票操作。用户发起下单操作,执行支付转账操作
39 |
40 | 扣减用户账户,增加商户账户金额
41 |
42 | 2. 转账完成之后,商户发起下单操作,售票平台进行下单操作及扣款操作,(此处为讲解重点-- **事务消息,分布式事务场景**)返回订单提交成功
43 | 3. 售票平台下单扣款完成后,认为售票成功,则返回结果通知给第三方售票网关(此处为讲解重点-- **普通消息,异步通知**)
44 | 4. 第三方售票网关自行给用户通知即可,未实现
45 |
46 | > 注意:商品信息直接在初始化的时候记载到第三方售票网关和售票平台的缓存中即可。
47 |
48 |
49 | ## 说明
50 |
51 | 下单与扣款通过事务消息保证一致性,保证成功率
52 |
53 | 通知过程通过MQ进行异步解耦,使用普通消息即可,因为通知过程本身是为了最大努力送达,属于最终一致性的范畴,不要求数据的强一致性。
54 |
55 | 如果通知达到上限阈值,则停止通知,等待商户侧发起主动查询即可。通过通知回调+主动查询,能够在跨网络的交易场景下,实现端与端之间的订单状态的最终一致。
56 |
57 | 在平台内部,跨服务之间的分布式事务,通过RMQ的事务消息得到保证,事务消息原理可简单介绍。
58 |
59 |
--------------------------------------------------------------------------------
/order-charge-gateway-merchant/src/main/java/com/snowalker/gateway/merchant/order/handler/GlobalExceptionHandler.java:
--------------------------------------------------------------------------------
1 | package com.snowalker.gateway.merchant.order.handler;
2 |
3 | import com.alibaba.fastjson.JSON;
4 | import com.snowalker.gateway.merchant.order.dto.CodeMsg;
5 | import com.snowalker.gateway.merchant.order.dto.Result;
6 | import com.snowalker.gateway.merchant.order.exception.ApiException;
7 | import org.springframework.validation.BindException;
8 | import org.springframework.validation.ObjectError;
9 | import org.springframework.web.bind.annotation.ControllerAdvice;
10 | import org.springframework.web.bind.annotation.ExceptionHandler;
11 | import org.springframework.web.bind.annotation.ResponseBody;
12 |
13 | import java.util.List;
14 |
15 | /**
16 | * @author snowalker
17 | * 全局异常解析
18 | */
19 | @ControllerAdvice
20 | @ResponseBody
21 | public class GlobalExceptionHandler {
22 |
23 | @ExceptionHandler(value = Exception.class)
24 | public Result exceptionHandler(Exception e){
25 | if (e instanceof ApiException) {
26 | ApiException apiException = (ApiException) e;
27 | return Result.error(apiException.getCodeMsg());
28 | } else if(e instanceof BindException) {
29 | BindException ex = (BindException)e;
30 | List errors = ex.getAllErrors();
31 | ObjectError error = errors.get(0);
32 | String msg = error.getDefaultMessage();
33 | return Result.error(CodeMsg.BIND_ERROR.fillArgs(msg));
34 | } else {
35 | return Result.error(CodeMsg.SERVER_ERROR);
36 | }
37 | }
38 | }
--------------------------------------------------------------------------------
/order-charge-gateway-server/src/main/java/com/snowalker/order/common/dto/Result.java:
--------------------------------------------------------------------------------
1 | package com.snowalker.order.common.dto;
2 |
3 | /**
4 | * 返回体包装
5 | * @author snowalker
6 | * @param
7 | */
8 | public class Result {
9 |
10 | private String code;
11 | private String msg;
12 | private T data;
13 |
14 | /**
15 | * 失败时候的调用
16 | */
17 | public static Result error(CodeMsg codeMsg) {
18 | return new Result(codeMsg);
19 | }
20 |
21 | public Result(T data) {
22 | this.data = data;
23 | }
24 |
25 | public Result(String code, String msg) {
26 | this.code = code;
27 | this.msg = msg;
28 | }
29 |
30 | public Result(String code, String msg, T t) {
31 | this.code = code;
32 | this.msg = msg;
33 | this.data = t;
34 | }
35 |
36 | private Result(CodeMsg codeMsg) {
37 | if (codeMsg != null) {
38 | this.code = codeMsg.getCode();
39 | this.msg = codeMsg.getMsg();
40 | this.data = null;
41 | }
42 | }
43 |
44 | public String getCode() {
45 | return code;
46 | }
47 |
48 | public Result setCode(String code) {
49 | this.code = code;
50 | return this;
51 | }
52 |
53 | public String getMsg() {
54 | return msg;
55 | }
56 |
57 | public Result setMsg(String msg) {
58 | this.msg = msg;
59 | return this;
60 | }
61 |
62 | public T getData() {
63 | return data;
64 | }
65 |
66 | public Result setData(T data) {
67 | this.data = data;
68 | return this;
69 | }
70 | }
--------------------------------------------------------------------------------
/order-charge-gateway-merchant/src/main/java/com/snowalker/gateway/merchant/order/dto/Result.java:
--------------------------------------------------------------------------------
1 | package com.snowalker.gateway.merchant.order.dto;
2 |
3 | /**
4 | * 返回体包装
5 | * @author snowalker
6 | * @param
7 | */
8 | public class Result {
9 |
10 | private String code;
11 | private String msg;
12 | private T data;
13 |
14 | /**
15 | * 失败时候的调用
16 | */
17 | public static Result error(CodeMsg codeMsg) {
18 | return new Result(codeMsg);
19 | }
20 |
21 | public Result(T data) {
22 | this.data = data;
23 | }
24 |
25 | public Result(String code, String msg) {
26 | this.code = code;
27 | this.msg = msg;
28 | }
29 |
30 | public Result(String code, String msg, T t) {
31 | this.code = code;
32 | this.msg = msg;
33 | this.data = t;
34 | }
35 |
36 | private Result(CodeMsg codeMsg) {
37 | if (codeMsg != null) {
38 | this.code = codeMsg.getCode();
39 | this.msg = codeMsg.getMsg();
40 | this.data = null;
41 | }
42 | }
43 |
44 | public String getCode() {
45 | return code;
46 | }
47 |
48 | public Result setCode(String code) {
49 | this.code = code;
50 | return this;
51 | }
52 |
53 | public String getMsg() {
54 | return msg;
55 | }
56 |
57 | public Result setMsg(String msg) {
58 | this.msg = msg;
59 | return this;
60 | }
61 |
62 | public T getData() {
63 | return data;
64 | }
65 |
66 | public Result setData(T data) {
67 | this.data = data;
68 | return this;
69 | }
70 | }
--------------------------------------------------------------------------------
/order-charge-gateway-merchant/src/main/java/com/snowalker/gateway/merchant/order/service/OrderService.java:
--------------------------------------------------------------------------------
1 | package com.snowalker.gateway.merchant.order.service;
2 |
3 | import com.snowalker.gateway.merchant.order.dataobject.ChargeOrderDO;
4 | import com.snowalker.gateway.merchant.order.dto.ChargeOrderDto;
5 | import com.snowalker.gateway.merchant.order.dto.Result;
6 |
7 | import java.sql.SQLException;
8 |
9 | /**
10 | * @author snowalker
11 | * @version 1.0
12 | * @date 2019/6/10 11:48
13 | * @className OrderService
14 | * @desc 订单交易
15 | */
16 | public interface OrderService {
17 |
18 | /**
19 | * 下单
20 | * @param phoneNum
21 | * @param chargeMoney
22 | * @param prodId
23 | * @return
24 | */
25 | Result chargeOrder(String phoneNum, String chargeMoney, String prodId);
26 |
27 | /**
28 | * 本地订单入库
29 | * @param chargeOrderDto
30 | * @return
31 | */
32 | boolean insertOrderInfo(ChargeOrderDto chargeOrderDto);
33 |
34 | /**
35 | * 订单状态更新
36 | * @param chargeOrderDto
37 | * @return
38 | */
39 | boolean updateOrderStatus(ChargeOrderDto chargeOrderDto);
40 |
41 | /**
42 | * 订单详情查询
43 | * @param channelOrderId
44 | * @return
45 | */
46 | ChargeOrderDO queryOrderByOrderId(String channelOrderId) throws SQLException;
47 |
48 | /**
49 | * 通知逻辑
50 | * @param sessionId
51 | * @param orderStatus
52 | * @param channelOrderId
53 | * @param platOrderId
54 | * @param finishTime
55 | * @return
56 | */
57 | String doNotify(String sessionId, String orderStatus, String channelOrderId, String platOrderId, String finishTime);
58 | }
59 |
60 |
--------------------------------------------------------------------------------
/order-charge-message-protocol/src/main/java/com/snowalker/order/charge/message/constant/MessageProtocolConst.java:
--------------------------------------------------------------------------------
1 | package com.snowalker.order.charge.message.constant;
2 |
3 | /**
4 | * @author snowalker
5 | * @version 1.0
6 | * @date 2019/6/11 14:45
7 | * @className MessageProtocolConst
8 | * @desc 消息协议常量
9 | */
10 | public enum MessageProtocolConst {
11 |
12 | /**WALLET_PAYMENT_TOPIC 钱包扣款协议*/
13 | WALLET_PAYMENT_TOPIC("WALLET_PAYMENT_TOPIC", "PID_WALLET_PAYMENT", "CID_WALLET_PAYMENT", "钱包扣款协议"),
14 | /**ORDER_STATUS_UPDATE_TOPIC 订单状态修改协议*/
15 | ORDER_STATUS_UPDATE_TOPIC("ORDER_STATUS_UPDATE_TOPIC", "PID_ORDER_STATUS_UPDATE", "CID_ORDER_STATUS_UPDATE", "订单状态修改协议"),
16 | /**ORDER_RESULT_NOTIFY_TOPIC 订单结果通知协议*/
17 | ORDER_RESULT_NOTIFY_TOPIC("ORDER_RESULT_NOTIFY_TOPIC", "PID_ORDER_RESULT_NOTIFY", "CID_ORDER_RESULT_NOTIFY", "订单结果通知协议")
18 | ;
19 | /**消息主题*/
20 | private String topic;
21 | /**生产者组*/
22 | private String producerGroup;
23 | /**消费者组*/
24 | private String consumerGroup;
25 | /**消息描述*/
26 | private String desc;
27 |
28 | MessageProtocolConst(String topic, String producerGroup, String consumerGroup, String desc) {
29 | this.topic = topic;
30 | this.producerGroup = producerGroup;
31 | this.consumerGroup = consumerGroup;
32 | this.desc = desc;
33 | }
34 |
35 | public String getTopic() {
36 | return topic;
37 | }
38 |
39 | public String getProducerGroup() {
40 | return producerGroup;
41 | }
42 |
43 | public String getDesc() {
44 | return desc;
45 | }
46 |
47 | public String getConsumerGroup() {
48 | return consumerGroup;
49 | }}
50 |
--------------------------------------------------------------------------------
/order-charge-gateway-server/src/main/java/com/snowalker/order/common/dto/CodeMsg.java:
--------------------------------------------------------------------------------
1 | package com.snowalker.order.common.dto;
2 |
3 | /**
4 | * @author snowalker
5 | * 错误码封装
6 | */
7 | public class CodeMsg {
8 |
9 | private String code;
10 | private String msg;
11 |
12 | /**通用的错误码*/
13 | public static CodeMsg SUCCESS = new CodeMsg("10000", "SUCCESS");
14 | public static CodeMsg UNKNOWN_ERROR = new CodeMsg("40004", "UNKNOWN_ERROR");
15 | public static CodeMsg SERVER_ERROR = new CodeMsg("40004", "服务端异常");
16 | public static CodeMsg BIND_ERROR = new CodeMsg("40006", "参数校验异常:s%");
17 | /**订单入库失败*/
18 | public static CodeMsg INSERT_ORDER_ERROR = new CodeMsg("40009", "订单入库异常");
19 | /**参数非法*/
20 | public static final String PARAM_ILLEGAL = "40006";
21 | /**产品不存在*/
22 | public static final String PRODUCT_NOT_EXIST = "40007";
23 | /**库存不足*/
24 | public static final String PRODUCT_STOCK_NOT_ENOUGH = "40008";
25 |
26 | public CodeMsg( ) {
27 | }
28 |
29 | public CodeMsg(String code, String msg ) {
30 | this.code = code;
31 | this.msg = msg;
32 | }
33 |
34 | public String getCode() {
35 | return code;
36 | }
37 |
38 | public CodeMsg setCode(String code) {
39 | this.code = code;
40 | return this;
41 | }
42 |
43 | public String getMsg() {
44 | return msg;
45 | }
46 |
47 | public CodeMsg setMsg(String msg) {
48 | this.msg = msg;
49 | return this;
50 | }
51 |
52 | public CodeMsg fillArgs(Object ... args) {
53 | String code = this.code;
54 | String message = String.format(this.msg, args);
55 | return new CodeMsg(code, message);
56 | }
57 |
58 | @Override
59 | public String toString() {
60 | return "CodeMsg [code=" + code + ", msg=" + msg + "]";
61 | }
62 |
63 | }
--------------------------------------------------------------------------------
/order-charge-gateway-server/src/main/java/com/snowalker/order/common/service/OrderChargeService.java:
--------------------------------------------------------------------------------
1 | package com.snowalker.order.common.service;
2 |
3 | import com.snowalker.order.charge.request.ChargeOrderRequest;
4 | import com.snowalker.order.common.dao.dataobject.OrderInfoDO;
5 | import com.snowalker.order.common.dao.dataobject.OrderInfoDobj;
6 | import com.snowalker.order.common.dto.Result;
7 |
8 | /**
9 | * @author snowalker
10 | * @version 1.0
11 | * @date 2019/6/11 15:12
12 | * @className OrderChargeService
13 | * @desc
14 | */
15 | public interface OrderChargeService {
16 |
17 | /**
18 | * 下单前置校验
19 | * @param chargeOrderRequest
20 | * @param sessionId
21 | * @return
22 | */
23 | boolean checkValidBeforeChargeOrder(ChargeOrderRequest chargeOrderRequest, String sessionId);
24 |
25 | /**
26 | * 下单并发送扣款事务消息
27 | * @param chargeOrderRequest
28 | * @param sessionId
29 | * @return
30 | */
31 | Result sendPaymentTransactionMsg(ChargeOrderRequest chargeOrderRequest, String sessionId);
32 |
33 | /**
34 | * 订单入库
35 | * @param orderInfoDO
36 | * @return
37 | */
38 | boolean insertOrder(OrderInfoDO orderInfoDO);
39 |
40 | /**
41 | * 订单查询
42 | * @param orderInfoDO
43 | * @return
44 | */
45 | OrderInfoDobj queryOrderInfo(OrderInfoDO orderInfoDO);
46 |
47 | /**
48 | * 订单状态修改为处理中
49 | * @param orderInfoDO
50 | * @return
51 | */
52 | boolean updateOrderDealing(OrderInfoDO orderInfoDO);
53 |
54 | /**
55 | * 支付状态修改为成功
56 | * @param orderInfoDO
57 | * @return
58 | */
59 | boolean updateOrderPayStatusSucc(OrderInfoDO orderInfoDO);
60 |
61 | /**
62 | * 订单通知状态修改成功
63 | * @param orderInfoDO
64 | * @return
65 | */
66 | boolean updateOrderNotifyStatusSucc(OrderInfoDO orderInfoDO);
67 | }
68 |
--------------------------------------------------------------------------------
/order-charge-gateway-server/src/main/java/com/snowalker/order/mq/notify/producer/OrderNotifySendProducer.java:
--------------------------------------------------------------------------------
1 | package com.snowalker.order.mq.notify.producer;
2 |
3 | import com.snowalker.order.charge.message.constant.MessageProtocolConst;
4 | import com.snowalker.order.common.util.LogExceptionWapper;
5 | import org.apache.rocketmq.client.exception.MQClientException;
6 | import org.apache.rocketmq.client.producer.DefaultMQProducer;
7 | import org.slf4j.Logger;
8 | import org.slf4j.LoggerFactory;
9 | import org.springframework.beans.factory.annotation.Value;
10 | import org.springframework.stereotype.Component;
11 |
12 | import javax.annotation.PostConstruct;
13 |
14 | /**
15 | * @author snowalker
16 | * @version 1.0
17 | * @date 2019/6/12 11:35
18 | * @className SendOrderNotifyProducer
19 | * @desc 订单通知发送生产者
20 | */
21 | @Component
22 | public class OrderNotifySendProducer {
23 |
24 | private static final Logger LOGGER = LoggerFactory.getLogger(OrderNotifySendProducer.class);
25 |
26 | @Value("${rocketmq.nameServer}")
27 | String nameSrvAddr;
28 |
29 | private DefaultMQProducer defaultMQProducer;
30 |
31 | @PostConstruct
32 | public void init() {
33 |
34 | defaultMQProducer =
35 | new DefaultMQProducer(MessageProtocolConst.ORDER_RESULT_NOTIFY_TOPIC.getProducerGroup());
36 | defaultMQProducer.setNamesrvAddr(nameSrvAddr);
37 | try {
38 | defaultMQProducer.start();
39 | } catch (MQClientException e) {
40 | LOGGER.error("[订单通知发送生产者]--OrderNotifySendProducer加载异常!e={}", LogExceptionWapper.getStackTrace(e));
41 | throw new RuntimeException("[订单通知发送生产者]--OrderNotifySendProducer加载异常!", e);
42 | }
43 | LOGGER.info("[订单通知发送生产者]--OrderNotifySendProducer加载完成!");
44 | }
45 |
46 | public DefaultMQProducer getProducer() {
47 | return defaultMQProducer;
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/order-charge-gateway-server/src/main/java/com/snowalker/order/common/config/MerchantInfoConfig.java:
--------------------------------------------------------------------------------
1 | package com.snowalker.order.common.config;
2 |
3 | import com.alibaba.fastjson.JSON;
4 | import com.snowalker.order.common.dao.dataobject.MerchantInfoDO;
5 | import com.snowalker.order.common.service.MerchantInfoService;
6 | import org.slf4j.Logger;
7 | import org.slf4j.LoggerFactory;
8 | import org.springframework.beans.factory.annotation.Autowired;
9 | import org.springframework.stereotype.Component;
10 |
11 | import javax.annotation.PostConstruct;
12 | import javax.annotation.Resource;
13 | import java.util.List;
14 | import java.util.Map;
15 | import java.util.concurrent.ConcurrentHashMap;
16 |
17 | /**
18 | * @author snowalker
19 | * @version 1.0
20 | * @date 2019/6/11 14:10
21 | * @className MerchantInfoConfig
22 | * @desc
23 | */
24 | @Component
25 | public class MerchantInfoConfig {
26 |
27 | private static final Logger LOGGER = LoggerFactory.getLogger(MerchantInfoConfig.class);
28 |
29 | private static final Map MERCHANTS_MAP = new ConcurrentHashMap<>(16);
30 |
31 | @Resource(name = "merchantInfoService")
32 | MerchantInfoService merchantInfoService;
33 |
34 | @PostConstruct
35 | public void init() {
36 |
37 | List list = merchantInfoService.queryMerchantList();
38 | if (list != null && list.size() > 0) {
39 | list.stream().forEach((merchantInfoDO -> {
40 | String key = merchantInfoDO.getMerchantPurseId();
41 | MERCHANTS_MAP.put(key, merchantInfoDO);
42 | }));
43 | LOGGER.info("商户配置信息初始化完成,MERCHANTS_MAP={}", JSON.toJSONString(MERCHANTS_MAP));
44 | } else {
45 | LOGGER.info("商户配置信息为空, 请及时添加");
46 | }
47 | }
48 |
49 | public static Map getMerchantsMap() {
50 | return MERCHANTS_MAP;
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/order-charge-gateway-merchant/src/main/java/com/snowalker/gateway/merchant/goods/ProductConfig.java:
--------------------------------------------------------------------------------
1 | package com.snowalker.gateway.merchant.goods;
2 |
3 | import com.alibaba.fastjson.JSON;
4 | import org.slf4j.Logger;
5 | import org.slf4j.LoggerFactory;
6 | import org.springframework.context.annotation.Configuration;
7 |
8 | import javax.annotation.PostConstruct;
9 | import java.util.Map;
10 | import java.util.concurrent.ConcurrentHashMap;
11 |
12 | /**
13 | * @author snowalker
14 | * @version 1.0
15 | * @date 2019/6/10 9:41
16 | * @className GoodsConfig
17 | * @desc 商品配置
18 | * prod_id:0001
19 | * prod_name:南方航空北京-三亚经济舱
20 | * prod_stock:100
21 | * prod_out_id:BJ_SY_JJC_01
22 | * prod_out_name:南航北京-三亚经济舱
23 | *
24 | * prod_id:BJ_SY_JJC_01
25 | * prod_name:南航北京-三亚经济舱
26 | * prod_stock:999
27 | */
28 | @Configuration
29 | public class ProductConfig {
30 |
31 | private static final Logger LOGGER = LoggerFactory.getLogger(ProductConfig.class);
32 |
33 | private static final Map PRODUCTS_MAP = new ConcurrentHashMap<>(16);
34 |
35 | /**渠道id:南方航空*/
36 | public static final String CHANNEL_ID_CHINA_CSAIR = "CHINA_CSAIR";
37 |
38 | @PostConstruct
39 | public void init() {
40 | ProductVO productVO = new ProductVO();
41 | String productId = "0001";
42 | productVO.setProductId(productId)
43 | .setProductName("南方航空北京-三亚经济舱")
44 | .setProductOutId("BJ_SY_JJC_01")
45 | .setProductOutName("南航北京-三亚经济舱")
46 | .setProductStock(100)
47 | .setProductChannelId(CHANNEL_ID_CHINA_CSAIR);
48 | PRODUCTS_MAP.put(productId, productVO);
49 | LOGGER.info("渠道商品配置加载完毕,productConfig={}", JSON.toJSONString(PRODUCTS_MAP));
50 | }
51 |
52 | public static Map getProductsMap() {
53 | return PRODUCTS_MAP;
54 | }
55 | }
56 |
--------------------------------------------------------------------------------
/order-charge-sdk/order-charge-sdk.iml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
--------------------------------------------------------------------------------
/order-charge-gateway-server/src/main/java/com/snowalker/order/common/dao/dataobject/MerchantInfoDO.java:
--------------------------------------------------------------------------------
1 | package com.snowalker.order.common.dao.dataobject;
2 |
3 | /**
4 | * @author snowalker
5 | * @version 1.0
6 | * @date 2019/6/11 14:15
7 | * @className MerchantInfoDO
8 | * @desc 商户配置信息
9 | */
10 | public class MerchantInfoDO {
11 |
12 | private String merchantPurseId;
13 | private String merchantName;
14 | private String merchantNotifyUrl;
15 | private String merchantPrivateKey;
16 |
17 | public String getMerchantPurseId() {
18 | return merchantPurseId;
19 | }
20 |
21 | public MerchantInfoDO setMerchantPurseId(String merchantPurseId) {
22 | this.merchantPurseId = merchantPurseId;
23 | return this;
24 | }
25 |
26 | public String getMerchantName() {
27 | return merchantName;
28 | }
29 |
30 | public MerchantInfoDO setMerchantName(String merchantName) {
31 | this.merchantName = merchantName;
32 | return this;
33 | }
34 |
35 | public String getMerchantNotifyUrl() {
36 | return merchantNotifyUrl;
37 | }
38 |
39 | public MerchantInfoDO setMerchantNotifyUrl(String merchantNotifyUrl) {
40 | this.merchantNotifyUrl = merchantNotifyUrl;
41 | return this;
42 | }
43 |
44 | public String getMerchantPrivateKey() {
45 | return merchantPrivateKey;
46 | }
47 |
48 | public MerchantInfoDO setMerchantPrivateKey(String merchantPrivateKey) {
49 | this.merchantPrivateKey = merchantPrivateKey;
50 | return this;
51 | }
52 |
53 | @Override
54 | public String toString() {
55 | return "MerchantInfoDO{" +
56 | "merchantPurseId='" + merchantPurseId + '\'' +
57 | ", merchantName='" + merchantName + '\'' +
58 | ", merchantNotifyUrl='" + merchantNotifyUrl + '\'' +
59 | ", merchantPrivateKey='" + merchantPrivateKey + '\'' +
60 | '}';
61 | }
62 | }
63 |
--------------------------------------------------------------------------------
/order-charge-gateway-merchant/src/main/java/com/snowalker/gateway/merchant/order/dto/CodeMsg.java:
--------------------------------------------------------------------------------
1 | package com.snowalker.gateway.merchant.order.dto;
2 |
3 | /**
4 | * @author snowalker
5 | * 错误码封装
6 | */
7 | public class CodeMsg {
8 |
9 | private String code;
10 | private String msg;
11 |
12 | /**通用的错误码*/
13 | public static CodeMsg SUCCESS = new CodeMsg("10000", "SUCCESS");
14 | public static CodeMsg UNKNOWN_ERROR = new CodeMsg("40004", "UNKNOWN_ERROR");
15 | public static CodeMsg SERVER_ERROR = new CodeMsg("40004", "服务端异常");
16 | public static CodeMsg BIND_ERROR = new CodeMsg("40006", "参数校验异常:s%");
17 | /**订单入库失败*/
18 | public static CodeMsg INSERT_ORDER_ERROR = new CodeMsg("40004", "订单入库异常");
19 | public static CodeMsg UPDATE_ORDER_ERROR = new CodeMsg("40004", "订单入库异常");
20 | public static CodeMsg CHARGE_ORDER_FAIL = new CodeMsg("20000", "下单失败");
21 | /**参数非法*/
22 | public static final String PARAM_ILLEGAL = "40006";
23 | /**产品不存在*/
24 | public static final String PRODUCT_NOT_EXIST = "40007";
25 | /**库存不足*/
26 | public static final String PRODUCT_STOCK_NOT_ENOUGH = "40008";
27 |
28 | public CodeMsg( ) {
29 | }
30 |
31 | public CodeMsg(String code, String msg ) {
32 | this.code = code;
33 | this.msg = msg;
34 | }
35 |
36 | public String getCode() {
37 | return code;
38 | }
39 |
40 | public CodeMsg setCode(String code) {
41 | this.code = code;
42 | return this;
43 | }
44 |
45 | public String getMsg() {
46 | return msg;
47 | }
48 |
49 | public CodeMsg setMsg(String msg) {
50 | this.msg = msg;
51 | return this;
52 | }
53 |
54 | public CodeMsg fillArgs(Object ... args) {
55 | String code = this.code;
56 | String message = String.format(this.msg, args);
57 | return new CodeMsg(code, message);
58 | }
59 |
60 | @Override
61 | public String toString() {
62 | return "CodeMsg [code=" + code + ", msg=" + msg + "]";
63 | }
64 |
65 | }
--------------------------------------------------------------------------------
/order-charge-gateway-server/src/main/java/com/snowalker/order/portal/OrderChargeController.java:
--------------------------------------------------------------------------------
1 | package com.snowalker.order.portal;
2 |
3 | import com.snowalker.order.common.dto.Result;
4 | import com.snowalker.order.charge.request.ChargeOrderRequest;
5 | import com.snowalker.order.common.service.OrderChargeService;
6 | import org.slf4j.Logger;
7 | import org.slf4j.LoggerFactory;
8 | import org.springframework.stereotype.Controller;
9 | import org.springframework.web.bind.annotation.RequestBody;
10 | import org.springframework.web.bind.annotation.RequestMapping;
11 | import org.springframework.web.bind.annotation.RequestMethod;
12 | import org.springframework.web.bind.annotation.ResponseBody;
13 | import org.springframework.web.context.request.RequestContextHolder;
14 | import org.springframework.web.context.request.ServletRequestAttributes;
15 |
16 | import javax.annotation.Resource;
17 |
18 | /**
19 | * @author snowalker
20 | * @version 1.0
21 | * @date 2019/6/10 16:13
22 | * @className OrderChargeController
23 | * @desc 订单充值接口
24 | */
25 | @Controller
26 | @RequestMapping("api")
27 | public class OrderChargeController {
28 |
29 | private static final Logger LOGGER = LoggerFactory.getLogger(OrderChargeController.class);
30 |
31 | @Resource(name = "orderChargeService")
32 | OrderChargeService orderChargeService;
33 |
34 | /**
35 | * 平台下单接口
36 | * @param chargeOrderRequest
37 | * @return
38 | */
39 | @RequestMapping(value = "charge.do", method = {RequestMethod.POST})
40 | public @ResponseBody Result chargeRequst(@RequestBody ChargeOrderRequest chargeOrderRequest) {
41 | ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
42 | String sessionId = attributes.getSessionId();
43 | // 下单前置校验
44 | if (!orderChargeService.checkValidBeforeChargeOrder(chargeOrderRequest, sessionId)) {
45 | return new Result("20000", "FAIL", null);
46 | }
47 | return orderChargeService.sendPaymentTransactionMsg(chargeOrderRequest, sessionId);
48 | }
49 |
50 | }
51 |
--------------------------------------------------------------------------------
/order-charge-message-protocol/order-charge-message-protocol.iml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/order-charge-sdk/src/main/java/com/snowalker/order/charge/response/ChargeOrderResponse.java:
--------------------------------------------------------------------------------
1 | package com.snowalker.order.charge.response;
2 |
3 | import java.io.Serializable;
4 |
5 | /**
6 | * @author snowalker
7 | * @version 1.0
8 | * @date 2019/6/10 16:03
9 | * @className ChargeOrderResponse
10 | * @desc 下单sdk接口返回参数
11 | */
12 | public class ChargeOrderResponse implements Serializable {
13 |
14 | private static final long serialVersionUID = -5685058946404699059L;
15 |
16 | /**商户订单号*/
17 | private String channelOrderId;
18 | private String userPhoneNum;
19 | private String chargePrice;
20 | private String merchantName;
21 | /**票务服务订单号*/
22 | private String platOrderId;
23 |
24 | public String getChannelOrderId() {
25 | return channelOrderId;
26 | }
27 |
28 | public ChargeOrderResponse setChannelOrderId(String channelOrderId) {
29 | this.channelOrderId = channelOrderId;
30 | return this;
31 | }
32 |
33 | public String getUserPhoneNum() {
34 | return userPhoneNum;
35 | }
36 |
37 | public ChargeOrderResponse setUserPhoneNum(String userPhoneNum) {
38 | this.userPhoneNum = userPhoneNum;
39 | return this;
40 | }
41 |
42 | public String getChargePrice() {
43 | return chargePrice;
44 | }
45 |
46 | public ChargeOrderResponse setChargePrice(String chargePrice) {
47 | this.chargePrice = chargePrice;
48 | return this;
49 | }
50 |
51 | public String getMerchantName() {
52 | return merchantName;
53 | }
54 |
55 | public ChargeOrderResponse setMerchantName(String merchantName) {
56 | this.merchantName = merchantName;
57 | return this;
58 | }
59 |
60 | public String getPlatOrderId() {
61 | return platOrderId;
62 | }
63 |
64 | public ChargeOrderResponse setPlatOrderId(String platOrderId) {
65 | this.platOrderId = platOrderId;
66 | return this;
67 | }
68 |
69 | @Override
70 | public String toString() {
71 | return "ChargeOrderResponse{" +
72 | "channelOrderId='" + channelOrderId + '\'' +
73 | ", userPhoneNum='" + userPhoneNum + '\'' +
74 | ", chargePrice='" + chargePrice + '\'' +
75 | ", merchantName='" + merchantName + '\'' +
76 | ", platOrderId='" + platOrderId + '\'' +
77 | '}';
78 | }
79 | }
80 |
--------------------------------------------------------------------------------
/order-charge-gateway-merchant/src/main/java/com/snowalker/gateway/merchant/order/OrderChargeController.java:
--------------------------------------------------------------------------------
1 | package com.snowalker.gateway.merchant.order;
2 |
3 | import com.alibaba.fastjson.JSON;
4 | import com.snowalker.gateway.merchant.order.dto.CodeMsg;
5 | import com.snowalker.gateway.merchant.order.dto.Result;
6 | import com.snowalker.gateway.merchant.order.handler.RequestParamValidateHandler;
7 | import com.snowalker.gateway.merchant.order.service.OrderService;
8 | import org.slf4j.Logger;
9 | import org.slf4j.LoggerFactory;
10 | import org.springframework.beans.factory.annotation.Autowired;
11 | import org.springframework.stereotype.Controller;
12 | import org.springframework.web.bind.annotation.RequestMapping;
13 | import org.springframework.web.bind.annotation.RequestMethod;
14 | import org.springframework.web.bind.annotation.ResponseBody;
15 |
16 | import javax.annotation.Resource;
17 | import javax.servlet.http.HttpServletRequest;
18 |
19 | /**
20 | * @author snowalker
21 | * @version 1.0
22 | * @date 2019/6/10 10:06
23 | * @className OrderChargeController
24 | * @desc 商户下单接口
25 | */
26 | @Controller
27 | @RequestMapping(value = "api")
28 | public class OrderChargeController {
29 |
30 | private static final Logger LOGGER = LoggerFactory.getLogger(OrderChargeController.class);
31 |
32 | @Autowired
33 | RequestParamValidateHandler requestParamValidateHandler;
34 |
35 | @Resource(name = "orderService")
36 | OrderService orderService;
37 |
38 | /**
39 | * 第三方渠道下单
40 | * @param request
41 | */
42 | @RequestMapping(value = "charge", method = {RequestMethod.POST})
43 | public @ResponseBody Result chargeRequst(HttpServletRequest request) {
44 |
45 | String phoneNum = request.getParameter("phone_num");
46 | String chargeMoney = request.getParameter("charge_money");
47 | String prodId = request.getParameter("prod_id");
48 |
49 | Result result;
50 | // 前置校验:校验参数、产品、库存等
51 | if (requestParamValidateHandler.checkRequestParams(phoneNum, chargeMoney, prodId)) {
52 | LOGGER.info("下单接口入参:phoneNum={},chargeMoney={},prodId={}", phoneNum, chargeMoney, prodId);
53 | result = orderService.chargeOrder(phoneNum, chargeMoney, prodId);
54 | } else {
55 | result = Result.error(CodeMsg.UNKNOWN_ERROR);
56 | }
57 | LOGGER.info("下单接口出参:result={}", JSON.toJSONString(result));
58 | return result;
59 | }
60 |
61 |
62 | }
63 |
--------------------------------------------------------------------------------
/order-charge-gateway-merchant/src/main/java/com/snowalker/gateway/merchant/order/handler/RequestParamValidateHandler.java:
--------------------------------------------------------------------------------
1 | package com.snowalker.gateway.merchant.order.handler;
2 |
3 | import com.snowalker.gateway.merchant.goods.ProductConfig;
4 | import com.snowalker.gateway.merchant.goods.ProductVO;
5 | import com.snowalker.gateway.merchant.order.dto.CodeMsg;
6 | import com.snowalker.gateway.merchant.order.exception.ApiException;
7 | import org.apache.commons.lang3.StringUtils;
8 | import org.slf4j.Logger;
9 | import org.slf4j.LoggerFactory;
10 | import org.springframework.beans.factory.annotation.Autowired;
11 | import org.springframework.stereotype.Component;
12 | import org.springframework.web.client.RestTemplate;
13 |
14 | import javax.annotation.Resource;
15 |
16 | /**
17 | * @author snowalker
18 | * @version 1.0
19 | * @date 2019/6/10 10:28
20 | * @className RequestParamValidateHandler
21 | * @desc 请求参数校验
22 | */
23 | @Component
24 | public class RequestParamValidateHandler {
25 |
26 | private static final Logger LOGGER = LoggerFactory.getLogger(RequestParamValidateHandler.class);
27 |
28 | /**
29 | * 下单请求参数校验
30 | * @param phoneNum
31 | * @param chargeMoney
32 | * @param prodId
33 | */
34 | public boolean checkRequestParams(String phoneNum, String chargeMoney, String prodId) {
35 | // 非空校验
36 | if (StringUtils.isBlank(phoneNum) || StringUtils.isBlank(chargeMoney) || StringUtils.isBlank(prodId)) {
37 | String errorMsg = String.format("下单请求入参存在空值, phoneNum=%s, chargeMoney=%s, prodId=%s", phoneNum, chargeMoney, prodId);
38 | LOGGER.error(errorMsg);
39 | throw new ApiException(new CodeMsg(CodeMsg.PARAM_ILLEGAL, errorMsg));
40 | }
41 | // 产品校验
42 | ProductVO productVO = ProductConfig.getProductsMap().get(prodId);
43 | if (productVO == null) {
44 | String errorMsg = String.format("产品不存在!, prodId=%s", prodId);
45 | LOGGER.error(errorMsg);
46 | throw new ApiException(new CodeMsg(CodeMsg.PRODUCT_NOT_EXIST, errorMsg));
47 | }
48 | // 库存校验
49 | int productStock = productVO.getProductStock();
50 | if (productStock <= 0) {
51 | String errorMsg = String.format("产品库存不足!, prodId=%s", prodId);
52 | LOGGER.error(errorMsg);
53 | throw new ApiException(new CodeMsg(CodeMsg.PRODUCT_STOCK_NOT_ENOUGH, errorMsg));
54 | }
55 | return true;
56 | }
57 | }
58 |
--------------------------------------------------------------------------------
/order-charge-gateway-merchant/src/main/resources/mapper/OrderInfoMapper.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
8 | insert into t_user_order3rd
9 | (
10 | order_id,
11 | order_status,
12 | user_phoneno,
13 | prod_id,
14 | prod_name,
15 | out_prod_id,
16 | out_prod_name,
17 | charge_money
18 | )
19 | values
20 | (
21 | #{orderId},
22 | #{orderStatus},
23 | #{phoneNum},
24 | #{productId},
25 | #{productName},
26 | #{outProductId},
27 | #{outProductName},
28 | #{chargeMoney}
29 | )
30 |
31 |
32 |
33 |
35 | update t_user_order3rd t
36 | set t.order_status = #{afterUpdateOrderStatus}
37 |
38 | ,t.finish_time = #{finishTime}
39 |
40 |
41 | ,t.out_order_id = #{outOrderId}
42 |
43 | where t.order_status = #{beforeUpdateOrderStatus}
44 | AND t.order_id = #{orderId}
45 |
46 |
47 |
48 |
68 |
69 |
--------------------------------------------------------------------------------
/order-charge-gateway-merchant/src/main/java/com/snowalker/gateway/merchant/goods/ProductVO.java:
--------------------------------------------------------------------------------
1 | package com.snowalker.gateway.merchant.goods;
2 |
3 | /**
4 | * @author snowalker
5 | * @version 1.0
6 | * @date 2019/6/10 9:45
7 | * @className ProductBean
8 | * @desc 商品配置领域
9 | */
10 | public class ProductVO {
11 |
12 | /**商品id*/
13 | private String productId;
14 | /**商品名*/
15 | private String productName;
16 | /**供应商商品id*/
17 | private String productOutId;
18 | /**供应商商品名*/
19 | private String productOutName;
20 | /**商品库存*/
21 | private Integer productStock;
22 | /**供应商渠道id*/
23 | private String productChannelId;
24 |
25 | public String getProductId() {
26 | return productId;
27 | }
28 |
29 | public ProductVO setProductId(String productId) {
30 | this.productId = productId;
31 | return this;
32 | }
33 |
34 | public String getProductName() {
35 | return productName;
36 | }
37 |
38 | public ProductVO setProductName(String productName) {
39 | this.productName = productName;
40 | return this;
41 | }
42 |
43 | public String getProductOutId() {
44 | return productOutId;
45 | }
46 |
47 | public ProductVO setProductOutId(String productOutId) {
48 | this.productOutId = productOutId;
49 | return this;
50 | }
51 |
52 | public String getProductOutName() {
53 | return productOutName;
54 | }
55 |
56 | public ProductVO setProductOutName(String productOutName) {
57 | this.productOutName = productOutName;
58 | return this;
59 | }
60 |
61 | public Integer getProductStock() {
62 | return productStock;
63 | }
64 |
65 | public ProductVO setProductStock(Integer productStock) {
66 | this.productStock = productStock;
67 | return this;
68 | }
69 |
70 | public String getProductChannelId() {
71 | return productChannelId;
72 | }
73 |
74 | public ProductVO setProductChannelId(String productChannelId) {
75 | this.productChannelId = productChannelId;
76 | return this;
77 | }
78 |
79 | @Override
80 | public String toString() {
81 | return "ProductVO{" +
82 | "productId='" + productId + '\'' +
83 | ", productName='" + productName + '\'' +
84 | ", productOutId='" + productOutId + '\'' +
85 | ", productOutName='" + productOutName + '\'' +
86 | ", productStock=" + productStock +
87 | ", productChannelId='" + productChannelId + '\'' +
88 | '}';
89 | }
90 | }
91 |
--------------------------------------------------------------------------------
/order-charge-gateway-notify/src/main/java/com/snowalker/notify/mq/notify/NotifySendConsumer.java:
--------------------------------------------------------------------------------
1 | package com.snowalker.notify.mq.notify;
2 |
3 | import com.snowalker.notify.common.util.LogExceptionWapper;
4 | import com.snowalker.notify.mq.payment.producer.OrderStatusUpdateProducer;
5 | import com.snowalker.order.charge.message.constant.MessageProtocolConst;
6 | import org.apache.rocketmq.client.consumer.DefaultMQPushConsumer;
7 | import org.apache.rocketmq.client.consumer.listener.MessageListenerConcurrently;
8 | import org.apache.rocketmq.client.exception.MQClientException;
9 | import org.apache.rocketmq.common.consumer.ConsumeFromWhere;
10 | import org.apache.rocketmq.common.protocol.heartbeat.MessageModel;
11 | import org.slf4j.Logger;
12 | import org.slf4j.LoggerFactory;
13 | import org.springframework.beans.factory.annotation.Value;
14 | import org.springframework.stereotype.Component;
15 |
16 | import javax.annotation.PostConstruct;
17 | import javax.annotation.Resource;
18 |
19 | /**
20 | * @author snowalker
21 | * @version 1.0
22 | * @date 2019/6/12 14:14
23 | * @className NotifySendConsumer
24 | * @desc 订单结果通知消息消费者
25 | * TODO 需要学员实现
26 | */
27 | @Component
28 | public class NotifySendConsumer {
29 |
30 | private static final Logger LOGGER = LoggerFactory.getLogger(NotifySendConsumer.class);
31 |
32 | @Value("${rocketmq.nameServer}")
33 | String nameSrvAddr;
34 |
35 | private DefaultMQPushConsumer defaultMQPushConsumer;
36 |
37 | @Resource(name = "notifySendListenerImpl")
38 | private MessageListenerConcurrently messageListener;
39 |
40 | @PostConstruct
41 | public void init() {
42 | defaultMQPushConsumer = new DefaultMQPushConsumer(MessageProtocolConst.ORDER_RESULT_NOTIFY_TOPIC.getConsumerGroup());
43 | defaultMQPushConsumer.setNamesrvAddr(nameSrvAddr);
44 | // 从头开始消费
45 | defaultMQPushConsumer.setConsumeFromWhere(ConsumeFromWhere.CONSUME_FROM_FIRST_OFFSET);
46 | // 消费模式:集群模式
47 | defaultMQPushConsumer.setMessageModel(MessageModel.CLUSTERING);
48 | // 注册监听器
49 | defaultMQPushConsumer.registerMessageListener(messageListener);
50 | // 订阅所有消息
51 | try {
52 | defaultMQPushConsumer.subscribe(MessageProtocolConst.ORDER_RESULT_NOTIFY_TOPIC.getTopic(), "*");
53 | defaultMQPushConsumer.start();
54 | } catch (MQClientException e) {
55 | LOGGER.error("[订单结果通知消息消费者]--NotifySendConsumer加载异常!e={}", LogExceptionWapper.getStackTrace(e));
56 | throw new RuntimeException("[订单结果通知消息消费者]--NotifySendConsumer加载异常!", e);
57 | }
58 | LOGGER.info("[订单结果通知消息消费者]--NotifySendConsumer加载完成!");
59 | }
60 | }
61 |
--------------------------------------------------------------------------------
/order-charge-gateway-notify/src/main/java/com/snowalker/notify/mq/payment/consumer/WalletPaymentConsumer.java:
--------------------------------------------------------------------------------
1 | package com.snowalker.notify.mq.payment.consumer;
2 |
3 | import com.snowalker.notify.common.service.WalletService;
4 | import com.snowalker.notify.common.util.LogExceptionWapper;
5 | import com.snowalker.order.charge.message.constant.MessageProtocolConst;
6 | import org.apache.rocketmq.client.consumer.DefaultMQPushConsumer;
7 | import org.apache.rocketmq.client.consumer.listener.MessageListenerConcurrently;
8 | import org.apache.rocketmq.client.exception.MQClientException;
9 | import org.apache.rocketmq.common.consumer.ConsumeFromWhere;
10 | import org.apache.rocketmq.common.protocol.heartbeat.MessageModel;
11 | import org.slf4j.Logger;
12 | import org.slf4j.LoggerFactory;
13 | import org.springframework.beans.factory.annotation.Autowired;
14 | import org.springframework.beans.factory.annotation.Value;
15 | import org.springframework.stereotype.Component;
16 |
17 | import javax.annotation.PostConstruct;
18 | import javax.annotation.Resource;
19 |
20 | /**
21 | * @author snowalker
22 | * @version 1.0
23 | * @date 2019/6/12 9:46
24 | * @className WalletPaymentConsumer
25 | * @desc 扣款消息消费者
26 | */
27 | @Component
28 | public class WalletPaymentConsumer {
29 |
30 | private static final Logger LOGGER = LoggerFactory.getLogger(WalletPaymentConsumer.class);
31 |
32 | @Value("${rocketmq.nameServer}")
33 | String nameSrvAddr;
34 |
35 | @Autowired
36 | WalletService walletService;
37 |
38 | @Resource(name = "walletPaymentMsgListenerImpl")
39 | private MessageListenerConcurrently messageListener;
40 |
41 | private DefaultMQPushConsumer defaultMQPushConsumer;
42 |
43 | @PostConstruct
44 | public void init() {
45 | defaultMQPushConsumer = new DefaultMQPushConsumer(MessageProtocolConst.WALLET_PAYMENT_TOPIC.getConsumerGroup());
46 | defaultMQPushConsumer.setNamesrvAddr(nameSrvAddr);
47 | // 从头开始消费
48 | defaultMQPushConsumer.setConsumeFromWhere(ConsumeFromWhere.CONSUME_FROM_FIRST_OFFSET);
49 | // 消费模式:集群模式
50 | defaultMQPushConsumer.setMessageModel(MessageModel.CLUSTERING);
51 | // 注册监听器
52 | defaultMQPushConsumer.registerMessageListener(messageListener);
53 | // 订阅所有消息
54 | try {
55 | defaultMQPushConsumer.subscribe(MessageProtocolConst.WALLET_PAYMENT_TOPIC.getTopic(), "*");
56 | defaultMQPushConsumer.start();
57 | } catch (MQClientException e) {
58 | LOGGER.error("[扣款消息消费者]--WalletPaymentConsumer加载异常!e={}", LogExceptionWapper.getStackTrace(e));
59 | throw new RuntimeException("[扣款消息消费者]--WalletPaymentConsumer加载异常!", e);
60 | }
61 | LOGGER.info("[扣款消息消费者]--WalletPaymentConsumer加载完成!");
62 | }
63 | }
64 |
--------------------------------------------------------------------------------
/order-charge-sdk/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
5 |
6 | order-charge-notify
7 | com.snowalker
8 | 1.0-SNAPSHOT
9 |
10 | 4.0.0
11 |
12 | com.snowalker
13 | order-charge-sdk
14 | 1.0.0
15 | order-charge-sdk
16 |
17 |
18 | 1.8
19 | 1.8
20 | UTF-8
21 | UTF-8
22 | 29.0-jre
23 |
24 |
25 |
26 |
27 | junit
28 | junit
29 | 4.13.1
30 | test
31 |
32 |
33 |
34 |
35 | org.apache.commons
36 | commons-lang3
37 | 3.4
38 |
39 |
40 |
41 |
42 | com.alibaba
43 | fastjson
44 | 1.2.58
45 |
46 |
47 |
48 |
49 | com.google.guava
50 | guava
51 | ${guava-version}
52 |
53 |
54 |
55 |
56 | commons-codec
57 | commons-codec
58 | 1.12
59 |
60 |
61 |
62 |
63 |
64 |
65 | org.apache.maven.plugins
66 | maven-compiler-plugin
67 |
68 | 8
69 | 8
70 |
71 |
72 |
73 |
74 |
75 |
--------------------------------------------------------------------------------
/order-charge-gateway-notify/src/main/resources/mapper/WalletMapper.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | INSERT INTO t_merchant_wallet (
8 | purse_id,
9 | merchant_name,
10 | balance_account,
11 | account_status)
12 | VALUES
13 | (
14 | #{purseId},
15 | #{merchantName},
16 | #{balanceAccount},
17 | 0
18 | )
19 |
20 |
21 |
22 |
23 | UPDATE t_merchant_wallet
24 | SET balance_account = balance_account - #{chargeMoney},
25 | version = version + 1
26 | WHERE
27 | version = #{version}
28 | AND purse_id = #{purseId}
29 |
30 |
31 |
32 |
33 | INSERT INTO t_merchant_charge_record (
34 | record_id,
35 | order_id,
36 | purse_id,
37 | merchant_name,
38 | charge_price)
39 | VALUES
40 | (
41 | #{recordId},
42 | #{orderId},
43 | #{purseId},
44 | #{merchantName},
45 | #{chargeMoney}
46 | )
47 |
48 |
49 |
50 |
65 |
66 |
67 |
83 |
--------------------------------------------------------------------------------
/order-charge-gateway-notify/src/main/java/com/snowalker/notify/mq/payment/producer/OrderStatusUpdateProducer.java:
--------------------------------------------------------------------------------
1 | package com.snowalker.notify.mq.payment.producer;
2 |
3 | import com.snowalker.order.charge.message.constant.MessageProtocolConst;
4 | import org.apache.rocketmq.client.exception.MQClientException;
5 | import org.apache.rocketmq.client.producer.TransactionListener;
6 | import org.apache.rocketmq.client.producer.TransactionMQProducer;
7 | import org.slf4j.Logger;
8 | import org.slf4j.LoggerFactory;
9 | import org.springframework.beans.factory.annotation.Value;
10 | import org.springframework.stereotype.Component;
11 |
12 | import javax.annotation.PostConstruct;
13 | import javax.annotation.Resource;
14 | import java.util.concurrent.ExecutorService;
15 | import java.util.concurrent.LinkedBlockingQueue;
16 | import java.util.concurrent.ThreadPoolExecutor;
17 | import java.util.concurrent.TimeUnit;
18 |
19 | /**
20 | * @author snowalker
21 | * @version 1.0
22 | * @date 2019/6/12 9:39
23 | * @className OrderStatusUpdateProducer
24 | * @desc 订单状态修改生产者
25 | */
26 | @Component
27 | public class OrderStatusUpdateProducer {
28 |
29 | private static final Logger LOGGER = LoggerFactory.getLogger(OrderStatusUpdateProducer.class);
30 |
31 | /**事务回查线程池*/
32 | private ExecutorService executorService;
33 | /**事务消息生产者*/
34 | private TransactionMQProducer transactionMQProducer;
35 |
36 | @Value("${rocketmq.nameServer}")
37 | private String nameSrvAddr;
38 |
39 | @Resource(name = "localTranListenerImpl")
40 | TransactionListener transactionListener;
41 |
42 | @PostConstruct
43 | public void init() {
44 | // 初始化回查线程池
45 | executorService = new ThreadPoolExecutor(
46 | 5,
47 | 512,
48 | 10000L,
49 | TimeUnit.MILLISECONDS,
50 | new LinkedBlockingQueue<>(512),
51 | runnable -> {
52 | Thread thread = new Thread(runnable);
53 | thread.setName(MessageProtocolConst.ORDER_STATUS_UPDATE_TOPIC.getProducerGroup() + "-check-thread");
54 | return null;
55 | });
56 |
57 | transactionMQProducer = new TransactionMQProducer(MessageProtocolConst.ORDER_STATUS_UPDATE_TOPIC.getProducerGroup());
58 | transactionMQProducer.setNamesrvAddr(nameSrvAddr);
59 | transactionMQProducer.setExecutorService(executorService);
60 | transactionMQProducer.setTransactionListener(transactionListener);
61 | try {
62 | transactionMQProducer.start();
63 | } catch (MQClientException e) {
64 | throw new RuntimeException("启动[订单状态修改生产者]OrderStatusUpdateProducer异常", e);
65 | }
66 | LOGGER.info("启动[订单状态修改生产者]OrderStatusUpdateProducer成功, topic={}", MessageProtocolConst.ORDER_STATUS_UPDATE_TOPIC.getTopic());
67 | }
68 |
69 | public TransactionMQProducer getProducer() {
70 | return transactionMQProducer;
71 | }
72 | }
73 |
--------------------------------------------------------------------------------
/order-charge-gateway-server/src/main/java/com/snowalker/order/mq/payment/producer/ChargeOrderPaymentTranProducer.java:
--------------------------------------------------------------------------------
1 | package com.snowalker.order.mq.payment.producer;
2 |
3 | import com.snowalker.order.charge.message.constant.MessageProtocolConst;
4 | import org.apache.rocketmq.client.exception.MQClientException;
5 | import org.apache.rocketmq.client.producer.TransactionListener;
6 | import org.apache.rocketmq.client.producer.TransactionMQProducer;
7 | import org.slf4j.Logger;
8 | import org.slf4j.LoggerFactory;
9 | import org.springframework.beans.factory.annotation.Value;
10 | import org.springframework.stereotype.Component;
11 |
12 | import javax.annotation.PostConstruct;
13 | import javax.annotation.Resource;
14 | import java.util.concurrent.ExecutorService;
15 | import java.util.concurrent.LinkedBlockingQueue;
16 | import java.util.concurrent.ThreadPoolExecutor;
17 | import java.util.concurrent.TimeUnit;
18 |
19 | /**
20 | * @author snowalker
21 | * @version 1.0
22 | * @date 2019/6/11 15:46
23 | * @className PaymentTransactionProducer
24 | * @desc 扣款事务消息生产者
25 | * TODO 需要学员实现
26 | */
27 | @Component
28 | public class ChargeOrderPaymentTranProducer {
29 |
30 | private static final Logger LOGGER = LoggerFactory.getLogger(ChargeOrderPaymentTranProducer.class);
31 |
32 | /**事务回查线程池*/
33 | private ExecutorService executorService;
34 | /**事务消息生产者*/
35 | private TransactionMQProducer transactionMQProducer;
36 |
37 | @Value("${rocketmq.nameServer}")
38 | private String nameSrvAddr;
39 |
40 | @Resource(name = "chargeOrderTranListenerImpl")
41 | TransactionListener transactionListener;
42 |
43 | @PostConstruct
44 | public void init() {
45 | // 初始化回查线程池
46 | executorService = new ThreadPoolExecutor(
47 | 5,
48 | 512,
49 | 10000L,
50 | TimeUnit.MILLISECONDS,
51 | new LinkedBlockingQueue<>(512),
52 | runnable -> {
53 | Thread thread = new Thread(runnable);
54 | thread.setName(MessageProtocolConst.WALLET_PAYMENT_TOPIC.getProducerGroup() + "-check-thread");
55 | return null;
56 | });
57 |
58 | transactionMQProducer = new TransactionMQProducer(MessageProtocolConst.WALLET_PAYMENT_TOPIC.getProducerGroup());
59 | transactionMQProducer.setNamesrvAddr(nameSrvAddr);
60 | transactionMQProducer.setExecutorService(executorService);
61 | transactionMQProducer.setTransactionListener(transactionListener);
62 | try {
63 | transactionMQProducer.start();
64 | } catch (MQClientException e) {
65 | throw new RuntimeException("启动[扣款事务消息生产者]ChargeOrderPaymentTranProducer异常", e);
66 | }
67 | LOGGER.info("启动[扣款事务消息生产者]ChargeOrderPaymentTranProducer成功, topic={}", MessageProtocolConst.WALLET_PAYMENT_TOPIC.getTopic());
68 | }
69 |
70 | public TransactionMQProducer getProducer() {
71 | return transactionMQProducer;
72 | }
73 |
74 | }
75 |
--------------------------------------------------------------------------------
/order-charge-gateway-server/src/main/resources/mapper/OrderChargeMapper.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
8 | insert into t_merchant_order
9 | (
10 | order_id,
11 | channel_order_id,
12 | order_status,
13 | notify_status,
14 | pay_status,
15 | user_phoneno,
16 | charge_price,
17 | purse_id,
18 | merchant_name
19 | )
20 | values
21 | (
22 | #{orderId},
23 | #{channelOrderId},
24 | 1,
25 | 1,
26 | 1,
27 | #{userPhoneNo},
28 | #{chargeMoney},
29 | #{purseId},
30 | #{merchantName}
31 | )
32 |
33 |
34 |
35 |
51 |
52 |
53 |
54 | UPDATE t_merchant_order
55 | SET order_status = 2,
56 | pay_status = 2
57 | WHERE
58 | order_status = 1
59 | AND pay_status = 1
60 | AND channel_order_id = #{channelOrderId}
61 |
62 |
63 |
64 |
65 | UPDATE t_merchant_order
66 | SET pay_status = 0,
67 | order_status = 0,
68 | notify_status = 2
69 | WHERE
70 | pay_status = 2
71 | AND order_status = 2
72 | AND notify_status = 1
73 | AND order_id = #{orderId}
74 |
75 |
76 |
77 |
78 | UPDATE t_merchant_order
79 | SET notify_status = 0
80 | WHERE
81 | order_status = 0
82 | AND notify_status = 2
83 | AND order_id = #{orderId}
84 |
85 |
--------------------------------------------------------------------------------
/order-charge-gateway-notify/src/main/java/com/snowalker/notify/common/dao/dataobject/ChargeRecordEntity.java:
--------------------------------------------------------------------------------
1 | package com.snowalker.notify.common.dao.dataobject;
2 |
3 | import java.math.BigDecimal;
4 | import java.util.Date;
5 |
6 | /**
7 | * @author snowalker
8 | * @version 1.0
9 | * @date 2019/2/15 17:21
10 | * @className ChargeRecordEntity
11 | * @desc 模拟钱包扣款流水
12 | */
13 | public class ChargeRecordEntity {
14 |
15 | private int id;
16 | /**扣款流水id*/
17 | private String recordId;
18 | private String orderId;
19 | private String purseId;
20 | private String merchantName;
21 | /**本次交易流水额度*/
22 | private BigDecimal chargePrice;
23 | private Date gmtCreate;
24 | private Date gmtUpdate;
25 |
26 | public String getMerchantName() {
27 | return merchantName;
28 | }
29 |
30 | public ChargeRecordEntity setMerchantName(String merchantName) {
31 | this.merchantName = merchantName;
32 | return this;
33 | }
34 |
35 | public int getId() {
36 | return id;
37 | }
38 |
39 | public ChargeRecordEntity setId(int id) {
40 | this.id = id;
41 | return this;
42 | }
43 |
44 | public String getRecordId() {
45 | return recordId;
46 | }
47 |
48 | public ChargeRecordEntity setRecordId(String recordId) {
49 | this.recordId = recordId;
50 | return this;
51 | }
52 |
53 | public String getOrderId() {
54 | return orderId;
55 | }
56 |
57 | public ChargeRecordEntity setOrderId(String orderId) {
58 | this.orderId = orderId;
59 | return this;
60 | }
61 |
62 | public String getPurseId() {
63 | return purseId;
64 | }
65 |
66 | public ChargeRecordEntity setPurseId(String purseId) {
67 | this.purseId = purseId;
68 | return this;
69 | }
70 |
71 |
72 | public BigDecimal getChargePrice() {
73 | return chargePrice;
74 | }
75 |
76 | public ChargeRecordEntity setChargePrice(BigDecimal chargePrice) {
77 | this.chargePrice = chargePrice;
78 | return this;
79 | }
80 |
81 | public Date getGmtCreate() {
82 | return gmtCreate;
83 | }
84 |
85 | public ChargeRecordEntity setGmtCreate(Date gmtCreate) {
86 | this.gmtCreate = gmtCreate;
87 | return this;
88 | }
89 |
90 | public Date getGmtUpdate() {
91 | return gmtUpdate;
92 | }
93 |
94 | public ChargeRecordEntity setGmtUpdate(Date gmtUpdate) {
95 | this.gmtUpdate = gmtUpdate;
96 | return this;
97 | }
98 |
99 | @Override
100 | public String toString() {
101 | return "ChargeRecordEntity{" +
102 | "id=" + id +
103 | ", recordId='" + recordId + '\'' +
104 | ", orderId='" + orderId + '\'' +
105 | ", purseId='" + purseId + '\'' +
106 | ", merchantName='" + merchantName + '\'' +
107 | ", chargePrice=" + chargePrice +
108 | ", gmtCreate=" + gmtCreate +
109 | ", gmtUpdate=" + gmtUpdate +
110 | '}';
111 | }
112 | }
113 |
--------------------------------------------------------------------------------
/order-charge-gateway-notify/src/main/java/com/snowalker/notify/common/dao/dataobject/WalletEntity.java:
--------------------------------------------------------------------------------
1 | package com.snowalker.notify.common.dao.dataobject;
2 |
3 | import java.math.BigDecimal;
4 | import java.util.Date;
5 |
6 | /**
7 | * @author snowalker
8 | * @version 1.0
9 | * @date 2019/2/15 16:54
10 | * @className PurseEntity
11 | * @desc 模拟钱包数据库操作实体
12 | */
13 | public class WalletEntity {
14 |
15 | private int id;
16 | private String purseId;
17 | private String merchantName;
18 | private BigDecimal balanceAccount;
19 | private BigDecimal chargeMoney;
20 | /**账户状态 账户状态 0 正常 1 异常*/
21 | private int accountStatus;
22 | private Date gmtCreate;
23 | private Date gmtUpdate;
24 | private int version;
25 |
26 | public BigDecimal getChargeMoney() {
27 | return chargeMoney;
28 | }
29 |
30 | public WalletEntity setChargeMoney(BigDecimal chargeMoney) {
31 | this.chargeMoney = chargeMoney;
32 | return this;
33 | }
34 |
35 | public int getVersion() {
36 | return version;
37 | }
38 |
39 | public WalletEntity setVersion(int version) {
40 | this.version = version;
41 | return this;
42 | }
43 |
44 | public int getId() {
45 | return id;
46 | }
47 |
48 | public WalletEntity setId(int id) {
49 | this.id = id;
50 | return this;
51 | }
52 |
53 | public String getPurseId() {
54 | return purseId;
55 | }
56 |
57 | public WalletEntity setPurseId(String purseId) {
58 | this.purseId = purseId;
59 | return this;
60 | }
61 |
62 | public BigDecimal getBalanceAccount() {
63 | return balanceAccount;
64 | }
65 |
66 | public WalletEntity setBalanceAccount(BigDecimal balanceAccount) {
67 | this.balanceAccount = balanceAccount;
68 | return this;
69 | }
70 |
71 | public int getAccountStatus() {
72 | return accountStatus;
73 | }
74 |
75 | public WalletEntity setAccountStatus(int accountStatus) {
76 | this.accountStatus = accountStatus;
77 | return this;
78 | }
79 |
80 | public Date getGmtCreate() {
81 | return gmtCreate;
82 | }
83 |
84 | public WalletEntity setGmtCreate(Date gmtCreate) {
85 | this.gmtCreate = gmtCreate;
86 | return this;
87 | }
88 |
89 | public Date getGmtUpdate() {
90 | return gmtUpdate;
91 | }
92 |
93 | public WalletEntity setGmtUpdate(Date gmtUpdate) {
94 | this.gmtUpdate = gmtUpdate;
95 | return this;
96 | }
97 |
98 | public String getMerchantName() {
99 | return merchantName;
100 | }
101 |
102 | public WalletEntity setMerchantName(String merchantName) {
103 | this.merchantName = merchantName;
104 | return this;
105 | }
106 |
107 | @Override
108 | public String toString() {
109 | return "WalletEntity{" +
110 | "id=" + id +
111 | ", purseId='" + purseId + '\'' +
112 | ", merchantName='" + merchantName + '\'' +
113 | ", balanceAccount=" + balanceAccount +
114 | ", chargeMoney=" + chargeMoney +
115 | ", accountStatus=" + accountStatus +
116 | ", gmtCreate=" + gmtCreate +
117 | ", gmtUpdate=" + gmtUpdate +
118 | ", version=" + version +
119 | '}';
120 | }
121 | }
122 |
--------------------------------------------------------------------------------
/order-charge-gateway-server/src/main/java/com/snowalker/order/common/dao/dataobject/OrderInfoDobj.java:
--------------------------------------------------------------------------------
1 | package com.snowalker.order.common.dao.dataobject;
2 |
3 | /**
4 | * @author snowalker
5 | * @version 1.0
6 | * @date 2019/6/11 19:50
7 | * @className OrderInfoDO
8 | * @desc 订单数据库映射实体
9 | */
10 | public class OrderInfoDobj {
11 |
12 | private Integer orderStatus;
13 | private Integer notifyStatus;
14 | private Integer payStatus;
15 | private String orderId;
16 | private String channelOrderId;
17 | private String userPhoneNo;
18 | private String chargeMoney;
19 | private String purseId;
20 | private String merchantName;
21 |
22 | public Integer getOrderStatus() {
23 | return orderStatus;
24 | }
25 |
26 | public OrderInfoDobj setOrderStatus(Integer orderStatus) {
27 | this.orderStatus = orderStatus;
28 | return this;
29 | }
30 |
31 | public Integer getNotifyStatus() {
32 | return notifyStatus;
33 | }
34 |
35 | public OrderInfoDobj setNotifyStatus(Integer notifyStatus) {
36 | this.notifyStatus = notifyStatus;
37 | return this;
38 | }
39 |
40 | public Integer getPayStatus() {
41 | return payStatus;
42 | }
43 |
44 | public OrderInfoDobj setPayStatus(Integer payStatus) {
45 | this.payStatus = payStatus;
46 | return this;
47 | }
48 |
49 | public String getOrderId() {
50 | return orderId;
51 | }
52 |
53 | public OrderInfoDobj setOrderId(String orderId) {
54 | this.orderId = orderId;
55 | return this;
56 | }
57 |
58 | public String getChannelOrderId() {
59 | return channelOrderId;
60 | }
61 |
62 | public OrderInfoDobj setChannelOrderId(String channelOrderId) {
63 | this.channelOrderId = channelOrderId;
64 | return this;
65 | }
66 |
67 | public String getUserPhoneNo() {
68 | return userPhoneNo;
69 | }
70 |
71 | public OrderInfoDobj setUserPhoneNo(String userPhoneNo) {
72 | this.userPhoneNo = userPhoneNo;
73 | return this;
74 | }
75 |
76 | public String getChargeMoney() {
77 | return chargeMoney;
78 | }
79 |
80 | public OrderInfoDobj setChargeMoney(String chargeMoney) {
81 | this.chargeMoney = chargeMoney;
82 | return this;
83 | }
84 |
85 | public String getPurseId() {
86 | return purseId;
87 | }
88 |
89 | public OrderInfoDobj setPurseId(String purseId) {
90 | this.purseId = purseId;
91 | return this;
92 | }
93 |
94 | public String getMerchantName() {
95 | return merchantName;
96 | }
97 |
98 | public OrderInfoDobj setMerchantName(String merchantName) {
99 | this.merchantName = merchantName;
100 | return this;
101 | }
102 |
103 | @Override
104 | public String toString() {
105 | return "OrderInfoDobj{" +
106 | "orderStatus=" + orderStatus +
107 | ", notifyStatus=" + notifyStatus +
108 | ", payStatus=" + payStatus +
109 | ", orderId='" + orderId + '\'' +
110 | ", channelOrderId='" + channelOrderId + '\'' +
111 | ", userPhoneNo='" + userPhoneNo + '\'' +
112 | ", chargeMoney='" + chargeMoney + '\'' +
113 | ", purseId='" + purseId + '\'' +
114 | ", merchantName='" + merchantName + '\'' +
115 | '}';
116 | }
117 | }
118 |
--------------------------------------------------------------------------------
/order-charge-gateway-merchant/src/main/java/com/snowalker/gateway/merchant/order/OrderNotifyController.java:
--------------------------------------------------------------------------------
1 | package com.snowalker.gateway.merchant.order;
2 |
3 | import com.snowalker.gateway.merchant.order.constant.NotifyConstant;
4 | import com.snowalker.gateway.merchant.order.service.OrderService;
5 | import com.snowalker.order.charge.request.ChargeNotifyRequest;
6 | import org.apache.commons.lang3.StringUtils;
7 | import org.slf4j.Logger;
8 | import org.slf4j.LoggerFactory;
9 | import org.springframework.beans.factory.annotation.Value;
10 | import org.springframework.stereotype.Controller;
11 | import org.springframework.web.bind.annotation.*;
12 | import org.springframework.web.context.request.RequestContextHolder;
13 | import org.springframework.web.context.request.ServletRequestAttributes;
14 |
15 | import javax.annotation.Resource;
16 | /**
17 | * @author snowalker
18 | * @version 1.0
19 | * @date 2019/6/10 10:07
20 | * @className OrderNotifyController
21 | * @desc 订单充值回调接口
22 | * 接收并处理成功返回T
23 | * 其余情况返回F,上游充值平台重试
24 | */
25 | @Controller
26 | @RequestMapping(value = "api")
27 | public class OrderNotifyController {
28 |
29 | private static final Logger LOGGER = LoggerFactory.getLogger(OrderNotifyController.class);
30 |
31 | @Resource(name = "orderService")
32 | OrderService orderService;
33 |
34 | @Value("${agent.config.private.key}")
35 | private String privateKey;
36 |
37 | /**
38 | * 接受充值结果通知
39 | * @param chargeNotifyRequest
40 | * orderStatus 订单状态
41 | * channelOrderId 本平台订单
42 | * platOrderId 充值平台订单
43 | * finishTime 订单结束时间,时间戳yyyyMMddHHmmss
44 | */
45 | @RequestMapping(value = "callback", method = {RequestMethod.POST})
46 | public @ResponseBody String chargeNotify(@ModelAttribute ChargeNotifyRequest chargeNotifyRequest) {
47 | ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
48 | String sessionId = attributes.getSessionId();
49 |
50 | if (chargeNotifyRequest == null) {
51 | LOGGER.info("sessionId={},通知请求参数chargeNotifyDto==null,不进行处理。", sessionId);
52 | return NotifyConstant.NOTIFY_RETURN_FAIL;
53 | }
54 | LOGGER.info("sessionId={},充值结果通知处理开始,请求入参:chargeNotifyRequest={}", sessionId, chargeNotifyRequest.toString());
55 | // 获取详细通知参数
56 | String orderStatus = chargeNotifyRequest.getOrder_status();
57 | String channelOrderId = chargeNotifyRequest.getChannel_orderid();
58 | String platOrderId = chargeNotifyRequest.getPlat_orderid();
59 | String finishTime = chargeNotifyRequest.getFinish_time();
60 |
61 | if (StringUtils.isBlank(orderStatus) ||
62 | StringUtils.isBlank(channelOrderId) ||
63 | StringUtils.isBlank(platOrderId) ||
64 | StringUtils.isBlank(finishTime)) {
65 | LOGGER.info("sessionId={},通知请求参数存在空值,不进行处理。", sessionId);
66 | return NotifyConstant.NOTIFY_RETURN_FAIL;
67 | }
68 | // 签名校验
69 | String originSign = chargeNotifyRequest.getSign();
70 | String localSign = chargeNotifyRequest.sign(privateKey);
71 | if (!localSign.equals(originSign)) {
72 | LOGGER.info("sessionId={},签名校验失败,不进行处理。originSign={},localSign={}", sessionId, originSign, localSign);
73 | return NotifyConstant.NOTIFY_RETURN_FAIL;
74 | }
75 | LOGGER.info("sessionId={},签名校验成功,准备进行通知处理。originSign={},localSign={}", sessionId, originSign, localSign);
76 | // 执行通知处理逻辑
77 | return orderService.doNotify(sessionId, orderStatus, channelOrderId, platOrderId, finishTime);
78 | }
79 |
80 | }
81 |
--------------------------------------------------------------------------------
/order-charge-message-protocol/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
5 |
6 | order-charge-notify
7 | com.snowalker
8 | 1.0-SNAPSHOT
9 |
10 | 4.0.0
11 |
12 | com.snowalker
13 | order-charge-message-protocol
14 | 1.0.0
15 |
16 | order-charge-message-protocol
17 |
18 |
19 | 1.8
20 | 1.8
21 | UTF-8
22 | UTF-8
23 |
24 |
25 |
26 |
27 | junit
28 | junit
29 | 4.13.1
30 | test
31 |
32 |
33 |
34 |
35 | org.apache.commons
36 | commons-lang3
37 | 3.7
38 |
39 |
40 |
41 |
42 | com.google.guava
43 | guava
44 | 29.0-jre
45 |
46 |
47 |
48 |
49 | org.slf4j
50 | slf4j-api
51 | 1.7.21
52 |
53 |
54 |
55 | junit
56 | junit
57 | 4.13.1
58 | test
59 |
60 |
61 |
62 |
63 | com.fasterxml.jackson.core
64 | jackson-databind
65 | 2.12.6.1
66 |
67 |
68 |
69 | com.fasterxml.jackson.core
70 | jackson-core
71 | 2.9.9
72 |
73 |
74 |
75 | com.fasterxml.jackson.core
76 | jackson-annotations
77 | 2.9.9
78 |
79 |
80 |
81 |
82 |
83 |
84 | org.apache.maven.plugins
85 | maven-compiler-plugin
86 |
87 | 8
88 | 8
89 |
90 |
91 |
92 |
93 |
94 |
--------------------------------------------------------------------------------
/order-charge-sdk/src/main/java/com/snowalker/order/charge/request/ChargeNotifyRequest.java:
--------------------------------------------------------------------------------
1 | package com.snowalker.order.charge.request;
2 |
3 | import com.google.common.base.Preconditions;
4 | import org.apache.commons.codec.digest.DigestUtils;
5 |
6 | import java.io.Serializable;
7 | import java.util.Map;
8 | import java.util.TreeMap;
9 |
10 | /**
11 | * @author snowalker
12 | * @version 1.0
13 | * @date 2019/6/11 10:57
14 | * @className ChargeNotifyDto
15 | * @desc 订单结果通知入参
16 | */
17 | public class ChargeNotifyRequest implements Serializable {
18 |
19 | private static final long serialVersionUID = -2278245695213335505L;
20 |
21 | /**订单状态*/
22 | private String order_status;
23 | /**渠道订单id*/
24 | private String channel_orderid;
25 | /**平台订单id*/
26 | private String plat_orderid;
27 | /**订单结束时间*/
28 | private String finish_time;
29 | /**签名*/
30 | private String sign;
31 |
32 | public String getSign() {
33 | return sign;
34 | }
35 |
36 | public ChargeNotifyRequest setSign(String sign) {
37 | this.sign = sign;
38 | return this;
39 | }
40 |
41 | public String getOrder_status() {
42 | return order_status;
43 | }
44 |
45 | public ChargeNotifyRequest setOrder_status(String order_status) {
46 | this.order_status = order_status;
47 | return this;
48 | }
49 |
50 | public String getChannel_orderid() {
51 | return channel_orderid;
52 | }
53 |
54 | public ChargeNotifyRequest setChannel_orderid(String channel_orderid) {
55 | this.channel_orderid = channel_orderid;
56 | return this;
57 | }
58 |
59 | public String getPlat_orderid() {
60 | return plat_orderid;
61 | }
62 |
63 | public ChargeNotifyRequest setPlat_orderid(String plat_orderid) {
64 | this.plat_orderid = plat_orderid;
65 | return this;
66 | }
67 |
68 | public String getFinish_time() {
69 | return finish_time;
70 | }
71 |
72 | public ChargeNotifyRequest setFinish_time(String finish_time) {
73 | this.finish_time = finish_time;
74 | return this;
75 | }
76 |
77 | /**
78 | * MD5签名
79 | */
80 | public String sign(String privateKey) {
81 | Preconditions.checkNotNull(this.getChannel_orderid());
82 | Preconditions.checkNotNull(this.getFinish_time());
83 | Preconditions.checkNotNull(this.getOrder_status());
84 | Preconditions.checkNotNull(this.getPlat_orderid());
85 | Preconditions.checkNotNull(privateKey);
86 | // 参数排序
87 | Map params = new TreeMap<>();
88 | params.put("order_status", this.getOrder_status());
89 | params.put("channel_orderid", this.getChannel_orderid());
90 | params.put("plat_orderid", this.getPlat_orderid());
91 | params.put("finish_time", this.getFinish_time());
92 | params.put("privateKey", privateKey);
93 | // 参数拼装并MD5签名
94 | StringBuilder signSourceBuilder = new StringBuilder();
95 | for (String key : params.keySet()) {
96 | signSourceBuilder.append(key).append("=").append(params.get(key)).append("&");
97 | }
98 | // 去除最后一个&
99 | String signSource = signSourceBuilder.toString();
100 | String beforeSign = signSource.substring(0, signSource.length() - 1);
101 | // md5签名
102 | return DigestUtils.md5Hex(beforeSign);
103 | }
104 |
105 | @Override
106 | public String toString() {
107 | return "ChargeNotifyRequest{" +
108 | "order_status='" + order_status + '\'' +
109 | ", channel_orderid='" + channel_orderid + '\'' +
110 | ", plat_orderid='" + plat_orderid + '\'' +
111 | ", finish_time='" + finish_time + '\'' +
112 | ", sign='" + sign + '\'' +
113 | '}';
114 | }
115 | }
116 |
--------------------------------------------------------------------------------
/order-charge-gateway-merchant/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 | 4.0.0
5 |
6 |
7 | org.springframework.boot
8 | spring-boot-starter-parent
9 | 2.1.5.RELEASE
10 |
11 |
12 |
13 | com.snowalker
14 | order-charge-gateway-merchant
15 | 1.0.0
16 | order-charge-gateway-merchant
17 | Demo project for Spring Boot
18 |
19 |
20 | 1.8
21 | 1.8
22 | UTF-8
23 | UTF-8
24 | 1.3.2
25 | 29.0-jre
26 |
27 |
28 |
29 |
30 |
31 |
32 | com.snowalker
33 | order-charge-sdk
34 | 1.0.0
35 |
36 |
37 |
38 | org.springframework.boot
39 | spring-boot-starter-web
40 |
41 |
42 |
43 | org.springframework.boot
44 | spring-boot-starter-test
45 | test
46 |
47 |
48 |
49 | org.springframework.boot
50 | spring-boot-starter-jdbc
51 |
52 |
53 |
54 | mysql
55 | mysql-connector-java
56 | runtime
57 |
58 |
59 |
60 |
61 | org.apache.commons
62 | commons-lang3
63 | 3.4
64 |
65 |
66 |
67 |
68 | com.alibaba
69 | fastjson
70 | 1.2.58
71 |
72 |
73 |
74 |
75 | com.google.guava
76 | guava
77 | ${guava-version}
78 |
79 |
80 |
81 |
82 | commons-codec
83 | commons-codec
84 | 1.12
85 |
86 |
87 |
88 |
89 | org.mybatis.spring.boot
90 | mybatis-spring-boot-starter
91 | ${mybatis-spring-boot-starter-version}
92 |
93 |
94 |
95 |
96 |
97 |
98 | org.springframework.boot
99 | spring-boot-maven-plugin
100 |
101 |
102 |
103 |
104 |
105 |
--------------------------------------------------------------------------------
/order-charge-gateway-server/src/main/java/com/snowalker/order/mq/payment/producer/listener/ChargeOrderTranListenerImpl.java:
--------------------------------------------------------------------------------
1 | package com.snowalker.order.mq.payment.producer.listener;
2 |
3 | /**
4 | * @author snowalker
5 | * @version 1.0
6 | * @date 2019/6/11 15:51
7 | * @className ChargeOrderTranListenerImpl
8 | * @desc 订单交易事务监听器回调实现
9 | */
10 | import com.snowalker.order.charge.message.protocol.WalletPaymentProtocol;
11 | import com.snowalker.order.common.dao.dataobject.OrderInfoDO;
12 | import com.snowalker.order.common.dao.dataobject.OrderInfoDobj;
13 | import com.snowalker.order.common.service.OrderChargeService;
14 | import com.snowalker.order.common.util.LogExceptionWapper;
15 | import org.apache.rocketmq.client.producer.LocalTransactionState;
16 | import org.apache.rocketmq.client.producer.TransactionListener;
17 | import org.apache.rocketmq.common.message.Message;
18 | import org.apache.rocketmq.common.message.MessageExt;
19 | import org.slf4j.Logger;
20 | import org.slf4j.LoggerFactory;
21 | import org.springframework.beans.BeanUtils;
22 | import org.springframework.stereotype.Component;
23 |
24 | import javax.annotation.Resource;
25 |
26 | /**
27 | * 下单事务消息本地回调实现
28 | * 主要实现:本地订单入库、订单事务回查
29 | * TODO 需要学员实现
30 | * @author snowalker
31 | * @date 2019/6/11 16:09
32 | */
33 | @Component(value = "chargeOrderTranListenerImpl")
34 | public class ChargeOrderTranListenerImpl implements TransactionListener {
35 |
36 | private static final Logger LOGGER = LoggerFactory.getLogger(ChargeOrderTranListenerImpl.class);
37 |
38 | @Resource(name = "orderChargeService")
39 | OrderChargeService orderChargeService;
40 |
41 | /**
42 | * 执行本地订单入库操作
43 | * @param msg
44 | * @param arg
45 | * @return
46 | */
47 | @Override
48 | public LocalTransactionState executeLocalTransaction(Message msg, Object arg) {
49 | // 消息解码
50 | String message = new String(msg.getBody());
51 | WalletPaymentProtocol walletPaymentProtocol = new WalletPaymentProtocol();
52 | walletPaymentProtocol.decode(message);
53 | LOGGER.info("订单入库实体WalletPaymentProtocol={}", walletPaymentProtocol.toString());
54 | // 组装下单实体
55 | OrderInfoDO orderInfoDO = new OrderInfoDO();
56 | BeanUtils.copyProperties(walletPaymentProtocol, orderInfoDO);
57 | String orderId = orderInfoDO.getOrderId();
58 | // 执行下单操作
59 | try {
60 | if (!orderChargeService.insertOrder(orderInfoDO)) {
61 | LOGGER.error("订单入库失败,事务消息回滚,LocalTransactionState={},orderId={}", LocalTransactionState.ROLLBACK_MESSAGE, orderId);
62 | return LocalTransactionState.ROLLBACK_MESSAGE;
63 | }
64 | } catch (Exception e) {
65 | LOGGER.error("订单入库异常,等待回查发起,orderId={},e={}", orderId, LogExceptionWapper.getStackTrace(e));
66 | return LocalTransactionState.UNKNOW;
67 | }
68 | LOGGER.info("订单入库成功,orderId={}", orderId);
69 | return LocalTransactionState.COMMIT_MESSAGE;
70 | }
71 |
72 | /**
73 | * 根据订单号进行回查
74 | * @param msg
75 | * @return
76 | */
77 | @Override
78 | public LocalTransactionState checkLocalTransaction(MessageExt msg) {
79 | String message = new String(msg.getBody());
80 | String msgId = msg.getMsgId();
81 | int reconsumeTimes = msg.getReconsumeTimes();
82 | LOGGER.info("订单入库本地事务回查--接收到消息, msgId={},message={},reconsumeTimes={}", msgId, message, reconsumeTimes);
83 | // 消息解码
84 | WalletPaymentProtocol walletPaymentProtocol = new WalletPaymentProtocol();
85 | walletPaymentProtocol.decode(message);
86 | String orderId = walletPaymentProtocol.getOrderId();
87 | // 订单查询
88 | OrderInfoDO orderInfoDO = new OrderInfoDO().setOrderId(orderId);
89 | OrderInfoDobj orderInfoDobj = orderChargeService.queryOrderInfo(orderInfoDO);
90 | if (orderInfoDobj == null) {
91 | LOGGER.info("订单入库本地事务回查--本地不存在订单,[消息回滚],orderId={},msgId={}", orderId, msgId);
92 | return LocalTransactionState.ROLLBACK_MESSAGE;
93 | }
94 | LOGGER.info("订单入库本地事务回查--本地存在订单信息,orderInfoDobj={},msgId={},[消息提交]", orderInfoDobj, msgId);
95 | return LocalTransactionState.COMMIT_MESSAGE;
96 | }
97 | }
98 |
--------------------------------------------------------------------------------
/order-charge-gateway-notify/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 | 4.0.0
5 |
6 | org.springframework.boot
7 | spring-boot-starter-parent
8 | 2.1.5.RELEASE
9 |
10 |
11 | com.snowalker
12 | order-charge-notify
13 | 1.0.0
14 | order-charge-notify
15 | Demo project for Spring Boot
16 |
17 |
18 | 1.8
19 | 1.8
20 | UTF-8
21 | UTF-8
22 | 1.3.2
23 | 29.0-jre
24 |
25 |
26 |
27 |
28 |
29 | org.springframework.boot
30 | spring-boot-starter-web
31 |
32 |
33 |
34 |
35 | com.snowalker
36 | order-charge-sdk
37 | 1.0.0
38 |
39 |
40 |
41 |
42 | org.apache.rocketmq
43 | rocketmq-client
44 | 4.3.2
45 |
46 |
47 |
48 | com.snowalker
49 | order-charge-message-protocol
50 | 1.0.0
51 |
52 |
53 |
54 | org.springframework.boot
55 | spring-boot-starter-test
56 | test
57 |
58 |
59 |
60 | org.springframework.boot
61 | spring-boot-starter-jdbc
62 |
63 |
64 |
65 | mysql
66 | mysql-connector-java
67 | runtime
68 |
69 |
70 |
71 |
72 | org.apache.commons
73 | commons-lang3
74 | 3.4
75 |
76 |
77 |
78 |
79 | com.alibaba
80 | fastjson
81 | 1.2.58
82 |
83 |
84 |
85 |
86 | com.google.guava
87 | guava
88 | ${guava-version}
89 |
90 |
91 |
92 |
93 | commons-codec
94 | commons-codec
95 | 1.12
96 |
97 |
98 |
99 |
100 | org.mybatis.spring.boot
101 | mybatis-spring-boot-starter
102 | ${mybatis-spring-boot-starter-version}
103 |
104 |
105 |
106 |
107 |
108 |
109 | org.springframework.boot
110 | spring-boot-maven-plugin
111 |
112 |
113 |
114 |
115 |
116 |
--------------------------------------------------------------------------------
/order-charge-gateway-server/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 | 4.0.0
5 |
6 |
7 | org.springframework.boot
8 | spring-boot-starter-parent
9 | 2.1.5.RELEASE
10 |
11 |
12 |
13 | com.snowalker
14 | order-charge-gateway
15 | 1.0.0
16 | order-charge-gateway
17 | Demo project for Spring Boot
18 |
19 |
20 | 1.8
21 | 1.8
22 | UTF-8
23 | UTF-8
24 | 1.3.2
25 | 29.0-jre
26 |
27 |
28 |
29 |
30 |
31 |
32 | com.snowalker
33 | order-charge-sdk
34 | 1.0.0
35 |
36 |
37 |
38 |
39 | org.apache.rocketmq
40 | rocketmq-client
41 | 4.3.2
42 |
43 |
44 |
45 | com.snowalker
46 | order-charge-message-protocol
47 | 1.0.0
48 |
49 |
50 |
51 | org.springframework.boot
52 | spring-boot-starter-web
53 |
54 |
55 |
56 | org.springframework.boot
57 | spring-boot-starter-test
58 | test
59 |
60 |
61 |
62 | org.springframework.boot
63 | spring-boot-starter-jdbc
64 |
65 |
66 |
67 | mysql
68 | mysql-connector-java
69 | runtime
70 |
71 |
72 |
73 |
74 | org.apache.commons
75 | commons-lang3
76 | 3.4
77 |
78 |
79 |
80 |
81 | com.alibaba
82 | fastjson
83 | 1.2.58
84 |
85 |
86 |
87 |
88 | com.google.guava
89 | guava
90 | ${guava-version}
91 |
92 |
93 |
94 |
95 | commons-codec
96 | commons-codec
97 | 1.12
98 |
99 |
100 |
101 |
102 | org.mybatis.spring.boot
103 | mybatis-spring-boot-starter
104 | ${mybatis-spring-boot-starter-version}
105 |
106 |
107 |
108 |
109 |
110 |
111 | org.springframework.boot
112 | spring-boot-maven-plugin
113 |
114 |
115 |
116 |
117 |
118 |
--------------------------------------------------------------------------------
/order-charge-gateway-notify/src/main/java/com/snowalker/notify/common/service/impl/WalletServiceImpl.java:
--------------------------------------------------------------------------------
1 | package com.snowalker.notify.common.service.impl;
2 |
3 | import com.snowalker.notify.common.dao.WalletMapper;
4 | import com.snowalker.notify.common.dao.dataobject.ChargeRecordEntity;
5 | import com.snowalker.notify.common.dao.dataobject.OrderEntity;
6 | import com.snowalker.notify.common.dao.dataobject.WalletEntity;
7 | import com.snowalker.notify.common.service.WalletService;
8 | import org.slf4j.Logger;
9 | import org.slf4j.LoggerFactory;
10 | import org.springframework.beans.factory.annotation.Autowired;
11 | import org.springframework.stereotype.Service;
12 | import org.springframework.transaction.annotation.Transactional;
13 |
14 | import java.util.HashMap;
15 | import java.util.Map;
16 | import java.util.UUID;
17 |
18 | /**
19 | * @author snowalker
20 | * @version 1.0
21 | * @date 2019/6/12 9:20
22 | * @className WalletServiceImpl
23 | * @desc 钱包接口实现
24 | */
25 | @Service(value = "walletService")
26 | public class WalletServiceImpl implements WalletService {
27 |
28 | private static final Logger LOGGER = LoggerFactory.getLogger(WalletServiceImpl.class);
29 |
30 | @Autowired
31 | WalletMapper walletMapper;
32 |
33 | /**
34 | * 新增用户钱包
35 | * @param walletEntity
36 | */
37 | @Transactional(rollbackFor = Exception.class)
38 | @Override
39 | public void insertWallet(WalletEntity walletEntity) {
40 | String purseId = walletEntity.getPurseId();
41 | try {
42 | walletMapper.insertWallet(walletEntity);
43 | LOGGER.info("钱包数据插入成功,purseId={}", purseId);
44 | } catch (Exception e) {
45 | LOGGER.error("钱包数据插入异常,purseId={},e={}", purseId, e);
46 | throw e;
47 | }
48 | }
49 |
50 | /**
51 | * 修改用户钱包数据
52 | * @param walletEntity
53 | * @return
54 | */
55 | @Transactional(rollbackFor = Exception.class)
56 | @Override
57 | public boolean updateWallet(WalletEntity walletEntity, String orderId) {
58 | // 插入扣款流水
59 | Map paramsInsert = new HashMap<>(16);
60 | String recordId = UUID.randomUUID().toString().replace("-", "");
61 | paramsInsert.put("recordId", recordId);
62 | paramsInsert.put("orderId", orderId);
63 | paramsInsert.put("purseId", walletEntity.getPurseId());
64 | paramsInsert.put("merchantName", walletEntity.getMerchantName());
65 | paramsInsert.put("chargeMoney", walletEntity.getChargeMoney());
66 | try {
67 | walletMapper.insertChargeRecord(paramsInsert);
68 | LOGGER.info("扣款流水插入成功,purseId={},recordId={}", walletEntity.getPurseId(), recordId);
69 | } catch (Exception e) {
70 | LOGGER.error("扣款流水插入异常,purseId={},recordId={},e={}", walletEntity.getPurseId(), recordId, e);
71 | throw e;
72 | }
73 | // 执行扣款
74 | Map paramsUpdate = new HashMap<>(16);
75 | paramsUpdate.put("chargeMoney", walletEntity.getChargeMoney());
76 | paramsUpdate.put("version", walletEntity.getVersion());
77 | paramsUpdate.put("purseId", walletEntity.getPurseId());
78 | int updateCount = walletMapper.updateWallet(paramsUpdate);
79 | if (updateCount == 1) {
80 | LOGGER.info("钱包数据修改成功,purseId={}", walletEntity.getPurseId());
81 | return true;
82 | } else {
83 | LOGGER.error("并发修改钱包数据修改异常,purseId={}", walletEntity.getPurseId());
84 | throw new RuntimeException("Exception occurred while updating wallet, purseId=" + walletEntity.getPurseId());
85 | }
86 | }
87 |
88 | /**
89 | * 查询扣款流水
90 | * @param orderId
91 | * @return
92 | */
93 | @Override
94 | public ChargeRecordEntity queryChargeRecordByOrderId(String orderId) {
95 | OrderEntity orderEntity = new OrderEntity();
96 | orderEntity.setOrderId(orderId);
97 | return walletMapper.queryChargeRecordByOrderId(orderEntity);
98 | }
99 |
100 | /**
101 | * 查询钱包信息
102 | * @param purseId
103 | * @return
104 | */
105 | @Override
106 | public WalletEntity queryWalletInfoByPurseId(String purseId) {
107 | Map queryParams = new HashMap<>(16);
108 | queryParams.put("purseId", purseId);
109 | WalletEntity walletEntity = walletMapper.queryWalletInfoByPurseId(queryParams);
110 | LOGGER.info("根据钱包purseId={},查询到钱包信息:walletInfo={}", purseId, walletEntity.toString());
111 | return walletEntity;
112 | }
113 | }
114 |
--------------------------------------------------------------------------------
/order-charge-gateway-notify/src/main/java/com/snowalker/notify/mq/payment/producer/listener/LocalTranListenerImpl.java:
--------------------------------------------------------------------------------
1 | package com.snowalker.notify.mq.payment.producer.listener;
2 |
3 | import com.snowalker.notify.common.dao.dataobject.ChargeRecordEntity;
4 | import com.snowalker.notify.common.dao.dataobject.WalletEntity;
5 | import com.snowalker.notify.common.service.WalletService;
6 | import com.snowalker.notify.common.util.LogExceptionWapper;
7 | import com.snowalker.order.charge.message.protocol.OrderStatusUpdateProtocol;
8 | import com.snowalker.order.charge.message.protocol.WalletPaymentProtocol;
9 | import org.apache.rocketmq.client.producer.LocalTransactionState;
10 | import org.apache.rocketmq.client.producer.TransactionListener;
11 | import org.apache.rocketmq.common.message.Message;
12 | import org.apache.rocketmq.common.message.MessageExt;
13 | import org.slf4j.Logger;
14 | import org.slf4j.LoggerFactory;
15 | import org.springframework.beans.factory.annotation.Autowired;
16 | import org.springframework.stereotype.Component;
17 |
18 | import java.math.BigDecimal;
19 |
20 | /**
21 | * @author snowalker
22 | * @version 1.0
23 | * @date 2019/6/12 9:41
24 | * @className PaymentTranListenerImpl
25 | * @desc 扣款本地事务监听回调
26 | */
27 | @Component(value = "localTranListenerImpl")
28 | public class LocalTranListenerImpl implements TransactionListener {
29 |
30 | private static final Logger LOGGER = LoggerFactory.getLogger(LocalTranListenerImpl.class);
31 |
32 | @Autowired
33 | WalletService walletService;
34 |
35 | /**
36 | * 扣款本地事务
37 | * @param msg
38 | * @param arg
39 | * @return
40 | */
41 | @Override
42 | public LocalTransactionState executeLocalTransaction(Message msg, Object arg) {
43 | String message = new String(msg.getBody());
44 | LOGGER.info("[扣款本地事务监听回调]执行逻辑--接收到消息, message={}", message);
45 | OrderStatusUpdateProtocol protocol = new OrderStatusUpdateProtocol();
46 | protocol.decode(message);
47 | // 扣款
48 | String purseId = protocol.getPurseId();
49 | String merchantName = protocol.getMerchantName();
50 | LOGGER.info("[扣款本地事务监听回调]反序列化扣款消息成功,开始进行扣款操作,purseId={}", purseId);
51 | WalletEntity walletEntity = new WalletEntity();
52 | walletEntity.setChargeMoney(
53 | new BigDecimal(protocol.getChargeMoney()))
54 | .setPurseId(purseId)
55 | .setMerchantName(merchantName);
56 | // 查询当前账户信息获取版本号,基于乐观锁更新
57 | WalletEntity realWalletInfo = walletService.queryWalletInfoByPurseId(protocol.getPurseId());
58 | // 判断是否足够扣减
59 | BigDecimal currBalanceAccount = realWalletInfo.getBalanceAccount();
60 | if (currBalanceAccount.subtract(new BigDecimal(protocol.getChargeMoney())).longValue() < 0) {
61 | LOGGER.error("执行钱包扣款,账户不足扣减,消息回滚.purseId={}", purseId);
62 | return LocalTransactionState.ROLLBACK_MESSAGE;
63 | }
64 | // 足够扣减,进行账户扣减
65 | int version = realWalletInfo.getVersion();
66 | walletEntity.setVersion(version);
67 | try {
68 | if (!walletService.updateWallet(walletEntity, protocol.getOrderId())) {
69 | return LocalTransactionState.ROLLBACK_MESSAGE;
70 | }
71 | } catch (Exception e) {
72 | LOGGER.error("执行钱包扣款本地扣款异常,purseId={},e={}", purseId, LogExceptionWapper.getStackTrace(e));
73 | return LocalTransactionState.UNKNOW;
74 | }
75 | LOGGER.info("[扣款本地事务监听回调]扣款本地操作成功,本地事务提交,purseId={}", purseId);
76 | return LocalTransactionState.COMMIT_MESSAGE;
77 | }
78 |
79 | /**
80 | * 本地事务回查: 回查依据是否存在扣款流水
81 | * @param msg
82 | * @return
83 | */
84 | @Override
85 | public LocalTransactionState checkLocalTransaction(MessageExt msg) {
86 | // 本地事务回查,查询扣款流水
87 | String message = new String(msg.getBody());
88 | String msgId = msg.getMsgId();
89 | LOGGER.info("[扣款本地事务回查]-接收到消息,msgId={},message={}", msgId, message);
90 | WalletPaymentProtocol payProtocol = new WalletPaymentProtocol();
91 | payProtocol.decode(message);
92 | // 获取订单号
93 | String orderId = payProtocol.getOrderId();
94 | ChargeRecordEntity chargeRecordEntity =
95 | walletService.queryChargeRecordByOrderId(orderId);
96 | if (chargeRecordEntity == null) {
97 | LOGGER.info("[扣款本地事务回查]-本地不存在扣款流水,消息回滚,msgId={}", msgId);
98 | return LocalTransactionState.ROLLBACK_MESSAGE;
99 | }
100 | LOGGER.info("[扣款本地事务回查]-本地存在扣款流水,消息提交,msgId={}", msgId);
101 | return LocalTransactionState.COMMIT_MESSAGE;
102 | }
103 | }
104 |
--------------------------------------------------------------------------------
/order-charge-gateway-merchant/src/main/java/com/snowalker/gateway/merchant/order/dataobject/ChargeOrderDO.java:
--------------------------------------------------------------------------------
1 | package com.snowalker.gateway.merchant.order.dataobject;
2 |
3 | import java.math.BigDecimal;
4 | import java.util.Date;
5 |
6 | /**
7 | * @author snowalker
8 | * @version 1.0
9 | * @date 2019/6/11 11:26
10 | * @className ChargeOrderDO
11 | * @desc 订单数据库DO
12 | */
13 | public class ChargeOrderDO {
14 |
15 | private Integer id;
16 | private Date gmtCreate;
17 | private Date gmtUpdate;
18 | private String orderId;
19 | private Integer orderStatus;
20 | private String userPhoneNo;
21 | private String prodId;
22 | private String prodName;
23 | private String outProdId;
24 | private String outProdName;
25 | private BigDecimal chargeMoney;
26 | private Date finishTime;
27 | private String outOrderId;
28 |
29 | public Integer getId() {
30 | return id;
31 | }
32 |
33 | public ChargeOrderDO setId(Integer id) {
34 | this.id = id;
35 | return this;
36 | }
37 |
38 | public Date getGmtCreate() {
39 | return gmtCreate;
40 | }
41 |
42 | public ChargeOrderDO setGmtCreate(Date gmtCreate) {
43 | this.gmtCreate = gmtCreate;
44 | return this;
45 | }
46 |
47 | public Date getGmtUpdate() {
48 | return gmtUpdate;
49 | }
50 |
51 | public ChargeOrderDO setGmtUpdate(Date gmtUpdate) {
52 | this.gmtUpdate = gmtUpdate;
53 | return this;
54 | }
55 |
56 | public String getOrderId() {
57 | return orderId;
58 | }
59 |
60 | public ChargeOrderDO setOrderId(String orderId) {
61 | this.orderId = orderId;
62 | return this;
63 | }
64 |
65 | public Integer getOrderStatus() {
66 | return orderStatus;
67 | }
68 |
69 | public ChargeOrderDO setOrderStatus(Integer orderStatus) {
70 | this.orderStatus = orderStatus;
71 | return this;
72 | }
73 |
74 | public String getUserPhoneNo() {
75 | return userPhoneNo;
76 | }
77 |
78 | public ChargeOrderDO setUserPhoneNo(String userPhoneNo) {
79 | this.userPhoneNo = userPhoneNo;
80 | return this;
81 | }
82 |
83 | public String getProdId() {
84 | return prodId;
85 | }
86 |
87 | public ChargeOrderDO setProdId(String prodId) {
88 | this.prodId = prodId;
89 | return this;
90 | }
91 |
92 | public String getProdName() {
93 | return prodName;
94 | }
95 |
96 | public ChargeOrderDO setProdName(String prodName) {
97 | this.prodName = prodName;
98 | return this;
99 | }
100 |
101 | public String getOutProdId() {
102 | return outProdId;
103 | }
104 |
105 | public ChargeOrderDO setOutProdId(String outProdId) {
106 | this.outProdId = outProdId;
107 | return this;
108 | }
109 |
110 | public String getOutProdName() {
111 | return outProdName;
112 | }
113 |
114 | public ChargeOrderDO setOutProdName(String outProdName) {
115 | this.outProdName = outProdName;
116 | return this;
117 | }
118 |
119 | public BigDecimal getChargeMoney() {
120 | return chargeMoney;
121 | }
122 |
123 | public ChargeOrderDO setChargeMoney(BigDecimal chargeMoney) {
124 | this.chargeMoney = chargeMoney;
125 | return this;
126 | }
127 |
128 | public Date getFinishTime() {
129 | return finishTime;
130 | }
131 |
132 | public ChargeOrderDO setFinishTime(Date finishTime) {
133 | this.finishTime = finishTime;
134 | return this;
135 | }
136 |
137 | public String getOutOrderId() {
138 | return outOrderId;
139 | }
140 |
141 | public ChargeOrderDO setOutOrderId(String outOrderId) {
142 | this.outOrderId = outOrderId;
143 | return this;
144 | }
145 |
146 | @Override
147 | public String toString() {
148 | return "ChargeOrderDO{" +
149 | "id=" + id +
150 | ", gmtCreate=" + gmtCreate +
151 | ", gmtUpdate=" + gmtUpdate +
152 | ", orderId='" + orderId + '\'' +
153 | ", orderStatus=" + orderStatus +
154 | ", userPhoneNo='" + userPhoneNo + '\'' +
155 | ", prodId='" + prodId + '\'' +
156 | ", prodName='" + prodName + '\'' +
157 | ", outProdId='" + outProdId + '\'' +
158 | ", outProdName='" + outProdName + '\'' +
159 | ", chargeMoney=" + chargeMoney +
160 | ", finishTime=" + finishTime +
161 | ", outOrderId='" + outOrderId + '\'' +
162 | '}';
163 | }
164 | }
165 |
--------------------------------------------------------------------------------
/order-charge-gateway-merchant/src/main/java/com/snowalker/gateway/merchant/order/dto/ChargeOrderDto.java:
--------------------------------------------------------------------------------
1 | package com.snowalker.gateway.merchant.order.dto;
2 |
3 | import java.math.BigDecimal;
4 | import java.util.Date;
5 |
6 | /**
7 | * @author snowalker
8 | * @version 1.0
9 | * @date 2019/6/10 13:37
10 | * @className ChargeOrderDto
11 | * @desc 本地下单入参
12 | */
13 | public class ChargeOrderDto {
14 |
15 | private String orderId;
16 | private String phoneNum;
17 | private int orderStatus = 1;
18 | private String productId;
19 | private String productName;
20 | private String outProductId;
21 | private String outProductName;
22 | private BigDecimal chargeMoney;
23 |
24 | /**更新前状态*/
25 | private int beforeUpdateOrderStatus;
26 | /**欲更新状态*/
27 | private int afterUpdateOrderStatus;
28 | /**结束时间*/
29 | private Date finishTime;
30 | /**外部订单号*/
31 | private String outOrderId;
32 |
33 | public String getOutOrderId() {
34 | return outOrderId;
35 | }
36 |
37 | public ChargeOrderDto setOutOrderId(String outOrderId) {
38 | this.outOrderId = outOrderId;
39 | return this;
40 | }
41 |
42 | public Date getFinishTime() {
43 | return finishTime;
44 | }
45 |
46 | public ChargeOrderDto setFinishTime(Date finishTime) {
47 | this.finishTime = finishTime;
48 | return this;
49 | }
50 |
51 | public int getBeforeUpdateOrderStatus() {
52 | return beforeUpdateOrderStatus;
53 | }
54 |
55 | public ChargeOrderDto setBeforeUpdateOrderStatus(int beforeUpdateOrderStatus) {
56 | this.beforeUpdateOrderStatus = beforeUpdateOrderStatus;
57 | return this;
58 | }
59 |
60 | public int getAfterUpdateOrderStatus() {
61 | return afterUpdateOrderStatus;
62 | }
63 |
64 | public ChargeOrderDto setAfterUpdateOrderStatus(int afterUpdateOrderStatus) {
65 | this.afterUpdateOrderStatus = afterUpdateOrderStatus;
66 | return this;
67 | }
68 |
69 | public BigDecimal getChargeMoney() {
70 | return chargeMoney;
71 | }
72 |
73 | public ChargeOrderDto setChargeMoney(BigDecimal chargeMoney) {
74 | this.chargeMoney = chargeMoney;
75 | return this;
76 | }
77 |
78 | public String getOrderId() {
79 | return orderId;
80 | }
81 |
82 | public ChargeOrderDto setOrderId(String orderId) {
83 | this.orderId = orderId;
84 | return this;
85 | }
86 |
87 | public String getPhoneNum() {
88 | return phoneNum;
89 | }
90 |
91 | public ChargeOrderDto setPhoneNum(String phoneNum) {
92 | this.phoneNum = phoneNum;
93 | return this;
94 | }
95 |
96 | public int getOrderStatus() {
97 | return orderStatus;
98 | }
99 |
100 | public ChargeOrderDto setOrderStatus(int orderStatus) {
101 | this.orderStatus = orderStatus;
102 | return this;
103 | }
104 |
105 | public String getProductId() {
106 | return productId;
107 | }
108 |
109 | public ChargeOrderDto setProductId(String productId) {
110 | this.productId = productId;
111 | return this;
112 | }
113 |
114 | public String getProductName() {
115 | return productName;
116 | }
117 |
118 | public ChargeOrderDto setProductName(String productName) {
119 | this.productName = productName;
120 | return this;
121 | }
122 |
123 | public String getOutProductId() {
124 | return outProductId;
125 | }
126 |
127 | public ChargeOrderDto setOutProductId(String outProductId) {
128 | this.outProductId = outProductId;
129 | return this;
130 | }
131 |
132 | public String getOutProductName() {
133 | return outProductName;
134 | }
135 |
136 | public ChargeOrderDto setOutProductName(String outProductName) {
137 | this.outProductName = outProductName;
138 | return this;
139 | }
140 |
141 | @Override
142 | public String toString() {
143 | return "ChargeOrderDto{" +
144 | "orderId='" + orderId + '\'' +
145 | ", phoneNum='" + phoneNum + '\'' +
146 | ", orderStatus=" + orderStatus +
147 | ", productId='" + productId + '\'' +
148 | ", productName='" + productName + '\'' +
149 | ", outProductId='" + outProductId + '\'' +
150 | ", outProductName='" + outProductName + '\'' +
151 | ", chargeMoney=" + chargeMoney +
152 | ", beforeUpdateOrderStatus=" + beforeUpdateOrderStatus +
153 | ", afterUpdateOrderStatus=" + afterUpdateOrderStatus +
154 | ", finishTime=" + finishTime +
155 | ", outOrderId='" + outOrderId + '\'' +
156 | '}';
157 | }
158 | }
159 |
--------------------------------------------------------------------------------
/order-charge-gateway-server/src/main/java/com/snowalker/order/common/dao/dataobject/OrderInfoDO.java:
--------------------------------------------------------------------------------
1 | package com.snowalker.order.common.dao.dataobject;
2 |
3 | /**
4 | * @author snowalker
5 | * @version 1.0
6 | * @date 2019/6/11 19:50
7 | * @className OrderInfoDO
8 | * @desc 订单数据库映射实体
9 | */
10 | public class OrderInfoDO {
11 |
12 | private String orderId;
13 | private String channelOrderId;
14 | private String userPhoneNo;
15 | private String chargeMoney;
16 | private String purseId;
17 | private String merchantName;
18 |
19 | /**修改前后的订单状态*/
20 | private Integer beforeOrderStatus;
21 | private Integer afterOrderStatus;
22 | /**修改前后的通知状态*/
23 | private Integer beforeNotifyStatus;
24 | private Integer afterNotifyStatus;
25 | /**修改前后的支付状态*/
26 | private Integer beforePayStatus;
27 | private Integer afterPayStatus;
28 |
29 | public Integer getBeforeOrderStatus() {
30 | return beforeOrderStatus;
31 | }
32 |
33 | public OrderInfoDO setBeforeOrderStatus(Integer beforeOrderStatus) {
34 | this.beforeOrderStatus = beforeOrderStatus;
35 | return this;
36 | }
37 |
38 | public Integer getAfterOrderStatus() {
39 | return afterOrderStatus;
40 | }
41 |
42 | public OrderInfoDO setAfterOrderStatus(Integer afterOrderStatus) {
43 | this.afterOrderStatus = afterOrderStatus;
44 | return this;
45 | }
46 |
47 | public Integer getBeforeNotifyStatus() {
48 | return beforeNotifyStatus;
49 | }
50 |
51 | public OrderInfoDO setBeforeNotifyStatus(Integer beforeNotifyStatus) {
52 | this.beforeNotifyStatus = beforeNotifyStatus;
53 | return this;
54 | }
55 |
56 | public Integer getAfterNotifyStatus() {
57 | return afterNotifyStatus;
58 | }
59 |
60 | public OrderInfoDO setAfterNotifyStatus(Integer afterNotifyStatus) {
61 | this.afterNotifyStatus = afterNotifyStatus;
62 | return this;
63 | }
64 |
65 | public Integer getBeforePayStatus() {
66 | return beforePayStatus;
67 | }
68 |
69 | public OrderInfoDO setBeforePayStatus(Integer beforePayStatus) {
70 | this.beforePayStatus = beforePayStatus;
71 | return this;
72 | }
73 |
74 | public Integer getAfterPayStatus() {
75 | return afterPayStatus;
76 | }
77 |
78 | public OrderInfoDO setAfterPayStatus(Integer afterPayStatus) {
79 | this.afterPayStatus = afterPayStatus;
80 | return this;
81 | }
82 |
83 | public String getOrderId() {
84 | return orderId;
85 | }
86 |
87 | public OrderInfoDO setOrderId(String orderId) {
88 | this.orderId = orderId;
89 | return this;
90 | }
91 |
92 | public String getChannelOrderId() {
93 | return channelOrderId;
94 | }
95 |
96 | public OrderInfoDO setChannelOrderId(String channelOrderId) {
97 | this.channelOrderId = channelOrderId;
98 | return this;
99 | }
100 |
101 | public String getUserPhoneNo() {
102 | return userPhoneNo;
103 | }
104 |
105 | public OrderInfoDO setUserPhoneNo(String userPhoneNo) {
106 | this.userPhoneNo = userPhoneNo;
107 | return this;
108 | }
109 |
110 | public String getChargeMoney() {
111 | return chargeMoney;
112 | }
113 |
114 | public OrderInfoDO setChargeMoney(String chargeMoney) {
115 | this.chargeMoney = chargeMoney;
116 | return this;
117 | }
118 |
119 | public String getPurseId() {
120 | return purseId;
121 | }
122 |
123 | public OrderInfoDO setPurseId(String purseId) {
124 | this.purseId = purseId;
125 | return this;
126 | }
127 |
128 | public String getMerchantName() {
129 | return merchantName;
130 | }
131 |
132 | public OrderInfoDO setMerchantName(String merchantName) {
133 | this.merchantName = merchantName;
134 | return this;
135 | }
136 |
137 | @Override
138 | public String toString() {
139 | return "OrderInfoDO{" +
140 | "orderId='" + orderId + '\'' +
141 | ", channelOrderId='" + channelOrderId + '\'' +
142 | ", userPhoneNo='" + userPhoneNo + '\'' +
143 | ", chargeMoney='" + chargeMoney + '\'' +
144 | ", purseId='" + purseId + '\'' +
145 | ", merchantName='" + merchantName + '\'' +
146 | ", beforeOrderStatus=" + beforeOrderStatus +
147 | ", afterOrderStatus=" + afterOrderStatus +
148 | ", beforeNotifyStatus=" + beforeNotifyStatus +
149 | ", afterNotifyStatus=" + afterNotifyStatus +
150 | ", beforePayStatus=" + beforePayStatus +
151 | ", afterPayStatus=" + afterPayStatus +
152 | '}';
153 | }
154 | }
155 |
--------------------------------------------------------------------------------
/order-charge-gateway-notify/src/main/java/com/snowalker/notify/common/dao/dataobject/OrderEntity.java:
--------------------------------------------------------------------------------
1 | package com.snowalker.notify.common.dao.dataobject;
2 |
3 | import java.math.BigDecimal;
4 | import java.util.Date;
5 |
6 | /**
7 | * @author snowalker
8 | * @version 1.0
9 | * @date 2019/2/15 16:46
10 | * @className OrderEntity
11 | * @desc 模拟订单数据库实体
12 | */
13 | public class OrderEntity {
14 |
15 | private int id;
16 | private String orderId;
17 | /**支付状态 1 初始化 2 处理中 3 失败 0 成功*/
18 | private int orderStatus;
19 | /**支付状态 1 初始化 2 处理中 3 失败 0 成功*/
20 | private int payStatus;
21 | private String userName;
22 | private BigDecimal chargeMoney;
23 | /**钱包id*/
24 | private String purseId;
25 | private Date gmtCreate;
26 | private Date gmtUpdate;
27 | /**通知状态,1 初始化 2 通知处理中 3 失败 0 成功 -1 不需要通知*/
28 | private Integer notifyStatus;
29 | private String channelOrderId;
30 | private String userPhoneNo;
31 | private String merchantName;
32 |
33 | public Integer getNotifyStatus() {
34 | return notifyStatus;
35 | }
36 |
37 | public OrderEntity setNotifyStatus(Integer notifyStatus) {
38 | this.notifyStatus = notifyStatus;
39 | return this;
40 | }
41 |
42 | public String getChannelOrderId() {
43 | return channelOrderId;
44 | }
45 |
46 | public OrderEntity setChannelOrderId(String channelOrderId) {
47 | this.channelOrderId = channelOrderId;
48 | return this;
49 | }
50 |
51 | public String getUserPhoneNo() {
52 | return userPhoneNo;
53 | }
54 |
55 | public OrderEntity setUserPhoneNo(String userPhoneNo) {
56 | this.userPhoneNo = userPhoneNo;
57 | return this;
58 | }
59 |
60 | public String getMerchantName() {
61 | return merchantName;
62 | }
63 |
64 | public OrderEntity setMerchantName(String merchantName) {
65 | this.merchantName = merchantName;
66 | return this;
67 | }
68 |
69 | public BigDecimal getChargeMoney() {
70 | return chargeMoney;
71 | }
72 |
73 | public OrderEntity setChargeMoney(BigDecimal chargeMoney) {
74 | this.chargeMoney = chargeMoney;
75 | return this;
76 | }
77 |
78 | public String getPurseId() {
79 | return purseId;
80 | }
81 |
82 | public OrderEntity setPurseId(String purseId) {
83 | this.purseId = purseId;
84 | return this;
85 | }
86 |
87 | public int getId() {
88 | return id;
89 | }
90 |
91 | public OrderEntity setId(int id) {
92 | this.id = id;
93 | return this;
94 | }
95 |
96 | public String getOrderId() {
97 | return orderId;
98 | }
99 |
100 | public OrderEntity setOrderId(String orderId) {
101 | this.orderId = orderId;
102 | return this;
103 | }
104 |
105 | public int getOrderStatus() {
106 | return orderStatus;
107 | }
108 |
109 | public OrderEntity setOrderStatus(int orderStatus) {
110 | this.orderStatus = orderStatus;
111 | return this;
112 | }
113 |
114 | public int getPayStatus() {
115 | return payStatus;
116 | }
117 |
118 | public OrderEntity setPayStatus(int payStatus) {
119 | this.payStatus = payStatus;
120 | return this;
121 | }
122 |
123 | public String getUserName() {
124 | return userName;
125 | }
126 |
127 | public OrderEntity setUserName(String userName) {
128 | this.userName = userName;
129 | return this;
130 | }
131 |
132 | public Date getGmtCreate() {
133 | return gmtCreate;
134 | }
135 |
136 | public OrderEntity setGmtCreate(Date gmtCreate) {
137 | this.gmtCreate = gmtCreate;
138 | return this;
139 | }
140 |
141 | public Date getGmtUpdate() {
142 | return gmtUpdate;
143 | }
144 |
145 | public OrderEntity setGmtUpdate(Date gmtUpdate) {
146 | this.gmtUpdate = gmtUpdate;
147 | return this;
148 | }
149 |
150 | @Override
151 | public String toString() {
152 | return "OrderEntity{" +
153 | "id=" + id +
154 | ", orderId='" + orderId + '\'' +
155 | ", orderStatus=" + orderStatus +
156 | ", payStatus=" + payStatus +
157 | ", userName='" + userName + '\'' +
158 | ", chargeMoney=" + chargeMoney +
159 | ", purseId='" + purseId + '\'' +
160 | ", gmtCreate=" + gmtCreate +
161 | ", gmtUpdate=" + gmtUpdate +
162 | ", notifyStatus=" + notifyStatus +
163 | ", channelOrderId='" + channelOrderId + '\'' +
164 | ", userPhoneNo='" + userPhoneNo + '\'' +
165 | ", merchantName='" + merchantName + '\'' +
166 | '}';
167 | }
168 | }
169 |
--------------------------------------------------------------------------------
/order-charge-sdk/src/main/java/com/snowalker/order/charge/request/ChargeOrderRequest.java:
--------------------------------------------------------------------------------
1 | package com.snowalker.order.charge.request;
2 |
3 | import com.alibaba.fastjson.JSON;
4 | import com.google.common.base.Preconditions;
5 | import org.apache.commons.codec.digest.DigestUtils;
6 |
7 | import java.io.Serializable;
8 | import java.text.SimpleDateFormat;
9 | import java.util.Date;
10 | import java.util.Map;
11 | import java.util.TreeMap;
12 | import java.util.UUID;
13 |
14 | /**
15 | * @author snowalker
16 | * @version 1.0
17 | * @date 2019/6/10 14:33
18 | * @className ChargeOrderRequest
19 | * @desc 下单sdk接口请求参数
20 | */
21 | public class ChargeOrderRequest implements Serializable {
22 |
23 | private static final long serialVersionUID = 2596328097263464531L;
24 |
25 | /**商户订单号*/
26 | private String channelOrderId;
27 | private String userPhoneNum;
28 | private String chargePrice;
29 | private String purseId;
30 | private String merchantName;
31 | private String timestamp;
32 | private String prodId;
33 | private String sign;
34 |
35 | public String getProdId() {
36 | return prodId;
37 | }
38 |
39 | public ChargeOrderRequest setProdId(String prodId) {
40 | this.prodId = prodId;
41 | return this;
42 | }
43 |
44 | public String getTimestamp() {
45 | return timestamp;
46 | }
47 |
48 | public ChargeOrderRequest setTimestamp(String timestamp) {
49 | this.timestamp = timestamp;
50 | return this;
51 | }
52 |
53 | public String getChannelOrderId() {
54 | return channelOrderId;
55 | }
56 |
57 | public ChargeOrderRequest setChannelOrderId(String channelOrderId) {
58 | this.channelOrderId = channelOrderId;
59 | return this;
60 | }
61 |
62 | public String getUserPhoneNum() {
63 | return userPhoneNum;
64 | }
65 |
66 | public ChargeOrderRequest setUserPhoneNum(String userPhoneNum) {
67 | this.userPhoneNum = userPhoneNum;
68 | return this;
69 | }
70 |
71 | public String getChargePrice() {
72 | return chargePrice;
73 | }
74 |
75 | public ChargeOrderRequest setChargePrice(String chargePrice) {
76 | this.chargePrice = chargePrice;
77 | return this;
78 | }
79 |
80 | public String getPurseId() {
81 | return purseId;
82 | }
83 |
84 | public ChargeOrderRequest setPurseId(String purseId) {
85 | this.purseId = purseId;
86 | return this;
87 | }
88 |
89 | public String getMerchantName() {
90 | return merchantName;
91 | }
92 |
93 | public ChargeOrderRequest setMerchantName(String merchantName) {
94 | this.merchantName = merchantName;
95 | return this;
96 | }
97 |
98 | public String getSign() {
99 | return sign;
100 | }
101 |
102 | public ChargeOrderRequest setSign(String sign) {
103 | this.sign = sign;
104 | return this;
105 | }
106 |
107 | /**
108 | * MD5签名
109 | */
110 | public String sign(String privateKey) {
111 | Preconditions.checkNotNull(this.getChannelOrderId());
112 | Preconditions.checkNotNull(this.getUserPhoneNum());
113 | Preconditions.checkNotNull(this.getChargePrice());
114 | Preconditions.checkNotNull(this.getPurseId());
115 | Preconditions.checkNotNull(this.getMerchantName());
116 | Preconditions.checkNotNull(this.getTimestamp());
117 | Preconditions.checkNotNull(this.getProdId());
118 | Preconditions.checkNotNull(privateKey);
119 | // 参数排序
120 | Map params = new TreeMap<>();
121 | params.put("channelOrderId", this.getChannelOrderId());
122 | params.put("userPhoneNum", this.getUserPhoneNum());
123 | params.put("chargePrice", this.getChargePrice());
124 | params.put("purseId", this.getPurseId());
125 | params.put("merchantName", this.getMerchantName());
126 | params.put("timestamp", this.getTimestamp());
127 | params.put("prodId", this.getProdId());
128 | params.put("privateKey", privateKey);
129 | // 参数拼装并MD5签名
130 | StringBuilder signSourceBuilder = new StringBuilder();
131 | for (String key : params.keySet()) {
132 | signSourceBuilder.append(key).append("=").append(params.get(key)).append("&");
133 | }
134 | // 去除最后一个&
135 | String signSource = signSourceBuilder.toString();
136 | String beforeSign = signSource.substring(0, signSource.length() - 1);
137 | // md5签名
138 | return DigestUtils.md5Hex(beforeSign);
139 | }
140 |
141 | @Override
142 | public String toString() {
143 | return "ChargeOrderRequest{" +
144 | "channelOrderId='" + channelOrderId + '\'' +
145 | ", userPhoneNum='" + userPhoneNum + '\'' +
146 | ", chargePrice='" + chargePrice + '\'' +
147 | ", purseId='" + purseId + '\'' +
148 | ", merchantName='" + merchantName + '\'' +
149 | ", timestamp='" + timestamp + '\'' +
150 | ", prodId='" + prodId + '\'' +
151 | ", sign='" + sign + '\'' +
152 | '}';
153 | }
154 | }
155 |
--------------------------------------------------------------------------------
/order-charge-message-protocol/src/main/java/com/snowalker/order/charge/message/protocol/OrderStatusUpdateProtocol.java:
--------------------------------------------------------------------------------
1 | package com.snowalker.order.charge.message.protocol;
2 |
3 | import com.fasterxml.jackson.core.JsonProcessingException;
4 | import com.fasterxml.jackson.databind.JsonNode;
5 | import com.fasterxml.jackson.databind.ObjectMapper;
6 | import com.google.common.base.Preconditions;
7 | import com.google.common.collect.ImmutableMap;
8 | import com.snowalker.order.charge.message.constant.MessageProtocolConst;
9 |
10 | import java.io.IOException;
11 | import java.io.Serializable;
12 | import java.util.Map;
13 |
14 | /**
15 | * @author snowalker
16 | * @version 1.0
17 | * @date 2019/2/18 14:35
18 | * @className OrderStatusUpdateProtocol
19 | * @desc 订单状态修改消息协议
20 | */
21 | public class OrderStatusUpdateProtocol extends BaseMsg implements Serializable {
22 |
23 | private static final long serialVersionUID = -6415079919585308245L;
24 |
25 | private String purseId;
26 | private String merchantName;
27 | private String orderId;
28 | private String chargeMoney;
29 | private String eventType;
30 |
31 | private Map header;
32 | private Map body;
33 |
34 | @Override
35 | public String encode() {
36 | // 组装消息协议头
37 | ImmutableMap.Builder headerBuilder = new ImmutableMap.Builder()
38 | .put("version", this.getVersion())
39 | .put("topicName", MessageProtocolConst.ORDER_STATUS_UPDATE_TOPIC.getTopic());
40 | header = headerBuilder.build();
41 |
42 | body = new ImmutableMap.Builder()
43 | .put("purseId", this.getPurseId())
44 | .put("merchantName", this.getMerchantName())
45 | .put("chargeMoney", this.getChargeMoney())
46 | .put("orderId", this.getOrderId())
47 | .put("eventType", this.getEventType())
48 | .build();
49 |
50 | ImmutableMap map = new ImmutableMap.Builder()
51 | .put("header", header)
52 | .put("body", body)
53 | .build();
54 | // 返回序列化消息Json串
55 | String ret_string = null;
56 | ObjectMapper objectMapper = new ObjectMapper();
57 | try {
58 | ret_string = objectMapper.writeValueAsString(map);
59 | } catch (JsonProcessingException e) {
60 | throw new RuntimeException("OrderStatusUpdateProtocol消息序列化json异常", e);
61 | }
62 | return ret_string;
63 | }
64 |
65 | @Override
66 | public void decode(String msg) {
67 | Preconditions.checkNotNull(msg);
68 | ObjectMapper mapper = new ObjectMapper();
69 | try {
70 | JsonNode root = mapper.readTree(msg);
71 | // header
72 | this.setVersion(root.get("header").get("version").asText());
73 | this.setTopicName(root.get("header").get("topicName").asText());
74 | // body
75 | this.setPurseId(root.get("body").get("purseId").asText());
76 | this.setMerchantName(root.get("body").get("merchantName").asText());
77 | this.setChargeMoney(root.get("body").get("chargeMoney").asText());
78 | this.setOrderId(root.get("body").get("orderId").asText());
79 | this.setEventType(root.get("body").get("eventType").asText());
80 | } catch (IOException e) {
81 | throw new RuntimeException("OrderStatusUpdateProtocol消息反序列化异常", e);
82 | }
83 | }
84 |
85 | public String getOrderId() {
86 | return orderId;
87 | }
88 |
89 | public OrderStatusUpdateProtocol setOrderId(String orderId) {
90 | this.orderId = orderId;
91 | return this;
92 | }
93 |
94 | public String getPurseId() {
95 | return purseId;
96 | }
97 |
98 | public OrderStatusUpdateProtocol setPurseId(String purseId) {
99 | this.purseId = purseId;
100 | return this;
101 | }
102 |
103 | public String getMerchantName() {
104 | return merchantName;
105 | }
106 |
107 | public OrderStatusUpdateProtocol setMerchantName(String merchantName) {
108 | this.merchantName = merchantName;
109 | return this;
110 | }
111 |
112 | public String getChargeMoney() {
113 | return chargeMoney;
114 | }
115 |
116 | public OrderStatusUpdateProtocol setChargeMoney(String chargeMoney) {
117 | this.chargeMoney = chargeMoney;
118 | return this;
119 | }
120 |
121 | public String getEventType() {
122 | return eventType;
123 | }
124 |
125 | public OrderStatusUpdateProtocol setEventType(String eventType) {
126 | this.eventType = eventType;
127 | return this;
128 | }
129 |
130 | @Override
131 | public String toString() {
132 | return "OrderStatusUpdateProtocol{" +
133 | "purseId='" + purseId + '\'' +
134 | ", merchantName='" + merchantName + '\'' +
135 | ", orderId='" + orderId + '\'' +
136 | ", chargeMoney='" + chargeMoney + '\'' +
137 | ", eventType='" + eventType + '\'' +
138 | ", header=" + header +
139 | ", body=" + body +
140 | "} " + super.toString();
141 | }
142 | }
143 |
--------------------------------------------------------------------------------
/order-charge-gateway-merchant/src/main/java/com/snowalker/gateway/merchant/order/manager/OrderChargeManager.java:
--------------------------------------------------------------------------------
1 | package com.snowalker.gateway.merchant.order.manager;
2 |
3 | import com.alibaba.fastjson.JSON;
4 | import com.snowalker.gateway.merchant.order.dto.ChargeOrderDto;
5 | import com.snowalker.gateway.merchant.order.dto.Result;
6 | import com.snowalker.gateway.merchant.order.util.DateUtil;
7 | import com.snowalker.gateway.merchant.order.util.LogExceptionWapper;
8 | import com.snowalker.order.charge.constant.ResponseCodeEnum;
9 | import com.snowalker.order.charge.request.ChargeOrderRequest;
10 | import org.slf4j.Logger;
11 | import org.slf4j.LoggerFactory;
12 | import org.springframework.beans.factory.annotation.Autowired;
13 | import org.springframework.beans.factory.annotation.Value;
14 | import org.springframework.http.HttpEntity;
15 | import org.springframework.http.HttpHeaders;
16 | import org.springframework.http.MediaType;
17 | import org.springframework.http.ResponseEntity;
18 | import org.springframework.stereotype.Component;
19 | import org.springframework.web.client.RestTemplate;
20 |
21 | import java.util.Date;
22 | import java.util.HashMap;
23 | import java.util.Map;
24 |
25 | /**
26 | * @author snowalker
27 | * @version 1.0
28 | * @date 2019/6/10 16:39
29 | * @className OrderChargeManager
30 | * @desc 远程下单交互防腐层
31 | */
32 | @Component
33 | public class OrderChargeManager {
34 |
35 | private static final Logger LOGGER = LoggerFactory.getLogger(OrderChargeManager.class);
36 |
37 | @Autowired
38 | RestTemplate restTemplate;
39 |
40 | @Value("${agent.config.purseid}")
41 | private String purseId;
42 |
43 | @Value("${agent.config.merchant.name}")
44 | private String merchantName;
45 |
46 | @Value("${agent.config.private.key}")
47 | private String privateKey;
48 |
49 | @Value("${agent.config.request.url}")
50 | private String requestUrl;
51 |
52 | /**
53 | * 下单接口调用
54 | * @param chargeOrderDto
55 | * @return
56 | */
57 | public ResponseCodeEnum chargeRequest(ChargeOrderDto chargeOrderDto) {
58 |
59 | // 组装请求参数
60 | ChargeOrderRequest chargeOrderRequest = new ChargeOrderRequest();
61 | chargeOrderRequest.setChannelOrderId(chargeOrderDto.getOrderId())
62 | .setChargePrice(chargeOrderDto.getChargeMoney().toString())
63 | .setPurseId(purseId)
64 | .setMerchantName(merchantName)
65 | .setUserPhoneNum(chargeOrderDto.getPhoneNum())
66 | .setTimestamp(DateUtil.formatDate(new Date(System.currentTimeMillis())))
67 | .setProdId(chargeOrderDto.getOutProductId())
68 | .setSign(chargeOrderRequest.sign(privateKey));
69 | // 1. 设置请求头
70 | HttpHeaders headers = new HttpHeaders();
71 | headers.setContentType(MediaType.APPLICATION_JSON);
72 | // 2. 设置请求参数
73 | Map requestParam = new HashMap<>();
74 | requestParam.put("channelOrderId", chargeOrderRequest.getChannelOrderId());
75 | requestParam.put("chargePrice", chargeOrderRequest.getChargePrice());
76 | requestParam.put("merchantName", chargeOrderRequest.getMerchantName());
77 | requestParam.put("purseId", chargeOrderRequest.getPurseId());
78 | requestParam.put("timestamp", chargeOrderRequest.getTimestamp());
79 | requestParam.put("userPhoneNum", chargeOrderRequest.getUserPhoneNum());
80 | requestParam.put("prodId", chargeOrderRequest.getProdId());
81 | requestParam.put("sign", chargeOrderRequest.getSign());
82 | LOGGER.info("请求远端下单地址:{}, 下单入参:{}", requestUrl, requestParam.toString());
83 | // 3. 请求开始
84 | HttpEntity