自学内容网 自学内容网

Java接入支付宝实现扫码支付

支付宝接入扫码支付还是比较简单的,为了方便开发还专门提供了沙箱环境,如果不想创建应用的可以直接使用沙箱环境的参数

提前准备

登录支付宝开放平台:登录 - 支付宝欢迎登录支付宝,支付宝-全球领先的独立第三方支付平台,致力于为广大用户提供安全快速的电子支付/网上支付/安全支付/手机支付体验以及转账收款/水电煤缴费/信用卡还款等生活服务应用;为广大为从事电子商务的网站提供支付产品/支付服务的在线订购和技术支持等服务,帮助商家快速接入支付工具,高效、安全、快捷地开展电子商务。icon-default.png?t=O83Ahttps://open.alipay.com/develop/manage

选择网页/移动应用,点击创建应用

 填写完信息后点击立即创建,创建完成后点击开发设置,设置支付加签和密钥

加签密钥需要使用支付宝的密钥生成工具 

密钥工具下载地址:小程序文档 - 支付宝文档中心

生成密钥 

将生成的公钥填入支付宝开放平台,确认

然后点击提交审核

使用沙箱环境

如果自己没有申请应用的,可以使用沙箱环境进行开发 

沙箱环境地址:

登录 - 支付宝欢迎登录支付宝,支付宝-全球领先的独立第三方支付平台,致力于为广大用户提供安全快速的电子支付/网上支付/安全支付/手机支付体验以及转账收款/水电煤缴费/信用卡还款等生活服务应用;为广大为从事电子商务的网站提供支付产品/支付服务的在线订购和技术支持等服务,帮助商家快速接入支付工具,高效、安全、快捷地开展电子商务。icon-default.png?t=O83Ahttps://open.alipay.com/develop/sandbox/app

代码开发

引入pom

<!-- 支付宝支付包 -->
<dependency>
    <groupId>com.alipay.sdk</groupId>
    <artifactId>alipay-sdk-java</artifactId>
    <version>4.10.209.ALL</version>
</dependency>yml配置文件

 yml文件添加支付配置

alipay:
  # 支付宝网关名、partnerId和appId
  openApiDomain: https://openapi.alipay.com/gateway.do
  mcloudApiDomain: http://mcloudmonitor.com/gateway.do
  appId: 1235656
  pid: 1556
  # RSA私钥、公钥和支付宝公钥
  #此处请填写你的应用私钥且转PKCS8格式
  privateKey:
  #此处请填写你的应用公钥
  publicKey:
  #SHA256withRsa对应支付宝公钥
  alipayPublicKey:
  # 签名类型: RSA->SHA1withRsa,RSA2->SHA256withRsa
  signType: RSA2
  #异步通知url(注意拦截器是否拦截)
  notifyUrl: http://8u862c.natappfree.cc/NBOSTA_WSBM/Alipay/ZFBcallbackAction.do

 这些参数沙箱环境都已经配置好了,可以拿过来使用

读取配置文件参数:

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

    //网关名称
    private String openApiDomain;
    private String mcloudApiDomain;
    //app id
    private String appId;
    // pid
    private String pid;
    //私钥
    private String privateKey;
    //公钥
    private String publicKey;
    //SHA256withRsa对应支付宝公钥
    private String alipayPublicKey;
    //签名类型: RSA->SHA1withRsa,RSA2->SHA256withRsa
    private String signType;
    //回调地址
    private String notifyUrl;
}

创建AlipayClient:

@Autowired
private final AlipayConfig aliPayConfig;

private AlipayClient getAlipayClient() {
        return new DefaultAlipayClient(
                aliPayConfig.getOpenApiDomain(),
                aliPayConfig.getAppId(),
                aliPayConfig.getPrivateKey(),
                AlipayConstants.FORMAT_JSON,
                AlipayConstants.CHARSET_UTF8,
                aliPayConfig.getAlipayPublicKey(),
                aliPayConfig.getSignType()
        );
    }

支付预下单

官方开发文档:​​​​​​​小程序文档 - 支付宝文档中心

入参实体:

@Data
public class AliPayFaceToFaceModel {
    private String outTradeNo;
    private String subject;
    private String totalAmount;
    private String body;
}

 出参实体:

@Data
public class AliPayResultModel {
    //商户订单号
    private String outTradeNo;
    //支付 二维码地址
    private String qrCode;
    //支付宝交易号
    private String tradeNo;
    /**
     *交易状态
     * WAIT_BUYER_PAY(交易创建,等待买家付款)
     * TRADE_CLOSED(未付款交易超时关闭,或支付完成后全额退款)
     * TRADE_SUCCESS(交易支付成功)
     * TRADE_FINISHED(交易结束,不可退款)
     * 状态业务说明
     * 1. 交易创建成功后,用户支付成功,交易状态转为 TRADE_SUCCESS(交易成功)。
     * 2. 交易成功后,规定退款时间内没有退款,交易状态转为 TRADE_FINISHED(交易完成)。
     * 3. 交易支付成功后,交易部分退款,交易状态为 TRADE_SUCCESS(交易成功)。
     * 4. 交易成功后,交易全额退款,交易状态转为 TRADE_CLOSED(交易关闭)。
     * 5. 交易创建成功后,用户未付款交易超时关闭,交易状态转为 TRADE_CLOSED(交易关闭)。
     * 6. 交易创建成功后,用户支付成功后,若用户商品不支持退款,交易状态直接转为 TRADE_FINISHED(交易完成)。
     * 注意:交易成功后部分退款,交易状态仍为 TRADE_SUCCESS(交易成功),如果一直部分退款退完所有交易金额则交易状态转为 TRADE_CLOSED(交易关闭),如果未退完所有交易金额,超过有效退款时间后交易状态转为 TRADE_FINISHED(交易完成)不可退款
     */
    private String tradeStatus;
    //交易金额
    private String totalAmount;
    //退款金额
    private String refundFee;
    //  本次退款是否发生了资金变化 Y: 资金发生变化,退款成功
    private String fundChange;
    //回调时返回请求传递时的body信息
    private String body;
}

 漏掉的方法

    private AlipayTradePrecreateRequest getTradePreCreateRequest(AliPayFaceToFaceModel aliPayFaceToFaceModel) {
        //实例化具体API对应的request类,类名称和接口名称对应,当前调用接口名称:alipay.trade.precreate(统一收单线下交易预创建(扫码支付)
        AlipayTradePrecreateRequest request = new AlipayTradePrecreateRequest();
        AlipayTradePrecreateModel model = new AlipayTradePrecreateModel();//设置业务参数
        model.setOutTradeNo(aliPayFaceToFaceModel.getOutTradeNo());//商户订单号,商户自定义,需保证在商户端不重复,如:20200612000001
        model.setSubject(aliPayFaceToFaceModel.getSubject());//订单标题
        model.setTotalAmount(aliPayFaceToFaceModel.getTotalAmount());//订单金额,精确到小数点后两位
        model.setBody(aliPayFaceToFaceModel.getBody());//订单描述

        request.setBizModel(model);
        /*
         异步通知地址,以http或者https开头的,商户外网可以post访问的异步地址,用于接收支付宝返回的支付结果,如果未收到该通知可参考该文档进行确认:https://opensupport.alipay.com/support/helpcenter/193/201602475759
         */
        request.setNotifyUrl(aliPayConfig.getNotifyUrl());

        return request;
    }

开始扫码下单: 

/**
     * 支付宝预下单
     */
    public AjaxResult aliPayPreorder(AliPayFaceToFaceModel aliPayFaceToFaceModel) {
        log.info("支付宝预下单,商户订单号:{}",aliPayFaceToFaceModel.getOutTradeNo());
        try {
            AlipayClient alipayClient = getAlipayClient();
            AlipayTradePrecreateRequest tradePreCreateRequest = getTradePreCreateRequest(aliPayFaceToFaceModel);
            AlipayTradePrecreateResponse response = alipayClient.execute(tradePreCreateRequest);
            log.info("支付宝预下单接口调用成功,返回参数:{}",response.getBody());
            // System.out.println(response.getBody());
            if(StringUtils.equalsAny(response.getCode(),"10000")){
                AliPayResultModel resultModel=new AliPayResultModel();
                resultModel.setOutTradeNo(response.getOutTradeNo());
                resultModel.setQrCode(response.getQrCode());
                return AjaxResult.success(resultModel);
            }else{
                return AjaxResult.error("获取支付二维码失败,错误信息:"+response.getSubMsg());
            }
        } catch (Exception e) {
            e.printStackTrace();
            return AjaxResult.error("下单失败");
        }
    }

查询订单状态

/**
     * 交易状态查询
     * 可以查看以下帮助文档:
     * 判断交易是否成功:https://opensupport.alipay.com/support/helpcenter/195/201602516393?ant_source=zsearch
     * 状态ACQ.TRADE_NOT_EXIST(交易不存在)https://opensupport.alipay.com/support/helpcenter/89/201602475600?ant_source=zsearch
     */
    public AjaxResult queryTrade(AliPayFaceToFaceModel aliPayFaceToFaceModel) {
        try {
            log.info("调用支付宝交易状态查询接口,单号:{}",aliPayFaceToFaceModel.getOutTradeNo());
            AlipayClient alipayClient = getAlipayClient();
            AlipayTradeQueryRequest request = new AlipayTradeQueryRequest();//实例化具体API对应的request类,类名称和接口名称对应,当前调用接口名称:alipay.trade.query(统一收单线下交易查询)
            AlipayTradeQueryModel model = new AlipayTradeQueryModel();
            // 注:交易号(TradeNo)与订单号(OutTradeNo)二选一传入即可,如果2个同时传入,则以交易号为准
            //支付接口传入的商户订单号。如:2020061601290011200000140004 **/
            model.setOutTradeNo(aliPayFaceToFaceModel.getOutTradeNo());
            // 异步通知/查询接口返回的支付宝交易号,如:2020061622001473951448314322 **/
            request.setBizModel(model);
            AlipayTradeQueryResponse response = alipayClient.execute(request);
            log.info("调用支付宝交易状态查询接口成功,返回参数:{}",response.getBody());
            if(response.isSuccess()){
                AliPayResultModel resultModel=new AliPayResultModel();
                resultModel.setOutTradeNo(response.getOutTradeNo());
                resultModel.setTradeStatus(response.getTradeStatus());
                resultModel.setTradeNo(response.getTradeNo());
                return AjaxResult.success(resultModel);
            }else{
                log.info("调用支付宝交易状态查询接口失败,失败信息:{}",response.getSubMsg());
                return AjaxResult.error("支付宝订单查询失败:"+response.getSubMsg());
            }
        } catch (Exception e) {
            e.printStackTrace();
            return AjaxResult.error("订单查询异常!");
        }
    }

交易退款接口

退款可以部分退款,根据自己业务需求修改,我这里是全额退款。

/**
     * 交易退款接口
     *
     * @param aliPayFaceToFaceModel 参数实体
     * @author: zm
     * @date: 2024/10/8 11:05
     * @rerturn: java.lang.String
     */
    public AjaxResult payTradeRefund(AliPayFaceToFaceModel aliPayFaceToFaceModel) {
        if(aliPayFaceToFaceModel == null || StringUtils.isEmpty(aliPayFaceToFaceModel.getOutTradeNo())){
            log.error("订单号为空,请检查参数");
            return AjaxResult.error("订单号为空");
        }
        try {
            log.info("调用支付宝退款接口,单号:{}",aliPayFaceToFaceModel.getOutTradeNo());
            AlipayClient alipayClient = getAlipayClient();
            AlipayTradeRefundRequest refundRequest=new AlipayTradeRefundRequest();
            AlipayTradeRefundModel refundModel =new AlipayTradeRefundModel();
            //商户订单号
            refundModel.setOutTradeNo(aliPayFaceToFaceModel.getOutTradeNo());
            //退款金额
            refundModel.setRefundAmount(aliPayFaceToFaceModel.getTotalAmount());
            //退款描述
            refundModel.setRefundReason("正常退款");
            refundRequest.setBizModel(refundModel);
            AlipayTradeRefundResponse response=alipayClient.execute(refundRequest);
            log.info("支付宝交易退款接口调用成功,返回参数:{}",response.getBody());
            if (!response.isSuccess())  {
                log.error("支付宝交易退款接口调用失败,单号:{}",aliPayFaceToFaceModel.getOutTradeNo());
                return AjaxResult.error("退款失败,错误信息:"+response.getSubMsg());
            }
            AliPayResultModel resultModel=new AliPayResultModel();
            resultModel.setOutTradeNo(response.getOutTradeNo());
            resultModel.setRefundFee(response.getRefundFee());
            resultModel.setTradeNo(response.getTradeNo());
            resultModel.setFundChange(response.getFundChange());
            return AjaxResult.success(resultModel);
        } catch (Exception e) {
            e.printStackTrace();
            return AjaxResult.error("退款异常!");
        }
    }

