/**
* 请求付款相关工具
*
* @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);
}
}