Commit f67985dc2a517fbf261dda5c686d93cf169aeb80
1 parent
8e38b431
forbit duplicate submit
Showing
11 changed files
with
315 additions
and
59 deletions
cashier-boss/src/main/java/com/diligrp/cashier/boss/BossConfiguration.java
| 1 | 1 | package com.diligrp.cashier.boss; |
| 2 | 2 | |
| 3 | +import com.diligrp.cashier.shared.http.DuplicateSubmitFilter; | |
| 3 | 4 | import com.diligrp.cashier.shared.mybatis.MybatisMapperSupport; |
| 4 | 5 | import com.diligrp.cashier.shared.service.LifeCycle; |
| 5 | 6 | import jakarta.annotation.Resource; |
| ... | ... | @@ -11,8 +12,10 @@ import org.springframework.boot.context.properties.ConfigurationProperties; |
| 11 | 12 | import org.springframework.context.annotation.Bean; |
| 12 | 13 | import org.springframework.context.annotation.ComponentScan; |
| 13 | 14 | import org.springframework.context.annotation.Configuration; |
| 15 | +import org.springframework.web.filter.GenericFilterBean; | |
| 14 | 16 | |
| 15 | 17 | import java.util.List; |
| 18 | +import java.util.concurrent.TimeUnit; | |
| 16 | 19 | |
| 17 | 20 | @Configuration |
| 18 | 21 | @ComponentScan("com.diligrp.cashier.boss") |
| ... | ... | @@ -28,6 +31,17 @@ public class BossConfiguration implements ApplicationRunner { |
| 28 | 31 | return new CashierDeskProperties(); |
| 29 | 32 | } |
| 30 | 33 | |
| 34 | + @Bean | |
| 35 | + public GenericFilterBean duplicateSubmitFilter() { | |
| 36 | + // 配置防重复提交过滤器 | |
| 37 | + DuplicateSubmitFilter.Builder builder = new DuplicateSubmitFilter.Builder(); | |
| 38 | + builder.requestMatcher("/payment/cashier/submitOrder") | |
| 39 | + .forbidSubmit(1, TimeUnit.SECONDS) | |
| 40 | + .requestMatchers("/payment/cashier/orderPayment", "/payment/cashier/orderRefund") | |
| 41 | + .forbidSubmit(1200, TimeUnit.MILLISECONDS); | |
| 42 | + return builder.build(); | |
| 43 | + } | |
| 44 | + | |
| 31 | 45 | @Override |
| 32 | 46 | public void run(ApplicationArguments args) throws Exception { |
| 33 | 47 | List<LifeCycle> lifeCycles = lifeCycleProvider.stream().toList(); | ... | ... |
cashier-boss/src/main/java/com/diligrp/cashier/boss/controller/WechatPaymentController.java
| 1 | 1 | package com.diligrp.cashier.boss.controller; |
| 2 | 2 | |
| 3 | 3 | import com.diligrp.cashier.boss.exception.BossServiceException; |
| 4 | -import com.diligrp.cashier.boss.util.HttpUtils; | |
| 5 | 4 | import com.diligrp.cashier.pipeline.core.WechatPartnerPipeline; |
| 6 | 5 | import com.diligrp.cashier.pipeline.core.WechatPipeline; |
| 7 | 6 | import com.diligrp.cashier.pipeline.domain.OnlinePaymentResponse; |
| ... | ... | @@ -17,6 +16,7 @@ import com.diligrp.cashier.pipeline.util.WechatStateUtils; |
| 17 | 16 | import com.diligrp.cashier.shared.ErrorCode; |
| 18 | 17 | import com.diligrp.cashier.shared.domain.Message; |
| 19 | 18 | import com.diligrp.cashier.shared.util.DateUtils; |
| 19 | +import com.diligrp.cashier.shared.util.HttpUtils; | |
| 20 | 20 | import com.diligrp.cashier.shared.util.JsonUtils; |
| 21 | 21 | import com.diligrp.cashier.trade.model.OnlinePayment; |
| 22 | 22 | import com.diligrp.cashier.trade.service.ICashierPaymentService; | ... | ... |
cashier-boss/src/main/java/com/diligrp/cashier/boss/util/HttpUtils.java deleted
100644 → 0
| 1 | -package com.diligrp.cashier.boss.util; | |
| 2 | - | |
| 3 | -import com.diligrp.cashier.boss.Constants; | |
| 4 | -import jakarta.servlet.http.HttpServletRequest; | |
| 5 | -import jakarta.servlet.http.HttpServletResponse; | |
| 6 | -import org.slf4j.Logger; | |
| 7 | -import org.slf4j.LoggerFactory; | |
| 8 | - | |
| 9 | -import java.io.BufferedReader; | |
| 10 | -import java.io.IOException; | |
| 11 | -import java.nio.charset.StandardCharsets; | |
| 12 | - | |
| 13 | -/** | |
| 14 | - * HTTP工具类 | |
| 15 | - */ | |
| 16 | -public final class HttpUtils { | |
| 17 | - | |
| 18 | - private static final Logger LOG = LoggerFactory.getLogger(HttpUtils.class); | |
| 19 | - | |
| 20 | - public static String httpBody(HttpServletRequest request) { | |
| 21 | - StringBuilder payload = new StringBuilder(); | |
| 22 | - try { | |
| 23 | - String line; | |
| 24 | - BufferedReader reader = request.getReader(); | |
| 25 | - while ((line = reader.readLine()) != null) { | |
| 26 | - payload.append(line); | |
| 27 | - } | |
| 28 | - } catch (IOException iex) { | |
| 29 | - LOG.error("Failed to extract http body", iex); | |
| 30 | - } | |
| 31 | - | |
| 32 | - return payload.toString(); | |
| 33 | - } | |
| 34 | - | |
| 35 | - public static void sendResponse(HttpServletResponse response, String payload) { | |
| 36 | - try { | |
| 37 | - response.setContentType(Constants.CONTENT_TYPE); | |
| 38 | - byte[] responseBytes = payload.getBytes(StandardCharsets.UTF_8); | |
| 39 | - response.setContentLength(responseBytes.length); | |
| 40 | - response.getOutputStream().write(responseBytes); | |
| 41 | - response.flushBuffer(); | |
| 42 | - } catch (IOException iex) { | |
| 43 | - LOG.error("Failed to write data packet back"); | |
| 44 | - } | |
| 45 | - } | |
| 46 | -} |
cashier-shared/src/main/java/com/diligrp/cashier/shared/Constants.java
| 1 | 1 | package com.diligrp.cashier.shared; |
| 2 | 2 | |
| 3 | 3 | public final class Constants { |
| 4 | - public static final String SIGN_ALGORITHM = "SHA1WithRSA"; | |
| 4 | + public static final String DUPLICATE_SUBMIT_KEY = "cashier:security:resubmit:%s"; | |
| 5 | 5 | |
| 6 | 6 | public static final String DATE_TIME_FORMAT = "yyyy-MM-dd HH:mm:ss"; |
| 7 | 7 | |
| ... | ... | @@ -9,10 +9,6 @@ public final class Constants { |
| 9 | 9 | |
| 10 | 10 | public static final String TIME_FORMAT = "HH:mm:ss"; |
| 11 | 11 | |
| 12 | - public static final int CORE_POOL_SIZE = Runtime.getRuntime().availableProcessors() + 1; | |
| 13 | - | |
| 14 | - public static final int MAX_POOL_SIZE = 200; | |
| 15 | - | |
| 16 | 12 | public final static String CONTENT_TYPE = "application/json;charset=UTF-8"; |
| 17 | 13 | |
| 18 | 14 | public final static String PRODUCT_NAME = "cashier:"; | ... | ... |
cashier-shared/src/main/java/com/diligrp/cashier/shared/codec/ByteCodec.java
| 1 | 1 | package com.diligrp.cashier.shared.codec; |
| 2 | 2 | |
| 3 | +import java.io.IOException; | |
| 4 | + | |
| 3 | 5 | public interface ByteCodec<T> { |
| 4 | 6 | |
| 5 | - T decode(byte[] payload); | |
| 7 | + T decode(byte[] payload) throws IOException; | |
| 6 | 8 | |
| 7 | - byte[] encode(T payload); | |
| 9 | + byte[] encode(T payload) throws IOException; | |
| 8 | 10 | } | ... | ... |
cashier-shared/src/main/java/com/diligrp/cashier/shared/codec/ObjectCodec.java
0 → 100644
| 1 | +package com.diligrp.cashier.shared.codec; | |
| 2 | + | |
| 3 | +import java.io.*; | |
| 4 | + | |
| 5 | +public final class ObjectCodec implements ByteCodec<Object> { | |
| 6 | + | |
| 7 | + public static ByteCodec<Object> INSTANCE = new ObjectCodec(); | |
| 8 | + | |
| 9 | + @Override | |
| 10 | + public Object decode(byte[] payload) throws IOException { | |
| 11 | + try (ObjectInputStream is = new ObjectInputStream(new ByteArrayInputStream(payload))) { | |
| 12 | + return is.readObject(); | |
| 13 | + } catch (Exception ex) { | |
| 14 | + throw new IOException(ex); | |
| 15 | + } | |
| 16 | + } | |
| 17 | + | |
| 18 | + @Override | |
| 19 | + public byte[] encode(Object payload) throws IOException { | |
| 20 | + ByteArrayOutputStream buffer = new ByteArrayOutputStream(); | |
| 21 | + ObjectOutputStream os = new ObjectOutputStream(buffer); | |
| 22 | + os.writeObject(payload); | |
| 23 | + os.close(); | |
| 24 | + return buffer.toByteArray(); | |
| 25 | + } | |
| 26 | +} | ... | ... |
cashier-shared/src/main/java/com/diligrp/cashier/shared/http/AntPathRequestMatcher.java
0 → 100644
| 1 | +package com.diligrp.cashier.shared.http; | |
| 2 | + | |
| 3 | +import jakarta.servlet.http.HttpServletRequest; | |
| 4 | +import org.springframework.http.HttpMethod; | |
| 5 | +import org.springframework.util.AntPathMatcher; | |
| 6 | +import org.springframework.util.Assert; | |
| 7 | +import org.springframework.util.PathMatcher; | |
| 8 | +import org.springframework.util.StringUtils; | |
| 9 | +import org.springframework.web.util.UrlPathHelper; | |
| 10 | + | |
| 11 | +public class AntPathRequestMatcher implements HttpRequestMatcher { | |
| 12 | + | |
| 13 | + private final String pattern; | |
| 14 | + | |
| 15 | + private final HttpMethod httpMethod; | |
| 16 | + | |
| 17 | + private final PathMatcher matcher; | |
| 18 | + | |
| 19 | + private final UrlPathHelper urlPathHelper; | |
| 20 | + | |
| 21 | + public AntPathRequestMatcher(String pattern, HttpMethod httpMethod, boolean caseSensitive) { | |
| 22 | + Assert.hasText(pattern, "Pattern cannot be null or empty"); | |
| 23 | + this.pattern = pattern; | |
| 24 | + this.httpMethod = httpMethod; | |
| 25 | + this.matcher = createPathMatcher(caseSensitive); | |
| 26 | + this.urlPathHelper = new UrlPathHelper(); | |
| 27 | + } | |
| 28 | + | |
| 29 | + @Override | |
| 30 | + public boolean matches(HttpServletRequest request) { | |
| 31 | + if (this.httpMethod != null && StringUtils.hasText(request.getMethod()) && | |
| 32 | + this.httpMethod != HttpMethod.valueOf(request.getMethod())) { | |
| 33 | + return false; | |
| 34 | + } | |
| 35 | + if (this.pattern.equals("/**")) { | |
| 36 | + return true; | |
| 37 | + } | |
| 38 | + | |
| 39 | + String url = this.urlPathHelper.getPathWithinApplication(request); | |
| 40 | + return this.matcher.match(this.pattern, url); | |
| 41 | + } | |
| 42 | + | |
| 43 | + private PathMatcher createPathMatcher(boolean caseSensitive) { | |
| 44 | + AntPathMatcher pathMatcher = new AntPathMatcher(); | |
| 45 | + pathMatcher.setTrimTokens(false); | |
| 46 | + pathMatcher.setCaseSensitive(caseSensitive); | |
| 47 | + return pathMatcher; | |
| 48 | + } | |
| 49 | +} | ... | ... |
cashier-shared/src/main/java/com/diligrp/cashier/shared/http/DuplicateSubmitFilter.java
0 → 100644
| 1 | +package com.diligrp.cashier.shared.http; | |
| 2 | + | |
| 3 | +import com.diligrp.cashier.shared.Constants; | |
| 4 | +import com.diligrp.cashier.shared.ErrorCode; | |
| 5 | +import com.diligrp.cashier.shared.codec.StringCodec; | |
| 6 | +import com.diligrp.cashier.shared.domain.Message; | |
| 7 | +import com.diligrp.cashier.shared.exception.PlatformServiceException; | |
| 8 | +import com.diligrp.cashier.shared.security.Md5Cipher; | |
| 9 | +import com.diligrp.cashier.shared.util.HttpUtils; | |
| 10 | +import com.diligrp.cashier.shared.util.JsonUtils; | |
| 11 | +import jakarta.annotation.Resource; | |
| 12 | +import jakarta.servlet.FilterChain; | |
| 13 | +import jakarta.servlet.ServletException; | |
| 14 | +import jakarta.servlet.ServletRequest; | |
| 15 | +import jakarta.servlet.ServletResponse; | |
| 16 | +import jakarta.servlet.http.HttpServletRequest; | |
| 17 | +import jakarta.servlet.http.HttpServletResponse; | |
| 18 | +import org.slf4j.Logger; | |
| 19 | +import org.slf4j.LoggerFactory; | |
| 20 | +import org.springframework.data.redis.core.StringRedisTemplate; | |
| 21 | +import org.springframework.http.HttpMethod; | |
| 22 | +import org.springframework.util.Assert; | |
| 23 | +import org.springframework.util.ObjectUtils; | |
| 24 | +import org.springframework.web.filter.GenericFilterBean; | |
| 25 | +import org.springframework.web.util.ContentCachingRequestWrapper; | |
| 26 | + | |
| 27 | +import java.io.IOException; | |
| 28 | +import java.util.ArrayList; | |
| 29 | +import java.util.Base64; | |
| 30 | +import java.util.Collections; | |
| 31 | +import java.util.List; | |
| 32 | +import java.util.concurrent.TimeUnit; | |
| 33 | + | |
| 34 | +/** | |
| 35 | + * 防重复提交过滤器 | |
| 36 | + */ | |
| 37 | +public class DuplicateSubmitFilter extends GenericFilterBean { | |
| 38 | + | |
| 39 | + private static final Logger LOG = LoggerFactory.getLogger(DuplicateSubmitFilter.class); | |
| 40 | + | |
| 41 | + private final List<RequestMapping> mappings; | |
| 42 | + | |
| 43 | + @Resource | |
| 44 | + private StringRedisTemplate stringRedisTemplate; | |
| 45 | + | |
| 46 | + public DuplicateSubmitFilter(List<RequestMapping> mappings) { | |
| 47 | + this.mappings = mappings; | |
| 48 | + } | |
| 49 | + | |
| 50 | + @Override | |
| 51 | + public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { | |
| 52 | + HttpServletRequest httpRequest = (HttpServletRequest) request; | |
| 53 | + for (RequestMapping mapping : this.mappings) { | |
| 54 | + try { | |
| 55 | + if (mapping.match((HttpServletRequest) request)) { | |
| 56 | + LOG.debug("{} filtered", this.getClass().getSimpleName()); | |
| 57 | + // 缓存当前请求以便可以重复读取请求数据 | |
| 58 | + request = new ContentCachingRequestWrapper(httpRequest); | |
| 59 | + String requestId = requestId((ContentCachingRequestWrapper) request); | |
| 60 | + String requestKey = String.format(Constants.DUPLICATE_SUBMIT_KEY, requestId); | |
| 61 | + Boolean success = stringRedisTemplate.opsForValue().setIfAbsent(requestKey, | |
| 62 | + requestId, mapping.getDuration(), mapping.getTimeUnit()); | |
| 63 | + if (success == null || !success) { | |
| 64 | + Message<?> message = Message.failure(ErrorCode.OPERATION_NOT_ALLOWED, "请求重复提交,访问被拒绝"); | |
| 65 | + HttpUtils.sendResponse((HttpServletResponse) response, JsonUtils.toJsonString(message)); | |
| 66 | + return; | |
| 67 | + } | |
| 68 | + } | |
| 69 | + } catch (PlatformServiceException ex) { | |
| 70 | + throw ex; | |
| 71 | + } catch (Exception ex) { | |
| 72 | + LOG.error("防重复提交过滤器处理失败", ex); | |
| 73 | + Message<?> message = Message.failure(ErrorCode.SYSTEM_UNKNOWN_ERROR, "防重复提交过滤器处理失败"); | |
| 74 | + HttpUtils.sendResponse((HttpServletResponse) response, JsonUtils.toJsonString(message)); | |
| 75 | + return; | |
| 76 | + } | |
| 77 | + } | |
| 78 | + | |
| 79 | + chain.doFilter(request, response); | |
| 80 | + } | |
| 81 | + | |
| 82 | + @Override | |
| 83 | + public void afterPropertiesSet() throws ServletException { | |
| 84 | + super.afterPropertiesSet(); | |
| 85 | + Assert.notEmpty(mappings, "duplicate submit request setting must be specified"); | |
| 86 | + } | |
| 87 | + | |
| 88 | + public static class RequestMapping { | |
| 89 | + private final HttpRequestMatcher requestMatcher; | |
| 90 | + | |
| 91 | + private final long duration; | |
| 92 | + | |
| 93 | + private final TimeUnit timeUnit; | |
| 94 | + | |
| 95 | + public RequestMapping(HttpRequestMatcher requestMatcher, long duration, TimeUnit timeUnit) { | |
| 96 | + this.requestMatcher = requestMatcher; | |
| 97 | + this.duration = duration; | |
| 98 | + this.timeUnit = timeUnit; | |
| 99 | + } | |
| 100 | + | |
| 101 | + public boolean match(HttpServletRequest request) { | |
| 102 | + return this.requestMatcher.matches(request); | |
| 103 | + } | |
| 104 | + | |
| 105 | + public long getDuration() { | |
| 106 | + return duration; | |
| 107 | + } | |
| 108 | + | |
| 109 | + public TimeUnit getTimeUnit() { | |
| 110 | + return timeUnit; | |
| 111 | + } | |
| 112 | + } | |
| 113 | + | |
| 114 | + private String requestId(ContentCachingRequestWrapper request) throws Exception { | |
| 115 | + String requestURI = request.getRequestURI(); | |
| 116 | + String queryString = request.getQueryString(); | |
| 117 | + if (!ObjectUtils.isEmpty(queryString)) { | |
| 118 | + requestURI = requestURI.concat("?").concat(queryString); | |
| 119 | + } | |
| 120 | + | |
| 121 | + byte[] uri = StringCodec.INSTANCE.encode(requestURI); | |
| 122 | + byte[] body = request.getContentAsByteArray(); | |
| 123 | + byte[] data = new byte[uri.length + body.length]; | |
| 124 | + System.arraycopy(uri, 0, data, 0, uri.length); | |
| 125 | + System.arraycopy(body, 0, data, uri.length, body.length); | |
| 126 | + | |
| 127 | + return Base64.getEncoder().encodeToString(Md5Cipher.encrypt(data)); | |
| 128 | + } | |
| 129 | + | |
| 130 | + public static class Builder { | |
| 131 | + | |
| 132 | + private final List<RequestMapping> mappings = new ArrayList<>(); | |
| 133 | + | |
| 134 | + public RequestMappingBuilder requestMatcher(String pattern) { | |
| 135 | + return requestMatcher(null, pattern); | |
| 136 | + } | |
| 137 | + | |
| 138 | + public RequestMappingBuilder requestMatcher(HttpMethod method, String pattern) { | |
| 139 | + Assert.hasText(pattern, "patterns must not be empty"); | |
| 140 | + return new RequestMappingBuilder(new AntPathRequestMatcher(pattern, method, true)); | |
| 141 | + } | |
| 142 | + | |
| 143 | + public RequestMappingBuilder requestMatchers(String... patterns) { | |
| 144 | + return requestMatchers(null, patterns); | |
| 145 | + } | |
| 146 | + | |
| 147 | + public RequestMappingBuilder requestMatchers(HttpMethod method, String... patterns) { | |
| 148 | + Assert.notEmpty(patterns, "patterns must not be empty"); | |
| 149 | + List<HttpRequestMatcher> requestMatchers = new ArrayList<>(patterns.length); | |
| 150 | + for (String pattern : patterns) { | |
| 151 | + requestMatchers.add(new AntPathRequestMatcher(pattern, method, true)); | |
| 152 | + } | |
| 153 | + return new RequestMappingBuilder(new OrRequestMatcher(requestMatchers)); | |
| 154 | + } | |
| 155 | + | |
| 156 | + public DuplicateSubmitFilter build() { | |
| 157 | + return new DuplicateSubmitFilter(Collections.unmodifiableList(this.mappings)); | |
| 158 | + } | |
| 159 | + | |
| 160 | + public class RequestMappingBuilder { | |
| 161 | + private final HttpRequestMatcher requestMatcher; | |
| 162 | + | |
| 163 | + public RequestMappingBuilder(HttpRequestMatcher requestMatcher) { | |
| 164 | + this.requestMatcher = requestMatcher; | |
| 165 | + } | |
| 166 | + | |
| 167 | + public Builder forbidSubmit(long duration, TimeUnit timeUnit) { | |
| 168 | + Assert.isTrue(duration > 0, "Invalid duration"); | |
| 169 | + Assert.notNull(timeUnit, "timeUnit must not be null"); | |
| 170 | + Builder.this.mappings.add(new RequestMapping(requestMatcher, duration, timeUnit)); | |
| 171 | + return Builder.this; | |
| 172 | + } | |
| 173 | + } | |
| 174 | + } | |
| 175 | +} | ... | ... |
cashier-shared/src/main/java/com/diligrp/cashier/shared/http/HttpRequestMatcher.java
0 → 100644
cashier-shared/src/main/java/com/diligrp/cashier/shared/http/OrRequestMatcher.java
0 → 100644
| 1 | +package com.diligrp.cashier.shared.http; | |
| 2 | + | |
| 3 | +import jakarta.servlet.http.HttpServletRequest; | |
| 4 | + | |
| 5 | +import java.util.Arrays; | |
| 6 | +import java.util.List; | |
| 7 | + | |
| 8 | +public class OrRequestMatcher implements HttpRequestMatcher { | |
| 9 | + private final List<HttpRequestMatcher> requestMatchers; | |
| 10 | + | |
| 11 | + public OrRequestMatcher(List<HttpRequestMatcher> requestMatchers) { | |
| 12 | + this.requestMatchers = requestMatchers; | |
| 13 | + } | |
| 14 | + | |
| 15 | + public OrRequestMatcher(HttpRequestMatcher... requestMatchers) { | |
| 16 | + this(Arrays.asList(requestMatchers)); | |
| 17 | + } | |
| 18 | + | |
| 19 | + @Override | |
| 20 | + public boolean matches(HttpServletRequest request) { | |
| 21 | + for (HttpRequestMatcher matcher : this.requestMatchers) { | |
| 22 | + if (matcher.matches(request)) { | |
| 23 | + return true; | |
| 24 | + } | |
| 25 | + } | |
| 26 | + return false; | |
| 27 | + } | |
| 28 | + | |
| 29 | + @Override | |
| 30 | + public String toString() { | |
| 31 | + return "Or " + this.requestMatchers; | |
| 32 | + } | |
| 33 | +} | ... | ... |
cashier-trade/src/main/java/com/diligrp/cashier/trade/manager/PaymentResultManager.java
| ... | ... | @@ -76,7 +76,7 @@ public class PaymentResultManager { |
| 76 | 76 | * 通知业务系统退款处理结果 |
| 77 | 77 | */ |
| 78 | 78 | public void notifyRefundResult(String uri, OnlineRefundResult refundResult) { |
| 79 | - LOG.info("Notifying online payment result: {}, {}", refundResult.getTradeId(), refundResult.getRefundId()); | |
| 79 | + LOG.info("Notifying online refund result: {}, {}", refundResult.getTradeId(), refundResult.getRefundId()); | |
| 80 | 80 | ThreadPoolService.getIoThreadPoll().submit(() -> { |
| 81 | 81 | List<IPaymentEventListener> lifeCycles = eventListeners.stream().toList(); |
| 82 | 82 | if (!lifeCycles.isEmpty()) { |
| ... | ... | @@ -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 payment refund result", ex); | |
| 89 | + LOG.error("Failed to notify online 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 payment refund result: {}", payload); | |
| 98 | + LOG.info("Notifying online 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 payment refund result"); | |
| 101 | + LOG.error("Failed to notify online refund result"); | |
| 102 | 102 | } |
| 103 | 103 | } catch (Exception ex) { |
| 104 | - LOG.error("Failed to notify payment refund result", ex); | |
| 104 | + LOG.error("Failed to notify online refund result", ex); | |
| 105 | 105 | } |
| 106 | 106 | }); |
| 107 | 107 | } | ... | ... |