Java 实现支付宝支付、退款、订单查询

2 篇文章 1 订阅

最在开发一款APP,需要实现支付宝支付,记录一下实现过程

流程整体交互图如下所示
在这里插入图片描述

一、引入pom依赖

            <dependency>
                <groupId>com.aliyun</groupId>
                <artifactId>aliyun-java-sdk-core</artifactId>
                <version>4.0.3</version>
            </dependency>

二、初始化请求对象

@SneakyThrows(value = AlipayApiException.class)
    public AlipayClient initAlipay() {
        //构造client
        CertAlipayRequest certAlipayRequest = new CertAlipayRequest();
        //设置网关地址
        certAlipayRequest.setServerUrl(AliPayUtil.SERVER_URL);
        //设置应用Id
        certAlipayRequest.setAppId(AliPayUtil.APP_ID);
        //设置应用私钥
        certAlipayRequest.setPrivateKey(AliPayUtil.PRIVATE_KEY);
        //设置请求格式,固定值json
        certAlipayRequest.setFormat(AliPayUtil.FORMAT);
        //设置字符集
        certAlipayRequest.setCharset(AliPayUtil.CHARSET);
        //设置签名类型
        certAlipayRequest.setSignType(AliPayUtil.SIGN_TYPE);
        //设置应用公钥证书路径
        certAlipayRequest.setCertPath(AliPayUtil.CERT_PATH);
        //设置支付宝公钥证书路径
        certAlipayRequest.setAlipayPublicCertPath(AliPayUtil.ALIPAY_PUBLIC_CER_PATH);
        //设置支付宝根证书路径
        certAlipayRequest.setRootCertPath(AliPayUtil.ROOT_CER_PATH);
        //构造client
        return new DefaultAlipayClient(certAlipayRequest);
    }

三、生成支付宝订单

注意,这里返回orderStr需要返回前端、用于唤起支付宝APP

@SneakyThrows(value = AlipayApiException.class)
    public String alipayRecharge(AliPayModel aliPayModel) {

        //初始化配置信息
        AlipayClient alipayClient = initAlipay();

        //实例化具体API对应的request类,类名称和接口名称对应,当前调用接口名称:alipay.trade.app.pay
        AlipayTradeAppPayRequest request = new AlipayTradeAppPayRequest();

        //SDK已经封装掉了公共参数,这里只需要传入业务参数。以下方法为sdk的model入参方式(model和biz_content同时存在的情况下取biz_content)。
        AlipayTradeAppPayModel model = new AlipayTradeAppPayModel();
        String orderNumber = aliPayModel.getOrderNumber();

        model.setBody(aliPayModel.getBody());
        model.setSubject(aliPayModel.getSubject());
        model.setOutTradeNo(orderNumber);
        model.setTimeoutExpress(AliPayUtil.TIME_OUT_EXPRESS);
        model.setTotalAmount(aliPayModel.getTotalAmount());
        request.setBizModel(model);

        //异步通知地址
        request.setNotifyUrl(AliPayUtil.NOTIFY_URL);
        try  {
            //业务处理
            //dosomething
            //这里和普通的接口调用不同,使用的是sdkExecute
            AlipayTradeAppPayResponse response = alipayClient.sdkExecute(request);

            if (!response.isSuccess()) {
                log.error("接口调用错误:{}",response.getBody());
                throw new AlipayApiException("接口调用错误");
            }

            AliPayUtil.NOT_CLOSE_ORDER.put(orderNumber,aliPayModel);

            return response.getBody(); //就是orderString 可以直接给客户端请求,无需再做处理。
        }catch(AlipayApiException e) {
            log.error("生成支付订单错误:",e);
            return null;
        }
    }

三、回调方法

用户在支付宝支付成功之后会回调此方法,接口在步骤二设置。

