支付宝支付接口的调用(转)

支付宝支付接口的调用

2018年04月07日 17:54:51 Forward_duyu 阅读数:15167

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/zoroduyu/article/details/79825880

应公司业务要求,需要调用支付宝的支付接口进行支付的操作,于是将整个调用过程用博客形式记录下来,以供以后使用。

本次调用支付宝采用的是电脑支付,官方文档页面如下:

电脑端调用支付宝,流程很简单,在页面有一个立即支付的按钮,点击进入商户的后台,商户的后台将支付所需的参数传给支付宝,支付宝返回给商户一个字符串形式的form表单,商户将这个form表单传给前台,前台对表单进行提交即可跳转到支付包页面,用户在支付宝页面支付完成后,支付宝会先调取我们的通知接口进行支付结果通知。然后跳转到我们传给支付包的回调页面。这就是电脑端调用支付宝的整个流程。

要调用支付宝的接口,首先需要下载支付宝的sdk。这里给出官方的下载地址: 
支付宝sdk下载地址。下载下来的是一个zip包,里面文件如下:

这四个jar包文件如下: 
alipay-sdk-java-3.0.0.jar┈┈┈┈┈┈┈支付宝SDK编译文件jar 
alipay-sdk-java-3.0.0-source.jar┈┈┈ 支付宝SDK源码文件jar 
commons-logging-1.1.1.jar┈┈┈┈┈┈SDK依赖的日志jar 
commons-logging-1.1.1-sources.jar┈┈SDK依赖的日志源码jar 
项目中需要引入的是alipay-sdk-java-3.0.0.jar和commons-logging-1.1.1.jar。对于commons-logging-1.1.1.jar,可以直接在pom文件中添加依赖:

<!-- https://mvnrepository.com/artifact/commons-logging/commons-logging -->
<dependency>
    <groupId>commons-logging</groupId>
    <artifactId>commons-logging</artifactId>
    <version>1.1.1</version>
</dependency>

对于alipay-sdk-java-3.0.0.jar,目前maven仓库没有该依赖,只能手动添加。首先将alipay-sdk-java-3.0.0.jar放入D盘的根目录下,然后运行mvn命令:

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

此命令会把支付宝的jar包打包到maven本地仓库下,然后在pom文件中引用:

<dependency>
          <groupId>com.alipay</groupId>
          <artifactId>sdk-java</artifactId>
          <version>3.0.0</version>
    </dependency>
  • 1
  • 2
  • 3
  • 4
  • 5

即可完成支付宝jar包的导入。

前面准备工作已经做好,现在来看看代码,我把对支付宝的调用都封装到了一个工具类中:

package com.avie.ltd.utils;

import java.util.HashMap;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;

import com.alipay.api.AlipayApiException;
import com.alipay.api.AlipayClient;
import com.alipay.api.DefaultAlipayClient;
import com.alipay.api.internal.util.AlipaySignature;
import com.alipay.api.request.AlipayTradePagePayRequest;
import com.alipay.api.request.AlipayTradeRefundRequest;
import com.avie.ltd.config.AlipayConfig;

public class PayUtil {

    /**
     *
     * @param outTradeNo  商户订单号,商户网站订单系统中唯一订单号,必填   对应缴费记录的orderNo
     * @param totalAmount  付款金额,必填
     * @param subject 主题
     * @param body 商品描述,可空
     * @return
     */
    public static String alipay(String outTradeNo,String totalAmount,String subject,String body) {
        //获得初始化的AlipayClient
                AlipayClient alipayClient = new DefaultAlipayClient(AlipayConfig.gatewayUrl, AlipayConfig.app_id, AlipayConfig.merchant_private_key, "json", AlipayConfig.charset, AlipayConfig.alipay_public_key, AlipayConfig.sign_type);

                //设置请求参数
                AlipayTradePagePayRequest alipayRequest = new AlipayTradePagePayRequest();
                alipayRequest.setReturnUrl(AlipayConfig.return_url);
                alipayRequest.setNotifyUrl(AlipayConfig.notify_url);
                try {
                alipayRequest.setBizContent("{\"out_trade_no\":\""+ outTradeNo +"\","
                        + "\"total_amount\":\""+ totalAmount +"\","
                        + "\"subject\":\""+ subject +"\","
                        + "\"timeout_express\":\""+ Constants.TIMEOUT_EXPRESS +"\","
                        + "\"body\":\""+ body +"\","
                        + "\"qr_pay_mode\":\""+ Constants.QR_PAY_MODE +"\","
                        + "\"product_code\":\"FAST_INSTANT_TRADE_PAY\"}");                                                                                                                                                               

                //请求
                String result;

                result = alipayClient.pageExecute(alipayRequest).getBody();
                System.out.println("*********************\n返回结果为:"+result);
                return result;
                } catch (Exception e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                    return null;
                }
    }

