Spring Boot интегрирует оплату Alipay, просто прочитайте эту статью
Spring Boot интегрирует оплату Alipay, просто прочитайте эту статью

Привет всем, я Букай Чен~

Этапы работы с веб-страницей

1. Войдите в платформу разработки Alipay — среду песочницы.

Используйте учетную запись разработчика для входа на открытую платформу управления платформой.

2. Нажмите на песочницу, чтобы войти в нее.

Примечание. Продукты, поддерживаемые средой песочницы, можно найти в консоли песочницы. Приложение-песочница > Список продуктов Посмотреть в .

3. Войдите в песочницу и настройте метод подписи интерфейса.

Перед отладкой в ​​изолированной программной среде необходимо убедиться, что ключ/сертификат настроен для подписи. Alipay предоставляет два способа настройки системного ключа по умолчанию и пользовательского ключа. Здесь я использую метод по умолчанию:

Если разработчикам необходимо использовать системный ключ/сертификат по умолчанию, они могут выбрать системный ключ по умолчанию в информации о разработке. Примечание. При использовании онлайн-инструмента отладки API для отладки OpenAPI необходимо использовать системный ключ по умолчанию.

4. Настройте шлюз приложений

Шлюз приложений используется для получения асинхронных уведомлений из изолированной среды Alipay (подключенных к сообщениям From Ant), например пассивных уведомлений о создании магазина.

Примечание. Только из сообщений ant в режиме подписки HTTP необходимо настроить шлюз приложений, а из сообщений ant в режиме подписки WebSocket не нужно настраивать шлюз приложений.

5. Создайте свой собственный ключ

На этом этапе работа веб-страницы завершена.

этапы работы идеи

1. Импортировать зависимости

Язык кода:javascript
копировать
<dependency>
   <groupId>com.alipay.sdk</groupId>
   <artifactId>alipay-sdk-java</artifactId>
   <version>4.22.110.ALL</version>
</dependency>

2. Настройте в application.yml

Язык кода:javascript
копировать
alipay:
  appId: 
  appPrivateKey: 
  alipayPublicKey: 
  notifyUrl: (перезвонитьинтерфейс)

3. Конфигурация JAVA Alipay: AlipayConfig.java.

Прочитайте информацию о конфигурации в yml и автоматически заполните соответствующие атрибуты.

Язык кода:javascript
копировать
@Data
@Component
@ConfigurationProperties(prefix = "alipay")
public class AliPayConfig {
    private String appId;
    private String appPrivateKey;
    private String alipayPublicKey;
    private String notifyUrl;

}

4. Платежный интерфейс Создайте новый AliPayController.java.

  1. существуетController в Конфигурацияgateway_url (адрес шлюза, который вызывает URL-адрес Alipay)、формат (формат JSON)、charset(UTF-8)、Sign_type (метод подписи-rsa2
  2. Напишите запрос на получение,(Параметр метода представляет собой класс конфигурации AliPay, который включает номер заказа и общую информацию, созданную вами. сумма、Название платежа、Номер ваучера транзакции Alipay и HttpServletResponse);сосредоточиться на публичном аккаунте: Колонка технологий Code Обезьяна, ключевое слово ответа: 1111 Получите внутреннее руководство Alibaba по оптимизации производительности Java!
  3. создаватьClient(Это клиент, предоставляемый универсальным SDK.,Отвечает за вызов API Alipay.,Параметры настройки включают в себяшлюзадрес、appid、ключ、открытый ключ、format、charset、Метод подписи)----------------------->создаватьClient,Это клиент, предоставляемый универсальным SDK.,Отвечает за вызов API Alipay.
  4. Создайте AlipayTradePagePayRequest, КонфигурациюnotifyUrl и задайте параметр Request (параметр содержит номер заказа、Общая сумма、Название платежа)(Формат:JSONФормат)------------------------->создавать Запрос и установка параметров запроса
  5. проходитьAlipayClientосуществлятьrequestВызов SDK для создания формы,Используйте HttpServletResponse (поток ответа браузера) для записи содержимого формы.,создаватьодинhtmlизвеб-страница)--------------------------->Выполните запрос, получите результат ответа и верните его в браузер.
Язык кода:javascript
копировать
@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();
}

Добавьте перехватчик, чтобы игнорировать конфигурацию интерфейса Alipay.

Встречающиеся подводные камни:

Если в URL-адресе есть китайские символы, появится сообщение об ошибке. Замените зависимость.

Официальный сайт предоставляет простую версию и официальную версию.

easy-sdk, похоже, не поддерживает китайскую тематику, иначе biz_content будет искажен, поэтому я просто использовал официальную версию alipay-sdk.

6. Интерфейс обратного вызова

  1. Используемый постинтерфейс,Сначала проверьте, успешен ли статус транзакции.,Получите информацию в запросе
  2. Проверка подписи Alipay (с использованием AlipaySignature (класс, предоставляемый универсальным SDK) для получения строковой строки и проверки ее с помощью подписи подписи), после ее передачи используйте OrderMapper для обновления базы данных)

Интерфейс Post используется, поскольку официальная рекомендация заключается в обработке операции после успешной оплаты методом асинхронного вызова. Асинхронный вызов представляет собой почтовый запрос. Метод асинхронного обратного вызова должен быть IP-адресом общедоступной сети, поскольку Alipay основан на доступе к общедоступной сети. не может получить доступ к локальному хосту и нуждается в прокси-сервере. Есть два варианта установки общедоступного IP-адреса: 1. Проникновение в интрасеть, 2. Развертывание проекта на сервере. Наш проект использует проникновение в интрасеть, используя natapp, настройте бесплатный туннель и настройте notifyurl. идея.