public String aliPayNotify(HttpServletRequest request) {

        // 将异步通知中收到的待验证所有参数都存放到map中
        Map<String, String> params = AliPayUtil.convertRequestParamsToMapWith(request);
        String paramsJson = JSON.toJSONString(params);
        log.info("支付宝回调,{}", paramsJson);
        try {
            // 调用SDK验证签名
            boolean signVerified = AlipaySignature.rsaCertCheckV1(params, AliPayUtil.ALIPAY_PUBLIC_CER_PATH,
                    AliPayUtil.CHARSET, AliPayUtil.SIGN_TYPE);
            if (signVerified) {
                // 按照支付结果异步通知中的描述,对支付结果中的业务内容进行1\2\3\4二次校验,校验成功后在response中返回success,校验失败返回failure
                AliPayUtil.check(params);
                String tradeStatus = params.get("trade_status");
                String outTradeNo = params.get("out_trade_no");
                String tradeNo = params.get("trade_no");
                //通知状态为TRADE_SUCCESS或TRADE_FINISHED时,支付宝才会认定为买家付款成功
                if(tradeStatus.equals(AliPayUtil.TRADE_SUCCESS) || tradeStatus.equals(AliPayUtil.TRADE_FINISHED)){
                    //业务逻辑处理
                    //do something

                }
                return "success";
            } else {
                log.info("支付宝回调签名认证失败,signVerified=false, paramsJson:{}", paramsJson);
                return "failure";
            }
        } catch (AlipayApiException e) {
            log.error("支付宝回调签名认证失败,paramsJson:{},errorMsg:{}", paramsJson, e.getMessage());
            return "failure";
        }
    }

注意:此处需返回给支付宝状态 success 或 failure

四、查询订单

   @SneakyThrows(value = AlipayApiException.class)
    public String getAlipayOutTradeNo(Long outTradeNo, Long tradeNo) {

        //初始化支付宝配置
        AlipayClient alipayClient = initAlipay();
        AlipayTradeQueryRequest request = new AlipayTradeQueryRequest();
        AlipayTradeQueryModel model = new AlipayTradeQueryModel();
        model.setOutTradeNo(outTradeNo.toString());
        if(tradeNo != null){
            model.setTradeNo(tradeNo.toString());
        }
        request.setBizModel(model);
        AlipayTradeQueryResponse response = alipayClient.certificateExecute(request);
        return response.getBody();
    }

注意:查询订单时可用商品订单号(自己生成的订单号)或支付订单号(支付宝返回的订单号)进行查询,两个都有的情况下优先使用支付宝订单号~

五、退款

    @SneakyThrows(value = AlipayApiException.class)
    public Boolean refund(String outTradeNo,String refundAmount,String refundReason) {

        AlipayClient alipayClient = initAlipay();

        AlipayTradeRefundRequest alipayTradeCloseRequest =new AlipayTradeRefundRequest();
        //请求参数集合对象,除了公共参数之外,所有参数都可通过此对象传递
        AlipayTradeRefundModel alipayTradeRefundModel =new AlipayTradeRefundModel();
        //退款的订单号,传入生成支付订单时的订单号即可
        alipayTradeRefundModel.setOutTradeNo(outTradeNo);
        //退款金额
        alipayTradeRefundModel.setRefundAmount(refundAmount);
        //退款的原因
        alipayTradeRefundModel.setRefundReason(refundReason);
        alipayTradeCloseRequest.setBizModel(alipayTradeRefundModel);

        //退款的执行流程与支付不太一样,支付时成功之后,需要通知回调接口,而退款则不需要,只需判断响应			参数 refundResponse.getFundChange().equals("Y") 判断是否发生了资金变化, equals("Y")表示资金发生了变化,退款成功
        AlipayTradeRefundResponse response = alipayClient.execute(alipayTradeCloseRequest);
        return response.isSuccess() && response.getFundChange().equals("Y");
    }

注意:退款需要传三个参数,商品订单号(自己生成的订单号)、退款原因和退款金额

六、使用到的工具类(仅供参考)

工具类包含支付宝初始化参数订单号生成方法解析支付宝消息方法订单金额验证方法和签名验证方法

