SpringBoot集成华为支付

华为支付

华为支付不像微信/支付宝支付那样的流程,而是直接由客户端APP进行发起的支付回调。

华为支付官网地址

个人支付案例git地址[微信支付/支付宝支付/华为支付/苹果支付/小米支付]:https://gitee.com/wazk2008/demo-pay

支付回调

yml配置

huawei:
  appid: 自己的appid
  client-secret: 自己的app对应的密钥

回调参数

@Data
public class PayHuaweiCallbackRequest implements Serializable {

    private String inAppDataSignature;

    private String inAppPurchaseData;

}
@Data
public class InAppPurchaseData implements Serializable {

    // (必要参数) 消耗型商品/非消耗型商品
    private Boolean autoRenewing;

    // (必要参数) 商户订单ID,唯一标识一次交易,由华为应用内支付服务器在支付时生成。
    private String orderId;

    // 应用安装包名。
    private String packageName;

    // (必要参数) 应用ID
    private Long applicationId;

    // (必要参数) 商品类别,取值包括:0:消耗型商品 1:非消耗型商品 2:订阅型商品
    private Integer kind;

    // (必要参数) 商品ID。每种商品必须有唯一的ID,由应用在PMS中维护,或者应用发起购买时传入。
    // 即 local_transaction_id 本地支付流水号
    private String productId;

    private String productName;

    // 商品购买时间的时间戳,即自1970年1月1日0时起到商品购买时间的毫秒数。
    private Long purchaseTime;

    // (必要参数) 订单交易状态。-1:初始化 0:已购买 1:已取消 2:已退款
    private Integer purchaseState;

    // (必要参数) 用于唯一标识商品和用户对应关系的购买令牌,在支付完成时由华为应用内支付服务器生成。
    private String purchaseToken;

    // 消费状态,仅一次性商品存在,取值包括: 0:未消费 1:已消费
    private String consumptionState;

    private String currency;

    private Long price;

    private String country;

    // (必要参数) 商户订单ID,唯一标识一次交易,由华为应用内支付服务器在支付时生成。
    // 即 third_transaction_id 第三方支付流水号
    private String payOrderId;

    private String payType;

    private Integer accountFlag;

}

回调Controller

@RestController
@RequestMapping(value = "/pay")
@Slf4j
public class PayController {

    @Autowired
    private HuaweiService huaweiService;

    @PostMapping(value = "/huaweiPayCallback")
    public Result<Object> payHuaweiCallback (@RequestBody PayHuaweiCallbackRequest payHuaweiCallbackRequest) {
        try {
            log.info("华为支付回调接口开始执行,请求参数:{}", JSON.toJSON(payHuaweiCallbackRequest));
            huaweiService.payCallback(payHuaweiCallbackRequest);
            log.info("华为支付回调接口执行成功,请求参数:{}", JSON.toJSON(payHuaweiCallbackRequest));
            return Result.getSuccess();
        } catch (ResponseException e) {
            log.error("华为支付回调接口执行失败1,请求参数:{},异常原因:{}", JSON.toJSON(payHuaweiCallbackRequest), e.getMessage());
            e.printStackTrace();
            return Result.getFail(e.getCode(), e.getMessage());
        } catch (Exception e) {
            log.error("华为支付回调接口执行失败2,请求参数:{},异常原因:{}", JSON.toJSON(payHuaweiCallbackRequest), e.getMessage());
            e.printStackTrace();
            return Result.getFail(ResultCode.INTERNAL_SERVER_ERROR);
        }
    }

}

回调Service

@Service
public class HuaweiService {

    private static final String ACCESS_TOKEN_URL = "https://oauth-login.cloud.huawei.com/oauth2/v3/token";
    private static final String TOKEN_VERIFY_HOST1 = "https://orders-drcn.iap.hicloud.com";
    private static final String TOKEN_VERIFY_HOST2 = "https://orders-at-dre.iap.dbankcloud.com";
    private static final String TOKEN_VERIFY_URL = "/applications/purchases/tokens/verify";

    @Value("${huawei.appid}")
    private String APP_ID;
    @Value("${huawei.client-secret}")
    private String CLIENT_SECRET;

