Java之spring cloud框架实现支付宝支付功能

现在越来越多的企业愿意接入支付宝或微信的支付功能,因为受众面大,客户的信赖程度也高。

那么这篇文章简单来讲一讲我们如何在spring cloud框架下实现支付宝支付的功能。

常量配置

我们可以建立一个常量配置文件,例如就叫AlipayConfig

// 请求网关地址
public static final String URL = "https://openapi.alipay.com/gateway.do";
// 编码格式
public static final String CHARSET = "UTF-8";
// 返回格式
public static final String FORMAT = "json";
// 加密类型RSA2
public static final String SIGNTYPE = "RSA2";
// appid
public static final String h5APPID="*****";
// 支付公钥
public  static  final  String h5_ALIPAY_PUBLIC_KEY="";
// 应用私钥
public static final String h5_PRIVATE_KEY="";
配置回调地址和通知页面

回调地址和通知页面是在application.yml中配置的,代码如下:

阿里云支付回调(官方)这里配置回调用于处理支付成功后的逻辑
h5_alis_gf_notify_url: http://127.0.0.1:8888/uncheck/aliNotifyUrl
阿里云支付成功跳转(官方)这里配置支付完后跳转的页面
h5_alis_gf_query_url: https://127.0.0.1:8888/paySuccess
支付业务接口代码

这里主要定义了查询订单状态、统一下单拉起支付、支付完回调这3个接口

public interface AliPayAppService {
//查询订单状态 
Map<String,Object> getStatus(OrderVo orderVo); 
//统一下单拉起支付 
Map<String,Object>geth5AliPayOrderStr(OrderVo orderVo); 
//支付完回调 
String h5AliNotifyUrl(Map<String, String> conversionParams);
}
支付业务实现类

主要是对接口的业务实现,代码比较长

//支付回调地址
@Value(value="${h5_alis_gf_notify_url}")
private String h5_alis_gf_notify_url;
//支付成功地址
@Value(value="${h5_alis_gf_query_url}")
private String h5_alis_gf_query_url;
/**
 *
 * @param orderVo 订单实体类
 * @return
 */