@Slf4j
public class AliPayUtil {

    public static Map<String, AliPayModel> NOT_CLOSE_ORDER = new HashMap<>();

    public static String TIME_OUT_EXPRESS = "30m";
    public static String APP_ID = "";
    public static String SERVER_URL = "";
    public static String PRIVATE_KEY = "";
    public static String NOTIFY_URL = "";
    public static String CERT_PATH = "";
    public static String ALIPAY_PUBLIC_CER_PATH = "";
    public static String ROOT_CER_PATH = "";

    public static String CHARSET = "utf-8";

    public static String FORMAT = "json";

    public static String SIGN_TYPE = "RSA2";
    public static String TRADE_SUCCESS = "TRADE_SUCCESS";
    public static String TRADE_FINISHED = "TRADE_FINISHED";


    private static final Random random = new Random();

    public static String generateOrderNumber(int userId, int productId) {
        // 获取当前时间戳
        long timestamp = System.currentTimeMillis();

        // 生成6位随机数
        int randomNum = random.nextInt(900000) + 100000;

        // 组装订单号
        return String.format("%d%d%d%d", timestamp, randomNum, userId, productId);
    }


    /**
     * request 转 map
     *
     * @param request
     * @return
     */
    public static Map<String, String> convertRequestParamsToMapWith(HttpServletRequest request) {
        Map<String, String> params = new HashMap<String, String>();
        Map requestParams = request.getParameterMap();
        for (Iterator 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);
        }
        return params;
    }

    /**
     * 1、商户需要验证该通知数据中的out_trade_no是否为商户系统中创建的订单号,
     * 2、判断total_amount是否确实为该订单的实际金额(即商户订单创建时的金额),
     * 3、校验通知中的seller_id(或者seller_email)是否为out_trade_no这笔单据的对应的操作方(有的时候,一个商户可能有多个seller_id/seller_email),
     * 4、验证app_id是否为该商户本身。上述1、2、3、4有任何一个验证不通过,则表明本次通知是异常通知,务必忽略。
     * 在上述验证通过后商户必须根据支付宝不同类型的业务通知,正确的进行不同的业务处理,并且过滤重复的通知结果数据。
     * 在支付宝的业务通知中,只有交易通知状态为TRADE_SUCCESS或TRADE_FINISHED时,支付宝才会认定为买家付款成功。
     *
     * @param params 支付宝回调参数
     */

    @SneakyThrows(value = AlipayApiException.class)
    public static void check(Map<String, String> params) {
        //订单号
        String outTradeNo = params.get("out_trade_no");
        //商户订单实际金额
        String totalAmount = params.get("total_amount");
        //APPId
        String appId = params.get("app_id");

        //验证订单号
        AliPayModel aliPayModel = NOT_CLOSE_ORDER.get(outTradeNo);

        if (aliPayModel == null) {
            throw new AlipayApiException("out_trade_no错误");
        }
        //验证订单实际金额
        if (!totalAmount.equals(aliPayModel.getTotalAmount())) {
            throw new AlipayApiException("支付金额不一致");
        }

        //验证app_id是否为商户本身
        if (!appId.equals(AliPayUtil.APP_ID)) {
            throw new AlipayApiException("app_id不一致");
        }
    }


    /**
     * 客户端同步验签
     *
     * @param request
     * @return true:验证成功,false:验证失败
     * @throws AlipayApiException
     */
    public Boolean getVerifySignResult(HttpServletRequest request) throws AlipayApiException {
        Map<String, String> params = AliPayUtil.convertRequestParamsToMapWith(request);
        String paramsJson = JSON.toJSONString(params);
        log.info("支付宝回调,{}", paramsJson);
        return AlipaySignature.rsaCertCheckV1(params, AliPayUtil.ALIPAY_PUBLIC_CER_PATH,
                AliPayUtil.CHARSET, AliPayUtil.SIGN_TYPE);
    }

