支付宝支付功能

支付宝支付功能

Scroll Down

支付宝支付功能

时序图

萨达萨达

在本地Maven仓库安装sdk

  • mvn install:install-file -DgroupId=com.alipay -DartifactId=alipay-sdk -Dversion=3.0.0 -Dpackaging=jar -Dfile=alipay-sdk-java20180104135026.jar

在pom.xml中导入

<dependency>
   <groupId>com.alipay</groupId>
   <artifactId>alipay-sdk</artifactId>
   <version>3.0.0</version>
</dependency>

调用支付宝生成二维码

1. 如何保证消息的幂等性?(第三方交易编号)

2.时序图

0ba3e82ad37ecf8649ee4219cfe9d16b

导入alipay.properties

alipay_url=https://openapi.alipaydev.com/gateway.do

app_id=2016103000778093

app_private_key=MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDf6+I2ykInMNpnsmcQUYrEiOBo5kjQrwpuyY9yhmDV4rgTre6uSa7vzknmo48+aNFQNL9y69cnClKHyq+dB7o8nMXfv4zd8tfepElUqxGw2LH3KFtid1ricc8dZQzodczhWOSDcHeub6ESA1tTdK+4eDGbPjX6yp/Hq2aegt1+gAzuUQQCCg6u8N4T53z4Uc1T5232Kw9jTRRr0+UOuXV11A8P3vBA/ry7TDEgGhnJk/GzV3ln5Y56vPuuUBvAZVaa59zFkUAUy4xKC4YcKcugVqGHwUSkkgCzlhp4kydgkaGwSCcbp/Qw+vw4b5K4aR+aiTKRvAm93DG2O8aX5LFFAgMBAAECggEBAMrIPYZMyHfhYAjEoV0/2yF8q22UDqEdw57s3gFi/FL2DKmVvC8N/2SgNoCt4k0sc1HlUvNp7OAoEvFydnMIynmVqASm3ZUqFKBFuzr36P90XkZrv8Z+PEoRsvT1zCjAdZgl/luiAGByKzW64HvFklTGVHY4cn35/ZS+/iHSdW/WKG+hj6LhgRG+Jsb1c4nmpe2hovdtxvUY7Sb7E7ygKFfqCZXUZR5vGAI7zlaVNmd8Gv18ww6rsDPTACjQcBlIehEa1m0HaYOdizNGeHSea2l/r9/x5ccEfk8JBNuF351OhzG2vPIq40/lj4d4tbTfE1o1kYareG+5VXwIbRgHsQECgYEA/k3ls42FN5XGOFxqd5YpBx6siGN/yY5j1dnw5mPWFiFnmOMsAvDxHjPt9myOVhW8Q8OXXYtvYMX9/yIfwxXyfrSUI1QrrYppcI0GUZNDjh2bbqzmSLB38n0fVsmgMbyibjII3JaCo0sV54ciXPJUzYYxBj+qpDqomMTLsKF9KWECgYEA4WofR+moPHUstywulYgBExJI6ahNQ9XKoq8l1QKSQlW3T0+9tNaR3+oEJ46MLtO1KV7SSHs8B7umohZ/5g9jYNoQgadxvhNWbJXJgBeVLJgI4IFRpZqh1eHAcj6BG1w4IT8XPiDMtmW/rXOKl9y2c5j+npt12/8Or9L36OTqHmUCgYAM/cXCSnSHxmr97hqySUWHS5Xc0dhxX4jSH/QikO8a6lH0iYZyEAUBWf3KHPmYhDu96nwNF1Z1RygWpJOiz7g3qNn4hBBHKU8BpPKxsCg/VlveZ47MH9fA14uGT36Ti+NwZbX2Luo1lVxlG44x2V9jsHtIqm/5O9XpGASf3WAbgQKBgDPIHB15+JLC3B3MAXuKPazy41sBtZYis6UBlTBEofKpHC4VBGBZdjM43/FyVpOfQJubU7Ug0h54pgPQJVtlJ5AlJ+uQ2pkuegkBs8NAJ52R42AndOkVB55JeNsFrsTpP1+rzZwRDtXLs+eVhj3yjtspRzyKO93ozqfnT9npVDrdAoGAN1eITpbqJ4rzay/K4yESfflzaHE+szr7wzeSCta3x0BBqh/rbj92dUxcm+brVufFI2z6gahbRyCmPd5PBHFwu34cNUzQ+0lm9PrzRL+Zz/UOShctX0WfrEQWCn1SVcHblLNxiF8O7gNIqd8oFyybAkpU9sk21rgUz6mgIyj54IM=