@Override
public Map<String, Object> geth5AliPayOrderStr(OrderVo orderVo) {
    /*********************** 先校验订单有效性*********************************/


    Map<String, Object> map = new HashMap<>();
    // 最终返回加签之后的,app需要传给支付宝app的订单信息字符串
    String orderString = "0";
    logger.info("支付宝下单,商户订单号为:" + orderVo.geteName());

    //这个类对应的表存储支付完回调信息的
    Alipaymentorder alipaymentOrder = new Alipaymentorder();




    if (orderVo.geteId() != null) {
        alipaymentOrder.setOrderId(orderVo.geteId().longValue()); // 商户订单主键
    }
    alipaymentOrder.setOutTradeNo(orderVo.geteName());// 商户订单号
    alipaymentOrder.setTradeStatus(0);// 交易状态
    //这个金额正式的需要根据订单号去查
    alipaymentOrder.setTotalAmount(new BigDecimal(0.01));// 订单金额

    alipaymentOrder.setRefundFee(0.00); // 总退款金额

    try {
        // 实例化客户端(参数:网关地址、商户appid、商户私钥、格式、编码、支付宝公钥、加密类型),为了取得预付订单信息
        AlipayClient alipayClient = new DefaultAlipayClient(AlipayConfig.URL, AlipayConfig.h5APPID,
                AlipayConfig.h5_PRIVATE_KEY, AlipayConfig.FORMAT, AlipayConfig.CHARSET,
                AlipayConfig.h5_ALIPAY_PUBLIC_KEY, AlipayConfig.SIGNTYPE);

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

        // SDK已经封装掉了公共参数,这里只需要传入业务参数。以下方法为sdk的model入参方式
        AlipayTradeAppPayModel model = new AlipayTradeAppPayModel();

        model.setSubject("此订单"); // 商品名称
        model.setOutTradeNo(orderVo.geteName()); // 商户订单号
        // model.setTimeoutExpress("30m"); //交易超时时间

        model.setTotalAmount("0.01");

        /****************************/

        model.setProductCode("QUICK_WAP_WAY"); // 销售产品码(固定值)
        request.setBizModel(model);


        request.setNotifyUrl(h5_alis_gf_notify_url); // 异步回调地址(后台)
        request.setReturnUrl(h5_alis_gf_query_url);//设置支付成功跳转页面的地址
        //ali_request.setReturnUrl(AlipayAppConfig.return_url); // 同步回调地址(APP)
        //Requestcontent 是一个请求报文表与支付业务无关
        Requestcontent requestcontent=new Requestcontent();
        requestcontent.setContent(request.toString());//报文内容
        requestcontent.setContentType(Constants.CALLBACK_ALI_APP);//支付方式
        requestcontent.setContenTime(new Date());//时间
        requestcontent.setEntrydetailId(orderVo.geteName());//订单号
        requestcontentMapper.insertSelective(requestcontent);//添加报文
        // 这里和普通的接口调用不同,使用的是sdkExecute
        AlipayTradeWapPayResponse alipayTradeAppPayResponse = alipayClient.sdkExecute(request); // 返回支付宝订单信息(预处理)

        if(alipayTradeAppPayResponse.isSuccess()){
            // 如果商家订单表没有该订单数据则添加
            if (alipaymentorderService.getAlipaymentorder(orderVo.geteName()).size() == 0) {
                alipaymentorderService.addAlipaymentorder(alipaymentOrder); //创建新的商户支付宝订单
            }
            DateAndStrUtil strUtil = DateAndStrUtil.getDateAndStr();
            //DateAndStrUtil 是一个时间工具类 requestTimestamp格式为yyyy-MM-dd HH:mm:ss
            String requestTimestamp = strUtil.dateToStr(new Date());
            orderString = alipayTradeAppPayResponse.getBody();
            map.put("orderString", "https://openapi.alipay.com/gateway.do?"+orderString+"&timestamp="+requestTimestamp);
            //前端直接访问orderString", "https://openapi.alipay.com/gateway.do?"+orderString+"&timestamp="+requestTimestamp 即可拉起支付
            return Utils.packageResponseData(MapConstants.mapSuccessCode, "拉起成功", map);
        }else{
            return Utils.packageResponseData(MapConstants.mapErrorCode, "拉起失败", map);
        }



    } catch (Exception e) {
        e.printStackTrace();
        logger.info("与支付宝交互出错,未能生成订单,请检查代码!");
        return Utils.packageResponseData(MapConstants.mapErrorCode, "拉起失败", map);

    }



}

/**
 *功能描述: 支付宝查询订单状态
 * @author
 * @date 2020/7/2
 * @param orderVo
 * @return java.util.Map<java.lang.String,java.lang.Object>
 */

@Override
public Map<String, Object> getStatus(OrderVo orderVo) {

    Map<String,Object> map=new HashMap<>();

    if(Strings.isNullOrEmpty(orderVo.geteName())) {
        return Utils.packageResponseData(MapConstants.mapNullCode, "订单号不能为空", map);
    }
    AlipayClient alipayClient = new DefaultAlipayClient(AlipayConfig.URL, AlipayConfig.h5APPID,
            AlipayConfig.h5_PRIVATE_KEY, AlipayConfig.FORMAT, AlipayConfig.CHARSET,
            AlipayConfig.h5_ALIPAY_PUBLIC_KEY, AlipayConfig.SIGNTYPE);

    // 实例化具体API对应的request类,类名称和接口名称对应,当前调用接口名称:alipay.trade.app.pay
    AlipayTradeQueryRequest request = new AlipayTradeQueryRequest();
    request.setBizContent("{" + "\"out_trade_no\" : \"" + orderVo.geteName() + "\"}");
    try {
        AlipayTradeQueryResponse response = alipayClient.execute(request);
        if (response.isSuccess()) {
            switch (response.getTradeStatus()) // 判断交易结果
            {
                case "TRADE_FINISHED": // 交易结束并不可退款
                    map.put("status",3);
                    break;
                case "TRADE_SUCCESS": // 交易支付成功
                    map.put("status",2);
                    break;
                case "TRADE_CLOSED": // 未付款交易超时关闭或支付完成后全额退款
                    map.put("status",1);
                    break;
                case "WAIT_BUYER_PAY": // 交易创建并等待买家付款
                    map.put("status",0);
                    break;
                default:
                    break;
            }
            return Utils.packageResponseData(MapConstants.mapSuccessCode, "查询成功", map);

        } else {
            logger.info("调用支付宝查询接口失败!");
            return Utils.packageResponseData(MapConstants.mapErrorCode, "调用支付宝查询接口失败!", map);

        }

    } catch (Exception e) {
        e.printStackTrace();
        return Utils.packageResponseData(MapConstants.mapErrorCode, "查询失败", map);
    }

}
//官方支付宝异步请求逻辑处理
@Override
public String h5AliNotifyUrl(Map<String, String> conversionParams) {
    logger.info("官方支付宝异步请求逻辑处理");

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

    try {
        // 调用SDK验证签名
        signVerified = AlipaySignature.rsaCheckV1(conversionParams, AlipayConfig.h5_ALIPAY_PUBLIC_KEY,
                AlipayConfig.CHARSET, AlipayConfig.SIGNTYPE);

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

    // 对验签进行处理
    if (signVerified) {
        System.out.println("支付宝回调验签通过");
        // 验签通过
        // 获取需要保存的数据
        String appId = conversionParams.get("app_id");

        Alipaymentorder alipaymentOrder=getAlipayMent(conversionParams);

        if (AlipayConfig.h5APPID.equals(appId)) {
            EntrydetailExample entrydetailExample=new EntrydetailExample();
            entrydetailExample.createCriteria().andENameEqualTo(alipaymentOrder.getOutTradeNo());
            List<Entrydetail> list=entrydetailMapper.selectByExample(entrydetailExample);
            alipaymentOrder.setUserId(list.get(0).geteUid());
            //更新回调表中的内容
            int returnResult = alipaymentorderService.updateAlipaymentorder(alipaymentOrder); // 更新交易表中状态
            // 修改交易表状态,支付成功
            if (returnResult > 0) {
                logger.info("======官方支付宝更新商户订单表成功======");

                return "SUCCESS";//如果不反回将会持续回调24小时


            } else {
                logger.info("更新表状态失败");

                return "FAILED";
            }


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

            return "FAILED";
        }

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

        return "FAILED";

    }
}
//回调用到的getAlipayMent方法
public Alipaymentorder getAlipayMent(Map<String, String> conversionParams){
    DateAndStrUtil dateAndStrUtil = new DateAndStrUtil();
    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 tradeNo = conversionParams.get("trade_no");// 支付宝的交易号
    String outTradeNo = conversionParams.get("out_trade_no");// 获取商户之前传给支付宝的订单号(商户系统的唯一订单号)

    String totalAmount = conversionParams.get("total_amount");// 订单金额:本次交易支付的订单金额,单位为人民币(元)
    String receiptAmount = conversionParams.get("receipt_amount");// 实收金额:商家在交易中实际收到的款项,单位为元

    String buyerPayAmount = conversionParams.get("buyer_pay_amount");// 付款金额:用户在交易中支付的金额
    String tradeStatus = conversionParams.get("trade_status");// 获取交易状态

    // 支付宝官方建议校验的值(out_trade_no、total_amount、sellerId、app_id)
    List<Alipaymentorder> alipaymentOrderList = alipaymentorderService.getAlipaymentorder(outTradeNo);
    Alipaymentorder alipaymentOrder = alipaymentOrderList.get(0);
    alipaymentOrder.setNotifyTime(dateAndStrUtil.strToDate(notifyTime));  // 通知时间
    alipaymentOrder.setGmtCreate(dateAndStrUtil.strToDate(gmtCreate));      // 交易创建时间
    alipaymentOrder.setGmtPayment(dateAndStrUtil.strToDate(gmtPayment));  // 交易付款时间
    //alipaymentOrder.setGmt_refund(DateUtils.parse(gmtRefund));  // 交易退款时间
    //alipaymentOrder.setGmt_close(DateUtils.parse(gmtClose));   // 交易结束时间
    alipaymentOrder.setTradeNo(tradeNo);    // 支付宝交易号
    //alipaymentOrder.setOut_biz_no(outBizNo);  // 商户业务号(商户业务ID,主要是退款通知中返回退款申请的流水号)

    alipaymentOrder.setTotalAmount(new BigDecimal(totalAmount));  //订单金额:本次交易支付的订单金额,单位为人民币(元)
    alipaymentOrder.setReceiptAmount(new BigDecimal(receiptAmount)); // 实收金额:商家在交易中实际收到的款项,单位为元
    //alipaymentOrder.setInvoiceAmount(Double.parseDouble(invoiceAmount)); // 开票金额:用户在交易中支付的可开发票的金额
    alipaymentOrder.setBuyerPayAmount(new BigDecimal(buyerPayAmount)); // 付款金额:用户在交易中支付的金额
    Utils.getStatus(alipaymentOrder,tradeStatus);
    return alipaymentOrder;
}
util工具类

在实现业务逻辑的过程中,将一些通用的代码抽象到工具类里面

public class Utils {


public static void getStatus(Alipaymentorder alipaymentorder,String status){



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


/**
*
* MapString
* @param map
* @return
*/
public static String getMapToString(Map<String,String> map){
Set<String> keySet = map.keySet();
//将set集合转换为数组
String[] keyArray = keySet.toArray(new String[keySet.size()]);
//给数组排序(升序)
Arrays.sort(keyArray);
//因为String拼接效率会很低的,所以转用StringBuilder
StringBuilder sb = new StringBuilder();
for (int i = 0; i < keyArray.length; i++) {
// 参数值为空,则不参与签名 这个方法trim()是去空格
if ((String.valueOf(map.get(keyArray[i]))).trim().length() > 0) {
sb.append(keyArray[i]).append(":").append(String.valueOf(map.get(keyArray[i])).trim());
}
if(i != keyArray.length-1){
sb.append(",");
}
}
return sb.toString();
}
}
支付控制器

这是控制器的代码,作为支付服务的入口。

/**
 *功能描述:支付宝拉起支付
 * @author 666
 * @date 2020/7/6
 * @return java.util.Map<java.lang.String,java.lang.Object>
 */
@RequestMapping(value="/geth5AliPayOrderStr",method= RequestMethod.POST)
public Map<String,Object> geth5AliPayOrderStr(@RequestBody OrderVo orderVo){

    return  aliPayAppService.geth5AliPayOrderStr(orderVo);
}
/**
 *功能描述:查询订单状态
 * @author 666
 * @date 2020/7/2
 * @param orderVo
 * @return java.util.Map<java.lang.String,java.lang.Object>
 */

@RequestMapping(value = "/getStatus", method = RequestMethod.POST)
public Map<String, Object> getStatus(@RequestBody OrderVo orderVo) {

    return aliPayAppService.getStatus(orderVo);

}
/**
 * 支付宝官方回调
 * @param request
 * @param response
 * @return
 */
@RequestMapping(value="/h5AliNotifyUrl",method= RequestMethod.POST)
public String h5AliNotifyUrl(HttpServletRequest request, HttpServletResponse response) {

    logger.info("官方支付宝异步返回支付结果开始");

    String map = aliPayAppService.h5AliNotifyUrl(Utils.map(request, response));

    return map;
}

到此,支付宝的支付功能就实现了。

发表评论

邮箱地址不会被公开。 必填项已用*标注