Merge remote-tracking branch 'origin/feature/mall_product' into feature/mall_product

This commit is contained in:
zhijiantianya@gmail.com 2023-07-12 12:52:58 +08:00
commit 35ceef371c
9 changed files with 81 additions and 154 deletions

View File

@ -18,15 +18,6 @@ import java.util.Set;
@Data @Data
public class AlipayPayClientConfig implements PayClientConfig { public class AlipayPayClientConfig implements PayClientConfig {
/**
* 网关地址 - 线上
*/
public static final String SERVER_URL_PROD = "https://openapi.alipay.com/gateway.do";
/**
* 网关地址 - 沙箱
*/
public static final String SERVER_URL_SANDBOX = "https://openapi.alipaydev.com/gateway.do";
/** /**
* 公钥类型 - 公钥模式 * 公钥类型 - 公钥模式
*/ */
@ -43,8 +34,9 @@ public class AlipayPayClientConfig implements PayClientConfig {
/** /**
* 网关地址 * 网关地址
* 1. {@link #SERVER_URL_PROD} *
* 2. {@link #SERVER_URL_SANDBOX} * 1. <a href="https://openapi.alipay.com/gateway.do">生产环境</a>
* 2. <a href="https://openapi-sandbox.dl.alipaydev.com/gateway.do">沙箱环境</a>
*/ */
@NotBlank(message = "网关地址不能为空", groups = {ModePublicKey.class, ModeCertificate.class}) @NotBlank(message = "网关地址不能为空", groups = {ModePublicKey.class, ModeCertificate.class})
private String serverUrl; private String serverUrl;

View File

@ -24,6 +24,8 @@ import java.io.FileNotFoundException;
@Disabled @Disabled
public class PayClientFactoryImplIntegrationTest { public class PayClientFactoryImplIntegrationTest {
private static final String SERVER_URL_SANDBOX = "https://openapi.alipaydev.com/gateway.do";
private final PayClientFactoryImpl payClientFactory = new PayClientFactoryImpl(); private final PayClientFactoryImpl payClientFactory = new PayClientFactoryImpl();
/** /**
@ -79,7 +81,7 @@ public class PayClientFactoryImplIntegrationTest {
// 创建配置 // 创建配置
AlipayPayClientConfig config = new AlipayPayClientConfig(); AlipayPayClientConfig config = new AlipayPayClientConfig();
config.setAppId("2021000118634035"); config.setAppId("2021000118634035");
config.setServerUrl(AlipayPayClientConfig.SERVER_URL_SANDBOX); config.setServerUrl(SERVER_URL_SANDBOX);
config.setSignType(AlipayPayClientConfig.SIGN_TYPE_DEFAULT); config.setSignType(AlipayPayClientConfig.SIGN_TYPE_DEFAULT);
config.setPrivateKey("MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCHsEV1cDupwJv890x84qbppUtRIfhaKSwSVN0thCcsDCaAsGR5MZslDkO8NCT9V4r2SVXjyY7eJUZlZd1M0C8T01Tg4UOx5LUbic0O3A1uJMy6V1n9IyYwbAW3AEZhBd5bSbPgrqvmv3NeWSTQT6Anxnllf+2iDH6zyA2fPl7cYyQtbZoDJQFGqr4F+cGh2R6akzRKNoBkAeMYwoY6es2lX8sJxCVPWUmxNUoL3tScwlSpd7Bxw0q9c/X01jMwuQ0+Va358zgFiGERTE6yD01eu40OBDXOYO3z++y+TAYHlQQ2toMO63trepo88X3xV3R44/1DH+k2pAm2IF5ixiLrAgMBAAECggEAPx3SoXcseaD7rmcGcE0p4SMfbsUDdkUSmBBbtfF0GzwnqNLkWa+mgE0rWt9SmXngTQH97vByAYmLPl1s3G82ht1V7Sk7yQMe74lhFllr8eEyTjeVx3dTK1EEM4TwN+936DTXdFsr4TELJEcJJdD0KaxcCcfBLRDs2wnitEFZ9N+GoZybVmY8w0e0MI7PLObUZ2l0X4RurQnfG9ZxjXjC7PkeMVv7cGGylpNFi3BbvkRhdhLPDC2E6wqnr9e7zk+hiENivAezXrtxtwKovzCtnWJ1r0IO14Rh47H509Ic0wFnj+o5YyUL4LdmpL7yaaH6fM7zcSLFjNZPHvZCKPwYcQKBgQDQFho98QvnL8ex4v6cry4VitGpjSXm1qP3vmMQk4rTsn8iPWtcxPjqGEqOQJjdi4Mi0VZKQOLFwlH0kl95wNrD/isJ4O1yeYfX7YAXApzHqYNINzM79HemO3Yx1qLMW3okRFJ9pPRzbQ9qkTpsaegsmyX316zOBhzGRYjKbutTYwKBgQCm7phr9XdFW5Vh+XR90mVs483nrLmMiDKg7YKxSLJ8amiDjzPejCn7i95Hah08P+2MIZLIPbh2VLacczR6ltRRzN5bg5etFuqSgfkuHyxpoDmpjbe08+Q2h8JBYqcC5Nhv1AKU4iOUhVLHo/FBAQliMcGc/J3eiYTFC7EsNx382QKBgClb20doe7cttgFTXswBvaUmfFm45kmla924B7SpvrQpDD/f+VDtDZRp05fGmxuduSjYdtA3aVtpLiTwWu22OUUvZZqHDGruYOO4Hvdz23mL5b4ayqImCwoNU4bAZIc9v18p/UNf3/55NNE3oGcf/bev9rH2OjCQ4nM+Ktwhg8CFAoGACSgvbkShzUkv0ZcIf9ppu+ZnJh1AdGgINvGwaJ8vQ0nm/8h8NOoFZ4oNoGc+wU5Ubops7dUM6FjPR5e+OjdJ4E7Xp7d5O4J1TaIZlCEbo5OpdhaTDDcQvrkFu+Z4eN0qzj+YAKjDAOOrXc4tbr5q0FsgXscwtcNfaBuzFVTUrUkCgYEAwzPnMNhWG3zOWLUs2QFA2GP4Y+J8cpUYfj6pbKKzeLwyG9qBwF1NJpN8m+q9q7V9P2LY+9Lp9e1mGsGeqt5HMEA3P6vIpcqLJLqE/4PBLLRzfccTcmqb1m71+erxTRhHBRkGS+I7dZEb3olQfnS1Y1tpMBxiwYwR3LW4oXuJwj8="); config.setPrivateKey("MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCHsEV1cDupwJv890x84qbppUtRIfhaKSwSVN0thCcsDCaAsGR5MZslDkO8NCT9V4r2SVXjyY7eJUZlZd1M0C8T01Tg4UOx5LUbic0O3A1uJMy6V1n9IyYwbAW3AEZhBd5bSbPgrqvmv3NeWSTQT6Anxnllf+2iDH6zyA2fPl7cYyQtbZoDJQFGqr4F+cGh2R6akzRKNoBkAeMYwoY6es2lX8sJxCVPWUmxNUoL3tScwlSpd7Bxw0q9c/X01jMwuQ0+Va358zgFiGERTE6yD01eu40OBDXOYO3z++y+TAYHlQQ2toMO63trepo88X3xV3R44/1DH+k2pAm2IF5ixiLrAgMBAAECggEAPx3SoXcseaD7rmcGcE0p4SMfbsUDdkUSmBBbtfF0GzwnqNLkWa+mgE0rWt9SmXngTQH97vByAYmLPl1s3G82ht1V7Sk7yQMe74lhFllr8eEyTjeVx3dTK1EEM4TwN+936DTXdFsr4TELJEcJJdD0KaxcCcfBLRDs2wnitEFZ9N+GoZybVmY8w0e0MI7PLObUZ2l0X4RurQnfG9ZxjXjC7PkeMVv7cGGylpNFi3BbvkRhdhLPDC2E6wqnr9e7zk+hiENivAezXrtxtwKovzCtnWJ1r0IO14Rh47H509Ic0wFnj+o5YyUL4LdmpL7yaaH6fM7zcSLFjNZPHvZCKPwYcQKBgQDQFho98QvnL8ex4v6cry4VitGpjSXm1qP3vmMQk4rTsn8iPWtcxPjqGEqOQJjdi4Mi0VZKQOLFwlH0kl95wNrD/isJ4O1yeYfX7YAXApzHqYNINzM79HemO3Yx1qLMW3okRFJ9pPRzbQ9qkTpsaegsmyX316zOBhzGRYjKbutTYwKBgQCm7phr9XdFW5Vh+XR90mVs483nrLmMiDKg7YKxSLJ8amiDjzPejCn7i95Hah08P+2MIZLIPbh2VLacczR6ltRRzN5bg5etFuqSgfkuHyxpoDmpjbe08+Q2h8JBYqcC5Nhv1AKU4iOUhVLHo/FBAQliMcGc/J3eiYTFC7EsNx382QKBgClb20doe7cttgFTXswBvaUmfFm45kmla924B7SpvrQpDD/f+VDtDZRp05fGmxuduSjYdtA3aVtpLiTwWu22OUUvZZqHDGruYOO4Hvdz23mL5b4ayqImCwoNU4bAZIc9v18p/UNf3/55NNE3oGcf/bev9rH2OjCQ4nM+Ktwhg8CFAoGACSgvbkShzUkv0ZcIf9ppu+ZnJh1AdGgINvGwaJ8vQ0nm/8h8NOoFZ4oNoGc+wU5Ubops7dUM6FjPR5e+OjdJ4E7Xp7d5O4J1TaIZlCEbo5OpdhaTDDcQvrkFu+Z4eN0qzj+YAKjDAOOrXc4tbr5q0FsgXscwtcNfaBuzFVTUrUkCgYEAwzPnMNhWG3zOWLUs2QFA2GP4Y+J8cpUYfj6pbKKzeLwyG9qBwF1NJpN8m+q9q7V9P2LY+9Lp9e1mGsGeqt5HMEA3P6vIpcqLJLqE/4PBLLRzfccTcmqb1m71+erxTRhHBRkGS+I7dZEb3olQfnS1Y1tpMBxiwYwR3LW4oXuJwj8=");
config.setAlipayPublicKey("MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAnq90KnF4dTnlzzmxpujbI05OYqi5WxAS6cL0gnZFv2gK51HExF8v/BaP7P979PhFMgWTqmOOI+Dtno5s+yD09XTY1WkshbLk6i4g2Xlr8fyW9ODnkU88RI2w9UdPhQU4cPPwBNlrsYhKkVK2OxwM3kFqjoBBY0CZoZCsSQ3LDH5WeZqPArlsS6xa2zqJBuuoKjMrdpELl3eXSjP8K54eDJCbeetCZNKWLL3DPahTPB7LZikfYmslb0QUvCgGapD0xkS7eVq70NaL1G57MWABs4tbfWgxike4Daj3EfUrzIVspQxj7w8HEj9WozJPgL88kSJSits0pqD3n5r8HSuseQIDAQAB"); config.setAlipayPublicKey("MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAnq90KnF4dTnlzzmxpujbI05OYqi5WxAS6cL0gnZFv2gK51HExF8v/BaP7P979PhFMgWTqmOOI+Dtno5s+yD09XTY1WkshbLk6i4g2Xlr8fyW9ODnkU88RI2w9UdPhQU4cPPwBNlrsYhKkVK2OxwM3kFqjoBBY0CZoZCsSQ3LDH5WeZqPArlsS6xa2zqJBuuoKjMrdpELl3eXSjP8K54eDJCbeetCZNKWLL3DPahTPB7LZikfYmslb0QUvCgGapD0xkS7eVq70NaL1G57MWABs4tbfWgxike4Daj3EfUrzIVspQxj7w8HEj9WozJPgL88kSJSits0pqD3n5r8HSuseQIDAQAB");
@ -103,7 +105,7 @@ public class PayClientFactoryImplIntegrationTest {
// 创建配置 // 创建配置
AlipayPayClientConfig config = new AlipayPayClientConfig(); AlipayPayClientConfig config = new AlipayPayClientConfig();
config.setAppId("2021000118634035"); config.setAppId("2021000118634035");
config.setServerUrl(AlipayPayClientConfig.SERVER_URL_SANDBOX); config.setServerUrl(SERVER_URL_SANDBOX);
config.setSignType(AlipayPayClientConfig.SIGN_TYPE_DEFAULT); config.setSignType(AlipayPayClientConfig.SIGN_TYPE_DEFAULT);
config.setPrivateKey("MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCHsEV1cDupwJv890x84qbppUtRIfhaKSwSVN0thCcsDCaAsGR5MZslDkO8NCT9V4r2SVXjyY7eJUZlZd1M0C8T01Tg4UOx5LUbic0O3A1uJMy6V1n9IyYwbAW3AEZhBd5bSbPgrqvmv3NeWSTQT6Anxnllf+2iDH6zyA2fPl7cYyQtbZoDJQFGqr4F+cGh2R6akzRKNoBkAeMYwoY6es2lX8sJxCVPWUmxNUoL3tScwlSpd7Bxw0q9c/X01jMwuQ0+Va358zgFiGERTE6yD01eu40OBDXOYO3z++y+TAYHlQQ2toMO63trepo88X3xV3R44/1DH+k2pAm2IF5ixiLrAgMBAAECggEAPx3SoXcseaD7rmcGcE0p4SMfbsUDdkUSmBBbtfF0GzwnqNLkWa+mgE0rWt9SmXngTQH97vByAYmLPl1s3G82ht1V7Sk7yQMe74lhFllr8eEyTjeVx3dTK1EEM4TwN+936DTXdFsr4TELJEcJJdD0KaxcCcfBLRDs2wnitEFZ9N+GoZybVmY8w0e0MI7PLObUZ2l0X4RurQnfG9ZxjXjC7PkeMVv7cGGylpNFi3BbvkRhdhLPDC2E6wqnr9e7zk+hiENivAezXrtxtwKovzCtnWJ1r0IO14Rh47H509Ic0wFnj+o5YyUL4LdmpL7yaaH6fM7zcSLFjNZPHvZCKPwYcQKBgQDQFho98QvnL8ex4v6cry4VitGpjSXm1qP3vmMQk4rTsn8iPWtcxPjqGEqOQJjdi4Mi0VZKQOLFwlH0kl95wNrD/isJ4O1yeYfX7YAXApzHqYNINzM79HemO3Yx1qLMW3okRFJ9pPRzbQ9qkTpsaegsmyX316zOBhzGRYjKbutTYwKBgQCm7phr9XdFW5Vh+XR90mVs483nrLmMiDKg7YKxSLJ8amiDjzPejCn7i95Hah08P+2MIZLIPbh2VLacczR6ltRRzN5bg5etFuqSgfkuHyxpoDmpjbe08+Q2h8JBYqcC5Nhv1AKU4iOUhVLHo/FBAQliMcGc/J3eiYTFC7EsNx382QKBgClb20doe7cttgFTXswBvaUmfFm45kmla924B7SpvrQpDD/f+VDtDZRp05fGmxuduSjYdtA3aVtpLiTwWu22OUUvZZqHDGruYOO4Hvdz23mL5b4ayqImCwoNU4bAZIc9v18p/UNf3/55NNE3oGcf/bev9rH2OjCQ4nM+Ktwhg8CFAoGACSgvbkShzUkv0ZcIf9ppu+ZnJh1AdGgINvGwaJ8vQ0nm/8h8NOoFZ4oNoGc+wU5Ubops7dUM6FjPR5e+OjdJ4E7Xp7d5O4J1TaIZlCEbo5OpdhaTDDcQvrkFu+Z4eN0qzj+YAKjDAOOrXc4tbr5q0FsgXscwtcNfaBuzFVTUrUkCgYEAwzPnMNhWG3zOWLUs2QFA2GP4Y+J8cpUYfj6pbKKzeLwyG9qBwF1NJpN8m+q9q7V9P2LY+9Lp9e1mGsGeqt5HMEA3P6vIpcqLJLqE/4PBLLRzfccTcmqb1m71+erxTRhHBRkGS+I7dZEb3olQfnS1Y1tpMBxiwYwR3LW4oXuJwj8="); config.setPrivateKey("MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCHsEV1cDupwJv890x84qbppUtRIfhaKSwSVN0thCcsDCaAsGR5MZslDkO8NCT9V4r2SVXjyY7eJUZlZd1M0C8T01Tg4UOx5LUbic0O3A1uJMy6V1n9IyYwbAW3AEZhBd5bSbPgrqvmv3NeWSTQT6Anxnllf+2iDH6zyA2fPl7cYyQtbZoDJQFGqr4F+cGh2R6akzRKNoBkAeMYwoY6es2lX8sJxCVPWUmxNUoL3tScwlSpd7Bxw0q9c/X01jMwuQ0+Va358zgFiGERTE6yD01eu40OBDXOYO3z++y+TAYHlQQ2toMO63trepo88X3xV3R44/1DH+k2pAm2IF5ixiLrAgMBAAECggEAPx3SoXcseaD7rmcGcE0p4SMfbsUDdkUSmBBbtfF0GzwnqNLkWa+mgE0rWt9SmXngTQH97vByAYmLPl1s3G82ht1V7Sk7yQMe74lhFllr8eEyTjeVx3dTK1EEM4TwN+936DTXdFsr4TELJEcJJdD0KaxcCcfBLRDs2wnitEFZ9N+GoZybVmY8w0e0MI7PLObUZ2l0X4RurQnfG9ZxjXjC7PkeMVv7cGGylpNFi3BbvkRhdhLPDC2E6wqnr9e7zk+hiENivAezXrtxtwKovzCtnWJ1r0IO14Rh47H509Ic0wFnj+o5YyUL4LdmpL7yaaH6fM7zcSLFjNZPHvZCKPwYcQKBgQDQFho98QvnL8ex4v6cry4VitGpjSXm1qP3vmMQk4rTsn8iPWtcxPjqGEqOQJjdi4Mi0VZKQOLFwlH0kl95wNrD/isJ4O1yeYfX7YAXApzHqYNINzM79HemO3Yx1qLMW3okRFJ9pPRzbQ9qkTpsaegsmyX316zOBhzGRYjKbutTYwKBgQCm7phr9XdFW5Vh+XR90mVs483nrLmMiDKg7YKxSLJ8amiDjzPejCn7i95Hah08P+2MIZLIPbh2VLacczR6ltRRzN5bg5etFuqSgfkuHyxpoDmpjbe08+Q2h8JBYqcC5Nhv1AKU4iOUhVLHo/FBAQliMcGc/J3eiYTFC7EsNx382QKBgClb20doe7cttgFTXswBvaUmfFm45kmla924B7SpvrQpDD/f+VDtDZRp05fGmxuduSjYdtA3aVtpLiTwWu22OUUvZZqHDGruYOO4Hvdz23mL5b4ayqImCwoNU4bAZIc9v18p/UNf3/55NNE3oGcf/bev9rH2OjCQ4nM+Ktwhg8CFAoGACSgvbkShzUkv0ZcIf9ppu+ZnJh1AdGgINvGwaJ8vQ0nm/8h8NOoFZ4oNoGc+wU5Ubops7dUM6FjPR5e+OjdJ4E7Xp7d5O4J1TaIZlCEbo5OpdhaTDDcQvrkFu+Z4eN0qzj+YAKjDAOOrXc4tbr5q0FsgXscwtcNfaBuzFVTUrUkCgYEAwzPnMNhWG3zOWLUs2QFA2GP4Y+J8cpUYfj6pbKKzeLwyG9qBwF1NJpN8m+q9q7V9P2LY+9Lp9e1mGsGeqt5HMEA3P6vIpcqLJLqE/4PBLLRzfccTcmqb1m71+erxTRhHBRkGS+I7dZEb3olQfnS1Y1tpMBxiwYwR3LW4oXuJwj8=");
config.setAlipayPublicKey("MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAnq90KnF4dTnlzzmxpujbI05OYqi5WxAS6cL0gnZFv2gK51HExF8v/BaP7P979PhFMgWTqmOOI+Dtno5s+yD09XTY1WkshbLk6i4g2Xlr8fyW9ODnkU88RI2w9UdPhQU4cPPwBNlrsYhKkVK2OxwM3kFqjoBBY0CZoZCsSQ3LDH5WeZqPArlsS6xa2zqJBuuoKjMrdpELl3eXSjP8K54eDJCbeetCZNKWLL3DPahTPB7LZikfYmslb0QUvCgGapD0xkS7eVq70NaL1G57MWABs4tbfWgxike4Daj3EfUrzIVspQxj7w8HEj9WozJPgL88kSJSits0pqD3n5r8HSuseQIDAQAB"); config.setAlipayPublicKey("MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAnq90KnF4dTnlzzmxpujbI05OYqi5WxAS6cL0gnZFv2gK51HExF8v/BaP7P979PhFMgWTqmOOI+Dtno5s+yD09XTY1WkshbLk6i4g2Xlr8fyW9ODnkU88RI2w9UdPhQU4cPPwBNlrsYhKkVK2OxwM3kFqjoBBY0CZoZCsSQ3LDH5WeZqPArlsS6xa2zqJBuuoKjMrdpELl3eXSjP8K54eDJCbeetCZNKWLL3DPahTPB7LZikfYmslb0QUvCgGapD0xkS7eVq70NaL1G57MWABs4tbfWgxike4Daj3EfUrzIVspQxj7w8HEj9WozJPgL88kSJSits0pqD3n5r8HSuseQIDAQAB");

View File

@ -82,9 +82,9 @@ public class TenantUtils {
* 将多租户编号添加到 header * 将多租户编号添加到 header
* *
* @param headers HTTP 请求 headers * @param headers HTTP 请求 headers
* @param tenantId 租户编号
*/ */
public static void addTenantHeader(Map<String, String> headers) { public static void addTenantHeader(Map<String, String> headers, Long tenantId) {
Long tenantId = TenantContextHolder.getTenantId();
if (tenantId != null) { if (tenantId != null) {
headers.put(HEADER_TENANT_ID, tenantId.toString()); headers.put(HEADER_TENANT_ID, tenantId.toString());
} }

View File

@ -1,6 +1,6 @@
package cn.iocoder.yudao.module.pay.dal.dataobject.notify; package cn.iocoder.yudao.module.pay.dal.dataobject.notify;
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; import cn.iocoder.yudao.framework.tenant.core.db.TenantBaseDO;
import cn.iocoder.yudao.module.pay.dal.dataobject.app.PayAppDO; import cn.iocoder.yudao.module.pay.dal.dataobject.app.PayAppDO;
import cn.iocoder.yudao.module.pay.dal.dataobject.order.PayOrderDO; import cn.iocoder.yudao.module.pay.dal.dataobject.order.PayOrderDO;
import cn.iocoder.yudao.module.pay.dal.dataobject.refund.PayRefundDO; import cn.iocoder.yudao.module.pay.dal.dataobject.refund.PayRefundDO;
@ -25,7 +25,7 @@ import java.time.LocalDateTime;
@Data @Data
@EqualsAndHashCode(callSuper = true) @EqualsAndHashCode(callSuper = true)
@Accessors(chain = true) @Accessors(chain = true)
public class PayNotifyTaskDO extends BaseDO { public class PayNotifyTaskDO extends TenantBaseDO {
/** /**
* 通知频率单位为秒 * 通知频率单位为秒

View File

@ -24,10 +24,11 @@ import cn.iocoder.yudao.module.pay.service.order.PayOrderService;
import cn.iocoder.yudao.module.pay.service.refund.PayRefundService; import cn.iocoder.yudao.module.pay.service.refund.PayRefundService;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Lazy; import org.springframework.context.annotation.Lazy;
import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor; import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.support.TransactionSynchronization;
import org.springframework.transaction.support.TransactionSynchronizationManager;
import javax.annotation.Resource; import javax.annotation.Resource;
import javax.validation.Valid; import javax.validation.Valid;
@ -86,6 +87,7 @@ public class PayNotifyServiceImpl implements PayNotifyService {
private PayNotifyServiceImpl self; private PayNotifyServiceImpl self;
@Override @Override
@Transactional(rollbackFor = Exception.class)
public void createPayNotifyTask(PayNotifyTaskCreateReqDTO reqDTO) { public void createPayNotifyTask(PayNotifyTaskCreateReqDTO reqDTO) {
PayNotifyTaskDO task = new PayNotifyTaskDO(); PayNotifyTaskDO task = new PayNotifyTaskDO();
task.setType(reqDTO.getType()).setDataId(reqDTO.getDataId()); task.setType(reqDTO.getType()).setDataId(reqDTO.getDataId());
@ -105,8 +107,13 @@ public class PayNotifyServiceImpl implements PayNotifyService {
// 执行插入 // 执行插入
payNotifyTaskMapper.insert(task); payNotifyTaskMapper.insert(task);
// 异步直接发起任务虽然会有定时任务扫描但是会导致延迟 // 必须在事务提交后在发起任务否则 PayNotifyTaskDO 还没入库就提前回调接入的业务
self.executeNotifyAsync(task); TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronization() {
@Override
public void afterCommit() {
executeNotify(task);
}
});
} }
@Override @Override
@ -121,7 +128,7 @@ public class PayNotifyServiceImpl implements PayNotifyService {
CountDownLatch latch = new CountDownLatch(tasks.size()); CountDownLatch latch = new CountDownLatch(tasks.size());
tasks.forEach(task -> threadPoolTaskExecutor.execute(() -> { tasks.forEach(task -> threadPoolTaskExecutor.execute(() -> {
try { try {
executeNotifySync(task); executeNotify(task);
} finally { } finally {
latch.countDown(); latch.countDown();
} }
@ -150,22 +157,12 @@ public class PayNotifyServiceImpl implements PayNotifyService {
log.error("[awaitExecuteNotify][任务未处理完,总任务数({}) 剩余任务数({})]", size, latch.getCount()); log.error("[awaitExecuteNotify][任务未处理完,总任务数({}) 剩余任务数({})]", size, latch.getCount());
} }
/**
* 异步执行单个支付通知
*
* @param task 通知任务
*/
@Async
public void executeNotifyAsync(PayNotifyTaskDO task) {
self.executeNotifySync(task); // 使用 self避免事务不发起
}
/** /**
* 同步执行单个支付通知 * 同步执行单个支付通知
* *
* @param task 通知任务 * @param task 通知任务
*/ */
public void executeNotifySync(PayNotifyTaskDO task) { public void executeNotify(PayNotifyTaskDO task) {
// 分布式锁避免并发问题 // 分布式锁避免并发问题
payNotifyLockCoreRedisDAO.lock(task.getId(), NOTIFY_TIMEOUT_MILLIS, () -> { payNotifyLockCoreRedisDAO.lock(task.getId(), NOTIFY_TIMEOUT_MILLIS, () -> {
// 校验当前任务是否已经被通知过 // 校验当前任务是否已经被通知过
@ -178,12 +175,12 @@ public class PayNotifyServiceImpl implements PayNotifyService {
} }
// 执行通知 // 执行通知
self.executeNotify(dbTask); self.executeNotify0(dbTask);
}); });
} }
@Transactional @Transactional
public void executeNotify(PayNotifyTaskDO task) { public void executeNotify0(PayNotifyTaskDO task) {
// 发起回调 // 发起回调
CommonResult<?> invokeResult = null; CommonResult<?> invokeResult = null;
Throwable invokeException = null; Throwable invokeException = null;
@ -223,7 +220,7 @@ public class PayNotifyServiceImpl implements PayNotifyService {
} }
// 拼接 header 参数 // 拼接 header 参数
Map<String, String> headers = new HashMap<>(); Map<String, String> headers = new HashMap<>();
TenantUtils.addTenantHeader(headers); TenantUtils.addTenantHeader(headers, task.getTenantId());
// 发起请求 // 发起请求
try (HttpResponse response = HttpUtil.createPost(task.getNotifyUrl()) try (HttpResponse response = HttpUtil.createPost(task.getNotifyUrl())

View File

@ -33,6 +33,8 @@ import static org.junit.jupiter.api.Assertions.*;
@Import({PayChannelServiceImpl.class}) @Import({PayChannelServiceImpl.class})
public class PayChannelServiceTest extends BaseDbUnitTest { public class PayChannelServiceTest extends BaseDbUnitTest {
private static final String ALIPAY_SERVER_URL = "https://openapi.alipay.com/gateway.do";
@Resource @Resource
private PayChannelServiceImpl channelService; private PayChannelServiceImpl channelService;
@ -106,7 +108,6 @@ public class PayChannelServiceTest extends BaseDbUnitTest {
assertPojoEquals(reqVO, channel, "config"); assertPojoEquals(reqVO, channel, "config");
// 关于config 对象应该拿出来重新对比 // 关于config 对象应该拿出来重新对比
assertPojoEquals(payClientConfig, channel.getConfig()); assertPojoEquals(payClientConfig, channel.getConfig());
} }
@Test @Test
@ -291,7 +292,7 @@ public class PayChannelServiceTest extends BaseDbUnitTest {
public AlipayPayClientConfig getPublicKeyConfig() { public AlipayPayClientConfig getPublicKeyConfig() {
return new AlipayPayClientConfig() return new AlipayPayClientConfig()
.setServerUrl(AlipayPayClientConfig.SERVER_URL_PROD) .setServerUrl(ALIPAY_SERVER_URL)
.setAppId("APP00001") .setAppId("APP00001")
.setSignType(AlipayPayClientConfig.SIGN_TYPE_DEFAULT) .setSignType(AlipayPayClientConfig.SIGN_TYPE_DEFAULT)
.setMode(AlipayPayClientConfig.MODE_PUBLIC_KEY) .setMode(AlipayPayClientConfig.MODE_PUBLIC_KEY)
@ -304,7 +305,7 @@ public class PayChannelServiceTest extends BaseDbUnitTest {
public AlipayPayClientConfig getCertificateConfig() { public AlipayPayClientConfig getCertificateConfig() {
return new AlipayPayClientConfig() return new AlipayPayClientConfig()
.setServerUrl(AlipayPayClientConfig.SERVER_URL_PROD) .setServerUrl(ALIPAY_SERVER_URL)
.setAppId("APP00001") .setAppId("APP00001")
.setSignType(AlipayPayClientConfig.SIGN_TYPE_DEFAULT) .setSignType(AlipayPayClientConfig.SIGN_TYPE_DEFAULT)
.setMode(AlipayPayClientConfig.MODE_CERTIFICATE) .setMode(AlipayPayClientConfig.MODE_CERTIFICATE)

View File

@ -36,6 +36,9 @@ export default {
return router.push(lastPath || '/'); return router.push(lastPath || '/');
}); });
} }
if (typeof obj === "function") {
return store.dispatch('tagsView/delView', router.currentRoute).then(obj);
}
return store.dispatch('tagsView/delView', obj); return store.dispatch('tagsView/delView', obj);
}, },
// 关闭所有tab页签 // 关闭所有tab页签

View File

@ -41,17 +41,17 @@
</el-radio-group> </el-radio-group>
</el-form-item> </el-form-item>
<div v-if="form.aliPayConfig.mode === 1"> <div v-if="form.aliPayConfig.mode === 1">
<el-form-item label-width="180px" label="商户私钥" prop="aliPayConfig.privateKey"> <el-form-item label-width="180px" label="应用私钥" prop="aliPayConfig.privateKey">
<el-input type="textarea" :autosize="{minRows: 8, maxRows: 8}" v-model="form.aliPayConfig.privateKey" <el-input type="textarea" :autosize="{minRows: 8, maxRows: 8}" v-model="form.aliPayConfig.privateKey"
placeholder="请输入商户私钥" clearable :style="{width: '100%'}"> placeholder="请输入应用私钥" clearable :style="{width: '100%'}">
</el-input> </el-input>
</el-form-item> </el-form-item>
<el-form-item label-width="180px" label="支付宝公钥字符串" prop="aliPayConfig.alipayPublicKey"> <el-form-item label-width="180px" label="支付宝公钥" prop="aliPayConfig.alipayPublicKey">
<el-input <el-input
type="textarea" type="textarea"
:autosize="{minRows: 8, maxRows: 8}" :autosize="{minRows: 8, maxRows: 8}"
v-model="form.aliPayConfig.alipayPublicKey" v-model="form.aliPayConfig.alipayPublicKey"
placeholder="请输入支付宝公钥字符串" clearable placeholder="请输入支付宝公钥" clearable
:style="{width: '100%'}"> :style="{width: '100%'}">
</el-input> </el-input>
</el-form-item> </el-form-item>

View File

@ -48,15 +48,6 @@
<qrcode-vue :value="qrCode.url" size="310" level="L" /> <qrcode-vue :value="qrCode.url" size="310" level="L" />
</el-dialog> </el-dialog>
<!-- 展示形式IFrame -->
<el-dialog :title="iframe.title" :visible.sync="iframe.visible" width="800px" height="800px" append-to-body
:close-on-press-escape="false">
<iframe :src="iframe.url" width="100%" />
</el-dialog>
<!-- 展示形式Form -->
<div ref="formRef" v-html="form.value" />
<!-- 展示形式BarCode 条形码 --> <!-- 展示形式BarCode 条形码 -->
<el-dialog :title="barCode.title" :visible.sync="barCode.visible" width="500px" append-to-body <el-dialog :title="barCode.title" :visible.sync="barCode.visible" width="500px" append-to-body
:close-on-press-escape="false"> :close-on-press-escape="false">
@ -146,14 +137,6 @@ export default {
title: '', title: '',
visible: false, visible: false,
}, },
iframe: { // iframe
url: '',
title: '',
visible: false
},
form: { // form
html: '',
},
barCode: { // barCode: { //
channelCode: '', channelCode: '',
value: '', value: '',
@ -175,21 +158,24 @@ export default {
// 1.1 // 1.1
if (!this.id) { if (!this.id) {
this.$message.error('未传递支付单号,无法查看对应的支付信息'); this.$message.error('未传递支付单号,无法查看对应的支付信息');
this.goBackToList(); this.goReturnUrl('cancel');
return; return;
} }
getOrder(this.id).then(response => { getOrder(this.id).then(response => {
// 1.2 // 1.2
if (!response.data) { if (!response.data) {
this.$message.error('支付订单不存在,请检查!'); this.$message.error('支付订单不存在,请检查!');
this.goBackToList(); this.goReturnUrl('cancel');
return; return;
} }
// 1.3 // 1.3
// TODO if (response.data.status === PayOrderStatusEnum.SUCCESS.status) {
if (response.data.status !== PayOrderStatusEnum.WAITING.status) { this.$message.success('支付成功');
this.$message.error('支付订单不处于待支付状态,请检查!'); this.goReturnUrl('success');
this.goBackToList(); return;
} else if (response.data.status === PayOrderStatusEnum.CLOSED.status) {
this.$message.error('无法支付,原因:订单已关闭');
this.goReturnUrl('close');
return; return;
} }
@ -218,15 +204,12 @@ export default {
submitOrder({ submitOrder({
id: this.id, id: this.id,
channelCode: channelCode, channelCode: channelCode,
returnUrl: location.href, // {@link returnUrl}
...this.buildSubmitParam(channelCode) ...this.buildSubmitParam(channelCode)
}).then(response => { }).then(response => {
const data = response.data const data = response.data
if (data.displayMode === PayDisplayModeEnum.IFRAME.mode) { if (data.displayMode === PayDisplayModeEnum.URL.mode) {
this.displayIFrame(channelCode, data)
} else if (data.displayMode === PayDisplayModeEnum.URL.mode) {
this.displayUrl(channelCode, data) this.displayUrl(channelCode, data)
} else if (data.displayMode === PayDisplayModeEnum.FORM.mode) {
this.displayForm(channelCode, data)
} else if (data.displayMode === PayDisplayModeEnum.QR_CODE.mode) { } else if (data.displayMode === PayDisplayModeEnum.QR_CODE.mode) {
this.displayQrCode(channelCode, data) this.displayQrCode(channelCode, data)
} }
@ -239,53 +222,7 @@ export default {
}, },
/** 构建提交支付的额外参数 */ /** 构建提交支付的额外参数 */
buildSubmitParam(channelCode) { buildSubmitParam(channelCode) {
// PC // BarCode authCode
if (channelCode === PayChannelEnum.ALIPAY_PC.code) {
// iframe
// 0- iframe 600px 300px
// return {
// "channelExtras": {
// "qr_pay_mode": "0"
// }
// }
// 1-iframe 300px 600px
// return {
// "channelExtras": {
// "qr_pay_mode": "1"
// }
// }
// 3- iframe 75px 75px
// return {
// "channelExtras": {
// "qr_pay_mode": "3"
// }
// }
// 4-
// return {
// "channelExtras": {
// "qr_pay_mode": "4"
// }
// }
//
return {
"channelExtras": {
"qr_pay_mode": "2"
}
}
//
// return {
// displayMode: PayDisplayModeEnum.FORM.mode
// }
}
// Wap
if (channelCode === PayChannelEnum.ALIPAY_WAP.code) {
return {
displayMode: PayDisplayModeEnum.QR_CODE.mode
}
}
// BarCode authCode
if (channelCode === PayChannelEnum.ALIPAY_BAR.code) { if (channelCode === PayChannelEnum.ALIPAY_BAR.code) {
return { return {
"channelExtras": { "channelExtras": {
@ -295,37 +232,12 @@ export default {
} }
return {} return {}
}, },
/** 提交支付后IFrame 内置 URL 的展示形式 */
displayIFrame(channelCode, data) {
// TODO
this.iframe = {
title: '支付窗口',
url: data.displayContent,
visible: true
}
this.submitLoading = false
},
/** 提交支付后URL 的展示形式 */ /** 提交支付后URL 的展示形式 */
displayUrl(channelCode, data) { displayUrl(channelCode, data) {
// window.open(data.displayContent)window // window.open(data.displayContent)
location.href = data.displayContent location.href = data.displayContent
this.submitLoading = false this.submitLoading = false
}, },
/** 提交支付后Form 的展示形式 */
displayForm(channelCode, data) {
//
this.form = {
value: data.displayContent
}
//
this.$nextTick(() => {
//
this.$refs.formRef.children[0].submit();
setTimeout(() => {
this.submitLoading = false
}, 1000);
});
},
/** 提交支付后(支付宝扫码支付) */ /** 提交支付后(支付宝扫码支付) */
displayQrCode(channelCode, data) { displayQrCode(channelCode, data) {
let title = '请使用手机浏览器“扫一扫”'; let title = '请使用手机浏览器“扫一扫”';
@ -354,13 +266,13 @@ export default {
if (response.data.status === PayOrderStatusEnum.SUCCESS.status) { if (response.data.status === PayOrderStatusEnum.SUCCESS.status) {
this.clearQueryInterval(); this.clearQueryInterval();
this.$message.success('支付成功!'); this.$message.success('支付成功!');
this.goBackToList(); this.goReturnUrl();
} }
// //
if (response.data.status === PayOrderStatusEnum.CLOSED.status) { if (response.data.status === PayOrderStatusEnum.CLOSED.status) {
this.clearQueryInterval(); this.clearQueryInterval();
this.$message.error('支付已关闭!'); this.$message.error('支付已关闭!');
this.goBackToList(); this.goReturnUrl();
} }
}) })
}, 1000 * 2) }, 1000 * 2)
@ -377,14 +289,34 @@ export default {
clearInterval(this.interval) clearInterval(this.interval)
this.interval = undefined this.interval = undefined
}, },
/** 回到列表 **/ /**
goBackToList() { * 回到业务的 URL
*
* @param payResult 支付结果
* success支付成功
* cancel取消支付
* close支付已关闭
*/
goReturnUrl(payResult) {
//
if (!this.returnUrl) {
this.$tab.closePage(); this.$tab.closePage();
this.$router.go(-1); return
// TODO }
// this.$router.push({
// path: this.returnUrl const url = this.returnUrl.indexOf('?') >= 0
// }); ? this.returnUrl + '&payResult=' + payResult
: this.returnUrl + '?payResult=' + payResult
// http
if (this.returnUrl.indexOf('http') === 0) {
location.href = url;
} else {
this.$tab.closePage(() => {
this.$router.push({
path: url
});
});
}
} }
} }
}; };