alipay_public_key=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAkBLAabYiepY4M1j9ZbGTXt5CuO2YcqjjRZYBNpLYFFw01EQmfIz5cer6tLZ7VK/hvNX0al3xlc4c/YFQrdj3jxz5XSl6qxCbD3HHjbUXzKf7fFbkp9wPixGe+9ZvcR8bHp7FbAUBtMu4jqeNleEF33TP0PIisw3lFUTIrWitsMF99gVPzzryKHJm/8lZNrRi29t1Y1ZaWd9xIlRQiHEtxIusWTvzw3IIm4EKIeP5CAvsnUVOLY/3pmVcAnBHu9KvlmTE5gPs77zHn4iInsGph4qToahpyGsNAIghS83JSNruyND9XBXKw1weUOfx7pKyXSdONTamElql/xGVJ307+wIDAQAB

return_payment_url=http://payment.gmall.com/alipay/callback/return

notify_payment_url=http://60.205.215.91/alipay/callback/notify

return_order_url=http://order.gmall.com/list

AlipayConfig

@Configuration
@PropertySource("classpath:alipay.properties")
public class AlipayConfig {

    @Value("${alipay_url}")
    private String alipay_url;

    @Value("${app_private_key}")
    private String app_private_key;

    @Value("${app_id}")
    private String app_id;


    public final static String format="json";
    public final static String charset="utf-8";
    public final static String sign_type="RSA2";


    public static String return_payment_url;

    public static  String notify_payment_url;

    public static  String return_order_url;

    public static  String alipay_public_key;

    @Value("${alipay_public_key}")
    public   void setAlipay_public_key(String alipay_public_key) {
        AlipayConfig.alipay_public_key = alipay_public_key;
    }

    @Value("${return_payment_url}")
    public   void setReturn_url(String return_payment_url) {
        AlipayConfig.return_payment_url = return_payment_url;
    }

    @Value("${notify_payment_url}")
    public   void setNotify_url(String notify_payment_url) {
        AlipayConfig.notify_payment_url = notify_payment_url;
    }

    @Value("${return_order_url}")
    public   void setReturn_order_url(String return_order_url) {
        AlipayConfig.return_order_url = return_order_url;
    }

    @Bean
    public AlipayClient alipayClient(){
        AlipayClient alipayClient=new DefaultAlipayClient(alipay_url,app_id,app_private_key,format,charset, alipay_public_key,sign_type );
        return alipayClient;
    }

}

生成二维码页面