    /**
     * 支付宝退款接口
     * @param outTradeNo
     * @param tradeNo
     * @param refundAmount
     * @param refundReason
     * @param out_request_no  标识一次退款请求,同一笔交易多次退款需要保证唯一,如需部分退款,则此参数必传
     * @return
     */
    public static String aliRefund(String outTradeNo,String tradeNo,String refundAmount,String refundReason,String out_request_no) {
        //获得初始化的AlipayClient
                AlipayClient alipayClient = new DefaultAlipayClient(AlipayConfig.gatewayUrl, AlipayConfig.app_id, AlipayConfig.merchant_private_key, "json", AlipayConfig.charset, AlipayConfig.alipay_public_key, AlipayConfig.sign_type);

                //设置请求参数
                AlipayTradeRefundRequest alipayRequest = new AlipayTradeRefundRequest();
                alipayRequest.setReturnUrl(AlipayConfig.return_url);
                alipayRequest.setNotifyUrl(AlipayConfig.notify_url);
                try {
                    alipayRequest.setBizContent("{\"out_trade_no\":\""+ outTradeNo +"\","
                            + "\"trade_no\":\""+ tradeNo +"\","
                            + "\"refund_amount\":\""+ refundAmount +"\","
                            + "\"refund_reason\":\""+ refundReason +"\","
                            + "\"out_request_no\":\""+ out_request_no +"\"}");                                                                                                                                                               

                //请求
                String result;

                //请求
                result = alipayClient.execute(alipayRequest).getBody();
                System.out.println("*********************\n返回结果为:"+result);
                return result;
                } catch (Exception e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                    return null;
                }
    }

    /**
     * 支付宝的验签方法
     * @param req
     * @return
     */
    public static boolean checkSign(HttpServletRequest req) {
        Map<String, String[]> requestMap = req.getParameterMap();
        Map<String, String> paramsMap = new HashMap<>();
        requestMap.forEach((key, values) -> {
              String strs = "";
              for(String value : values) {
              strs = strs + value;
              }
              System.out.println(("key值为"+key+"value为:"+strs));
              paramsMap.put(key, strs);
            });

        //调用SDK验证签名
        try {
            return  AlipaySignature.rsaCheckV1(paramsMap, AlipayConfig.alipay_public_key, AlipayConfig.charset, AlipayConfig.sign_type);
        } catch (AlipayApiException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
            System.out.println("*********************验签失败********************");
            return false;
        }
    }
}

这个工具类一共有三个静态方法。 
alipay:支付宝的下单接口 
aliRefund:支付宝的退款方法 
checkSign:支付宝的验签方法

先来讲alipay这个方法,当我们需要下单的时候,需要在业务逻辑代码中调用该工具类的该方法。该方法需要传入的参数如下:

outTradeNo: 商户订单号,商户网站订单系统中唯一订单号,必填 。需要保证商户端唯一。 
totalAmount :付款金额,必填 
subject:主题 
body:商品描述,可空

都是一些商品属性的基本参数,一般都是根据我们具体的业务逻辑去设置。进入方法,第一句话:

AlipayClient alipayClient = new DefaultAlipayClient(AlipayConfig.gatewayUrl, AlipayConfig.app_id, AlipayConfig.merchant_private_key, "json", AlipayConfig.charset, AlipayConfig.alipay_public_key, AlipayConfig.sign_type);
  • 1

这句话主要是初始化一个DefaultAlipayClient,这个类的初始化构造器需要传很多参数,从左往右依次为:支付宝的网关,商户的appid,商户的私钥,传参的格式,传参的字符集,商户的公钥,商户的签名类型。这里都把这些参数封装进了AlipayConfig这个类里面,来看看AlipayConfig这个类:

package com.avie.ltd.config;

import java.io.FileWriter;
import java.io.IOException;

/* *
 *类名:AlipayConfig
 *功能:基础配置类
 *详细:设置帐户有关信息及返回路径
 *修改日期:2017-04-05
 *说明:
 *以下代码只是为了方便商户测试而提供的样例代码,商户可以根据自己网站的需要,按照技术文档编写,并非一定要使用该代码。
 *该代码仅供学习和研究支付宝接口使用,只是提供一个参考。
 */

public class AlipayConfig {

//↓↓↓↓↓↓↓↓↓↓请在这里配置您的基本信息↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓

    // 应用ID,您的APPID,收款账号既是您的APPID对应支付宝账号
    public static String app_id = "你的APPID";

    // 商户私钥,您的PKCS8格式RSA2私钥
    public static String merchant_private_key = "你的商户私钥";

    // 支付宝公钥,查看地址:https://openhome.alipay.com/platform/keyManage.htm 对应APPID下的支付宝公钥。
    public static String alipay_public_key = "你的支付宝公钥";

    // 服务器异步通知页面路径  需http://格式的完整路径,不能加?id=123这类自定义参数,必须外网可以正常访问
    public static String notify_url = "你的异步通知页面";

    // 页面跳转同步通知页面路径 需http://格式的完整路径,不能加?id=123这类自定义参数,必须外网可以正常访问
    public static String return_url = "你的回调页面";

    // 签名方式
    public static String sign_type = "RSA2";

    // 字符编码格式
    public static String charset = "utf-8";

    // 支付宝网关
    public static String gatewayUrl = "https://openapi.alipay.com/gateway.do";

    // 支付宝网关
    public static String log_path = "C:\\";

//↑↑↑↑↑↑↑↑↑↑请在这里配置您的基本信息↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑

    /**
     * 写日志,方便测试(看网站需求,也可以改成把记录存入数据库)
     * @param sWord 要写入日志里的文本内容
     */
    public static void logResult(String sWord) {
        FileWriter writer = null;
        try {
            writer = new FileWriter(log_path + "alipay_log_" + System.currentTimeMillis()+".txt");
            writer.write(sWord);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (writer != null) {
                try {
                    writer.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

这个类其实很简单,就是存储了一些支付所需的公钥啊,私钥啊等参数,方便同意管理和使用。代码往下走AlipayTradePagePayRequest alipayRequest = new AlipayTradePagePayRequest();就是初始化一个阿里封装的request,后面几句就是设置这个request要传入的参数,把回调函数地址,外部订单好,金额都设置到request里面。然后执行alipayClient.pageExecute(alipayRequest).getBody();这个方法,即可向支付宝发起一个下单请求,支付宝返回给我们的是一个字符串,这个字符串实际上是一个form表单。现在,我们写个简单的方法来测试以下,代码如下:

package com.avie.itd;

import com.avie.ltd.utils.PayUtil;

public class Test {

    public static void main(String[] args) {

        String str = PayUtil.alipay("2313131", "0.01", "hehe", "haha");
        System.out.println(str);
    }

}

测试方式非常简单,不需要弄什么运行环境或者一大堆依赖,就写个main方法,调用我的PayUtil的alipay方法,传入自己随便编的参数,右键运行即可。如果基本的参数配置都没有错,那么你的控制台会打印出如下结果:

看到了吗,返回的结果实际上是一个表单加上一个javascript脚本,脚本的目的在于提交表单。所以在实际开发中,你只需要拿到这个返回结果,把结果传给前端,前端把用jquery把这段代码放入一个div即可。表单自动提交,然后你就会跳转到支付宝的支付页面了。

那么到这里就完了吗?肯定还没有,支付完成后,支付宝会将支付结果推送到我们自己的业务系统中,因此我们需要为支付宝写个异步通知的接口。先来看代码:

package com.avie.ltd.controller;

import java.io.IOException;
import java.util.SortedMap;
import java.util.TreeMap;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

import com.avie.ltd.entity.AliReturnPayBean;
import com.avie.ltd.service.TbPaymentRecordsService;
import com.avie.ltd.utils.JaxbUtil;
import com.avie.ltd.utils.PayUtil;
import com.avie.ltd.utils.wxUtil.UnifiedOrderRespose;
import com.thoughtworks.xstream.XStream;

import net.sf.json.JSONObject;

@Controller
@RequestMapping(value = "/returnPay")
public class ReturnController {

    private static Logger logger = LoggerFactory.getLogger(ReturnController.class);
    @Autowired
    private TbPaymentRecordsService tbPaymentRecordsService;

    /**
     * 支付宝回调的接口
     *
     * @param uuid
     * @return
     * @throws IOException
     */
    @RequestMapping(value = "/aliReturnPay", method = RequestMethod.POST)
    public void returnPay(HttpServletResponse response, AliReturnPayBean returnPay, HttpServletRequest req)
            throws IOException {
        response.setContentType("type=text/html;charset=UTF-8");
        logger.info("****************************************支付宝的的回调函数被调用******************************");
        if (!PayUtil.checkSign(req)) {
            logger.info("****************************************验签失败*******************************************");
            response.getWriter().write("failture");
            return;
        }
        if (returnPay == null) {
            logger.info("支付宝的returnPay返回为空");
            response.getWriter().write("success");
            return;
        }
        logger.info("支付宝的returnPay" + returnPay.toString());
        if (returnPay.getTrade_status().equals("TRADE_SUCCESS")) {
            logger.info("支付宝的支付状态为TRADE_SUCCESS");
            tbPaymentRecordsService.aliPaySuccess(returnPay);
        }
        response.getWriter().write("success");
    }
}

首先需要注意的是,这个类只能被@Controller注释修饰,不能用@RestController,因为@RestController会将该类中所有方法的返回值自动转为json格式,而此处支付宝的返回值不需要json格式。这里因为线上环境不能debug,我打印了大量的日志以监控该方法的运行情况。在支付的回调方法中,首先要做的就是验证签名,所以刚进入方法首先调用了PayUtil.checkSign(req)这个验证签名的方法,我们来看看这个checkSign(req)里面是怎么写的:

/**
     * 支付宝的验签方法
     * @param req
     * @return
     */
    public static boolean checkSign(HttpServletRequest req) {
        Map<String, String[]> requestMap = req.getParameterMap();
        Map<String, String> paramsMap = new HashMap<>();
        requestMap.forEach((key, values) -> {
              String strs = "";
              for(String value : values) {
              strs = strs + value;
              }
              System.out.println(("key值为"+key+"value为:"+strs));
              paramsMap.put(key, strs);
            });

        //调用SDK验证签名
        try {
            return  AlipaySignature.rsaCheckV1(paramsMap, AlipayConfig.alipay_public_key, AlipayConfig.charset, AlipayConfig.sign_type);
        } catch (AlipayApiException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
            System.out.println("*********************验签失败********************");
            return false;
        }
    }

首先我们先看最下面: AlipaySignature.rsaCheckV1(paramsMap, AlipayConfig.alipay_public_key, AlipayConfig.charset, AlipayConfig.sign_type);这句话是调用支付宝给我们封装的验证签名的方法,右键指上去,会发现该方法的描述是这个样子的:

boolean com.alipay.api.internal.util.AlipaySignature.rsaCheckV1(Map<String, String> params, String publicKey, String charset, String signType) throws AlipayApiException
  • 1

看到Map

package com.avie.ltd.entity;

import java.io.Serializable;

public class AliReturnPayBean  implements Serializable{

    /**
     *
     */
    private static final long serialVersionUID = 1L;

    /**
     * 开发者的app_id
     */
    private String app_id;

    /**
     * 商户订单号
     */
    private String out_trade_no;

    /**
     * 签名
     */
    private String sign;

    /**
     * 交易状态
     */
    private String trade_status;

    /**
     *  支付宝交易号
     */
    private String trade_no;

    /**
     * 交易的金额
     */
    private String total_amount;

    public String getTotal_amount() {
        return total_amount;
    }

    public void setTotal_amount(String total_amount) {
        this.total_amount = total_amount;
    }

    public String getApp_id() {
        return app_id;
    }

    public void setApp_id(String app_id) {
        this.app_id = app_id;
    }

    public String getOut_trade_no() {
        return out_trade_no;
    }

    public void setOut_trade_no(String out_trade_no) {
        this.out_trade_no = out_trade_no;
    }

    public String getSign() {
        return sign;
    }

    public void setSign(String sign) {
        this.sign = sign;
    }

    public String getTrade_status() {
        return trade_status;
    }

    public void setTrade_status(String trade_status) {
        this.trade_status = trade_status;
    }

    public String getTrade_no() {
        return trade_no;
    }

    public void setTrade_no(String trade_no) {
        this.trade_no = trade_no;
    }

    @Override
    public String toString() {
        return "AliReturnPayBean [app_id=" + app_id + ", out_trade_no=" + out_trade_no + ", sign=" + sign
                + ", trade_status=" + trade_status + ", trade_no=" + trade_no + "]";
    }

}

将返回参数封装在实体bean中,这样springmvc会利用反射机制自动将相关参数映射进实体bean里面,省去了我们自己再去解析参数的麻烦。后面那句returnPay.getTrade_status().equals(“TRADE_SUCCESS”)是得到支付宝中trade_status这个参数,在支付宝的接口文档中,若这个参数等于TRADE_SUCCESS,则说明支付是成功的,然后我就会调用tbPaymentRecordsService.aliPaySuccess(returnPay);。这句代码就是具体的业务逻辑代码了,对成功返回的参数进行处理,由于每个人业务逻辑都不一样,我就不再赘述了。你们只需将这局代码替换成你们的业务逻辑代码即可。

这样,支付下单的流程就走通了。当然我还有一个退款的接口没讲。这个接口其实和下单接口大同小异,我也写了相关注释。就请各位自行阅读,我就不做解释了。

那这次支付宝的调用就先写到这里,下次我还会写一些关于微信的支付接口,喜欢的小伙伴可以点波关注哦。

支付宝支付接口的调用

2018年04月07日 17:54:51 Forward_duyu 阅读数:15167

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/zoroduyu/article/details/79825880

应公司业务要求,需要调用支付宝的支付接口进行支付的操作,于是将整个调用过程用博客形式记录下来,以供以后使用。

本次调用支付宝采用的是电脑支付,官方文档页面如下:

电脑端调用支付宝,流程很简单,在页面有一个立即支付的按钮,点击进入商户的后台,商户的后台将支付所需的参数传给支付宝,支付宝返回给商户一个字符串形式的form表单,商户将这个form表单传给前台,前台对表单进行提交即可跳转到支付包页面,用户在支付宝页面支付完成后,支付宝会先调取我们的通知接口进行支付结果通知。然后跳转到我们传给支付包的回调页面。这就是电脑端调用支付宝的整个流程。

要调用支付宝的接口,首先需要下载支付宝的sdk。这里给出官方的下载地址: 
支付宝sdk下载地址。下载下来的是一个zip包,里面文件如下:

这四个jar包文件如下: 
alipay-sdk-java-3.0.0.jar┈┈┈┈┈┈┈支付宝SDK编译文件jar 
alipay-sdk-java-3.0.0-source.jar┈┈┈ 支付宝SDK源码文件jar 
commons-logging-1.1.1.jar┈┈┈┈┈┈SDK依赖的日志jar 
commons-logging-1.1.1-sources.jar┈┈SDK依赖的日志源码jar 
项目中需要引入的是alipay-sdk-java-3.0.0.jar和commons-logging-1.1.1.jar。对于commons-logging-1.1.1.jar,可以直接在pom文件中添加依赖:

<!-- https://mvnrepository.com/artifact/commons-logging/commons-logging -->
<dependency>
    <groupId>commons-logging</groupId>
    <artifactId>commons-logging</artifactId>
    <version>1.1.1</version>
</dependency>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

对于alipay-sdk-java-3.0.0.jar,目前maven仓库没有该依赖,只能手动添加。首先将alipay-sdk-java-3.0.0.jar放入D盘的根目录下,然后运行mvn命令:

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

此命令会把支付宝的jar包打包到maven本地仓库下,然后在pom文件中引用:

<dependency>
          <groupId>com.alipay</groupId>
          <artifactId>sdk-java</artifactId>
          <version>3.0.0</version>
    </dependency>
  • 1
  • 2
  • 3
  • 4
  • 5

即可完成支付宝jar包的导入。

前面准备工作已经做好,现在来看看代码,我把对支付宝的调用都封装到了一个工具类中:

package com.avie.ltd.utils;

import java.util.HashMap;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;

import com.alipay.api.AlipayApiException;
import com.alipay.api.AlipayClient;
import com.alipay.api.DefaultAlipayClient;
import com.alipay.api.internal.util.AlipaySignature;
import com.alipay.api.request.AlipayTradePagePayRequest;
import com.alipay.api.request.AlipayTradeRefundRequest;
import com.avie.ltd.config.AlipayConfig;

public class PayUtil {

    /**
     *
     * @param outTradeNo  商户订单号,商户网站订单系统中唯一订单号,必填   对应缴费记录的orderNo
     * @param totalAmount  付款金额,必填
     * @param subject 主题
     * @param body 商品描述,可空
     * @return
     */
    public static String alipay(String outTradeNo,String totalAmount,String subject,String body) {
        //获得初始化的AlipayClient
                AlipayClient alipayClient = new DefaultAlipayClient(AlipayConfig.gatewayUrl, AlipayConfig.app_id, AlipayConfig.merchant_private_key, "json", AlipayConfig.charset, AlipayConfig.alipay_public_key, AlipayConfig.sign_type);

                //设置请求参数
                AlipayTradePagePayRequest alipayRequest = new AlipayTradePagePayRequest();
                alipayRequest.setReturnUrl(AlipayConfig.return_url);
                alipayRequest.setNotifyUrl(AlipayConfig.notify_url);
                try {
                alipayRequest.setBizContent("{\"out_trade_no\":\""+ outTradeNo +"\","
                        + "\"total_amount\":\""+ totalAmount +"\","
                        + "\"subject\":\""+ subject +"\","
                        + "\"timeout_express\":\""+ Constants.TIMEOUT_EXPRESS +"\","
                        + "\"body\":\""+ body +"\","
                        + "\"qr_pay_mode\":\""+ Constants.QR_PAY_MODE +"\","
                        + "\"product_code\":\"FAST_INSTANT_TRADE_PAY\"}");                                                                                                                                                               

                //请求
                String result;

                result = alipayClient.pageExecute(alipayRequest).getBody();
                System.out.println("*********************\n返回结果为:"+result);
                return result;
                } catch (Exception e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                    return null;
                }
    }

    /**
     * 支付宝退款接口
     * @param outTradeNo
     * @param tradeNo
     * @param refundAmount
     * @param refundReason
     * @param out_request_no  标识一次退款请求,同一笔交易多次退款需要保证唯一,如需部分退款,则此参数必传
     * @return
     */
    public static String aliRefund(String outTradeNo,String tradeNo,String refundAmount,String refundReason,String out_request_no) {
        //获得初始化的AlipayClient
                AlipayClient alipayClient = new DefaultAlipayClient(AlipayConfig.gatewayUrl, AlipayConfig.app_id, AlipayConfig.merchant_private_key, "json", AlipayConfig.charset, AlipayConfig.alipay_public_key, AlipayConfig.sign_type);

                //设置请求参数
                AlipayTradeRefundRequest alipayRequest = new AlipayTradeRefundRequest();
                alipayRequest.setReturnUrl(AlipayConfig.return_url);
                alipayRequest.setNotifyUrl(AlipayConfig.notify_url);
                try {
                    alipayRequest.setBizContent("{\"out_trade_no\":\""+ outTradeNo +"\","
                            + "\"trade_no\":\""+ tradeNo +"\","
                            + "\"refund_amount\":\""+ refundAmount +"\","
                            + "\"refund_reason\":\""+ refundReason +"\","
                            + "\"out_request_no\":\""+ out_request_no +"\"}");                                                                                                                                                               

                //请求
                String result;

                //请求
                result = alipayClient.execute(alipayRequest).getBody();
                System.out.println("*********************\n返回结果为:"+result);
                return result;
                } catch (Exception e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                    return null;
                }
    }

    /**
     * 支付宝的验签方法
     * @param req
     * @return
     */
    public static boolean checkSign(HttpServletRequest req) {
        Map<String, String[]> requestMap = req.getParameterMap();
        Map<String, String> paramsMap = new HashMap<>();
        requestMap.forEach((key, values) -> {
              String strs = "";
              for(String value : values) {
              strs = strs + value;
              }
              System.out.println(("key值为"+key+"value为:"+strs));
              paramsMap.put(key, strs);
            });

        //调用SDK验证签名
        try {
            return  AlipaySignature.rsaCheckV1(paramsMap, AlipayConfig.alipay_public_key, AlipayConfig.charset, AlipayConfig.sign_type);
        } catch (AlipayApiException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
            System.out.println("*********************验签失败********************");
            return false;
        }
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122

这个工具类一共有三个静态方法。 
alipay:支付宝的下单接口 
aliRefund:支付宝的退款方法 
checkSign:支付宝的验签方法

先来讲alipay这个方法,当我们需要下单的时候,需要在业务逻辑代码中调用该工具类的该方法。该方法需要传入的参数如下:

outTradeNo: 商户订单号,商户网站订单系统中唯一订单号,必填 。需要保证商户端唯一。 
totalAmount :付款金额,必填 
subject:主题 
body:商品描述,可空

都是一些商品属性的基本参数,一般都是根据我们具体的业务逻辑去设置。进入方法,第一句话:

AlipayClient alipayClient = new DefaultAlipayClient(AlipayConfig.gatewayUrl, AlipayConfig.app_id, AlipayConfig.merchant_private_key, "json", AlipayConfig.charset, AlipayConfig.alipay_public_key, AlipayConfig.sign_type);
  • 1

这句话主要是初始化一个DefaultAlipayClient,这个类的初始化构造器需要传很多参数,从左往右依次为:支付宝的网关,商户的appid,商户的私钥,传参的格式,传参的字符集,商户的公钥,商户的签名类型。这里都把这些参数封装进了AlipayConfig这个类里面,来看看AlipayConfig这个类:

package com.avie.ltd.config;

import java.io.FileWriter;
import java.io.IOException;

/* *
 *类名:AlipayConfig
 *功能:基础配置类
 *详细:设置帐户有关信息及返回路径
 *修改日期:2017-04-05
 *说明:
 *以下代码只是为了方便商户测试而提供的样例代码,商户可以根据自己网站的需要,按照技术文档编写,并非一定要使用该代码。
 *该代码仅供学习和研究支付宝接口使用,只是提供一个参考。
 */

public class AlipayConfig {

//↓↓↓↓↓↓↓↓↓↓请在这里配置您的基本信息↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓

    // 应用ID,您的APPID,收款账号既是您的APPID对应支付宝账号
    public static String app_id = "你的APPID";

    // 商户私钥,您的PKCS8格式RSA2私钥
    public static String merchant_private_key = "你的商户私钥";

    // 支付宝公钥,查看地址:https://openhome.alipay.com/platform/keyManage.htm 对应APPID下的支付宝公钥。
    public static String alipay_public_key = "你的支付宝公钥";

    // 服务器异步通知页面路径  需http://格式的完整路径,不能加?id=123这类自定义参数,必须外网可以正常访问
    public static String notify_url = "你的异步通知页面";

    // 页面跳转同步通知页面路径 需http://格式的完整路径,不能加?id=123这类自定义参数,必须外网可以正常访问
    public static String return_url = "你的回调页面";

    // 签名方式
    public static String sign_type = "RSA2";

    // 字符编码格式
    public static String charset = "utf-8";

    // 支付宝网关
    public static String gatewayUrl = "https://openapi.alipay.com/gateway.do";

    // 支付宝网关
    public static String log_path = "C:\\";

//↑↑↑↑↑↑↑↑↑↑请在这里配置您的基本信息↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑

    /**
     * 写日志,方便测试(看网站需求,也可以改成把记录存入数据库)
     * @param sWord 要写入日志里的文本内容
     */
    public static void logResult(String sWord) {
        FileWriter writer = null;
        try {
            writer = new FileWriter(log_path + "alipay_log_" + System.currentTimeMillis()+".txt");
            writer.write(sWord);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (writer != null) {
                try {
                    writer.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71

这个类其实很简单,就是存储了一些支付所需的公钥啊,私钥啊等参数,方便同意管理和使用。代码往下走AlipayTradePagePayRequest alipayRequest = new AlipayTradePagePayRequest();就是初始化一个阿里封装的request,后面几句就是设置这个request要传入的参数,把回调函数地址,外部订单好,金额都设置到request里面。然后执行alipayClient.pageExecute(alipayRequest).getBody();这个方法,即可向支付宝发起一个下单请求,支付宝返回给我们的是一个字符串,这个字符串实际上是一个form表单。现在,我们写个简单的方法来测试以下,代码如下:

package com.avie.itd;

import com.avie.ltd.utils.PayUtil;

public class Test {

    public static void main(String[] args) {

        String str = PayUtil.alipay("2313131", "0.01", "hehe", "haha");
        System.out.println(str);
    }

}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

测试方式非常简单,不需要弄什么运行环境或者一大堆依赖,就写个main方法,调用我的PayUtil的alipay方法,传入自己随便编的参数,右键运行即可。如果基本的参数配置都没有错,那么你的控制台会打印出如下结果:

看到了吗,返回的结果实际上是一个表单加上一个javascript脚本,脚本的目的在于提交表单。所以在实际开发中,你只需要拿到这个返回结果,把结果传给前端,前端把用jquery把这段代码放入一个div即可。表单自动提交,然后你就会跳转到支付宝的支付页面了。

那么到这里就完了吗?肯定还没有,支付完成后,支付宝会将支付结果推送到我们自己的业务系统中,因此我们需要为支付宝写个异步通知的接口。先来看代码:

package com.avie.ltd.controller;

import java.io.IOException;
import java.util.SortedMap;
import java.util.TreeMap;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

import com.avie.ltd.entity.AliReturnPayBean;
import com.avie.ltd.service.TbPaymentRecordsService;
import com.avie.ltd.utils.JaxbUtil;
import com.avie.ltd.utils.PayUtil;
import com.avie.ltd.utils.wxUtil.UnifiedOrderRespose;
import com.thoughtworks.xstream.XStream;

import net.sf.json.JSONObject;

@Controller
@RequestMapping(value = "/returnPay")
public class ReturnController {

    private static Logger logger = LoggerFactory.getLogger(ReturnController.class);
    @Autowired
    private TbPaymentRecordsService tbPaymentRecordsService;

    /**
     * 支付宝回调的接口
     *
     * @param uuid
     * @return
     * @throws IOException
     */
    @RequestMapping(value = "/aliReturnPay", method = RequestMethod.POST)
    public void returnPay(HttpServletResponse response, AliReturnPayBean returnPay, HttpServletRequest req)
            throws IOException {
        response.setContentType("type=text/html;charset=UTF-8");
        logger.info("****************************************支付宝的的回调函数被调用******************************");
        if (!PayUtil.checkSign(req)) {
            logger.info("****************************************验签失败*******************************************");
            response.getWriter().write("failture");
            return;
        }
        if (returnPay == null) {
            logger.info("支付宝的returnPay返回为空");
            response.getWriter().write("success");
            return;
        }
        logger.info("支付宝的returnPay" + returnPay.toString());
        if (returnPay.getTrade_status().equals("TRADE_SUCCESS")) {
            logger.info("支付宝的支付状态为TRADE_SUCCESS");
            tbPaymentRecordsService.aliPaySuccess(returnPay);
        }
        response.getWriter().write("success");
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64

首先需要注意的是,这个类只能被@Controller注释修饰,不能用@RestController,因为@RestController会将该类中所有方法的返回值自动转为json格式,而此处支付宝的返回值不需要json格式。这里因为线上环境不能debug,我打印了大量的日志以监控该方法的运行情况。在支付的回调方法中,首先要做的就是验证签名,所以刚进入方法首先调用了PayUtil.checkSign(req)这个验证签名的方法,我们来看看这个checkSign(req)里面是怎么写的:

/**
     * 支付宝的验签方法
     * @param req
     * @return
     */
    public static boolean checkSign(HttpServletRequest req) {
        Map<String, String[]> requestMap = req.getParameterMap();
        Map<String, String> paramsMap = new HashMap<>();
        requestMap.forEach((key, values) -> {
              String strs = "";
              for(String value : values) {
              strs = strs + value;
              }
              System.out.println(("key值为"+key+"value为:"+strs));
              paramsMap.put(key, strs);
            });

        //调用SDK验证签名
        try {
            return  AlipaySignature.rsaCheckV1(paramsMap, AlipayConfig.alipay_public_key, AlipayConfig.charset, AlipayConfig.sign_type);
        } catch (AlipayApiException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
            System.out.println("*********************验签失败********************");
            return false;
        }
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27

首先我们先看最下面: AlipaySignature.rsaCheckV1(paramsMap, AlipayConfig.alipay_public_key, AlipayConfig.charset, AlipayConfig.sign_type);这句话是调用支付宝给我们封装的验证签名的方法,右键指上去,会发现该方法的描述是这个样子的:

boolean com.alipay.api.internal.util.AlipaySignature.rsaCheckV1(Map<String, String> params, String publicKey, String charset, String signType) throws AlipayApiException
  • 1

看到Map

package com.avie.ltd.entity;

import java.io.Serializable;

public class AliReturnPayBean  implements Serializable{

    /**
     *
     */
    private static final long serialVersionUID = 1L;

    /**
     * 开发者的app_id
     */
    private String app_id;

    /**
     * 商户订单号
     */
    private String out_trade_no;

    /**
     * 签名
     */
    private String sign;

    /**
     * 交易状态
     */
    private String trade_status;

    /**
     *  支付宝交易号
     */
    private String trade_no;

    /**
     * 交易的金额
     */
    private String total_amount;

    public String getTotal_amount() {
        return total_amount;
    }

    public void setTotal_amount(String total_amount) {
        this.total_amount = total_amount;
    }

    public String getApp_id() {
        return app_id;
    }

    public void setApp_id(String app_id) {
        this.app_id = app_id;
    }

    public String getOut_trade_no() {
        return out_trade_no;
    }

    public void setOut_trade_no(String out_trade_no) {
        this.out_trade_no = out_trade_no;
    }

    public String getSign() {
        return sign;
    }

    public void setSign(String sign) {
        this.sign = sign;
    }

    public String getTrade_status() {
        return trade_status;
    }

    public void setTrade_status(String trade_status) {
        this.trade_status = trade_status;
    }

    public String getTrade_no() {
        return trade_no;
    }

    public void setTrade_no(String trade_no) {
        this.trade_no = trade_no;
    }

    @Override
    public String toString() {
        return "AliReturnPayBean [app_id=" + app_id + ", out_trade_no=" + out_trade_no + ", sign=" + sign
                + ", trade_status=" + trade_status + ", trade_no=" + trade_no + "]";
    }

}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97

将返回参数封装在实体bean中,这样springmvc会利用反射机制自动将相关参数映射进实体bean里面,省去了我们自己再去解析参数的麻烦。后面那句returnPay.getTrade_status().equals(“TRADE_SUCCESS”)是得到支付宝中trade_status这个参数,在支付宝的接口文档中,若这个参数等于TRADE_SUCCESS,则说明支付是成功的,然后我就会调用tbPaymentRecordsService.aliPaySuccess(returnPay);。这句代码就是具体的业务逻辑代码了,对成功返回的参数进行处理,由于每个人业务逻辑都不一样,我就不再赘述了。你们只需将这局代码替换成你们的业务逻辑代码即可。

这样,支付下单的流程就走通了。当然我还有一个退款的接口没讲。这个接口其实和下单接口大同小异,我也写了相关注释。就请各位自行阅读,我就不做解释了。

那这次支付宝的调用就先写到这里,下次我还会写一些关于微信的支付接口,喜欢的小伙伴可以点波关注哦。

原文地址:https://www.cnblogs.com/LiZhongZhongY/p/10992550.html

时间: 2024-07-31 01:12:52

支付宝支付接口的调用(转)的相关文章

微信支付接口的调用(转)

微信支付接口的调用 2018年04月13日 10:53:16 Forward_duyu 阅读数:20092 版权声明:本文为博主原创文章,未经博主允许不得转载. https://blog.csdn.net/zoroduyu/article/details/79911278 在上周的博客中我讲了调用支付宝的接口实现支付,这周我们继续来讲一讲如何调用微信的支付接口. 在讲之前依然先给出微信的官方接口说明.官方的场景介绍图如下: 其实pc端的支付场景都差不多,用户点击按钮,生成一个二维码,微信扫码之后

php编程之如何调用支付宝支付接口的实现

对于任何一款软件来说,支付功能都是核心的,那么目前的主流支付接口主要是支付宝.微信和银联卡,而大多数开发技术人员对于如何调用支付宝的支付接口还存在很大的困扰,今天就来跟大家分享一下如何正确调用支付宝支付接口的实现,代码如下所示:public function zfbpay1(){require_once './ThinkPHP/Extend/Vendor/alipay1/config.php';require_once './ThinkPHP/Extend/Vendor/alipay1/page

PC端支付宝支付接口实现

首先要2个jar包 一个是alipay-sdk--java-4.9.79.ALL.jar 一个是aliyun-java-sdk-dysmsapi-1.0.0 基本配置信息: package com.zhetian.www.alibaba; import java.io.FileWriter; import java.io.IOException; /** * @Copyright (C)遮天网络有限公司 * @Author: YUAN HUAI XING * @Date 2020/3/31 17

对接支付宝支付接口开发详细步骤(证书签名方式)

对接支付宝支付接口,官方文档已经写的很清楚了,但是也有很多像我一样的小白,第一次对接支付宝支付接口,会有些迷茫,所以我在此写下这篇文章,给我和我一样的同学,一点思路吧.需要思路的可以私聊我 两大支付平台感觉都有坑人之处吧(终归是学艺不精,哈哈哈哈!!) 不过支付宝相做的较好的一点是有技术和你在线调试,这就很舒服,哈哈. 寻找技术地址:支付宝开放平台 - 开发者中心 - 网页&移动应用 - 右边有个立即咨询 - 智能问答(多发送几次就有技术出来了) 第一步:(先要在支付宝进行操做,拿到我们需要开发

Java调用支付宝支付接口

一.场景:公司需要在网站上进行支付宝支付. 二.API:使用支付宝开放平台的支付能力-即时到账接口.支付宝开放平台链接 三.分析: 1.支付宝的文档比较容易看,主要是有相应的DEMO,我这里看的DEMO是 JAVA-UTF-8版本. ? 2.导入DEMO,在com.alipay.config中填入对应的partner和key(在对应的商户后台获取)就可以直接运行了解支付流程了. ? 3.改写:我这边使用的是springmvc+mybatis.商品发起购买(走支付宝支付).跳转到支付宝.支付宝回调

支付宝支付接口开发

1.简单点说就是调用支付宝那边的接口方法,然后传递数据过去,之后会返回一个是否成功的值,然后你拿到之后判断就好了 2.首先你得有淘宝的商铺的合作身份ID,和Key,这个key就是你的密钥.当你的表单提交的时候,表单中的参数会根据这个key来md5加密,同明文参数一同发送到支付宝那边的,然后支付宝那边根据你的key(他们是知道你的key的.因为这个key是他们给你的)来再次加密你的明文参数.如果加密后的数据和你一起传递的密文是相同的话则表示数据在传输过程中没有被修改,就会处理你的请求...处理完之

客服端与服务端APP支付宝支付接口联调的那些坑

根据支付宝官方提供的文档的建议: TIPS:这一步应在商户服务端完成,商户服务端直接将组装和签名后的请求串orderString传给客户端,客户端直接传给SDK发起请求.文档和Demo是为了示例效果在客户端实现. 商品的订单信息和签名应该放在服务端进行,将最好生成的orderString发送给客户端,客户端直接换起支付,处理好回调就ok.思路很简单,但实现却要下番功夫. 坑一: 如果以PHP为服务后台为例,官网是没有提供集成好的PHP运行DEMO,我们的处理方式是参展APPDemo里的思路,和官

支付宝支付接口功能

官方文档:https://doc.open.alipay.com/docs/doc.htm?treeId=203&articleId=105288&docType=1 支付宝支付功能申请条件 一.实名支付宝账号. 二.要求是企业账户. 三.已经签约手机支付功能. Linux环境下生成RSA私钥和公钥 https://doc.open.alipay.com/doc2/detail?treeId=44&articleId=103242&docType=1 命令行: openss

支付宝支付接口

-支付宝支付 -商户号:需要营业执照 -沙箱环境(测试环境) -支付宝支付有java版的demo,php版的demo,但是没有python版的demo 买家账号bfxtlv8393@sandbox.com 登录密码111111 支付密码111111 -支付宝demo 安装模块:pip3 install pycryptodome -关于支付私钥公钥 非对称加密有公钥和私钥:公钥是给别人用,私钥是自己用的 -用户私钥 -用户公钥 -支付宝公钥 -项目中使用支付宝支付: -pay.py类放到项目中 -