/** * 请求付款相关工具 * * @author Luyao * */ public class PaymentKit { /** * 请求微信付款 * * @param orderNo * @param productName * @param amount * @param platform * @param openId * @return */ public static Ret requestWechatPay(String orderNo, String productName, BigDecimal amount, String notifyUrl, int platform, String... openId) { Prop prop = PropKit.use("wechat.txt"); // 应用id String appId = prop.get("mp_appid"); String tradeType = prop.get("mp_trade_type"); if (platform == PlatformEnum.APP.getCode()) { appId = prop.get("pay_appid"); tradeType = prop.get("app_trade_type"); } else if (platform == PlatformEnum.PC.getCode()) { appId = prop.get("pay_appid"); tradeType = prop.get("pc_trade_type"); } // 封装请求参数 Map<String, String> params = new HashMap<>(); params.put("appid", appId); // 商户id params.put("mch_id", prop.get("mchid")); // 随机数 params.put("nonce_str", StrKit.getRandomUUID()); // 商品信息 params.put("body", productName); // 订单号 params.put("out_trade_no", orderNo); // 订单金额 params.put("total_fee", String.valueOf(amount.multiply(new BigDecimal("100")).intValue())); // 回调地址 params.put("notify_url", PropKit.use("app_config.txt").get("domain_name") + notifyUrl); // 支付类型 params.put("trade_type", tradeType); // 支付超时时间 Calendar expiredTime = Calendar.getInstance(); expiredTime.add(Calendar.MINUTE, 5); params.put("time_expire", DateKit.toStr(expiredTime.getTime(), "yyyyMMddHHmmss")); // 如果是小程序支付,还需传入openId if (platform == PlatformEnum.MP.getCode()) { if (openId.length == 0 || StrKit.isBlank(openId[0])) return Ret.fail("msg", ErrorMsg.PARA_EMPTY); params.put("openid", openId[0]); } // MD5签名 String signKey = prop.get("key"); params.put("sign", StringKit.genMd5Sign(params, signKey)); // 发送付款请求并返回结果 String result = HttpKit.post(prop.get("pay_url"), StringKit.mapToXml(params)); if (StrKit.isBlank(result)) return Ret.fail("msg", ErrorMsg.REQUEST_FAIL); Map<String, String> response = StringKit.xmlToMap(result); // 请求成功需返回状态和返回结果均为成功 if (response == null || !response.get("return_code").equals(UserPaymetRecord.WechatResult.CODE) || !response.get("result_code").equals(UserPaymetRecord.WechatResult.CODE)) { LogKit.error("请求微信支付失败:" + response.get("err_code_des")); return Ret.fail("msg", ErrorMsg.REQUEST_FAIL); } // 根据不同平台返回不同数据 return packageWechatPayData(response, platform, signKey); } /** * 封装微信支付需要的参数 * * @param response * @param platform * @param signKey * @return */ private static Ret packageWechatPayData(Map<String, String> response, int platform, String signKey) { // 小程序和app支付,都需封装map Map<String, String> data = new HashMap<>(); if (platform == PlatformEnum.MP.getCode()) { // 小程序应用id data.put("appId", response.get("appid")); // 时间戳 data.put("timeStamp", new Date().getTime() + ""); // 随机字符串 data.put("nonceStr", StrKit.getRandomUUID()); // 数据包 data.put("package", "prepay_id=" + response.get("prepay_id")); // 签名方式 data.put("signType", "MD5"); // 数据签名 data.put("paySign", StringKit.genMd5Sign(data, signKey)); } else if (platform == PlatformEnum.APP.getCode()) { // APP应用id data.put("appid", response.get("appid")); // 商户id data.put("partnerid", response.get("mch_id")); // 预支付交易会话id data.put("prepayid", response.get("prepay_id")); // 数据包 data.put("package", "Sign=WXPay"); // 随机字符串 data.put("noncestr", StrKit.getRandomUUID()); // 时间戳 data.put("timestamp", new Date().getTime() + ""); // 数据签名 data.put("sign", StringKit.genMd5Sign(data, signKey)); } else { // PC端二维码支付,获取要生成二维码的付款链接 String codeUrl = response.get("code_url"); if (StrKit.isBlank(codeUrl)) return Ret.fail("msg", ErrorMsg.REQUEST_FAIL); // 生成Base64形式的包含微信支付logo的二维码图片并返回 // TODO return Ret.ok("data", codeUrl); } return Ret.ok("data", data); } /** * 微信支付回调处理 * * @param xmlData * @return */ public static Ret wechatCallback(String xmlData) { Map<String, String> xmlMap = new HashMap<>(); xmlMap.put("return_code", WechatResult.CODE); xmlMap.put("return_msg", WechatResult.MSG); String result = StringKit.mapToXml(xmlMap); // 判断是否为空 if (StrKit.notBlank(xmlData)) { // 校验签名 Map<String, String> data = StringKit.xmlToMap(xmlData); String signKey = PropKit.use("wechat.txt").get("key"); if (StringKit.verifyMd5Sign(data, signKey)) { // 判断支付状态 if (WechatResult.CODE.equals(data.get("result_code"))) { // 封装返回的数据 PaymentResult paymentResult = new PaymentResult(); paymentResult.setOrderNo(data.get("out_trade_no")); paymentResult.setPlatfromOrderNo(data.get("transaction_id")); paymentResult.setAmount(new BigDecimal(data.get("total_fee")).divide(new BigDecimal("100"))); // 转换日期格式:yyyyMMddHHmmss to -> yyyy-MM-dd HH:mm:ss String date = data.get("time_end"); String reg = "(\\d{4})(\\d{2})(\\d{2})(\\d{2})(\\d{2})(\\d{2})"; date = date.replaceAll(reg, "$1-$2-$3 $4:$5:$6"); paymentResult.setSuccessTime(DateKit.toDate(date)); // 将通知结果和返回参数一起封装 Map<String, Object> response = new HashMap<>(); response.put("xml", result); response.put("data", paymentResult); return Ret.ok("map", response); } } } return Ret.fail("xml", result); } /** * 请求支付宝付款 * * @param orderNo * @param productName * @param amount * @param notifyUrl * @param platform * @return */ public static Ret requestAlipay(String orderNo, String productName, BigDecimal amount, String notifyUrl, int platform) { Prop prop = PropKit.use("alipay.txt"); if (platform == PlatformEnum.APP.getCode()) { AlipayClient alipayClient = new DefaultAlipayClient(prop.get("open_api_domain"), prop.get("appid"), prop.get("private_key"), "JSON", Const.CHARSET, prop.get("alipay_public_key"), prop.get("sign_type")); AlipayTradeAppPayRequest request = new AlipayTradeAppPayRequest(); AlipayTradeAppPayModel model = new AlipayTradeAppPayModel(); model.setBody(productName); model.setSubject(productName); model.setOutTradeNo(orderNo); model.setTimeoutExpress("5m"); model.setTotalAmount(amount.toString()); model.setProductCode("QUICK_MSECURITY_PAY"); request.setBizModel(model); request.setNotifyUrl(PropKit.use("app_config.txt").get("domain_name") + notifyUrl); try { return Ret.ok("data", alipayClient.sdkExecute(request).getBody()); } catch (AlipayApiException e) { e.printStackTrace(); return Ret.fail("msg", ErrorMsg.REQUEST_FAIL); } } else if (platform == PlatformEnum.PC.getCode()) { // 创建扫码支付请求builder,设置请求参数 AlipayTradePrecreateRequestBuilder builder = new AlipayTradePrecreateRequestBuilder() .setSubject(productName).setTotalAmount(amount.toString()).setOutTradeNo(orderNo) .setTimeoutExpress("5m").setStoreId("001").setNotifyUrl(prop.get("domain_name") + notifyUrl); Configs.init("alipay.txt"); AlipayTradeService tradeService = new AlipayTradeServiceImpl.ClientBuilder().build(); AlipayTradePrecreateResponse response = tradeService.tradePrecreate(builder).getResponse(); if (response.isSuccess()) { // 生成Base64形式的包含支付宝logo的二维码图片并返回 // TODO return Ret.ok("data", response.getQrCode()); } return Ret.fail("msg", ErrorMsg.REQUEST_FAIL); } else { return Ret.fail("msg", ErrorMsg.PARA_ERROR); } } /** * 支付宝回调处理 * * @param params * @return */ public static Ret alipayCallback(Map<String, String[]> params) { // 解析参数 Map<String, String> data = new HashMap<>(); for (Iterator<String> iterator = params.keySet().iterator(); iterator.hasNext();) { String name = iterator.next(); String[] values = params.get(name); StringBuilder value = new StringBuilder(); for (String param : values) value.append(param); data.put(name, value.toString()); } String returnResult = AlipayResult.SUCCESS; // 判断是否为空 if (data.size() > 0) { // 校验签名 boolean result = false; try { result = AlipaySignature.rsaCheckV1(data, "your AlipayPublicKey", Const.CHARSET, "your SignType"); } catch (AlipayApiException e) { e.printStackTrace(); return Ret.fail("result", returnResult); } if (result) { // 判断支付状态 if (AlipayResult.TRADE_STATUS_SUCCESS.equals(data.get("trade_status"))) { // 封装返回的数据 PaymentResult paymentResult = new PaymentResult(); paymentResult.setOrderNo(data.get("out_trade_no")); paymentResult.setPlatfromOrderNo(data.get("trade_no")); paymentResult.setAmount(new BigDecimal(data.get("total_amount"))); paymentResult.setSuccessTime(DateKit.toDate(data.get("gmt_payment"))); // 将通知结果和返回参数一起封装 Map<String, Object> response = new HashMap<>(); response.put("result", returnResult); response.put("data", paymentResult); return Ret.ok("map", response); } } } return Ret.fail("result", returnResult); } }