大功告成,文章中若有不对请指出,望见谅~

  • 8
    点赞
  • 24
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
### 回答1: 在 Java实现微信支付需要使用微信支付 SDK。您可以在微信支付官方网站上下载最新版本的 SDK,并在您的 Java 项目中使用它。 使用微信支付 SDK 的具体步骤如下: 1. 注册微信支付商户并获取商户 ID 和密钥。 2. 下载并导入微信支付 SDK。 3. 创建支付订单并获取支付二维码。 4. 使用扫码支付或者 JSAPI 支付接口调用微信支付。 5. 接收微信支付的异步通知并进行订单状态的更新。 有关微信支付的更多信息,您可以参考微信支付官方文档:https://pay.weixin.qq.com/wiki/doc/api/index.html 希望这些信息对您有帮助! ### 回答2: 要实现微信支付功能,可以使用Java编程语言结合微信支付开放平台提供的API来实现。 首先,需要在微信支付开放平台注册并创建一个应用,获取到应用的AppID、商户号、AppSecret等信息。 接下来,在Java项目中引入微信支付SDK,可以使用第三方库,如"wechatpay-api"来简化开发流程。然后,通过使用SDK提供的相关方法,可以实现以下功能: 1. 获取access_token:通过获取 access_token 接口,获取微信支付接口调用凭证,用于后续接口调用的身份验证。 2. 统一下单:使用统一下单接口,将用户提交的支付信息传给微信支付平台,生成预支付订单,并返回预付款二维码链接或者支付ID。 3. 生成支付链接或二维码:将预付款二维码链接或支付ID返回给前端,通过生成支付链接或者二维码的方式,提供给用户进行支付。 4. 微信支付回调:在用户支付成功后,微信支付平台会异步调用开发者设置的支付结果通知地址,向该地址发送支付结果信息。开发者需要在接收到回调时,验证回调的合法性,并及时处理支付结果。 5. 查询订单状态:通过订单查询接口,可以查询用户支付订单的当前状态,如支付成功、支付失败等。 6. 退款:使用退款接口,可以实现订单退款操作,退还用户支付的金额。 以上是使用Java实现微信支付的基本步骤。在具体实现过程中,还需注意接口调用的参数传递、异常处理、数据加密等问题。为确保支付安全,建议使用HTTPS协议进行数据传输,并加强对接口的签名验证。 ### 回答3: Java 实现微信支付可以通过微信支付开放平台提供的开发工具包来完成。首先,需要在微信支付开放平台注册一个开发者账号,并创建一个应用获取对应的应用ID和应用密钥。 接下来,可以使用Java语言进行开发。首先,需要引入微信支付Java SDK,例如官方提供的weixin-java-pay SDK。通过在项目的pom.xml文件中添加相关依赖,即可将SDK集成到项目中。 然后,通过在代码中进行配置,将应用ID和应用密钥等信息设置到SDK中。可以使用SDK提供的配置类进行设置,例如WxPayConfig。 接下来,可以使用SDK提供的API进行微信支付的相关操作。例如,使用SDK提供的统一下单API可以生成一个支付链接,通过该链接用户可以进行支付操作。可以通过创建对应的请求对象,并调用SDK提供的发送请求的方法来实现支付结果通知可以使用SDK提供的回调接口来处理,当支付完成后,微信支付平台会向预先设置的回调URL发送通知。可以在代码中编写对应的处理逻辑,接收并解析微信支付平台发送的通知,校验数据的正确性,并进行相应的业务处理。 最后,可以使用SDK提供的查询订单API来查询订单支付结果。可以根据订单号或其他查询条件,调用SDK提供的查询订单接口来获取订单的最新支付状态。 通过以上步骤,就可以使用Java实现微信支付功能。需要注意的是,开发过程中需要仔细阅读微信支付开放平台提供的文档和SDK的使用指南,并按照实际需求进行相关配置和操作。同时,为了确保支付过程的安全性,建议使用SSL证书进行加密传输。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

程序猿小张丶

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值