Springboot se da cuenta del pago de Alipay

1. Ingrese a la plataforma abierta de Ant Financial

https://open.alipay.com/platform/home.htm

2. Descargue la demostración oficial de Alipay, configure y pruebe

Dirección del documento:

https://openhome.alipay.com/docCenter/docCenter.htm Cree los documentos correspondientes de la aplicación

https://opendocs.alipay.com/open/200/105304 Documentación de la aplicación móvil web

https://opendocs.alipay.com/open/54/cyz7do Demo relacionada
Inserte la descripción de la imagen aquí
Inserte la descripción de la imagen aquí
Inserte la descripción de la imagen aquí

3. Utilice la zona de pruebas para realizar pruebas

https://openhome.alipay.com/platform/appDaily.htm?tab=info
Inserte la descripción de la imagen aquí

4. ¿Qué es clave pública, clave privada, cifrado, firma y verificación?

1. La clave pública, la clave privada, la clave pública y la clave privada son un concepto relativo

Su carácter público y privado es relativo al generador.

Después de que se genera un par de claves, la clave privada se mantiene en manos del generador y la clave pública que publica el generador es la clave pública.

Inserte la descripción de la imagen aquí

Descargar el asistente de desarrollo de la plataforma de desarrollo AlipayInserte la descripción de la imagen aquí

5. Proceso de pago de Alipay

https://opendocs.alipay.com/open/270/105898

1. Guíe a los usuarios a la página de Alipay.

1 、 pom.xml

<!--支付宝模块-->
 <dependency>
     <groupId>com.alipay.sdk</groupId>
     <artifactId>alipay-sdk-java</artifactId>
     <version>4.9.28.ALL</version>
 </dependency>

2. Introducir los archivos proporcionados por el material en el proyecto.

AlipayTemplate 、 PayVo 、 PaySyncVo

AlipayTemplate
se agrega en application.yml

#配置支付宝
alipay:
  app_id: 2016101800718205

Inserte la descripción de la imagen aquí

package com.atguigu.gulimall.order.config;

import com.alipay.api.AlipayApiException;
import com.alipay.api.AlipayClient;
import com.alipay.api.DefaultAlipayClient;
import com.alipay.api.request.AlipayTradePagePayRequest;
import com.atguigu.gulimall.order.vo.PayVo;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;

@ConfigurationProperties(prefix = "alipay")
@Component
@Data
public class AlipayTemplate {
    
    

    //在支付宝创建的应用的id
    private   String app_id = "2016092200568607";

    // 商户私钥,您的PKCS8格式RSA2私钥
    private  String merchant_private_key = "XXX";
    // 支付宝公钥,查看地址:https://openhome.alipay.com/platform/keyManage.htm 对应APPID下的支付宝公钥。
    private  String alipay_public_key = "XXX";
    // 服务器[异步通知]页面路径  需http://格式的完整路径,不能加?id=123这类自定义参数,必须外网可以正常访问
    // 支付宝会悄悄的给我们发送一个请求,告诉我们支付成功的信息
    private  String notify_url="http://eaact93of6.52http.tech/payed/notify";

    // 页面跳转同步通知页面路径 需http://格式的完整路径,不能加?id=123这类自定义参数,必须外网可以正常访问
    //同步通知,支付成功,一般跳转到成功页
    //在本地开发的时候可以使用内网穿透的生成的域名来做测试。
    private  String return_url = "http://member.gulimall.com/memberOrder.html";

    // 签名方式
    private  String sign_type = "RSA2";

    // 字符编码格式
    private  String charset = "utf-8";
    // 订单超时时间,到达超时时间后自动关闭订单不能再继续支付
    private String timeout = "30m";

    // 支付宝网关; https://openapi.alipaydev.com/gateway.do
    private  String gatewayUrl = "https://openapi.alipaydev.com/gateway.do";

