Привет всем, я Букай Чен~
Используйте учетную запись разработчика для входа на открытую платформу управления платформой.
Примечание. Продукты, поддерживаемые средой песочницы, можно найти в консоли песочницы. Приложение-песочница > Список продуктов Посмотреть в .
Перед отладкой в изолированной программной среде необходимо убедиться, что ключ/сертификат настроен для подписи. Alipay предоставляет два способа настройки системного ключа по умолчанию и пользовательского ключа. Здесь я использую метод по умолчанию:
Если разработчикам необходимо использовать системный ключ/сертификат по умолчанию, они могут выбрать системный ключ по умолчанию в информации о разработке. Примечание. При использовании онлайн-инструмента отладки API для отладки OpenAPI необходимо использовать системный ключ по умолчанию.
Шлюз приложений используется для получения асинхронных уведомлений из изолированной среды Alipay (подключенных к сообщениям From Ant), например пассивных уведомлений о создании магазина.
Примечание. Только из сообщений ant в режиме подписки HTTP необходимо настроить шлюз приложений, а из сообщений ant в режиме подписки WebSocket не нужно настраивать шлюз приложений.
На этом этапе работа веб-страницы завершена.
<dependency>
<groupId>com.alipay.sdk</groupId>
<artifactId>alipay-sdk-java</artifactId>
<version>4.22.110.ALL</version>
</dependency>
alipay:
appId:
appPrivateKey:
alipayPublicKey:
notifyUrl: (перезвонитьинтерфейс)
Прочитайте информацию о конфигурации в yml и автоматически заполните соответствующие атрибуты.
@Data
@Component
@ConfigurationProperties(prefix = "alipay")
public class AliPayConfig {
private String appId;
private String appPrivateKey;
private String alipayPublicKey;
private String notifyUrl;
}
@Data
public class AliPay {
private String traceNo;
private double totalAmount;
private String subject;
private String alipayTraceNo;
}
private static final String GATEWAY_URL = "https://openapi.alipaydev.com/gateway.do";
private static final String FORMAT = "JSON";
private static final String CHARSET = "UTF-8";
//Метод подписи
private static final String SIGN_TYPE = "RSA2";
@Resource
private AliPayConfig aliPayConfig;
@Resource
private OrdersMapper ordersMapper;
@GetMapping("/pay") // &subject=xxx&traceNo=xxx&totalAmount=xxx
public void pay(AliPay aliPay, HttpServletResponse httpResponse) throws Exception {
// 1. СоздательClient, клиент, предоставляемый универсальным SDK, отвечает за вызов API Alipay.
AlipayClient alipayClient = new DefaultAlipayClient(GATEWAY_URL, aliPayConfig.getAppId(),
aliPayConfig.getAppPrivateKey(), FORMAT, CHARSET, aliPayConfig.getAlipayPublicKey(), SIGN_TYPE);
// 2. создавать Запрос и установка параметров запроса
AlipayTradePagePayRequest request = new AlipayTradePagePayRequest(); // отправка запроса Запросить класс
request.setNotifyUrl(aliPayConfig.getNotifyUrl());
JSONObject bizContent = new JSONObject();
bizContent.set("out_trade_no", aliPay.getTraceNo()); // Номер заказа генерируется нами самими
bizContent.set("total_amount", aliPay.getTotalAmount()); // Общая сумма заказа
bizContent.set("subject", aliPay.getSubject()); // Название платежа
bizContent.set("product_code", "FAST_INSTANT_TRADE_PAY"); // зафиксированный Конфигурация request.setBizContent(bizContent.toString());
// Выполните запрос, получите результат ответа и верните его в браузер.
String form = "";
try {
form = alipayClient.pageExecute(request).getBody(); // Вызов SDK для создания формы
} catch (AlipayApiException e) {
e.printStackTrace();
}
httpResponse.setContentType("text/html;charset=" + CHARSET);
httpResponse.getWriter().write(form);// Непосредственно выводить полную HTML-форму на страницу.
httpResponse.getWriter().flush();
httpResponse.getWriter().close();
}
Встречающиеся подводные камни:
Если в URL-адресе есть китайские символы, появится сообщение об ошибке. Замените зависимость.
Официальный сайт предоставляет простую версию и официальную версию.
easy-sdk, похоже, не поддерживает китайскую тематику, иначе biz_content будет искажен, поэтому я просто использовал официальную версию alipay-sdk.
Интерфейс Post используется, поскольку официальная рекомендация заключается в обработке операции после успешной оплаты методом асинхронного вызова. Асинхронный вызов представляет собой почтовый запрос. Метод асинхронного обратного вызова должен быть IP-адресом общедоступной сети, поскольку Alipay основан на доступе к общедоступной сети. не может получить доступ к локальному хосту и нуждается в прокси-сервере. Есть два варианта установки общедоступного IP-адреса: 1. Проникновение в интрасеть, 2. Развертывание проекта на сервере. Наш проект использует проникновение в интрасеть, используя natapp, настройте бесплатный туннель и настройте notifyurl. идея.
@PostMapping("/notify") // Обратите внимание, что это должен быть POSTинтерфейс.
public String payNotify(HttpServletRequest request) throws Exception {
if (request.getParameter("trade_status").equals("TRADE_SUCCESS")) {
System.out.println("==========Асинхронный обратный вызов Alipay========");
Map<String, String> params = new HashMap<>();
Map<String, String[]> requestParams = request.getParameterMap();
for (String name : requestParams.keySet()) {
params.put(name, request.getParameter(name));
// System.out.println(name + " = " + request.getParameter(name));
}
String tradeNo = params.get("out_trade_no");
String gmtPayment = params.get("gmt_payment");
String alipayTradeNo = params.get("trade_no");
String sign = params.get("sign");
String content = AlipaySignature.getSignCheckContentV1(params);
boolean checkSignature = AlipaySignature.rsa256CheckContent(content, sign, aliPayConfig.getAlipayPublicKey(), "UTF-8"); // Подтвердить подпись
// Проверка подписи Alipay
if (checkSignature) {
// Прошел проверку подписи
System.out.println("Имя транзакции: " + params.get("subject"));
System.out.println("Состояние транзакции: " + params.get("trade_status"));
System.out.println("Номер ваучера транзакции Alipay: " + params.get("trade_no"));
System.out.println("Номер заказа продавца: " + params.get("out_trade_no"));
System.out.println("Сумма транзакции: " + params.get("total_amount"));
System.out.println("Уникальный идентификатор покупателя существует в Alipay: " + params.get("buyer_id"));
System.out.println("Время оплаты покупателя: " + params.get("gmt_payment"));
System.out.println("Сумма платежа покупателя: " + params.get("buyer_pay_amount"));
// Заказ на обновление не оплачен
ordersMapper.updateState(tradeNo, "оплаченный", gmtPayment, alipayTradeNo);
}
}
return "success";
}
@GetMapping("/return")
public Result returnPay(AliPay aliPay) throws AlipayApiException {
// 7 дней без причины возврат средств
String now = DateUtil.now();
Orders orders = ordersMapper.getByNo(aliPay.getTraceNo());
if (orders != null) {
// Класс инструмента hutool, определение временного интервала
long between = DateUtil.between(DateUtil.parseDateTime(orders.getPaymentTime()), DateUtil.parseDateTime(now), DateUnit.DAY);
if (between > 7) {
return Result.error("-1", «Этому заказу более 7 дней и возврат средств не поддерживается»);
}
}
// 1. СоздательClient, клиент, предоставляемый универсальным SDK, отвечает за вызов API Alipay.
AlipayClient alipayClient = new DefaultAlipayClient(GATEWAY_URL,
aliPayConfig.getAppId(), aliPayConfig.getAppPrivateKey(), FORMAT, CHARSET,
aliPayConfig.getAlipayPublicKey(), SIGN_TYPE);
// 2. создавать Запрос, установка параметров
AlipayTradeRefundRequest request = new AlipayTradeRefundRequest();
JSONObject bizContent = new JSONObject();
bizContent.set("trade_no", aliPay.getAlipayTraceNo()); // Серийный номер заказа обратного вызова Alipay
bizContent.set("refund_amount", aliPay.getTotalAmount()); // Общая сумма заказа
bizContent.set("out_request_no", aliPay.getTraceNo()); // Мой номер заказа
// Параметры возвращаемого параметра, передаваемые по мере необходимости
//JSONArray queryOptions = new JSONArray();
//queryOptions.add("refund_detail_item_list");
//bizContent.put("query_options", queryOptions);
request.setBizContent(bizContent.toString());
// 3. Выполнить запрос
AlipayTradeRefundResponse response = alipayClient.execute(request);
if (response.isSuccess()) { // Возврат прошел успешно, isSuccess это правда
System.out.println("Вызов успешен");
// 4. Обновить статус базы данных
ordersMapper.updatePayState(aliPay.getTraceNo(), «Возврат», now);
return Result.success();
} else { // Возврат не выполнен, isSuccess ложно
System.out.println(response.getBody());
return Result.error(response.getCode(), response.getBody());
}
}
Использовать очередь сообщений
Мы можем использовать очередь задержки RabbitMQ. RabbitMQ имеет следующие две функции для реализации очередей задержки:
RabbitMQ может установить x-message-tt для Queue и Message, чтобы контролировать время существования сообщения. Если время ожидания истекло, сообщение становится неработающим.
Очередь RabbitMQ может быть настроена с двумя параметрами: x-dead-letter-exchange и x-dead-letter-routing-key (необязательно), которые используются для контроля появления недоставленного письма в очереди и перенаправляются в соответствии с этими двумя параметрами. . Объединив две вышеуказанные функции, вы можете имитировать функцию отложенных сообщений.
Преимущества и недостатки
После того, как пользователь размещает заказ, сообщение msg доставляется и сохраняется на сервере сообщений. Срок действия сообщения составляет 30 минут, и оно не было использовано потребителем заказа. Сообщение будет передано коммутатору недоставленных сообщений. и направляется в очередь недоставленных писем, где они будут использоваться нашими потребителями недоставленных писем, получающими сообщения через 30 минут.
Потребитель недоставленного письма проверяет статус платежного поручения по номеру заказа. Если платеж не произведен, время ожидания заказа не истекает.
Проверьте отфильтрованные номера заказов: