APP对接支付宝付款

1、支付宝开发平台:https://openhome.alipay.com/

2、进去沙箱,配置支付密钥

 

 

 

 

 记录下appid,然后设置秘钥;

 

 

 

 

 

 

 

 3、后端代码,配置类

pom文件sdk添加依赖

<!--pom.xml  支付宝sdk -->
        <dependency>
            <groupId>com.alipay.sdk</groupId>
            <artifactId>alipay-sdk-java</artifactId>
            <version>3.1.0</version>
        </dependency>
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>1.2.58</version>
        </dependency>

 

@Configuration
public class AppPayConfig {
   /**
    * 1.商户appid
    */
   public static String APPID = "";

   /**
    * 私钥 pkcs8格式的
    * 这个就是我上面说的应用私钥生成 注意这里是私钥
    */
   public static String RSA_PRIVATE_KEY =""
    * 3.支付宝公钥
    */
   public static String ALIPAY_PUBLIC_KEY = "";

   /**
    * 4.服务器异步通知页面路径 需http://或者https://格式的完整路径,不能加?id=123这类自定义参数,必须外网可以正常访问
    */
   //这个着重讲一下..支付完成后,支付宝会通过这个url请求到你的服务端..
   //这个url一定是要公网可以访问才行...如果需要测试的话..我后面有讲到..
   //这里你可以先写你本地项目的url 例如:localhost:8080/项目名/访问路径
   public static String notify_url = "http://4e69yn.natappfree.cc/api/v1/aliPayApp/notify_url";

   /**
    * 5.页面跳转同步通知页面路径 需http://或者https://格式的完整路径,不能加?id=123这类自定义参数,必须外网可以正常访问 商户可以自定义同步跳转地址
    */
   //这里同上..不做详细说明了..
   public static String return_url = "http://4e69yn.natappfree.cc/api/v1/aliPayApp/notify_url";

   /**
    * 正式环境支付宝网关,如果是沙箱环境需更改成https://openapi.alipaydev.com/gateway.do
    */
   public static String URL = "https://openapi.alipaydev.com/gateway.do";

   /**
    * 7.编码
    */
   public static String CHARSET = "UTF-8";

   /**
    * 私钥 pkcs8格式的
    */
   // 8.返回格式
   public static String FORMAT = "json";

   /**
    * //签名方式 加密类型
    */
   public static String SIGNTYPE = "RSA2";
}

4、控制层

@RestController
@RequestMapping("api/v1/aliPayApp")
@Slf4j
public class AliPayAppController {
    @Autowired
    private AliPayAppService aliPayAppService;

    /**
     * 获取支付宝加签后台的订单信息字符串,唤起支付宝APP
     * @Title: getAliPayOrderStr
     * @description
     */
    @RequestMapping("/getAliPayOrderStr")
    @ResponseBody
    public JsonData getAliPayOrderStr(@RequestParam("userId") Integer userId, @RequestParam("videoId") Integer videoId) {
        String aliPayOrderStr = aliPayAppService.getAliPayOrderStr(userId, videoId);
        return JsonData.buildSuccess(aliPayOrderStr);
    }

    /**
     * 支付宝支付成功后.异步请求该接口
     * @Title: notify
     */
    @RequestMapping(value="/notify_url",method= RequestMethod.POST)
    @ResponseBody
    public JsonData notify(HttpServletRequest request, HttpServletResponse response) throws IOException {
        log.info("支付宝异步返回支付结果开始");
        // 1.从支付宝回调的request域中取值
        // 获取支付宝返回的参数集合
        Map<String, String[]> aliParams = request.getParameterMap();
        // 用以存放转化后的参数集合
        Map<String, String> conversionParams = new HashMap<String, String>();
        for (Iterator<String> iter = aliParams.keySet().iterator(); iter.hasNext();) {
            String key = iter.next();
            String[] values = aliParams.get(key);
            String valueStr = "";
            for (int i = 0; i < values.length; i++) {
                valueStr = (i == values.length - 1) ? valueStr + values[i] : valueStr + values[i] + ",";
            }
            // 乱码解决,这段代码在出现乱码时使用。如果mysign和sign不相等也可以使用这段代码转化
            // valueStr = new String(valueStr.getBytes("ISO-8859-1"), "uft-8");
            conversionParams.put(key, valueStr);
        }
        log.info("返回参数集合:" + conversionParams);
        String status = aliPayAppService.notify(conversionParams);
        if (status.equals("fail")){
            return JsonData.buildError("订单修改失败");
        }else {
            return JsonData.buildSuccess("订单修改失败");
        }

    }

