Java服务端对接支付宝支付,付款,退款,查看支付信息

史上最简单Java服务端对接支付宝支付教程,前端为APP。

一、支付业务流程

官方开发文档:https://docs.open.alipay.com/204/105297/
Java服务端对接支付宝支付,付款,退款,查看支付信息_第1张图片

  1. 下单时前端请求后台获取支付字符串
  2. 后台接收到请求支付字符串的请求,先处理自己的业务(生成待支付订单),然后根据支付配置参数生成加密字符串返回给前端
  3. 前端接收到支付字符串,吊起支付宝支付
  4. 支付宝支付完成后会主动访问我们配置好服务端的回调接口(异步回调),同时会同步回调给前端
  5. 我们根据支付宝的回调请求,获取回调参数,判断支付状态,进行下一步的业务处理(修改订单为已支付状态)

以上就是整个支付流程了,吭哧吭哧,开搞!

二、获取支付配置参数

在支付宝开放平台申请应用权限,开通支付功能,生成应用的私钥,公钥等等就不赘述了。上面贴的官方文档里面都有介绍。下面是需要用到的参数:
Java服务端对接支付宝支付,付款,退款,查看支付信息_第2张图片

三、代码实现

环境:

  • JDK8
  • SpringBoot - 2.1.5.RELEASE
  • IDEA - 2019.2

1、支付宝依赖


   com.alipay.sdk
    alipay-sdk-java
    3.3.4.ALL

2、配置参数

@Slf4j
public class AliPayProperties {

    public static final String APP_ID = "20...8";//APPID
    public static final String PRIVATE_KEY = "MIIEvgI.......q9s";//你的应用私钥
    public static final String PUBLIC_KEY = "MIIBIjA.......QAB";//支付宝公钥
    public static final String NOTIFY_URL = "http://..../v1/pay/ali/notify/";//你的支付回调地址
    public static final String RETURN_URL = "http://..../v1/pay/ali/notify/";//你的支付回调地址
    public static final String SIGN_TYPE = "RSA2";//签名加密类型(固定)
    public static final String CHARSET = "utf-8";
    public static final String GATEWAY_URL = "https://openapi.alipay.com/gateway.do";//支付宝网关(固定)
    public static final String FORMAT = "json";

}

3、Controller

@RestController
@RequestMapping("/v1/pay/ali")
@Slf4j
public class AliPayController {

    @Autowired
    private AliPayUtil aliPayUtil;

    /** * 获取支付宝支付加密字符串 * * @param * @param * @return * @throws Exception */
    @PostMapping(value = "/getAppPayOrderStr")
    @ApiOperation(value = "支付宝支付")
    @NoMaybeResponse//自定义注解,封装返回值的
    public String getAppPayOrderStr(@RequestBody @Validated AliPayDTO aliPayDTO) {
        return aliPayUtil.getAliPayOrderStr(aliPayDTO, CurrentUserSession.getUserId());
    }

    /** * 支付宝回调 * 注意,这个接口必须是开放式的,项目启动,能随便访问,避开自己项目的网关,验证之类的。 * @param request * @throws Exception */
    @RequestMapping(value = "/notify")
    @ApiOperation(value = "支付宝回调接口")
    public String notify(HttpServletRequest request) {
        return aliPayUtil.notify(request);
    }
}

AliPayDTO 是自定义的业务类,根据自己项目需要定义,我这里就传了订单的id,支付业务类型-订单支付。把各种支付的业务场景整合到一起了的。

4、处理支付

AliPayDTO.java

@Data
public class AliPayDTO {

    @ApiModelProperty("订单编号集-订单支付才需要传")
    private List<Long> orderNos;

    @ApiModelProperty("支付类型(必传) 1-订单第一次支付 2-订单补款 3-服务费充值")
    @NotNull
    private Integer payType;

    @ApiModelProperty("金额-服务费充值才需要传")
    private BigDecimal money;

    @ApiModelProperty("备用字段")
    private String temp;
}

AliPayUtil.java
包含了支付,支付回调,退款,查看支付信息等方法。

@Slf4j
@Component
public class AliPayUtil {

    @Autowired
    TOrderMapper orderMapper;

    @Autowired
    TOrderLineMapper orderLineMapper;

    @Autowired
    IOrderService orderService;

    @Autowired
    private IUserService userService;

