| | |
| | | package cc.mrbird.febs.pay.util; |
| | | |
| | | import cc.mrbird.febs.pay.model.RefundStatus; |
| | | import cn.hutool.json.JSONUtil; |
| | | import com.fasterxml.jackson.databind.ObjectMapper; |
| | | import lombok.extern.slf4j.Slf4j; |
| | | import org.apache.http.client.methods.HttpGet; |
| | | import org.apache.http.impl.client.CloseableHttpClient; |
| | | import org.apache.http.impl.client.HttpClients; |
| | | import org.apache.http.util.EntityUtils; |
| | | import org.springframework.stereotype.Service; |
| | | |
| | | import java.util.concurrent.*; |
| | | |
| | | import java.util.List; |
| | | @Slf4j |
| | | @Service(value="FiuuRefundUtil") |
| | | public class FiuuRefundUtil { |
| | | |
| | | private static final String API_BASE_URL = "https://api.fiuu.com/RMS/API/refundAPI/"; |
| | | private static final String MERCHANT_ID = "e2umart01"; |
| | | private static final String VERIFY_KEY = "4e3a4ed58e62ddbfacf41f6d5ec56bf2"; |
| | | private static final int MAX_RETRIES = 3; |
| | | private static final int POLL_INTERVAL = 1000; // 5秒 |
| | | private static final int TIMEOUT = 60000; // 60秒超时 |
| | | |
| | | private final ObjectMapper objectMapper = new ObjectMapper(); |
| | | |
| | |
| | | HttpGet request = new HttpGet(url); |
| | | try (CloseableHttpClient client = HttpClients.createDefault()) { |
| | | String response = EntityUtils.toString(client.execute(request).getEntity()); |
| | | return objectMapper.readValue(response, RefundStatus.class); |
| | | log.info("Response: " + response); |
| | | |
| | | List<RefundStatus> refundStatusList = JSONUtil.toList(JSONUtil.parseArray(response), RefundStatus.class); |
| | | return refundStatusList.get(0); |
| | | } |
| | | } |
| | | |
| | | // 异步轮询退款状态 |
| | | public RefundStatus pollRefundStatus(String txnId) throws Exception { |
| | | ExecutorService executor = Executors.newSingleThreadExecutor(); |
| | | Future<RefundStatus> future = executor.submit(() -> { |
| | | int retryCount = 0; |
| | | while (retryCount < MAX_RETRIES) { |
| | | try { |
| | | RefundStatus status = queryByTxnId(txnId); |
| | | if (!"pending".equals(status.getStatus())) { |
| | | return status; |
| | | } |
| | | Thread.sleep(POLL_INTERVAL); |
| | | retryCount++; |
| | | } catch (InterruptedException e) { |
| | | Thread.currentThread().interrupt(); |
| | | throw new RuntimeException("Polling interrupted", e); |
| | | } |
| | | } |
| | | throw new TimeoutException("Max retries reached"); |
| | | }); |
| | | |
| | | try { |
| | | return future.get(TIMEOUT, TimeUnit.MILLISECONDS); |
| | | } catch (TimeoutException e) { |
| | | future.cancel(true); |
| | | throw new RuntimeException("Refund status check timeout"); |
| | | } finally { |
| | | executor.shutdown(); |
| | | } |
| | | RefundStatus status = queryByTxnId(txnId); |
| | | return status; |
| | | } |
| | | } |