    public  String pay(PayVo vo) throws AlipayApiException {
    
    

        //AlipayClient alipayClient = new DefaultAlipayClient(AlipayTemplate.gatewayUrl, AlipayTemplate.app_id, AlipayTemplate.merchant_private_key, "json", AlipayTemplate.charset, AlipayTemplate.alipay_public_key, AlipayTemplate.sign_type);
        //1、根据支付宝的配置生成一个支付客户端
        AlipayClient alipayClient = new DefaultAlipayClient(gatewayUrl,
                app_id, merchant_private_key, "json",
                charset, alipay_public_key, sign_type);

        //2、创建一个支付请求 //设置请求参数
        AlipayTradePagePayRequest alipayRequest = new AlipayTradePagePayRequest();
        alipayRequest.setReturnUrl(return_url);
        alipayRequest.setNotifyUrl(notify_url);

        //商户订单号,商户网站订单系统中唯一订单号,必填
        String out_trade_no = vo.getOut_trade_no();
        //付款金额,必填
        String total_amount = vo.getTotal_amount();
        //订单名称,必填
        String subject = vo.getSubject();
        //商品描述,可空
        String body = vo.getBody();

        // timeout_express 订单支付超时时间
        alipayRequest.setBizContent("{\"out_trade_no\":\""+ out_trade_no +"\","
                + "\"total_amount\":\""+ total_amount +"\","
                + "\"subject\":\""+ subject +"\","
                + "\"body\":\""+ body +"\","
                + "\"timeout_express\":\"" + timeout + "\","
                + "\"product_code\":\"FAST_INSTANT_TRADE_PAY\"}");

        String result = alipayClient.pageExecute(alipayRequest).getBody();

        //会收到支付宝的响应,响应的是一个页面,只要浏览器显示这个页面,就会自动来到支付宝的收银台页面
        System.out.println("支付宝的响应:"+result);

        return result;
    }
}

PayVo

package com.atguigu.gulimall.order.vo;

import lombok.Data;

/**
 * 支付使用Vo
 */
@Data
public class PayVo {
    
    
    private String out_trade_no; // 商户订单号 必填
    private String subject; // 订单名称 必填
    private String total_amount;  // 付款金额 必填
    private String body; // 商品描述 可空
}

3. Escribe una empresa para ir a la página de pago.

controlador

/**
 * @author gcq
 * @Create 2021-01-08
 */
@Controller
public class PayWebController {
    
    

    @Autowired
    AlipayTemplate alipayTemplate;

    @Autowired
    OrderService orderService;

    /**
     * 1、跳转到支付页面
     * 2、用户支付成功后,我们要跳转到用户的订单列表页
     * produces 明确方法会返回什么类型,这里返回的是html页面
     * @param orderSn
     * @return
     * @throws AlipayApiException
     */
    @ResponseBody
    @GetMapping(value = "/payOrder",produces = "text/html")
    public String payOrder(@RequestParam("orderSn") String orderSn) throws AlipayApiException {
    
    
//        PayVo payVo = new PayVo();
//        payVo.setBody(); // 商品描述
//        payVo.setSubject(); //订单名称
//        payVo.setOut_trade_no(); // 订单号
//        payVo.setTotal_amount(); //总金额
        PayVo payvo = orderService.payOrder(orderSn);
        // 将返回支付宝的支付页面,需要将这个页面进行显示
        String pay = alipayTemplate.pay(payvo);
        System.out.println(pay);
        return pay;
    }
}

Servicio

 /**
     * 计算商品支付需要的信息
     * @param orderSn
     * @return
     */
    @Override
    public PayVo payOrder(String orderSn) {
    
    
        PayVo payVo = new PayVo();
        OrderEntity orderEntity = this.getOrderByOrderSn(orderSn); // 根据订单号查询到商品
        // 数据库中付款金额小数有4位,但是支付宝只接受2位,所以向上取整两位数
        BigDecimal decimal = orderEntity.getPayAmount().setScale(2, BigDecimal.ROUND_UP);
        payVo.setTotal_amount(decimal.toString());
        // 商户订单号
        payVo.setOut_trade_no(orderSn);
        // 查询出订单项,用来设置商品的描述和商品名称
        List<OrderItemEntity> itemEntities = orderItemService.list(new QueryWrapper<OrderItemEntity>()
                .eq("order_sn", orderSn));
        OrderItemEntity itemEntity = itemEntities.get(0);
        // 订单名称使用商品项的名字
        payVo.setSubject(itemEntity.getSkuName());
        // 商品的描述使用商品项的属性
        payVo.setBody(itemEntity.getSkuAttrsVals());
        return payVo;
    }

Finalmente, se genera la página de pago de Alipay.

3. Vaya a la página de éxito después de que el pago se haya realizado correctamente.

La página saltada se salta de acuerdo con la dirección de devolución de llamada definida por AlipayTemplate

  • notificar_url: devolución de llamada asíncrona para un pago exitoso, devuelve información sobre el pago exitoso, empalmado detrás de la dirección en forma de parámetros
  • return_url: Notificación sincrónica, donde la página salta después de un pago exitoso
   // 服务器[异步通知]页面路径  需http://格式的完整路径,不能加?id=123这类自定义参数,必须外网可以正常访问
    // 支付宝会悄悄的给我们发送一个请求,告诉我们支付成功的信息
    private  String notify_url = "http://eaact93of6.52http.tech/payed/notify";

 // 页面跳转同步通知页面路径 需http://格式的完整路径,不能加?id=123这类自定义参数,必须外网可以正常访问
 //同步通知,支付成功,一般跳转到成功页,这里跳转到我的订单页。
    private  String return_url = "http://member.gulimall.com/memberOrder.html";