@RequestMapping("alipay/submit")
    @ResponseBody
    public String alipaysubmit(HttpServletRequest request, HttpServletResponse httpResponse) {

        String orderId = request.getParameter("orderId");
        //通过orderId查询orderInfo
        OrderInfo orderInfo = orderService.getOrderInfo(orderId);

        //保存支付记录
        PaymentInfo paymentInfo = new PaymentInfo();

        //属性赋值
        paymentInfo.setOrderId(orderId);
        paymentInfo.setOutTradeNo(orderInfo.getOutTradeNo());
        paymentInfo.setTotalAmount(orderInfo.getTotalAmount());
        paymentInfo.setSubject("买东西");
        paymentInfo.setPaymentStatus(PaymentStatus.UNPAID);


        paymentService.savePaymentInfo(paymentInfo);

        //生成二维码
        //AlipayClient alipayClient =  new DefaultAlipayClient( "https://openapi.alipay.com/gateway.do" , APP_ID, APP_PRIVATE_KEY, FORMAT, CHARSET, ALIPAY_PUBLIC_KEY, SIGN_TYPE);  //获得初始化的AlipayClient
        AlipayTradePagePayRequest alipayRequest =  new  AlipayTradePagePayRequest(); //创建API对应的request
        alipayRequest.setReturnUrl(AlipayConfig.return_payment_url);
        alipayRequest.setNotifyUrl(AlipayConfig.notify_payment_url); //在公共参数中设置回跳和通知地址
//        alipayRequest.setReturnUrl( "http://domain.com/CallBack/return_url.jsp" );
//        alipayRequest.setNotifyUrl( "http://domain.com/CallBack/notify_url.jsp" ); //在公共参数中设置回跳和通知地址
//        //alipayRequest.putOtherTextParam("app_auth_token", "201611BB8xxxxxxxxxxxxxxxxxxxedcecde6");//如果 ISV 代商家接入电脑网站支付能力,则需要传入 app_auth_token,使用第三方应用授权;自研开发模式请忽略

        //参数
        Map<String,Object> map = new HashMap<>();
        map.put("out_trade_no",paymentInfo.getOutTradeNo());
        map.put("product_code","FAST_INSTANT_TRADE_PAY");
        map.put("total_amount",paymentInfo.getTotalAmount());
        map.put("subject",paymentInfo.getSubject());

        alipayRequest.setBizContent(JSON.toJSONString(map));

//        alipayRequest.setBizContent( "{"  +
//                "    \"out_trade_no\":\"20150320010101001\","  +
//                "    \"product_code\":\"FAST_INSTANT_TRADE_PAY\","  +
//                "    \"total_amount\":88.88,"  +
//                "    \"subject\":\"Iphone6 16G\","  +
//                "    \"body\":\"Iphone6 16G\","  +
//                "    \"passback_params\":\"merchantBizType%3d3C%26merchantBizNo%3d2016010101111\","  +
//                "    \"extend_params\":{"  +
//                "    \"sys_service_provider_id\":\"2088511833207846\""  +
//                "    }" +
//                "  }" ); //填充业务参数
        String form= "" ;
        try  {
            form = alipayClient.pageExecute(alipayRequest).getBody();  //调用SDK生成表单
        }  catch  (AlipayApiException e) {
            e.printStackTrace();
        }
        httpResponse.setContentType( "text/html;charset=UTF-8");
//        httpResponse.getWriter().write(form); //直接将完整的表单html输出到页面
//        httpResponse.getWriter().flush();
//        httpResponse.getWriter().close();
        return form;
    }

支付宝支付后的异步回调

  1. 在通知返回参数列表中,除去 sign、sign_type 两个参数外,凡是通知返回回来的参数皆是待验签的参数。

  2. 将剩下参数进行 url_decode,然后进行字典排序,组成字符串,得到待签名字符串

  3. 将签名参数(sign)使用 base64 解码为字节码串。

  4. 使用 RSA 的验签方法,通过签名字符串、签名参数(经过 base64 解码)及支付宝公钥验证签名。

  5. 需要严格按照如下描述校验通知数据的正确性**:**

    • 商户需要验证该通知数据中的 out_trade_no 是否为商户系统中创建的订单号;

    • 判断 total_amount 是否确实为该订单的实际金额(即商户订单创建时的金额);

    • 校验通知中的 seller_id 是否为 out_trade_no 这笔单据的对应的操作方(有的时候,一个商户可能有多个 seller_id);

    • 验证 app_id 是否为该商户本身。

  6. 上述 1、2、3、4 有任何一个验证不通过,则表明本次通知是异常通知,务必忽略。 在上述验证通过后商户必须根据支付宝不同类型的业务通知,正确的进行不同的业务处理,并且过滤重复的通知结果数据。在支付宝的业务通知中,只有交易通知状态为 TRADE_SUCCESS 或 TRADE_FINISHED 时,支付宝才会认定为买家付款成功。

验签