Язык кода:javascript
копировать
@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";
}

Процесс возврата

  1. создаватьClient(Это клиент, предоставляемый универсальным SDK.,Отвечает за вызов API Alipay.)(Параметры включают в себяшлюзадрес、appid、ключ、открытый ключ、format、charset、Метод подписи)---------------------->СоздательClient, клиент, предоставляемый универсальным SDK, отвечает за вызов API Alipay.
  2. создавать AlipayTradePagePayRequest,настраиватьRequestпараметр(Параметры включают в себя Серийный номер заказа обратного вызова Alipay、Общая сумма、Мой номер заказа)(Формат:JSONФормат)---------------------------->создавать Запрос, установка параметров
  3. Выполните запрос через AlipayClient, чтобы получить ответ.,Определите, успешно ли оно выполнено, с помощью isSuccess,после успеха Обновить статус базы данных------------->Выполнить запрос,Обновить базу данных
Язык кода:javascript
копировать
@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 (необязательно), которые используются для контроля появления недоставленного письма в очереди и перенаправляются в соответствии с этими двумя параметрами. . Объединив две вышеуказанные функции, вы можете имитировать функцию отложенных сообщений.

Преимущества и недостатки

  • Преимущества: Эффективность: вы можете использовать распределенные характеристики RabbitMQ для легкого горизонтального расширения, а постоянство поддержки сообщений повышает надежность.
  • Недостатки: простота использования зависит от эксплуатации и обслуживания RabbitMq. Поскольку требуется ссылка на RabbitMq, сложность и стоимость становятся выше.

После того, как пользователь размещает заказ, сообщение msg доставляется и сохраняется на сервере сообщений. Срок действия сообщения составляет 30 минут, и оно не было использовано потребителем заказа. Сообщение будет передано коммутатору недоставленных сообщений. и направляется в очередь недоставленных писем, где они будут использоваться нашими потребителями недоставленных писем, получающими сообщения через 30 минут.

Потребитель недоставленного письма проверяет статус платежного поручения по номеру заказа. Если платеж не произведен, время ожидания заказа не истекает.

Проверьте отфильтрованные номера заказов:

  1. Есть ли в этом порядке существование?
  2. Позвоните в Alipay и назовите номер заказа, чтобы проверить, находится ли статус оплаты заказа в ожидании оплаты.
  3. Обновить статус номера заказа
boy illustration
Артефакт, который делает код элегантным и лаконичным: программирование на Java8 Stream
boy illustration
Spring Boot(06): Spring Boot в сочетании с MySQL создает минималистскую и эффективную систему управления данными.
boy illustration
Как использовать ArrayPool
boy illustration
Интегрируйте iText в Spring Boot для реализации замены контента на основе шаблонов PDF.
boy illustration
Redis реализует очередь задержки на основе zset
boy illustration
Получить текущий пакет jar. path_java получает файл jar.
boy illustration
Краткое обсуждение высокопроизводительного шлюза Apache ShenYu
boy illustration
Если вы этого не понимаете, то на собеседовании даже не осмелитесь сказать, что знакомы с Redis.
boy illustration
elasticsearch медленный запрос, устранение неполадок записи, запрос с подстановочными знаками
boy illustration
По какому стандарту взимается плата за обслуживание программного обеспечения?
boy illustration
IP-адрес Получить
boy illustration
【Java】Решено: org.springframework.web.HttpRequestMethodNotSupportedException
boy illustration
Native js отправляет запрос на публикацию_javascript отправляет запрос на публикацию
boy illustration
.net PDF в Word_pdf в Word
boy illustration
[Пул потоков] Как Springboot использует пул потоков
boy illustration
Подробное объяснение в одной статье: Как работают пулы потоков
boy illustration
Серия SpringCloud (6) | Поговорим о балансировке нагрузки
boy illustration
IDEA Maven может упаковать все импортное полностью красное решение — универсальное решение.
boy illustration
Последний выпуск 2023 года, самое полное руководство по обучению Spring Boot во всей сети (с интеллект-картой).
boy illustration
[Решено — Практическая работа] SaTokenException: запрос не может быть получен в контексте, отличном от Интернета. Решение проблем — Практическая работа.
boy illustration
HikariPool-1 - Connection is not available, request timed out after 30000ms
boy illustration
Power Query: автоматическое суммирование ежемесячных данных с обновлением одним щелчком мыши.
boy illustration
установка Ubuntu в среде npm
boy illustration
3 Бесплатные системы управления складом (WMS) .NET с открытым исходным кодом
boy illustration
Глубокое погружение в библиотеку Python Lassie: мощный инструмент для автоматизации извлечения метаданных
boy illustration
Объяснение прослушивателя серии Activiti7 последней версии 2023 года
boy illustration
API-интерфейс Jitu Express для электронных счетов-Express Bird [просто для понимания]
boy illustration
Каковы архитектуры микросервисов Java. Серверная часть плавающей области обслуживания
boy illustration
Описание трех режимов жизненного цикла службы внедрения зависимостей Asp.net Core.
boy illustration
Java реализует пользовательские аннотации для доступа к интерфейсу без проверки токена.