    public void payCallback (PayHuaweiCallbackRequest payHuaweiCallbackRequest) throws Exception {
        // 校验 inAppPurchaseData
        InAppPurchaseData inAppPurchaseData = JSON.parseObject(payHuaweiCallbackRequest.getInAppPurchaseData(), InAppPurchaseData.class);
        Integer accountFlag = inAppPurchaseData.getAccountFlag();
        String productId = inAppPurchaseData.getProductId();
        String purchaseToken = inAppPurchaseData.getPurchaseToken();
        if (!verifyToken(purchaseToken, productId, accountFlag)) {
            throw new ResponseException(ResultCode.HUAWEI_PAY_VERIFY_PURCHASE_TOKEN_ERROR);
        }

        // todo 校验订单是否存在
        String outTradeNo = inAppPurchaseData.getProductId();

        // todo 校验订单是否已支付

        // todo 校验支付金额
        Double buyerPayAmount = Double.valueOf(inAppPurchaseData.getPrice()) / 100;

        // todo 修改支付和订单的状态

    }


    private boolean verifyToken(String purchaseToken, String productId, Integer accountFlag) throws Exception {
        String appAt = getAppAT();
        Map<String, String> headers = buildAuthorization(appAt);

        Map<String, String> bodyMap = new HashMap<>();
        bodyMap.put("purchaseToken", purchaseToken);
        bodyMap.put("productId", productId);

        String msgBody = JSONObject.toJSONString(bodyMap);

        String host = TOKEN_VERIFY_HOST1;
        if (!Objects.isNull(accountFlag) && accountFlag==1) {
            host = TOKEN_VERIFY_HOST2;
        }

        String response = httpPost(host + TOKEN_VERIFY_URL, "application/json; charset=UTF-8", msgBody, 5000, 5000, headers);
        JSONObject jsonRes = JSON.parseObject(response, JSONObject.class);

        return !Objects.isNull(jsonRes) && "0".equals(jsonRes.get("responseCode"));
    }

    private String getAppAT() throws Exception {
        String grantType = "client_credentials";
        String msgBody = MessageFormat.format("grant_type={0}&client_secret={1}&client_id={2}", grantType, URLEncoder.encode(CLIENT_SECRET, "UTF-8"), APP_ID);
        String response = httpPost(ACCESS_TOKEN_URL, "application/x-www-form-urlencoded; charset=UTF-8", msgBody, 5000, 5000, null);
        JSONObject obj = JSONObject.parseObject(response);
        return obj.getString("access_token");
    }

    private Map<String, String> buildAuthorization(String appAt) {
        String oriString = MessageFormat.format("APPAT:{0}", appAt);
        String authorization = MessageFormat.format("Basic {0}", Base64.encodeBase64String(oriString.getBytes(StandardCharsets.UTF_8)));
        Map<String, String> headers = new HashMap<>();
        headers.put("Authorization", authorization);
        headers.put("Content-Type", "application/json; charset=UTF-8");
        return headers;
    }

    private String httpPost(String httpUrl, String contentType, String data, int connectTimeout, int readTimeout,
                            Map<String, String> headers) throws IOException {
        OutputStream output = null;
        InputStream in = null;
        HttpURLConnection urlConnection = null;
        BufferedReader bufferedReader = null;
        InputStreamReader inputStreamReader = null;
        try {
            URL url = new URL(httpUrl);
            urlConnection = (HttpURLConnection) url.openConnection();
            urlConnection.setRequestMethod("POST");
            urlConnection.setDoOutput(true);
            urlConnection.setDoInput(true);
            urlConnection.setRequestProperty("Content-Type", contentType);
            if (headers != null) {
                for (String key : headers.keySet()) {
                    urlConnection.setRequestProperty(key, headers.get(key));
                }
            }
            urlConnection.setConnectTimeout(connectTimeout);
            urlConnection.setReadTimeout(readTimeout);
            urlConnection.connect();

            // POST data
            output = urlConnection.getOutputStream();
            output.write(data.getBytes("UTF-8"));
            output.flush();

            // read response
            if (urlConnection.getResponseCode() < 400) {
                in = urlConnection.getInputStream();
            } else {
                in = urlConnection.getErrorStream();
            }

            inputStreamReader = new InputStreamReader(in, "UTF-8");
            bufferedReader = new BufferedReader(inputStreamReader);
            StringBuilder strBuf = new StringBuilder();
            String str;
            while ((str = bufferedReader.readLine()) != null) {
                strBuf.append(str);
            }
            return strBuf.toString();
        } finally {
            if (bufferedReader != null) {
                bufferedReader.close();
            }
            if (inputStreamReader != null) {
                inputStreamReader.close();
            }
            if (in != null) {
                in.close();
            }
            if (urlConnection != null) {
                urlConnection.disconnect();
            }
        }
    }

}
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

难过的风景

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

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

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

打赏作者

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

抵扣说明:

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

余额充值