    /**
     * 向支付宝发起订单查询请求
     * @Title: checkAlipay
     * @description
     * @param orderNo 商户订单号
     */
    @RequestMapping("/checkAlipay")
    @ResponseBody
    public JsonData checkAlipay(String orderNo) {
        int result = aliPayAppService.checkAlipay(orderNo);
        return JsonData.buildSuccess(result);
    }

    /**
     * 向支付宝发起退款请求
     * @Title: alipayTradeRefund
     * @description
     * @param orderNo 商户订单号
     * @param refundFee 退款金额
     */
    @RequestMapping("/alipayTradeRefund")
    @ResponseBody
    public JsonData alipayTradeRefund(String orderNo, Double refundFee) {
        String tradeRefund = aliPayAppService.alipayTradeRefund(orderNo, refundFee);
        return JsonData.buildSuccess(tradeRefund);
    }
}

5、service层

/**
 * 支付宝APP支付业务层接口
 */
public interface AliPayAppService {

    /**
     *  获取支付宝加签后台的订单信息字符串 
     */
    public String getAliPayOrderStr(Integer userId, Integer videoId);
    
    /**
     * 支付宝异步请求逻辑处理
     */
    public String notify(Map<String, String> conversionParams);
    
    /**
     * 向支付宝发起订单查询请求 
     */
    public int checkAlipay(String order_no);
    
    /**
     * 向支付宝发起退款请求
     */
    public String alipayTradeRefund(String order_no, Double refund_fee);
}

6、serviceImpl层

/**
 * 阿里支付实现类
 */
@Service
@Slf4j
public class AliPayAppServiceImpl implements AliPayAppService {


    @Autowired
    private AliPayAppService aliPayAppService;

    @Autowired
    private VideoOrderMapper videoOrderMapper;

    @Autowired
    private VideoMapper videoMapper;

    /**
     * 获取支付宝加签后台的订单信息字符串
     */
    @Override
    @Transactional(propagation = Propagation.REQUIRED)
    public String getAliPayOrderStr(Integer userId, Integer videoId) {
        String orderString = "";
        try {
            Video video = videoMapper.selectById(videoId);
            //AppUser appUser = appUserMapper.selectById(userId);

            //生成订单
            VideoOrder videoOrder = new VideoOrder();
            videoOrder.setVideoId(video.getId());
            videoOrder.setOutTradeNo(CommonUtils.generateUUID());
            videoOrder.setState(0);
            videoOrder.setCreateTime(new Date());
            videoOrder.setTotalFee(video.getPrice());
            videoOrder.setVideoId(video.getId());
            videoOrder.setVideoTitle(video.getTitle());
            videoOrder.setVideoImg(video.getCoverImg());
            videoOrder.setUserId(userId);
            //生成未支付订单
            videoOrderMapper.insert(videoOrder);
            //实例化客户端(参数:网关地址、商户appid、商户私钥、格式、编码、支付宝公钥、加密类型),为了取得预付订单信息
            AlipayClient alipayClient = new DefaultAlipayClient(AppPayConfig.URL, AppPayConfig.APPID,
                    AppPayConfig.RSA_PRIVATE_KEY, "json", "utf-8",
                    AppPayConfig.ALIPAY_PUBLIC_KEY, "RSA2");
            //实例化具体API对应的request类,类名称和接口名称对应,当前调用接口名称:alipay.trade.app.pay
            AlipayTradeAppPayRequest ali_request = new AlipayTradeAppPayRequest();
            //SDK已经封装掉了公共参数,这里只需要传入业务参数。以下方法为sdk的model入参方式
            AlipayTradeAppPayModel model = new AlipayTradeAppPayModel();
            //业务参数传入,可以传很多,参考API
            //model.setPassbackParams(URLEncoder.encode(request.getBody().toString())); //公用参数(附加数据)
            //对一笔交易的具体描述信息。如果是多种商品,请将商品描述字符串累加传给body。
            model.setBody("云讯网购买视频课程");
            //商品名称
            model.setSubject(videoOrder.getVideoTitle());
            //商户订单号
            model.setOutTradeNo(videoOrder.getOutTradeNo());
            //交易超时时间 这里的30m就是30分钟
            model.setTimeoutExpress("30m");
            //支付金额 后面保留2位小数点..不能超过2位
//            model.setTotalAmount(String.valueOf(BigDecimal.valueOf(videoOrder.getTotalFee()).divide(BigDecimal.valueOf(100),2,BigDecimal.ROUND_DOWN)));
            model.setTotalAmount("0.01");

            //销售产品码(固定值) //这个不做多解释..看文档api接口参数解释
            model.setProductCode("FACE_TO_FACE_PAYMENT");

            //model.setPassbackParams(JSON.toJSONString(alipayBean));


            ali_request.setBizModel(model);
            //异步回调地址
            ali_request.setNotifyUrl(AppPayConfig.notify_url);
            //log.info("====================异步通知的地址为:" + ali_request.getNotifyUrl());
            //同步回调地址(APP)同上
            ali_request.setReturnUrl(AppPayConfig.return_url);
            //log.info("====================同步通知的地址为:" + ali_request.getReturnUrl());

            // 这里和普通的接口调用不同,使用的是sdkExecute
            //返回支付宝订单信息(预处理)
            AlipayTradeAppPayResponse alipayTradeAppPayResponse = alipayClient.sdkExecute(ali_request);
            //就是orderString 可以直接给APP请求,无需再做处理。
            orderString = alipayTradeAppPayResponse.getBody();
            System.out.println(orderString);

        } catch (Exception e) {
            e.printStackTrace();
            TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
            log.info("与支付宝交互出错,未能生成订单,请检查代码!");
        }
        return orderString;
    }

    /**
     * 向支付宝发起订单查询请求
     */
    @Override
    public int checkAlipay(String orderNo) {
        log.info("向支付宝发起查询,查询商户订单号为:" + orderNo);

        try {
            // 实例化客户端(参数:网关地址、商户appid、商户私钥、格式、编码、支付宝公钥、加密类型)
            AlipayClient alipayClient = new DefaultAlipayClient(AppPayConfig.URL, AppPayConfig.APPID,
                    AppPayConfig.RSA_PRIVATE_KEY, "json", "utf-8",
                    AppPayConfig.ALIPAY_PUBLIC_KEY, "RSA2");

            AlipayTradeQueryRequest alipayTradeQueryRequest = new AlipayTradeQueryRequest();
            alipayTradeQueryRequest.setBizContent("{" + "\"out_trade_no\" : \"" + orderNo + "\"}");

            AlipayTradeQueryResponse alipayTradeQueryResponse = alipayClient.execute(alipayTradeQueryRequest);
            if (alipayTradeQueryResponse.isSuccess()) {

                VideoOrder videoOrder = videoOrderMapper.selectById(orderNo);

                switch (alipayTradeQueryResponse.getTradeStatus()) // 判断交易结果
                {
                    case "TRADE_FINISHED": // 交易结束并不可退款
                        videoOrder.setState(3);
                        break;
                    case "TRADE_SUCCESS": // 交易支付成功
                        videoOrder.setState(1);
                        break;
                    case "TRADE_CLOSED": // 未付款交易超时关闭或支付完成后全额退款
                        videoOrder.setState(2);
                        break;
                    case "WAIT_BUYER_PAY": // 交易创建并等待买家付款
                        videoOrder.setState(0);
                        break;
                    default:
                        break;
                }

                videoOrderMapper.updateById(videoOrder);// 更新表记录
                return videoOrder.getState();
            } else {
                log.info("调用支付宝查询接口失败!");
            }
        } catch (AlipayApiException e) {
            e.printStackTrace();
        }
        return 0;
    }

    /**
     * 支付宝异步请求逻辑处理
     */
    @Override
    public String notify(Map<String, String> conversionParams) {
        log.info("支付宝异步请求逻辑处理");

        // 签名验证(对支付宝返回的数据验证,确定是支付宝返回的)
        boolean signVerified = false;

        try {
            // 调用SDK验证签名
            signVerified = AlipaySignature.rsaCheckV1(conversionParams, AppPayConfig.ALIPAY_PUBLIC_KEY,
                    "utf-8", "RSA2");

        } catch (AlipayApiException e) {
            log.info("验签失败 !");
            e.printStackTrace();
        }

        // 对验签进行处理
        if (signVerified) {
            System.out.println("验签通过");
            // 验签通过
            // 获取需要保存的数据
            String appId = conversionParams.get("app_id");// 支付宝分配给开发者的应用Id
            String notifyTime = conversionParams.get("notify_time");// 通知时间:yyyy-MM-dd HH:mm:ss
            String gmtCreate = conversionParams.get("gmt_create");// 交易创建时间:yyyy-MM-dd HH:mm:ss
            String gmtPayment = conversionParams.get("gmt_payment");// 交易付款时间
            //String gmtRefund = conversionParams.get("gmt_refund");// 交易退款时间
            //String gmtClose = conversionParams.get("gmt_close");// 交易结束时间
            String tradeNo = conversionParams.get("trade_no");// 支付宝的交易号
            String outTradeNo = conversionParams.get("out_trade_no");// 获取商户之前传给支付宝的订单号(商户系统的唯一订单号)
            //String outBizNo = conversionParams.get("out_biz_no");// 商户业务号(商户业务ID,主要是退款通知中返回退款申请的流水号)
            String buyerLogonId = conversionParams.get("buyer_logon_id");// 买家支付宝账号
            String buyerId = conversionParams.get("buyer_id"); //买家支付宝用户号(唯一)
            String sellerId = conversionParams.get("seller_id");// 卖家支付宝用户号
            String sellerEmail = conversionParams.get("seller_email");// 卖家支付宝账号
            String totalAmount = conversionParams.get("total_amount");// 订单金额:本次交易支付的订单金额,单位为人民币(元)
            String receiptAmount = conversionParams.get("receipt_amount");// 实收金额:商家在交易中实际收到的款项,单位为元
            //String invoiceAmount = conversionParams.get("invoice_amount");// 开票金额:用户在交易中支付的可开发票的金额
            String buyerPayAmount = conversionParams.get("buyer_pay_amount");// 付款金额:用户在交易中支付的金额
            String tradeStatus = conversionParams.get("trade_status");// 获取交易状态

            // 支付宝官方建议校验的值(out_trade_no、total_amount、sellerId、app_id)
            VideoOrder videoOrder = videoOrderMapper.selectOne(new QueryWrapper<VideoOrder>().eq("out_trade_no", outTradeNo));

            if (videoOrder != null && totalAmount.equals(videoOrder.getTotalFee().toString())) {
                // 修改数据库支付宝订单表(因为要保存每次支付宝返回的信息到数据库里,以便以后查证)

//                alipaymentOrder.setNotify_time(DateUtils.parse(notifyTime));  // 通知时间
//                alipaymentOrder.setGmt_create(DateUtils.parse(gmtCreate));      // 交易创建时间
//                alipaymentOrder.setGmt_payment(DateUtils.parse(gmtPayment));  // 交易付款时间
//                //alipaymentOrder.setGmt_refund(DateUtils.parse(gmtRefund));  // 交易退款时间
//                //alipaymentOrder.setGmt_close(DateUtils.parse(gmtClose));      // 交易结束时间
//                alipaymentOrder.setTrade_no(tradeNo);    // 支付宝交易号
//                //alipaymentOrder.setOut_biz_no(outBizNo);  // 商户业务号(商户业务ID,主要是退款通知中返回退款申请的流水号)
//                alipaymentOrder.setBuyer_logon_id(buyerLogonId);  // 买家支付宝账号
//                alipaymentOrder.setBuyer_id(buyerId); // 买家支付宝用户号(唯一)
//                alipaymentOrder.setSeller_id(sellerId);    // 卖家支付宝用户号
//                alipaymentOrder.setSeller_email(sellerEmail);  // 卖家支付宝账号
//                alipaymentOrder.setTotal_amount(Double.parseDouble(totalAmount));  //订单金额:本次交易支付的订单金额,单位为人民币(元)
//                alipaymentOrder.setReceipt_amount(Double.parseDouble(receiptAmount)); // 实收金额:商家在交易中实际收到的款项,单位为元
//                //alipaymentOrder.setInvoiceAmount(Double.parseDouble(invoiceAmount)); // 开票金额:用户在交易中支付的可开发票的金额
//                alipaymentOrder.setBuyer_pay_amount(Double.parseDouble(buyerPayAmount)); // 付款金额:用户在交易中支付的金额

                switch (tradeStatus) // 判断交易结果
                {
                    case "TRADE_FINISHED": // 交易结束并不可退款
                        videoOrder.setState(3);
                        break;
                    case "TRADE_CLOSED": // 未付款交易超时关闭或支付完成后全额退款
                        videoOrder.setState(2);
                        break;
                    case "TRADE_SUCCESS": // 交易支付成功
                        videoOrder.setState(1);
                        break;

                    case "WAIT_BUYER_PAY": // 交易创建并等待买家付款
                        videoOrder.setState(0);
                        break;
                    default:
                        break;
                }
                int returnResult = videoOrderMapper.updateById(videoOrder); // 更新交易表中状态

                if (tradeStatus.equals("TRADE_SUCCESS")) { // 只处理支付成功的订单:
                    // 修改交易表状态,支付成功
                    if (returnResult > 0) {
                        log.info("======更新商户订单表成功======");
                        return "success";
                    } else {
                        return "fail";
                    }
                } else {
                    return "fail";
                }

            } else {
                log.info("支付宝官方建议校验的值(out_trade_no、total_amount、sellerId、app_id),不一致!返回fail");
                return "fail";
            }

        } else { // 验签不通过
            log.info("验签不通过 !");
            return "fail";
        }
    }

