Commit eb7b1af06ed4b483f64670c48835e117bb130b85
1 parent
e2a07d8f
upgrade after testing
Showing
10 changed files
with
94 additions
and
124 deletions
cashier-pipeline/src/main/java/com/diligrp/cashier/pipeline/client/CardPaymentHttpClient.java
| ... | ... | @@ -68,7 +68,7 @@ public class CardPaymentHttpClient extends ServiceEndpointSupport { |
| 68 | 68 | LocalDateTime now = LocalDateTime.now(); |
| 69 | 69 | HttpResult result = send(uri, payload); |
| 70 | 70 | if (result.statusCode == 200) { |
| 71 | - LOG.debug("Received from card payment pipeline: {}\n{}", request.getPaymentId(), result.responseText); | |
| 71 | + LOG.debug("Card payment response received: {}\n{}", request.getPaymentId(), result.responseText); | |
| 72 | 72 | Map<String, Object> response = JsonUtils.fromJsonString(result.responseText, new TypeReference<>() {}); |
| 73 | 73 | if ("200".equals(response.get("code"))) { |
| 74 | 74 | Map<String, Object> data = (Map<String, Object>) response.get("data"); |
| ... | ... | @@ -99,7 +99,7 @@ public class CardPaymentHttpClient extends ServiceEndpointSupport { |
| 99 | 99 | LocalDateTime now = LocalDateTime.now(); |
| 100 | 100 | HttpResult result = send(uri, payload); |
| 101 | 101 | if (result.statusCode == 200) { |
| 102 | - LOG.debug("Received from card payment pipeline: {}\n", request.getRefundId(), result.responseText); | |
| 102 | + LOG.debug("Card refund response received: {}\n{}", request.getRefundId(), result.responseText); | |
| 103 | 103 | Map<String, Object> response = JsonUtils.fromJsonString(result.responseText, new TypeReference<>() {}); |
| 104 | 104 | if ("200".equals(response.get("code"))) { |
| 105 | 105 | return new OnlineRefundResponse(request.getRefundId(), null, now, |
| ... | ... | @@ -121,7 +121,7 @@ public class CardPaymentHttpClient extends ServiceEndpointSupport { |
| 121 | 121 | LOG.debug("Sending list user card request: {}\n{}", userId, payload); |
| 122 | 122 | HttpResult result = send(uri, payload); |
| 123 | 123 | if (result.statusCode == 200) { |
| 124 | - LOG.debug("Received from card payment pipeline: {}\n{}", userId, result.responseText); | |
| 124 | + LOG.debug("List user card response received: {}\n{}", userId, result.responseText); | |
| 125 | 125 | Map<String, Object> response = JsonUtils.fromJsonString(result.responseText, new TypeReference<>() {}); |
| 126 | 126 | if ("200".equals(response.get("code"))) { |
| 127 | 127 | List<UserCardDTO> userCards = new ArrayList<>(); | ... | ... |
cashier-pipeline/src/main/java/com/diligrp/cashier/pipeline/client/RcbOnlineHttpClient.java
| ... | ... | @@ -11,7 +11,6 @@ |
| 11 | 11 | import com.diligrp.cashier.shared.service.ServiceEndpointSupport; |
| 12 | 12 | import com.diligrp.cashier.shared.util.*; |
| 13 | 13 | import com.fasterxml.jackson.core.type.TypeReference; |
| 14 | - import jakarta.annotation.Resource; | |
| 15 | 14 | import org.slf4j.Logger; |
| 16 | 15 | import org.slf4j.LoggerFactory; |
| 17 | 16 | import org.springframework.dao.DataAccessException; |
| ... | ... | @@ -38,11 +37,6 @@ public class RcbOnlineHttpClient extends ServiceEndpointSupport { |
| 38 | 37 | |
| 39 | 38 | private static final Logger LOG = LoggerFactory.getLogger(RcbOnlineHttpClient.class); |
| 40 | 39 | |
| 41 | - // 微信API BASE URL | |
| 42 | - private static final String WECHAT_BASE_URL = "https://api.weixin.qq.com"; | |
| 43 | - // code2session接口: 根据登录凭证code获取登录信息 | |
| 44 | - private static final String CODE_TO_SESSION = "/sns/jscode2session?appid=%s&secret=%s&js_code=%s&grant_type=authorization_code"; | |
| 45 | - | |
| 46 | 40 | private static final int STATUS_OK = 200; |
| 47 | 41 | |
| 48 | 42 | private final String uri; |
| ... | ... | @@ -89,7 +83,7 @@ public class RcbOnlineHttpClient extends ServiceEndpointSupport { |
| 89 | 83 | LOG.error("Failed to send rcb MiniPro prepay request: {}", result.statusCode); |
| 90 | 84 | throw new PaymentPipelineException(ErrorCode.SYSTEM_UNKNOWN_ERROR, "调用小程序预支付接口失败: " + result.statusCode); |
| 91 | 85 | } |
| 92 | - LOG.debug("Received from rcb MiniPro pipeline: {}\n{}", request.getPaymentId(), result.responseText); | |
| 86 | + LOG.debug("Rcb MiniPro prepay received: {}\n{}", request.getPaymentId(), result.responseText); | |
| 93 | 87 | |
| 94 | 88 | Map<String, String> data = JsonUtils.fromJsonString(result.responseText, new TypeReference<>() {}); |
| 95 | 89 | String resultCode = data.get("resultCode"); |
| ... | ... | @@ -117,13 +111,13 @@ public class RcbOnlineHttpClient extends ServiceEndpointSupport { |
| 117 | 111 | |
| 118 | 112 | params.put("sign", RcbSignatureUtils.sign(params, key)); |
| 119 | 113 | String payload = JsonUtils.toJsonString(params); |
| 120 | - LOG.info("Sending rcb query prepay order state request: {}", request.getPaymentId()); | |
| 114 | + LOG.info("Sending query rcb prepay order request: {}", request.getPaymentId()); | |
| 121 | 115 | HttpResult result = send(uri + "/cposp/pay/orderQuery", payload); |
| 122 | 116 | if (result.statusCode != STATUS_OK) { |
| 123 | - LOG.error("Failed to query rcb prepay order state: {}", result.statusCode); | |
| 117 | + LOG.error("Failed to query rcb prepay order: {}", result.statusCode); | |
| 124 | 118 | throw new PaymentPipelineException(ErrorCode.SYSTEM_UNKNOWN_ERROR, "查询支付状态失败: " + result.statusCode); |
| 125 | 119 | } |
| 126 | - LOG.debug("Received from rcb online pipeline: {}\n{}", request.getPaymentId(), result.responseText); | |
| 120 | + LOG.debug("Query rcb prepay order response received: {}\n{}", request.getPaymentId(), result.responseText); | |
| 127 | 121 | |
| 128 | 122 | Map<String, String> data = JsonUtils.fromJsonString(result.responseText, new TypeReference<>() {}); |
| 129 | 123 | String signature = data.remove("sign"); |
| ... | ... | @@ -175,7 +169,7 @@ public class RcbOnlineHttpClient extends ServiceEndpointSupport { |
| 175 | 169 | LOG.error("Failed to close rcb prepay order: {}", request.getPaymentId()); |
| 176 | 170 | throw new PaymentPipelineException(ErrorCode.SYSTEM_UNKNOWN_ERROR, "关闭支付订单失败: " + result.statusCode); |
| 177 | 171 | } |
| 178 | - LOG.debug("Received from rcb online pipeline: {}\n{}", request.getPaymentId(), result.responseText); | |
| 172 | + LOG.debug("Close rcb prepay order response received: {}\n{}", request.getPaymentId(), result.responseText); | |
| 179 | 173 | |
| 180 | 174 | Map<String, String> data = JsonUtils.fromJsonString(result.responseText, new TypeReference<>() {}); |
| 181 | 175 | String resultCode = data.get("resultCode"); |
| ... | ... | @@ -212,7 +206,7 @@ public class RcbOnlineHttpClient extends ServiceEndpointSupport { |
| 212 | 206 | LOG.error("Failed to send rcb refund request: {}", request.getRefundId()); |
| 213 | 207 | throw new PaymentPipelineException(ErrorCode.SYSTEM_UNKNOWN_ERROR, "发送退款请求失败: " + result.statusCode); |
| 214 | 208 | } |
| 215 | - LOG.debug("Received from rcb online pipeline: {}\n{}", request.getRefundId(), result.responseText); | |
| 209 | + LOG.debug("Rcb payment refund response received: {}\n{}", request.getRefundId(), result.responseText); | |
| 216 | 210 | |
| 217 | 211 | Map<String, String> data = JsonUtils.fromJsonString(result.responseText, new TypeReference<>() {}); |
| 218 | 212 | String resultCode = data.get("resultCode"); |
| ... | ... | @@ -252,7 +246,7 @@ public class RcbOnlineHttpClient extends ServiceEndpointSupport { |
| 252 | 246 | LOG.error("Failed to get rcb batch no, statusCode: {}", result.statusCode); |
| 253 | 247 | throw new PaymentPipelineException(ErrorCode.SYSTEM_UNKNOWN_ERROR, "获取签到批次号: " + result.statusCode); |
| 254 | 248 | } |
| 255 | - LOG.debug("Received from rcb online pipeline: {}", result.responseText); | |
| 249 | + LOG.debug("Rcb signIn response received: {}", result.responseText); | |
| 256 | 250 | |
| 257 | 251 | Map<String, String> data = JsonUtils.fromJsonString(result.responseText, new TypeReference<>() {}); |
| 258 | 252 | String resultCode = data.get("resultCode"); |
| ... | ... | @@ -262,13 +256,13 @@ public class RcbOnlineHttpClient extends ServiceEndpointSupport { |
| 262 | 256 | stringRedisTemplate.opsForValue().set(key, batchNo, 36 * 60 * 60, TimeUnit.SECONDS); |
| 263 | 257 | return batchNo; |
| 264 | 258 | } else { |
| 265 | - LOG.error("Failed to rcb sign in, errorCode: {}, resultMessage: {}", resultCode, resultMessage); | |
| 266 | - throw new PaymentPipelineException(ErrorCode.SERVICE_ACCESS_ERROR, "签到接口调用失败"); | |
| 259 | + LOG.error("Failed to rcb signIn: {}", result.responseText); | |
| 260 | + throw new PaymentPipelineException(ErrorCode.SERVICE_ACCESS_ERROR, "签到接口调用失败: " + resultMessage); | |
| 267 | 261 | } |
| 268 | 262 | } catch (ServiceAccessException | PaymentPipelineException rex) { |
| 269 | 263 | throw rex; |
| 270 | 264 | } catch (Exception ex) { |
| 271 | - LOG.error("Failed to get rcb sign in batchNo", ex); | |
| 265 | + LOG.error("Failed to rcb signIn", ex); | |
| 272 | 266 | throw new PaymentPipelineException(ErrorCode.SERVICE_ACCESS_ERROR, "获取签到批次号失败"); |
| 273 | 267 | } |
| 274 | 268 | } |
| ... | ... | @@ -326,57 +320,4 @@ public class RcbOnlineHttpClient extends ServiceEndpointSupport { |
| 326 | 320 | } |
| 327 | 321 | return Optional.ofNullable(sslContext); |
| 328 | 322 | } |
| 329 | - | |
| 330 | - private static class AuthorizationSession { | |
| 331 | - // 用户唯一标识 | |
| 332 | - private String openid; | |
| 333 | - // 会话密钥 | |
| 334 | - private String session_key; | |
| 335 | - // 用户在开放平台的唯一标识 | |
| 336 | - private String unionid; | |
| 337 | - // 错误码 | |
| 338 | - private Integer errcode; | |
| 339 | - // 错误信息 | |
| 340 | - private String errmsg; | |
| 341 | - | |
| 342 | - public String getOpenid() { | |
| 343 | - return openid; | |
| 344 | - } | |
| 345 | - | |
| 346 | - public void setOpenid(String openid) { | |
| 347 | - this.openid = openid; | |
| 348 | - } | |
| 349 | - | |
| 350 | - public String getSession_key() { | |
| 351 | - return session_key; | |
| 352 | - } | |
| 353 | - | |
| 354 | - public void setSession_key(String session_key) { | |
| 355 | - this.session_key = session_key; | |
| 356 | - } | |
| 357 | - | |
| 358 | - public String getUnionid() { | |
| 359 | - return unionid; | |
| 360 | - } | |
| 361 | - | |
| 362 | - public void setUnionid(String unionid) { | |
| 363 | - this.unionid = unionid; | |
| 364 | - } | |
| 365 | - | |
| 366 | - public Integer getErrcode() { | |
| 367 | - return errcode; | |
| 368 | - } | |
| 369 | - | |
| 370 | - public void setErrcode(Integer errcode) { | |
| 371 | - this.errcode = errcode; | |
| 372 | - } | |
| 373 | - | |
| 374 | - public String getErrmsg() { | |
| 375 | - return errmsg; | |
| 376 | - } | |
| 377 | - | |
| 378 | - public void setErrmsg(String errmsg) { | |
| 379 | - this.errmsg = errmsg; | |
| 380 | - } | |
| 381 | - } | |
| 382 | 323 | } | ... | ... |
cashier-pipeline/src/main/java/com/diligrp/cashier/pipeline/core/DefaultTimeStrategy.java
| ... | ... | @@ -7,10 +7,10 @@ public class DefaultTimeStrategy implements ScanTimeStrategy { |
| 7 | 7 | private final long[] prepayTimeArray = { 10 * ONE_MINUTE }; |
| 8 | 8 | |
| 9 | 9 | // 直接支付订单扫描时间策略 |
| 10 | - private final long[] paymentTimeArray = {5 * ONE_SECOND, 5 * ONE_SECOND, 5 * ONE_SECOND, 5 * ONE_SECOND, 5 * ONE_SECOND, 5 * ONE_SECOND, 5 * ONE_SECOND, 5 * ONE_SECOND, 10 * ONE_SECOND, 15 * ONE_SECOND}; | |
| 10 | + private final long[] paymentTimeArray = { 5 * ONE_SECOND, 5 * ONE_SECOND, 5 * ONE_SECOND, 5 * ONE_SECOND, 5 * ONE_SECOND, 5 * ONE_SECOND, 5 * ONE_SECOND, 5 * ONE_SECOND, 10 * ONE_SECOND, 15 * ONE_SECOND }; | |
| 11 | 11 | |
| 12 | 12 | // 退款订单扫描时间策略 |
| 13 | - private final long[] refundTimeArray = { 10 * ONE_MINUTE }; | |
| 13 | + private final long[] refundTimeArray = { ONE_MINUTE, 2 * ONE_MINUTE, 2 * ONE_MINUTE, 5 * ONE_MINUTE }; | |
| 14 | 14 | |
| 15 | 15 | @Override |
| 16 | 16 | public long nextPrepayScanTime(int times) { | ... | ... |
cashier-shared/src/main/java/com/diligrp/cashier/shared/service/ThreadPoolService.java
| 1 | 1 | package com.diligrp.cashier.shared.service; |
| 2 | 2 | |
| 3 | -import java.util.concurrent.ExecutorService; | |
| 4 | -import java.util.concurrent.LinkedBlockingQueue; | |
| 5 | -import java.util.concurrent.ThreadPoolExecutor; | |
| 6 | -import java.util.concurrent.TimeUnit; | |
| 3 | +import java.util.concurrent.*; | |
| 7 | 4 | |
| 8 | 5 | /** |
| 9 | 6 | * 请谨慎使用此线程池工具类,通常建议根据特定的使用场景设置线程池参数,不建议使用统一的线程池配置 |
| 10 | - * JDK的线程池类并不能很好区分"计算密集型"和"IO密集型"任务类型,并根据不同的任务类型去配置不同的参数 | |
| 7 | + * JDK的线程池类并不能很好区分"计算密集型"和"IO密集型"任务类型,应该根据不同的任务类型去配置不同的参数 | |
| 11 | 8 | */ |
| 12 | 9 | public final class ThreadPoolService { |
| 13 | 10 | |
| ... | ... | @@ -15,7 +12,7 @@ public final class ThreadPoolService { |
| 15 | 12 | |
| 16 | 13 | private static final int CPU_MAX_POOL_SIZE = 100; |
| 17 | 14 | |
| 18 | - private static final int IO_MAX_POOL_SIZE = 1000; | |
| 15 | +// private static final int IO_MAX_POOL_SIZE = 1000; | |
| 19 | 16 | |
| 20 | 17 | // CPU运算密集型任务的线程池实例 |
| 21 | 18 | private static volatile ExecutorService cpuThreadPoll; |
| ... | ... | @@ -32,11 +29,11 @@ public final class ThreadPoolService { |
| 32 | 29 | */ |
| 33 | 30 | public static ExecutorService getCpuThreadPoll() { |
| 34 | 31 | if (cpuThreadPoll == null) { |
| 32 | + | |
| 35 | 33 | synchronized (ThreadPoolService.class) { |
| 36 | 34 | if (cpuThreadPoll == null) { |
| 37 | - cpuThreadPoll = new ThreadPoolExecutor(CPU_CORE_NUM + 1, CPU_MAX_POOL_SIZE, | |
| 38 | - 20, TimeUnit.SECONDS, new LinkedBlockingQueue<>(100), | |
| 39 | - new ThreadPoolExecutor.AbortPolicy()); | |
| 35 | + cpuThreadPoll = new ThreadPoolExecutor(CPU_CORE_NUM + 1, CPU_MAX_POOL_SIZE, 20, | |
| 36 | + TimeUnit.SECONDS, new LinkedBlockingQueue<>(100), new LazyRejectedExecutionHandler()); | |
| 40 | 37 | } |
| 41 | 38 | } |
| 42 | 39 | } |
| ... | ... | @@ -51,12 +48,29 @@ public final class ThreadPoolService { |
| 51 | 48 | if (ioThreadPoll == null) { |
| 52 | 49 | synchronized (ThreadPoolService.class) { |
| 53 | 50 | if (ioThreadPoll == null) { |
| 54 | - ioThreadPoll = new ThreadPoolExecutor(CPU_CORE_NUM + 1, IO_MAX_POOL_SIZE, | |
| 55 | - 20, TimeUnit.SECONDS, new LinkedBlockingQueue<>(1000), | |
| 56 | - new ThreadPoolExecutor.AbortPolicy()); | |
| 51 | + ioThreadPoll = Executors.newVirtualThreadPerTaskExecutor(); | |
| 52 | + | |
| 53 | +// ioThreadPoll = new ThreadPoolExecutor(CPU_CORE_NUM + 1, IO_MAX_POOL_SIZE, 20, | |
| 54 | +// TimeUnit.SECONDS, new LinkedBlockingQueue<>(1000), new LazyRejectedExecutionHandler()); | |
| 57 | 55 | } |
| 58 | 56 | } |
| 59 | 57 | } |
| 60 | 58 | return ioThreadPoll; |
| 61 | 59 | } |
| 60 | + | |
| 61 | + private static class LazyRejectedExecutionHandler implements RejectedExecutionHandler { | |
| 62 | + @Override | |
| 63 | + public void rejectedExecution(Runnable task, ThreadPoolExecutor executor) { | |
| 64 | + boolean success = false; | |
| 65 | + try { | |
| 66 | + success = executor.getQueue().offer(task, 15, TimeUnit.SECONDS); | |
| 67 | + } catch (InterruptedException ex) { | |
| 68 | + Thread.currentThread().interrupt(); | |
| 69 | + } | |
| 70 | + | |
| 71 | + if (!success) { | |
| 72 | + throw new RejectedExecutionException("task queue is full"); | |
| 73 | + } | |
| 74 | + } | |
| 75 | + } | |
| 62 | 76 | } | ... | ... |
cashier-trade/src/main/java/com/diligrp/cashier/trade/manager/PaymentResultManager.java
| ... | ... | @@ -86,7 +86,7 @@ public class PaymentResultManager { |
| 86 | 86 | try { |
| 87 | 87 | listener.onEvent(refundEvent); |
| 88 | 88 | } catch (Exception ex) { |
| 89 | - LOG.error("Failed to notify trade refund result", ex); | |
| 89 | + LOG.error("Failed to notify payment refund result", ex); | |
| 90 | 90 | } |
| 91 | 91 | } |
| 92 | 92 | } |
| ... | ... | @@ -95,13 +95,13 @@ public class PaymentResultManager { |
| 95 | 95 | ThreadPoolService.getIoThreadPoll().submit(() -> { |
| 96 | 96 | try { |
| 97 | 97 | String payload = JsonUtils.toJsonString(refundResult); |
| 98 | - LOG.info("Notifying online trade refund result: {}", payload); | |
| 98 | + LOG.info("Notifying online payment refund result: {}", payload); | |
| 99 | 99 | ServiceEndpointSupport.HttpResult httpResult = new NotifyHttpClient(uri).send(payload); |
| 100 | 100 | if (httpResult.statusCode != 200) { |
| 101 | - LOG.error("Failed to notify trade refund result"); | |
| 101 | + LOG.error("Failed to notify payment refund result"); | |
| 102 | 102 | } |
| 103 | 103 | } catch (Exception ex) { |
| 104 | - LOG.error("Failed to notify trade refund result", ex); | |
| 104 | + LOG.error("Failed to notify payment refund result", ex); | |
| 105 | 105 | } |
| 106 | 106 | }); |
| 107 | 107 | } | ... | ... |
cashier-trade/src/main/java/com/diligrp/cashier/trade/manager/TaskMessageConsumer.java
| ... | ... | @@ -35,7 +35,7 @@ public class TaskMessageConsumer { |
| 35 | 35 | ? properties.getContentEncoding() : StandardCharsets.UTF_8.name(); |
| 36 | 36 | try { |
| 37 | 37 | String body = new String(packet, charSet); |
| 38 | - LOG.info("Receiving async delay task message: {}", body); | |
| 38 | + LOG.debug("Receiving async delay task message: {}", body); | |
| 39 | 39 | TaskMessage task = TaskMessage.fromJson(body); |
| 40 | 40 | int times = NumberUtils.str2Int(task.getParams(), Integer.MAX_VALUE); |
| 41 | 41 | if (task.getType() == TaskMessage.TYPE_CASHIER_ORDER_SCAN) { | ... | ... |
cashier-trade/src/main/java/com/diligrp/cashier/trade/manager/TaskMessageSender.java
| ... | ... | @@ -19,11 +19,6 @@ public class TaskMessageSender { |
| 19 | 19 | |
| 20 | 20 | private static final Logger LOG = LoggerFactory.getLogger(TaskMessageSender.class); |
| 21 | 21 | |
| 22 | - private static final long ONE_MINUTE = 60 * 1000; | |
| 23 | - | |
| 24 | - private static final long TEN_MINUTES = 10 * ONE_MINUTE; | |
| 25 | - | |
| 26 | - private static final long ONE_SECOND = 1000; | |
| 27 | 22 | |
| 28 | 23 | @Resource |
| 29 | 24 | private RabbitTemplate rabbitTemplate; |
| ... | ... | @@ -33,7 +28,7 @@ public class TaskMessageSender { |
| 33 | 28 | */ |
| 34 | 29 | public void sendDelayTaskMessage(TaskMessage task, long delayInMillis) { |
| 35 | 30 | if (delayInMillis < 0) { |
| 36 | - LOG.info("No need send scan order message: {}", task); | |
| 31 | + LOG.debug("No need send scan order message: {}", task); | |
| 37 | 32 | return; |
| 38 | 33 | } |
| 39 | 34 | |
| ... | ... | @@ -47,7 +42,7 @@ public class TaskMessageSender { |
| 47 | 42 | properties.setHeader("x-delay", String.valueOf(delayInMillis)); |
| 48 | 43 | String payload = JsonUtils.toJsonString(task); |
| 49 | 44 | Message message = new Message(payload.getBytes(StandardCharsets.UTF_8), properties); |
| 50 | - LOG.info("Sending async delay task message: {}", task.getPayload()); | |
| 45 | + LOG.debug("Sending async delay task message: {}", task.getPayload()); | |
| 51 | 46 | rabbitTemplate.send(Constants.PAYMENT_DELAY_EXCHANGE, Constants.PAYMENT_DELAY_KEY, message); |
| 52 | 47 | } catch (Exception ex) { |
| 53 | 48 | LOG.error("Failed to send async delay task message: {}", task.getPayload(), ex); | ... | ... |
cashier-trade/src/main/java/com/diligrp/cashier/trade/service/impl/CashierAssistantServiceImpl.java
| ... | ... | @@ -10,7 +10,9 @@ import com.diligrp.cashier.pipeline.service.IPaymentPipelineManager; |
| 10 | 10 | import com.diligrp.cashier.pipeline.type.PaymentState; |
| 11 | 11 | import com.diligrp.cashier.trade.Constants; |
| 12 | 12 | import com.diligrp.cashier.trade.dao.IOnlinePaymentDao; |
| 13 | +import com.diligrp.cashier.trade.domain.TaskMessage; | |
| 13 | 14 | import com.diligrp.cashier.trade.domain.TradeStateDTO; |
| 15 | +import com.diligrp.cashier.trade.manager.TaskMessageSender; | |
| 14 | 16 | import com.diligrp.cashier.trade.model.OnlinePayment; |
| 15 | 17 | import com.diligrp.cashier.trade.model.TradeOrder; |
| 16 | 18 | import com.diligrp.cashier.trade.service.ICashierAssistantService; |
| ... | ... | @@ -45,11 +47,14 @@ public class CashierAssistantServiceImpl implements ICashierAssistantService { |
| 45 | 47 | private TradeAssistantServiceImpl tradeAssistantService; |
| 46 | 48 | |
| 47 | 49 | @Resource |
| 50 | + private TaskMessageSender taskMessageSender; | |
| 51 | + | |
| 52 | + @Resource | |
| 48 | 53 | private RedissonClient redissonClient; |
| 49 | 54 | |
| 50 | 55 | @Override |
| 51 | 56 | public void scanCashierTradeOrder(String tradeId, int times) { |
| 52 | - LOG.debug("scanCashierTradeOrder{}: processing cashier trade order {}", times, tradeId); | |
| 57 | + LOG.info("scanCashierTradeOrder{}: processing cashier order {}", times, tradeId); | |
| 53 | 58 | String lockKey = String.format(Constants.TRADE_LOCK_REDIS_KEY, tradeId); |
| 54 | 59 | RLock lock = redissonClient.getLock(lockKey); |
| 55 | 60 | try { |
| ... | ... | @@ -64,12 +69,11 @@ public class CashierAssistantServiceImpl implements ICashierAssistantService { |
| 64 | 69 | // 在线支付通道才能关闭订单, 园区卡支付不支持 |
| 65 | 70 | if (pipeline instanceof OnlinePipeline<?> onlinePipeline) { |
| 66 | 71 | OnlinePrepayOrder order = new OnlinePrepayOrder(payment.getPaymentId(), payment.getOutTradeNo()); |
| 67 | - // 微信服务商模式,还需子商户 | |
| 68 | 72 | OnlinePaymentResponse response = onlinePipeline.queryPrepayResponse(order); |
| 69 | 73 | if (!PaymentState.isFinished(response.getState().getCode())) { |
| 70 | 74 | try { |
| 71 | 75 | onlinePipeline.closePrepayOrder(order); |
| 72 | - LOG.info("scanCashierTradeOrder: close online prepay order {}", payment.getPaymentId()); | |
| 76 | + LOG.debug("scanCashierTradeOrder: close online prepay order {}", payment.getPaymentId()); | |
| 73 | 77 | response = new OnlinePaymentResponse(response.getPaymentId(), response.getOutTradeNo(), |
| 74 | 78 | response.getOutPayType(), response.getPayerId(), response.getWhen(), |
| 75 | 79 | PaymentState.FAILED, "自动关闭超时的支付订单"); |
| ... | ... | @@ -85,7 +89,9 @@ public class CashierAssistantServiceImpl implements ICashierAssistantService { |
| 85 | 89 | if (!TradeState.isFinished(trade.getState())) { |
| 86 | 90 | TradeStateDTO tradeStateDTO = TradeStateDTO.of(trade.getTradeId(), TradeState.CLOSED, trade.getVersion(), now); |
| 87 | 91 | tradeAssistantService.proceedTradeOrder(tradeStateDTO); |
| 88 | - LOG.info("scanCashierTradeOrder: close cashier trade order {}", tradeId); | |
| 92 | + LOG.debug("scanCashierTradeOrder: close cashier order {}", tradeId); | |
| 93 | + } else { | |
| 94 | + LOG.debug("scanCashierTradeOrder: cashier order {} already accomplished", trade.getTradeId()); | |
| 89 | 95 | } |
| 90 | 96 | } finally { |
| 91 | 97 | if (lock.isHeldByCurrentThread()) { |
| ... | ... | @@ -96,10 +102,10 @@ public class CashierAssistantServiceImpl implements ICashierAssistantService { |
| 96 | 102 | |
| 97 | 103 | @Override |
| 98 | 104 | public void scanCashierRefundOrder(String refundId, int times) { |
| 99 | - LOG.debug("scanCashierRefundOrder{}: processing online refund order {}", times, refundId); | |
| 105 | + LOG.info("scanCashierRefundOrder{}: processing cashier refund order {}", times, refundId); | |
| 100 | 106 | OnlinePayment refund = tradeAssistantService.findByRefundId(refundId); |
| 101 | 107 | if (PaymentState.isFinished(refund.getState())) { |
| 102 | - LOG.debug("scanCashierRefundOrder{}: online refund order {} already accomplished", times, refundId); | |
| 108 | + LOG.debug("scanCashierRefundOrder{}: cashier refund order {} already accomplished", times, refundId); | |
| 103 | 109 | return; |
| 104 | 110 | } |
| 105 | 111 | |
| ... | ... | @@ -107,5 +113,10 @@ public class CashierAssistantServiceImpl implements ICashierAssistantService { |
| 107 | 113 | OnlineRefundOrder order = new OnlineRefundOrder(refundId, refund.getOutTradeNo()); |
| 108 | 114 | OnlineRefundResponse response = pipeline.queryRefundResponse(order); |
| 109 | 115 | cashierPaymentService.notifyRefundResult(response); |
| 116 | + if (!PaymentState.isFinished(response.getState().getCode())) { | |
| 117 | + long delay = pipeline.getTimeStrategy().nextRefundScanTime(times + 1); | |
| 118 | + TaskMessage message = new TaskMessage(TaskMessage.TYPE_CASHIER_REFUND_SCAN, refundId, String.valueOf(times + 1)); | |
| 119 | + taskMessageSender.sendDelayTaskMessage(message, delay); | |
| 120 | + } | |
| 110 | 121 | } |
| 111 | 122 | } | ... | ... |
cashier-trade/src/main/java/com/diligrp/cashier/trade/service/impl/CashierPaymentServiceImpl.java
| ... | ... | @@ -5,6 +5,7 @@ import com.diligrp.cashier.assistant.service.impl.SnowflakeKeyManager; |
| 5 | 5 | import com.diligrp.cashier.pipeline.core.DiliCardPipeline; |
| 6 | 6 | import com.diligrp.cashier.pipeline.core.OnlinePipeline; |
| 7 | 7 | import com.diligrp.cashier.pipeline.core.PaymentPipeline; |
| 8 | +import com.diligrp.cashier.pipeline.core.ScanTimeStrategy; | |
| 8 | 9 | import com.diligrp.cashier.pipeline.domain.*; |
| 9 | 10 | import com.diligrp.cashier.pipeline.domain.card.CardPaymentRequest; |
| 10 | 11 | import com.diligrp.cashier.pipeline.domain.card.CardPaymentResponse; |
| ... | ... | @@ -104,19 +105,19 @@ public class CashierPaymentServiceImpl implements ICashierPaymentService { |
| 104 | 105 | /** |
| 105 | 106 | * 收银台支付 |
| 106 | 107 | * |
| 107 | - * @param cashierPayment - 支付信息 | |
| 108 | + * @param payment - 支付信息 | |
| 108 | 109 | * @return 支付状态 |
| 109 | 110 | */ |
| 110 | 111 | @Override |
| 111 | 112 | @Transactional(rollbackFor = Exception.class) |
| 112 | - public OnlinePaymentStatus doPayment(CashierPayment cashierPayment) { | |
| 113 | + public OnlinePaymentStatus doPayment(CashierPayment payment) { | |
| 113 | 114 | // TODO: 接口防重复提交 |
| 114 | - String lockKey = String.format(Constants.TRADE_LOCK_REDIS_KEY, cashierPayment.getTradeId()); | |
| 115 | + String lockKey = String.format(Constants.TRADE_LOCK_REDIS_KEY, payment.getTradeId()); | |
| 115 | 116 | RLock lock = redissonClient.getLock(lockKey); |
| 116 | 117 | try { |
| 117 | 118 | boolean locked = lock.tryLock(Constants.TRADE_LOCK_TIMEOUT, TimeUnit.SECONDS); |
| 118 | 119 | if (locked) { |
| 119 | - TradeOrder trade = tradeAssistantService.findByTradeId(cashierPayment.getTradeId()); | |
| 120 | + TradeOrder trade = tradeAssistantService.findByTradeId(payment.getTradeId()); | |
| 120 | 121 | CashierType cashierType = CashierType.getByCode(trade.getType()); |
| 121 | 122 | if (TradeState.isFinished(trade.getState())) { |
| 122 | 123 | throw new TradePaymentException(ErrorCode.OPERATION_NOT_ALLOWED, "不能进行支付, 交易订单已经完成"); |
| ... | ... | @@ -125,6 +126,7 @@ public class CashierPaymentServiceImpl implements ICashierPaymentService { |
| 125 | 126 | if (cashierType != CashierType.MINIPRO) { |
| 126 | 127 | throw new TradePaymentException(ErrorCode.OPERATION_NOT_ALLOWED, "系统当前不支持的此收银台类型"); |
| 127 | 128 | } |
| 129 | + LOG.info("Requesting cashier order payment: {}", payment.getTradeId()); | |
| 128 | 130 | // 关闭支付中的支付订单, 避免一个交易订单存在多笔支付订单, 造成重复支付 |
| 129 | 131 | if (!tradeAssistantService.resetTradeOrder(trade)) { |
| 130 | 132 | throw new TradePaymentException(ErrorCode.OPERATION_NOT_ALLOWED, "不能进行支付, 交易订单正在支付中"); |
| ... | ... | @@ -132,26 +134,26 @@ public class CashierPaymentServiceImpl implements ICashierPaymentService { |
| 132 | 134 | |
| 133 | 135 | LocalDateTime now = LocalDateTime.now(); |
| 134 | 136 | // 获取支付通道 |
| 135 | - PaymentPipeline<?> pipeline = paymentPipelineManager.findPipelineById( | |
| 136 | - cashierPayment.getPipelineId(), PaymentPipeline.class); | |
| 137 | + PaymentPipeline<?> pipeline = paymentPipelineManager.findPipelineById(payment.getPipelineId(), PaymentPipeline.class); | |
| 137 | 138 | String paymentId = snowflakeKeyManager.getKeyGenerator(SnowflakeKey.PAYMENT_ID).nextId(); |
| 138 | 139 | if (pipeline instanceof OnlinePipeline<?> onlinePipeline) { // 在线支付通道 |
| 139 | 140 | // 在线支付通道: 不同的收银台类型使用不同的支付方式(目前只支持小程序收银台) |
| 140 | 141 | // 小程序收银台将使用在线支付通道的小程序支付 |
| 141 | - MiniProPrepayRequest request = new MiniProPaymentConverter(trade, paymentId, now).convert(cashierPayment); | |
| 142 | + MiniProPrepayRequest request = new MiniProPaymentConverter(trade, paymentId, now).convert(payment); | |
| 142 | 143 | MiniProPrepayResponse response = onlinePipeline.sendMiniProPrepayRequest(request); |
| 143 | 144 | String outMchId = request.getString(com.diligrp.cashier.pipeline.Constants.PARAM_MCH_ID); |
| 144 | - OnlinePayment payment = OnlinePayment.builder().outMchId(outMchId).tradeId(trade.getTradeId()) | |
| 145 | + OnlinePayment onlinePayment = OnlinePayment.builder().outMchId(outMchId).tradeId(trade.getTradeId()) | |
| 145 | 146 | .type(TradeType.TRADE).paymentId(paymentId).channelId(onlinePipeline.supportedChannel()) |
| 146 | 147 | .payType(PaymentType.MINI_PRO).pipelineId(onlinePipeline.pipelineId()).goods(trade.getGoods()) |
| 147 | 148 | .amount(trade.getAmount()).payerId(request.getOpenId()).outTradeNo(response.getOutTradeNo()) |
| 148 | 149 | .outPayType(OutPaymentType.NOP).finishTime(null).state(response.getState()) |
| 149 | 150 | .notifyUrl(trade.getNotifyUrl()).description(null).version(0).createdTime(now).modifiedTime(now).build(); |
| 150 | - onlinePaymentDao.insertOnlinePayment(payment); | |
| 151 | + onlinePaymentDao.insertOnlinePayment(onlinePayment); | |
| 152 | + LOG.debug("Cashier order payment result: {}:{}", response.getPaymentId(), response.getState().name()); | |
| 151 | 153 | return response; |
| 152 | 154 | } else if (pipeline instanceof DiliCardPipeline cardPipeline) { // 园区卡支付通道 |
| 153 | 155 | // 园区卡支付通道: 所有的收银台类型使用的是同一种园区卡支付流程 |
| 154 | - CardPaymentRequest request = new CardPaymentConverter(trade, paymentId, now).convert(cashierPayment); | |
| 156 | + CardPaymentRequest request = new CardPaymentConverter(trade, paymentId, now).convert(payment); | |
| 155 | 157 | // 园区卡支付需要订单来源 |
| 156 | 158 | request.attach("source", SourceType.getIfNonNull(trade.getSource())); |
| 157 | 159 | // 修改支付状态为支付中,防止重复支付 |
| ... | ... | @@ -160,14 +162,14 @@ public class CashierPaymentServiceImpl implements ICashierPaymentService { |
| 160 | 162 | if (response.getState() == PaymentState.SUCCESS) { |
| 161 | 163 | // 园区卡支付通道outMchId为市场ID |
| 162 | 164 | String outMchId = request.getString(com.diligrp.cashier.pipeline.Constants.PARAM_MCH_ID); |
| 163 | - OnlinePayment payment = OnlinePayment.builder().outMchId(outMchId).tradeId(trade.getTradeId()) | |
| 165 | + OnlinePayment onlinePayment = OnlinePayment.builder().outMchId(outMchId).tradeId(trade.getTradeId()) | |
| 164 | 166 | .type(TradeType.TRADE).paymentId(paymentId).channelId(cardPipeline.supportedChannel()) |
| 165 | 167 | .payType(PaymentType.DIRECT).pipelineId(cardPipeline.pipelineId()).goods(trade.getGoods()) |
| 166 | 168 | .amount(trade.getAmount()).payerId(response.getPayerId()).outTradeNo(response.getOutTradeNo()) |
| 167 | 169 | .outPayType(response.getOutPayType()).finishTime(response.getWhen()).state(response.getState()) |
| 168 | 170 | .notifyUrl(trade.getNotifyUrl()).description(response.getMessage()).version(0) |
| 169 | 171 | .createdTime(now).modifiedTime(now).build(); |
| 170 | - onlinePaymentDao.insertOnlinePayment(payment); | |
| 172 | + onlinePaymentDao.insertOnlinePayment(onlinePayment); | |
| 171 | 173 | |
| 172 | 174 | TradeStateDTO tradeStateDTO = TradeStateDTO.of(trade.getTradeId(), TradeState.SUCCESS, |
| 173 | 175 | trade.getVersion(), now); |
| ... | ... | @@ -178,6 +180,7 @@ public class CashierPaymentServiceImpl implements ICashierPaymentService { |
| 178 | 180 | response.getPayerId(), response.getWhen(), response.getMessage()); |
| 179 | 181 | paymentResultManager.notifyPaymentResult(trade.getNotifyUrl(), paymentResult, 500); |
| 180 | 182 | } |
| 183 | + LOG.debug("Cashier order payment result: {}:{}", response.getPaymentId(), response.getState().name()); | |
| 181 | 184 | return response; |
| 182 | 185 | } else { |
| 183 | 186 | // 目前只有两类支付通道: CardPipeline和OnlinePipeline, 程序逻辑不应该到达此代码块 |
| ... | ... | @@ -205,10 +208,10 @@ public class CashierPaymentServiceImpl implements ICashierPaymentService { |
| 205 | 208 | public void notifyPaymentResponse(OnlinePaymentResponse response) { |
| 206 | 209 | OnlinePayment payment = tradeAssistantService.findByPaymentId(response.getPaymentId()); |
| 207 | 210 | if (PaymentState.isFinished(payment.getState())) { |
| 208 | - LOG.warn("Duplicate process payment response: [{}:{}]", payment.getPaymentId(), response.getState()); | |
| 211 | + LOG.warn("Duplicate process cashier payment response: [{}:{}]", payment.getPaymentId(), response.getState().name()); | |
| 209 | 212 | return; |
| 210 | 213 | } |
| 211 | - LOG.info("Processing payment response: [{},{}]", payment.getPaymentId(), response.getState()); | |
| 214 | + LOG.info("Processing cashier payment response: [{},{}]", payment.getPaymentId(), response.getState().name()); | |
| 212 | 215 | |
| 213 | 216 | if (PaymentState.isFinished(response.getState().getCode())) { |
| 214 | 217 | LocalDateTime now = LocalDateTime.now(); |
| ... | ... | @@ -261,6 +264,7 @@ public class CashierPaymentServiceImpl implements ICashierPaymentService { |
| 261 | 264 | throw new TradePaymentException(ErrorCode.OPERATION_NOT_ALLOWED, "关闭交易订单失败: 无效的订单状态"); |
| 262 | 265 | } |
| 263 | 266 | |
| 267 | + LOG.info("Requesting close cashier trade order: {}", tradeId); | |
| 264 | 268 | LocalDateTime now = LocalDateTime.now(); |
| 265 | 269 | // 获取所有支付记录 |
| 266 | 270 | List<OnlinePayment> onlinePayments = onlinePaymentDao.listOnlinePayments(trade.getTradeId(), |
| ... | ... | @@ -326,6 +330,7 @@ public class CashierPaymentServiceImpl implements ICashierPaymentService { |
| 326 | 330 | TradeType.TRADE.getCode(), PaymentState.SUCCESS.getCode()).stream().findFirst() |
| 327 | 331 | .orElseThrow(() -> new TradePaymentException(ErrorCode.OPERATION_NOT_ALLOWED, "不能进行交易退款: 无支付信息")); |
| 328 | 332 | |
| 333 | + LOG.info("Requesting cashier payment refund: {}", request.getTradeId()); | |
| 329 | 334 | LocalDateTime now = LocalDateTime.now().withNano(0); |
| 330 | 335 | KeyGenerator refundIdKey = snowflakeKeyManager.getKeyGenerator(SnowflakeKey.PAYMENT_ID); |
| 331 | 336 | String refundId = refundIdKey.nextId(); |
| ... | ... | @@ -341,6 +346,7 @@ public class CashierPaymentServiceImpl implements ICashierPaymentService { |
| 341 | 346 | throw new TradePaymentException(ErrorCode.OPERATION_NOT_ALLOWED, "不支持的支付通道"); |
| 342 | 347 | } |
| 343 | 348 | |
| 349 | + LOG.debug("Cashier payment refund result: [{}:{}]", trade.getTradeId(), response.getState().name()); | |
| 344 | 350 | OnlinePayment refund = OnlinePayment.builder().outMchId(payment.getOutMchId()).tradeId(payment.getTradeId()) |
| 345 | 351 | .type(TradeType.REFUND).paymentId(refundId).channelId(payment.getChannelId()) |
| 346 | 352 | .payType(payment.getPayType()).pipelineId(payment.getPipelineId()).goods(payment.getGoods() + "-退款") |
| ... | ... | @@ -356,8 +362,11 @@ public class CashierPaymentServiceImpl implements ICashierPaymentService { |
| 356 | 362 | tradeAssistantService.proceedTradeOrder(tradeState); |
| 357 | 363 | } else if (!PaymentState.isFinished(response.getState().getCode())) { |
| 358 | 364 | // 固定周期后,查询退款状态,根据状态完成退款订单 |
| 359 | - TaskMessage message = new TaskMessage(TaskMessage.TYPE_CASHIER_REFUND_SCAN, refundId, "1"); | |
| 360 | - taskMessageSender.sendDelayTaskMessage(message, trade.getTimeout() * 1000); | |
| 365 | + if (pipeline instanceof OnlinePipeline<?> onlinePipeline) { // 只有在线支付通道允许查询退款状态 | |
| 366 | + long delay = onlinePipeline.getTimeStrategy().nextRefundScanTime(1); | |
| 367 | + TaskMessage message = new TaskMessage(TaskMessage.TYPE_CASHIER_REFUND_SCAN, refundId, "1"); | |
| 368 | + taskMessageSender.sendDelayTaskMessage(message, delay); | |
| 369 | + } | |
| 361 | 370 | } |
| 362 | 371 | |
| 363 | 372 | return new OnlineRefundResult(refundId, payment.getPaymentId(), response.getState().getCode(), |
| ... | ... | @@ -369,14 +378,14 @@ public class CashierPaymentServiceImpl implements ICashierPaymentService { |
| 369 | 378 | public void notifyRefundResult(OnlineRefundResponse response) { |
| 370 | 379 | OnlinePayment refund = tradeAssistantService.findByRefundId(response.getRefundId()); |
| 371 | 380 | if (PaymentState.isFinished(refund.getState())) { |
| 372 | - LOG.warn("Duplicate process online refund order[{}:{}]", response.getRefundId(), response.getState()); | |
| 381 | + LOG.warn("Duplicate process cashier refund response: [{}:{}]", response.getRefundId(), response.getState().name()); | |
| 373 | 382 | return; |
| 374 | 383 | } |
| 375 | 384 | if (!PaymentState.isFinished(response.getState().getCode())) { |
| 376 | - LOG.warn("Ignore online refund order[{}:{}]", response.getRefundId(), response.getState()); | |
| 385 | + LOG.warn("Ignore cashier refund response: [{}:{}]", response.getRefundId(), response.getState().name()); | |
| 377 | 386 | return; |
| 378 | 387 | } |
| 379 | - LOG.info("Processing online refund order[{}:{}]", response.getRefundId(), response.getState()); | |
| 388 | + LOG.info("Processing cashier refund response: [{}:{}]", response.getRefundId(), response.getState().name()); | |
| 380 | 389 | |
| 381 | 390 | LocalDateTime now = LocalDateTime.now(); |
| 382 | 391 | TradeOrder trade = tradeAssistantService.findByTradeId(refund.getTradeId()); | ... | ... |
cashier-trade/src/main/java/com/diligrp/cashier/trade/service/impl/TradeAssistantServiceImpl.java
| ... | ... | @@ -65,7 +65,7 @@ public class TradeAssistantServiceImpl implements ITradeAssistantService { |
| 65 | 65 | List<OnlinePayment> onlinePayments = onlinePaymentDao.listOnlinePayments(trade.getTradeId(), TradeType.TRADE.getCode(), null); |
| 66 | 66 | for (OnlinePayment payment : onlinePayments) { |
| 67 | 67 | if (!PaymentState.isFinished(payment.getState())) { |
| 68 | - LOG.info("Trying to close payment order in process: {}", payment.getPaymentId()); | |
| 68 | + LOG.debug("Trying to close payment order in process: {}", payment.getPaymentId()); | |
| 69 | 69 | PaymentPipeline<?> pipeline = paymentPipelineManager.findPipelineById(payment.getPipelineId(), PaymentPipeline.class); |
| 70 | 70 | if (pipeline instanceof OnlinePipeline<?> onlinePipeline) { |
| 71 | 71 | // 理论上只存在一条支付中的支付记录,否则后面的支付通道关闭失败时,会回滚前面支付记录的状态修改 | ... | ... |