    /** * 业务逻辑处理 * * @return */
    public String getAliPayOrderStr(AliPayDTO aliPayDTO, String userId) {
        if (aliPayDTO.getPayType().equals(PayServiceTypeEnum.SERVICE_FEE.getCode())) {
            //服务费充值业务处理
            WXServiceRechargeDTO rechargeDTO = new WXServiceRechargeDTO();
            rechargeDTO.setServiceMoney(aliPayDTO.getMoney());
            long no = userService.addServiceRecharge(rechargeDTO, userId);
            aliPayDTO.setTemp(String.valueOf(no));
            //获取支付字符串
            return this.createAliPayString(aliPayDTO);
        } else if (aliPayDTO.getPayType().equals(PayServiceTypeEnum.ORDER.getCode())) {
            // TODO 订单支付
            return null;
        } else {
            return null;
        }
    }

    /** * 获取支付宝加签后台的订单信息字符串 * * @return */
    public String createAliPayString(AliPayDTO aliPayDTO) {
        try {
            //实例化客户端
            AlipayClient alipayClient = this.getAliPayClient();
            AlipayTradeAppPayRequest aliPayRequest = new AlipayTradeAppPayRequest();
            AlipayTradeAppPayModel model = new AlipayTradeAppPayModel();
            model.setBody(JSONObject.toJSONString(aliPayDTO.getOrderNos()));
            model.setSubject("不可能科技支付宝销售订单");
            // 支付订单号 本系统定义的支付单号
            model.setOutTradeNo(RandomUtils.createNo32());
            // 业务参数(支付业务类型,订单的id),json格式,必须URLEncoder编码(可以把在回调时需要的参数放在这里,支付宝会原样返回)
            model.setPassbackParams(URLEncoder.encode(JSONObject.toJSONString(aliPayDTO), "GBK"));
            // 支付超时时间
            model.setTimeoutExpress("30m");
            // 支付金额 aliPayDTO.getMoney()
            model.setTotalAmount("0.01");
            model.setProductCode("QUICK_MSECURITY_PAY");
            aliPayRequest.setBizModel(model);
            // 支付成功后 接收支付宝异步通知的服务端url
            aliPayRequest.setNotifyUrl(AliPayProperties.NOTIFY_URL);
            AlipayTradeAppPayResponse aliPayResponse = alipayClient.sdkExecute(aliPayRequest);
            return aliPayResponse.getBody();
        } catch (UnsupportedEncodingException e) {
            throw new BusinessException(BusinessErrorCode.FAIL);
        } catch (AlipayApiException e) {
            log.info("getAliPayOrderStr error :{}", e);
            throw new BusinessException(BusinessErrorCode.GET_ALIPAY_PAY_STR_ERROR);
        }
    }

    public String notify(HttpServletRequest request) {
        log.info("支付宝支付回调开始----------------------------------------------------------!");
        //从支付宝回调的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] + ",";
            }
            // 解决乱码
            // valueStr = new String(valueStr.getBytes("ISO-8859-1"), "uft-8");
            conversionParams.put(key, valueStr);
        }
        return this.notify(conversionParams);
    }

    /** * 验证回调参数,根据支付的业务类型处理数据 * * @param conversionParams * @return */
    private String notify(Map<String, String> conversionParams) {
        //签名验证(对支付宝返回的数据验证,确定是支付宝返回的)
        boolean signVerified = false;
        try {
            //调用SDK验证签名
            signVerified = AlipaySignature.rsaCheckV1(conversionParams, AliPayProperties.PUBLIC_KEY, AliPayProperties.CHARSET, AliPayProperties.SIGN_TYPE);
        } catch (AlipayApiException e) {
            log.debug("支付宝回调,SDK验证签名失败!");
            e.printStackTrace();
        }
        if (signVerified) {
            //验签通过 修改订单状态
            String appId = conversionParams.get("app_id");
            //订单金额:本次交易支付的订单金额,单位为人民币(元)
            String totalAmount = conversionParams.get("total_amount");
            //业务参数 AliPayDTO
            String passbackParams = conversionParams.get("passback_params");
            //支付宝的交易号
            String tradeNo = conversionParams.get("trade_no");
            //商户系统的唯一订单号
            String outTradeNo = conversionParams.get("out_trade_no");
            // 获取交易状态
            String tradeStatus = conversionParams.get("trade_status");
            try {
                passbackParams = URLDecoder.decode(passbackParams, "GBK");
            } catch (UnsupportedEncodingException e) {
                log.info("URLDecoder.decode error");
            }
            // 支付的类型和关联的订单号
            AliPayDTO aliPayDTO = JSONArray.parseObject(passbackParams, AliPayDTO.class);
            log.info("本次支付类型:{},关联的订单号:{},本次支付总金额:{},appId:{},aliPayDTO:{}", aliPayDTO.getPayType(), aliPayDTO.getOrderNos(), totalAmount, appId, aliPayDTO);
            //验证支付状态
            boolean payStatus = false;
            switch (tradeStatus) {
                case "TRADE_FINISHED": //完成
                case "TRADE_SUCCESS":
                    payStatus = true;
                    break;
                case "WAIT_BUYER_PAY": //待支付
                    break;
                case "TRADE_CLOSED": //交易关闭
                    break;
                default:
                    break;
            }
            if (payStatus) {
                if (aliPayDTO.getPayType().equals(PayServiceTypeEnum.ORDER.getCode())) {
                    //TODO 订单支付
                } else if (aliPayDTO.getPayType().equals(PayServiceTypeEnum.SERVICE_FEE.getCode())) {
                    //服务费充值
                    Map<String, Object> params = new HashMap<>(2);
                    params.put("no", aliPayDTO.getTemp());
                    userService.rechargeNotify(params, tradeNo, null);
                }
                return "success";
            } else {
                return null;
            }
        } else {
            log.info("验签不通过");
            return "fail";
        }
    }

    /** * 查看支付订单信息 * * @param outTradeNo 商户网站唯一订单号 * @param tradeNo 支付宝交易号 * @return 公共响应参数 code,msg 响应参数: https://docs.open.alipay.com/api_1/alipay.trade.query */
    public String queryPayment(String outTradeNo, String tradeNo) {
        AlipayClient alipayClient = this.getAliPayClient();
        AlipayTradeQueryRequest alipayTradeQueryRequest = new AlipayTradeQueryRequest();
        AlipayTradeQueryModel model = new AlipayTradeQueryModel();
        model.setOutTradeNo(outTradeNo);
        model.setTradeNo(tradeNo);
        alipayTradeQueryRequest.setBizModel(model);
        try {
            AlipayTradeQueryResponse alipayTradeQueryResponse = alipayClient.execute(alipayTradeQueryRequest);
            String queryPaymentStr = alipayTradeQueryResponse.getBody();
            log.info("订单号:{},支付宝支付单号:{}", outTradeNo, tradeNo);
            return queryPaymentStr;
        } catch (AlipayApiException e) {
            e.printStackTrace();
        }
        return null;
    }

    /** * 支付宝订单退款 * * @param outTradeNo 本系统生成的商户订单编号 * @param tradeNo 支付宝订单交易号 * @param refundAmount 退款金额 不得大于订单金额 * @param refundReason 退款说明 * @param outRequestNo 标识一次退款请求,同一笔交易多次退款需要保证唯一,如需部分退款,则此参数必传。 * @return 公共返回参数 code,msg, 响应参数实例: https://docs.open.alipay.com/api_1/alipay.trade.refund */
    public void alipayRefund(String outTradeNo, String tradeNo, String refundAmount, String refundReason, String outRequestNo) {
        log.info("支付宝退款开始------------------------------------------------------!");
        AlipayClient alipayClient = this.getAliPayClient();
        //订单编号,支付宝交易号不为空
        if (outTradeNo != null && tradeNo != null) {
            AlipayTradeRefundRequest aliPayRequest = new AlipayTradeRefundRequest();
            AlipayTradeRefundModel model = new AlipayTradeRefundModel();
            model.setOutTradeNo(outTradeNo);
            model.setTradeNo(tradeNo);
            model.setRefundAmount(refundAmount);
            model.setRefundReason(refundReason);
            model.setOutRequestNo(outRequestNo);
            aliPayRequest.setBizModel(model);
            try {
                AlipayTradeRefundResponse aliPayResponse = alipayClient.execute(aliPayRequest);
                log.debug("aliPayResponse:{}", aliPayResponse);
                if (!"10000".equals(aliPayResponse.getCode())) {
                    log.info("支付宝退款失败,支付宝交易号:{},状态码:{}", tradeNo, aliPayResponse.getCode());
                    throw new BusinessException(BusinessErrorCode.ALIPAY_PAY_REFUND_ERROR);
                }
            } catch (AlipayApiException e) {
                e.printStackTrace();
            }
        }
    }

    /** * 获取支付宝Client * * @return */
    private AlipayClient getAliPayClient() {
        return new DefaultAlipayClient(
                AliPayProperties.GATEWAY_URL, AliPayProperties.APP_ID, AliPayProperties.PRIVATE_KEY, AliPayProperties.FORMAT,
                AliPayProperties.CHARSET, AliPayProperties.PUBLIC_KEY, AliPayProperties.SIGN_TYPE);
    }
}

就这么简单,支付宝支付,退款就可以对接完成。

你可能感兴趣的:(JAVA,SpringBoot,其他)