    /**
     * 向支付宝发起退款请求
     */
    @Transactional(propagation = Propagation.REQUIRED)
    @Override
    public String alipayTradeRefund(String order_no, Double refund_fee) {
        String returnStr = null;
        int code;
        try {

            AlipayClient alipayClient = new DefaultAlipayClient(AppPayConfig.URL, AppPayConfig.APPID,
                    AppPayConfig.RSA_PRIVATE_KEY, "json", "utf-8",
                    AppPayConfig.ALIPAY_PUBLIC_KEY, "RSA2");

            AlipayTradeRefundRequest request = new AlipayTradeRefundRequest();//创建API对应的request类
            request.setBizContent("{" +
                    "    \"out_trade_no\":\"" + order_no + "\"," +
                    "    \"refund_amount\":\"" + refund_fee + "\"" +
                    "  }");//设置业务参数
            AlipayTradeRefundResponse response = alipayClient.execute(request);//通过alipayClient调用API,获得对应的response类

            log.info("退款返回参数====" + response);

            if (response.isSuccess()) {
                log.info("====支付宝退款成功");
                // 通过订单号查询到商家支付宝订单信息
                VideoOrder videoOrder = videoOrderMapper.selectOne(new QueryWrapper<VideoOrder>().eq("out_trade_no", order_no));

                if (videoOrder == null) {
                    log.info("该订单不存在");
                }
//                // 退款总金额
//                videoOrder.setRefund_fee(Double.valueOf(response.getRefundFee()));
//                // 退款时间
//                alipaymentOrder.setGmt_refund(response.getGmtRefundPay());
//                // 退款状态
//                alipaymentOrder.setTrade_status(AlipayReturnEnum.TRADE_CLOSED.getIndex());
//                // 本次退款是否发生了资金变化
//                alipaymentOrder.setFund_change(response.getFundChange());
//                // 交易在支付时候的门店名称
//                alipaymentOrder.setStore_name(response.getStoreName());
                videoOrder.setState(2);
                // 修改商家支付宝订单状态以及退款金额
                videoOrderMapper.updateById(videoOrder);

                returnStr = response.getMsg();
            } else {
                // 返回退款失败消息
                log.info("===退款失败===原因:" + response.getSubMsg());
                returnStr = response.getSubMsg();
            }
            code = Integer.parseInt(response.getCode());

        } catch (Exception e) {
            e.printStackTrace();
            TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
        }
        return returnStr;
    }
}

 

posted on 2021-05-31 16:37  java老三  阅读(590)  评论(0)    收藏  举报

导航