1. Procesamiento de interfaz de devolución de llamada asíncrona después de un pago exitoso

Necesita tener un servidor o configurar la penetración de la intranet para recibir este método Modifique la información de configuración en el archivo de configuración nginx.
Inserte la descripción de la imagen aquí

Inserte la descripción de la imagen aquí

Inserte la descripción de la imagen aquí
Alipay vuelve a llamar al controlador de forma asincrónica. Aquí, Alipay vuelve a llamar a esta dirección utilizando la notificación de mejor esfuerzo en la transacción distribuida. Volverá a llamar a esta dirección de vez en cuando, y solo cuando esta dirección le devuelva el éxito es el final .


/**
 * 支付宝成功异步回调
 * @author gcq
 * @Create 2021-01-08
 */
@RestController
public class OrderPayedListenerController {
    
    
    @Autowired
    AlipayTemplate alipayTemplate;

    @Autowired
    OrderService orderService;

    /**
     * 支付宝异步通知回调接口,需要拥有内网穿透或服务器
     * @param request
     * @return
     */
    @PostMapping("/payed/notify")
    public String handleAlipayed(PayAsyncVo vo, HttpServletRequest request) throws UnsupportedEncodingException, AlipayApiException {
    
    
        /**
         * 重要一步验签名
         *  防止别人通过postman给我们发送一个请求,告诉我们请求成功,为了防止这种效果通过验签
         */
        Map<String,String> params = new HashMap<String,String>();
        Map<String,String[]> requestParams = request.getParameterMap();
        for (Iterator<String> iter = requestParams.keySet().iterator(); iter.hasNext();) {
    
    
            String name = (String) iter.next();
            String[] values = (String[]) requestParams.get(name);
            String valueStr = "";
            for (int i = 0; i < values.length; i++) {
    
    
                valueStr = (i == values.length - 1) ? valueStr + values[i]
                        : valueStr + values[i] + ",";
            }
            //乱码解决,这段代码在出现乱码时使用
            valueStr = new String(valueStr.getBytes("ISO-8859-1"), "utf-8");
            params.put(name, valueStr);
        }
        // 支付宝验签 防止恶意提交
        boolean signVerified = AlipaySignature.rsaCheckV1(params
                , alipayTemplate.getAlipay_public_key()
                , alipayTemplate.getCharset()
                , alipayTemplate.getSign_type());
        if (signVerified) {
    
    
            String result = orderService.handlePayResult(vo);
            return result;
        } else {
    
    
            return "error";
        }
    }
}

Servicio

 @Override
    public String handlePayResult(PayAsyncVo vo) {
    
    
        // 保存交易流水信息,每个月和支付宝进行对账
        PaymentInfoEntity infoEntity = new PaymentInfoEntity();
        // 设置核心字段
        infoEntity.setOrderSn(vo.getOut_trade_no());
        infoEntity.setAlipayTradeNo(vo.getTrade_no());
        infoEntity.setPaymentStatus(vo.getTrade_status());
        infoEntity.setCallbackTime(vo.getNotify_time());
        // 保存订单流水
        paymentInfoService.save(infoEntity);
        /**
         * 支付宝交易状态说明
         *      https://opendocs.alipay.com/open/270/105902
         */
        // TRADE_FINISHED 交易结束、不可退款
        // TRADE_SUCCESS 交易支付成功
        if (vo.getTrade_status().equals("TRADE_SUCCESS") || vo.getTrade_status().equals("TRADE_FINISHED")) {
    
    
            String outTradeNo = vo.getOut_trade_no();
            // 支付宝回调成功后,更改订单的支付状态位已支付
            this.baseMapper.updateOrderStatus(outTradeNo,OrderStatusEnum.PAYED.getCode());
        }
        return "success";
    }

Problema de adquisición:
Inserte la descripción de la imagen aquí
Pregunta 1. Puede establecer un período de tiempo de espera y no puede iniciar un pago después de que expire el período de tiempo.
Inserte la descripción de la imagen aquíInserte la descripción de la imagen aquí

Pregunta 2:
Consulte la lógica de la interfaz de cierre de transacción de adquisición unificada o el código de cierre de demostración descargado, y llame manualmente al apagado en la orden de monitoreo de tiempo de espera.

Supongo que te gusta

Origin blog.csdn.net/u014496893/article/details/114292481
Recomendado
Clasificación