//异步回调
    @RequestMapping("alipay/callback/notify")
    public String callbacknotify(@RequestParam Map<String, String> paramsMap,HttpServletRequest request) {

        //paramsMap = ... //将异步通知中收到的所有参数都存放到map中
        boolean signVerified = false; //调用SDK验证签名
        try {
            signVerified = AlipaySignature.rsaCheckV1(paramsMap, AlipayConfig.alipay_public_key, AlipayConfig.charset, AlipayConfig.sign_type);
        } catch (AlipayApiException e) {
            e.printStackTrace();
        }

        String out_trade_no = paramsMap.get("out_trade_no");

        if(signVerified){
            // TODO 验签成功后,按照支付结果异步通知中的描述,对支付结果中的业务内容进行二次校验,校验成功后在response中返回success并继续商户自身业务处理,校验失败返回failure

            //对业务的二次校验
            //只有交易通知状态为 TRADE_SUCCESS 或 TRADE_FINISHED 时,支付宝才会认定为买家付款成功。
            //需要得到trade_status
            String trade_status = paramsMap.get("trade_status");
            if ("TRADE_SUCCESS".equals(trade_status)||"TRADE_FINISHED".equals(trade_status)) {

                //根据out_trade_no查询paymentInfo
                PaymentInfo paymentInfo = new PaymentInfo();
                paymentInfo.setOutTradeNo(out_trade_no);
                PaymentInfo paymentInfoHas = paymentService.getPaymentInfo(paymentInfo);

                if (paymentInfoHas.getPaymentStatus()==PaymentStatus.PAID || paymentInfoHas.getPaymentStatus()==PaymentStatus.ClOSED) {
                    return "failure";
                }

                //更新交易记录状态
                PaymentInfo paymentInfoUPD = new PaymentInfo();
                paymentInfoUPD.setPaymentStatus(PaymentStatus.PAID);
                paymentInfoUPD.setCallbackTime(new Date());
                paymentService.updatePaymentInfo(out_trade_no,paymentInfoUPD);
                return "success";
            }

        }else{
            // TODO 验签失败则记录异常日志,并在response中返回failure.

            return "failure";
        }
        return "failure";

    }

退款接口

Controller

 /**
     * 根据oredrId退款
     */
    @RequestMapping("refund")
    @ResponseBody
    public String refund(String orderId) {
        Boolean result = paymentService.refund(orderId);
        return ""+result;
    }

service.impl

 @Override
    public Boolean refund(String orderId) {


        //通过orderId获取数据
        OrderInfo orderInfo = orderService.getOrderInfo(orderId);
        String outTradeNo = orderInfo.getOutTradeNo();

        //AlipayClient alipayClient = new DefaultAlipayClient("https://openapi.alipay.com/gateway.do","app_id","your private_key","json","GBK","alipay_public_key");
        AlipayTradeRefundRequest request = new AlipayTradeRefundRequest();

        Map<String,Object> map = new HashMap<>();
        map.put("out_trade_no",outTradeNo);
        map.put("refund_amount",orderInfo.getTotalAmount());
        map.put("refund_reason","不买了");
        request.setBizContent(JSON.toJSONString(map));

//        request.setBizContent("{" +
//                "    \"out_trade_no\":\"20150320010101001\"," +
//                "    \"trade_no\":\"2014112611001004680073956707\"," +
//                "    \"refund_amount\":200.12," +
//                "    \"refund_reason\":\"正常退款\"," +
//                "    \"out_request_no\":\"HZ01RF001\"," +
//                "    \"operator_id\":\"OP001\"," +
//                "    \"store_id\":\"NJ_S_001\"," +
//                "    \"terminal_id\":\"NJ_T_001\"" +
//                "  }");
        AlipayTradeRefundResponse response = null;
        try {
            response = alipayClient.execute(request);
        } catch (AlipayApiException e) {
            e.printStackTrace();
        }
        if(response.isSuccess()){
            //更新状态
            System.out.println("调用成功");
            return true;
        } else {
            System.out.println("调用失败");
            return false;
        }
    }