支付回调接口

/**
     * 支付宝支付回调
     * @param request 请求
     * @param response 响应
     * @author: zm
     * @date: 2024/10/10
     * @rerturn: void
     */
    public void notifyUrl(HttpServletRequest request, HttpServletResponse response){
        try {
            log.info("接收到支付回调信息");
            //获取支付宝公钥
            String aliPayPublicKey = aliPayConfig.getAlipayPublicKey();
            PrintWriter out;
            out = response.getWriter();
            //获取支付宝POST过来反馈信息
            Map<String, String> params = new HashMap<String, String>();
            Map requestParams = request.getParameterMap();
            //循环遍历支付宝请求过来的参数存入到params中
            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);
            }
            //异步验签:切记alipaypublickey是支付宝的公钥,请去open.alipay.com对应应用下查看。
            boolean flag = AlipaySignature.rsaCheckV1(params, aliPayPublicKey, "utf-8","RSA2");
            if (flag){
                log.info("验签成功,返回参数:{}",params.toString());
                AliPayResultModel resultModel=new AliPayResultModel();
                resultModel.setOutTradeNo(params.get("out_trade_no"));
                resultModel.setTradeStatus(params.get("trade_status"));
                resultModel.setTradeNo(params.get("trade_no"));
                resultModel.setBody(params.get("body"));
                //TODO 调用业务接口

                out.write("success");
               
            }else {
                log.info("支付宝验签失败,请联系工作人员");
                //验签失败该接口被别人调用
                out.write("支付宝异步回调验签失败,请留意");
            }
            out.flush();
            out.close();
        }catch (Exception e) {
            e.printStackTrace();
        }
    }

撤销订单接口

有业务需要的可以加上

    /**
     * 支付宝订单撤销(关闭订单)
     * @param payModel 请求参数
     * @author: zm
     * @date: 2024/10/10
     * @rerturn: void
     */
    public AjaxResult payTradeCancel(AliPayFaceToFaceModel payModel){
        log.info("调用支付宝订单撤销接口,单号:{}",payModel.getOutTradeNo());
        AlipayClient alipayClient = getAlipayClient();
        // 构造请求参数以调用接口
        AlipayTradeCancelRequest request = new AlipayTradeCancelRequest();
        AlipayTradeCancelModel model = new AlipayTradeCancelModel();
        // 设置原支付请求的商户订单号
        model.setOutTradeNo(payModel.getOutTradeNo());
        request.setBizModel(model);
        try {
            AlipayTradeCancelResponse response = alipayClient.execute(request);
            log.info("调用支付宝订单撤销接口成功,返回参数:{}",response.getBody());
            if (response.isSuccess()) {
                return AjaxResult.success();
            } else {
                return AjaxResult.error("关闭订单失败,失败原因:"+response.getSubMsg());
            }
        } catch (AlipayApiException e) {
            e.printStackTrace();
            return AjaxResult.error("关闭订单异常!");
        }
    }

好了支付宝支付到此结束,有疑问的可以留言!

异步通知需要内网穿透切记、切记、切记

参考博文:Java接入支付宝支付超级详细教程——从入门到精通_java接入支付宝自动扣费-CSDN博客


原文地址:https://blog.csdn.net/z132411/article/details/143741147

免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!