APP下单
商户系统先调用该接口在微信支付服务后台生成预支付交易单,返回正确的预支付交易会话标识后再按Native、JSAPI、APP等不同场景生成交易串调起支付。
代码
public static Object createOrder(String desc,Long amount,String orderSn) throws Exception {
PrivateKey merchantPrivateKey = PemUtil.loadPrivateKey(new ByteArrayInputStream(PayConstants.PRIVATE_KEY.getBytes(StandardCharsets.UTF_8)));
// 使用定时更新的签名验证器,不需要传入证书
ScheduledUpdateCertificatesVerifier verifier = new ScheduledUpdateCertificatesVerifier(
new WechatPay2Credentials(PayConstants.MCH_ID, new PrivateKeySigner(PayConstants.MCH_SERIAL_NO, merchantPrivateKey)),
PayConstants.API_V3KEY.getBytes(StandardCharsets.UTF_8));
CloseableHttpClient httpClient = WechatPayHttpClientBuilder.create()
.withMerchant(PayConstants.MCH_ID, PayConstants.MCH_SERIAL_NO, merchantPrivateKey)
.withValidator(new WechatPay2Validator(verifier))
.build();
HttpPost httpPost = new HttpPost("https://api.mch.weixin.qq.com/v3/pay/transactions/app");
httpPost.addHeader("Accept", "application/json");
httpPost.addHeader("Content-type","application/json; charset=utf-8");
ByteArrayOutputStream bos = new ByteArrayOutputStream();
ObjectMapper objectMapper = new ObjectMapper();
ObjectNode rootNode = objectMapper.createObjectNode();
rootNode.put("mchid", PayConstants.MCH_ID)
.put("appid", PayConstants.APP_ID)
.put("notify_url", PayConstants.NOTIFY_URL)
.put("description", desc)
.put("out_trade_no", orderSn);
rootNode.putObject("amount")
.put("total", amount);
objectMapper.writeValue(bos, rootNode);
httpPost.setEntity(new StringEntity(bos.toString("UTF-8"), "UTF-8"));
CloseableHttpResponse response = httpClient.execute(httpPost);
String bodyAsString = EntityUtils.toString(response.getEntity());
JsonNode node = objectMapper.readTree(bodyAsString);
System.out.println(node.get("prepay_id"));官方文档:微信支付-开发者文档
APP调起支付
通过APP下单接口获取到发起支付的必要参数prepay_id,可以按照接口定义中的规则,使用微信支付提供的SDK调起APP支付。
APP调起支付的参数需要按照签名规则进行签名计算:
1、构造签名串
签名串一共有四行,每一行为一个参数。行尾以\n(换行符,ASCII编码值为0x0A)结束,包括最后一行。 如果参数本身以\n结束,也需要附加一个\n
参与签名字段及格式
应用id
时间戳
随机字符串
预支付交易会话ID
数据举例
wx8888888888888888
1414561699
5K8264ILTKCH16CQ2502SI8ZNMTM67VS
WX1217752501201407033233368018
代码
//获取当前时间戳
String timestamp = System.currentTimeMillis() + "";
//随机字符串
String nonce = RandomUtil.randomString(32);
StringBuilder builder = new StringBuilder();
//应用id
builder.append(PayConstants.APP_ID).append("\n");
//时间戳
builder.append(timestamp).append("\n");
//随机字符串
builder.append(nonce).append("\n");
JsonNode node = objectMapper.readTree(bodyAsString);
//预支付交易会话ID
builder.append(node.get("prepay_id")).append("\n");2、计算签名值
static String sign(byte[] message) throws SignatureException, NoSuchAlgorithmException, InvalidKeyException{
Signature sign = Signature.getInstance("SHA256withRSA");
sign.initSign(PemUtil.loadPrivateKey(PayConstants.PRIVATE_KEY));
sign.update(message);
return Base64.getEncoder().encodeToString(sign.sign());
}String signature = sign(builder.toString().replace("\"","").getBytes(StandardCharsets.UTF_8));
System.out.println(signature);返回示例
Map<Object,Object> result = new HashMap<>();
result.put("nonceStr",nonce);
result.put("package",PayConstants.PACKAGE);
result.put("timestamp",timestamp);
result.put("sign",signature);
result.put("prepayId",node.get("prepay_id"));
result.put("mchId",PayConstants.MCH_ID);
logger.info("【请求结束】创建订单,result:{}", JSONObject.toJSONString(result));
return ResponseUtil.ok(result);创建订单完整代码
/**
* 创建订单
* @param desc
* @param amount
* @return
* @throws IOException
* @throws IllegalBlockSizeException
*/
public static Object createOrder(String desc,Long amount,String orderSn) throws Exception {
PrivateKey merchantPrivateKey = PemUtil.loadPrivateKey(new ByteArrayInputStream(PayConstants.PRIVATE_KEY.getBytes(StandardCharsets.UTF_8)));
// 使用定时更新的签名验证器,不需要传入证书
ScheduledUpdateCertificatesVerifier verifier = new ScheduledUpdateCertificatesVerifier(
new WechatPay2Credentials(PayConstants.MCH_ID, new PrivateKeySigner(PayConstants.MCH_SERIAL_NO, merchantPrivateKey)),
PayConstants.API_V3KEY.getBytes(StandardCharsets.UTF_8));
CloseableHttpClient httpClient = WechatPayHttpClientBuilder.create()
.withMerchant(PayConstants.MCH_ID, PayConstants.MCH_SERIAL_NO, merchantPrivateKey)
.withValidator(new WechatPay2Validator(verifier))
.build();
HttpPost httpPost = new HttpPost("https://api.mch.weixin.qq.com/v3/pay/transactions/app");
httpPost.addHeader("Accept", "application/json");
httpPost.addHeader("Content-type","application/json; charset=utf-8");
ByteArrayOutputStream bos = new ByteArrayOutputStream();
ObjectMapper objectMapper = new ObjectMapper();
ObjectNode rootNode = objectMapper.createObjectNode();
rootNode.put("mchid", PayConstants.MCH_ID)
.put("appid", PayConstants.APP_ID)
.put("notify_url", PayConstants.NOTIFY_URL)
.put("description", desc)
.put("out_trade_no", orderSn);
rootNode.putObject("amount")
.put("total", amount);
objectMapper.writeValue(bos, rootNode);
httpPost.setEntity(new StringEntity(bos.toString("UTF-8"), "UTF-8"));
CloseableHttpResponse response = httpClient.execute(httpPost);
String bodyAsString = EntityUtils.toString(response.getEntity());
System.out.println(bodyAsString);
//获取当前时间戳
String timestamp = System.currentTimeMillis() + "";
//随机字符串
String nonce = RandomUtil.randomString(32);
StringBuilder builder = new StringBuilder();
//应用id
builder.append(PayConstants.APP_ID).append("\n");
//时间戳
builder.append(timestamp).append("\n");
//随机字符串
builder.append(nonce).append("\n");
JsonNode node = objectMapper.readTree(bodyAsString);
//预支付交易会话ID
builder.append(node.get("prepay_id")).append("\n");
System.out.println(builder.toString().replace("\"",""));
String signature = sign(builder.toString().replace("\"","").getBytes(StandardCharsets.UTF_8));
System.out.println(signature);
Map<Object,Object> result = new HashMap<>();
result.put("nonceStr",nonce);
result.put("package",PayConstants.PACKAGE);
result.put("timestamp",timestamp);
result.put("sign",signature);
result.put("prepayId",node.get("prepay_id"));
result.put("mchId",PayConstants.MCH_ID);
logger.info("【请求结束】创建订单,result:{}", JSONObject.toJSONString(result));
return ResponseUtil.ok(result);
}配置类
package com.qiguliuxing.dts.core.util.wechat;
/**
* @author Xiong
* @date 2021/12/6 21:55
*/
public interface PayConstants {
/**
* 支付成功回调地址
*/
String NOTIFY_URL = "";
/**
* 商户号
*/
String MCH_ID = "";
/**
* 商户证书序列号
*/
String MCH_SERIAL_NO = "";
/**
* api密钥
*/
String API_V3KEY = "";
/**
* appId
*/
String APP_ID = "";
/**
* 签名固定字符串(微信要求的)
*/
String PACKAGE = "Sign=WXPay";
/**
* 你的商户私钥
*/
String PRIVATE_KEY = "-----BEGIN PRIVATE KEY-----\n" +
"" +
"-----END PRIVATE KEY-----";
}微信回调
/**
* 微信回调接口
* @param request
* @return
*/
public Map<Object,Object> weChatCallback(HttpServletRequest request){
logger.info("【请求开始】微信回调接口,body:{}",request);
logger.info("Wechatpay-Timestamp:" + request.getHeader("Wechatpay-Timestamp"));
logger.info("Wechatpay-Nonce:" + request.getHeader("Wechatpay-Nonce"));
logger.info("Wechatpay-Signature:" + request.getHeader("Wechatpay-Signature"));
logger.info("Wechatpay-Serial:" + request.getHeader("Wechatpay-Serial"));
Map<Object,Object> result = new HashMap<>();
result.put("code","FAIL");
try {
StringBuilder signStr = new StringBuilder();
signStr.append(request.getHeader("Wechatpay-Timestamp")).append("\n");
signStr.append(request.getHeader("Wechatpay-Nonce")).append("\n");
BufferedReader br = request.getReader();
String str = null;
StringBuilder builder = new StringBuilder();
while ((str = br.readLine()) != null){
builder.append(str);
}
signStr.append(builder).append("\n");
//验证签名
if (!PayUtil.signVerify(request.getHeader("Wechatpay-Serial"),signStr.toString(),request.getHeader("Wechatpay-Signature"))){
result.put("message","sign error");
return result;
}
ObjectMapper objectMapper = new ObjectMapper();
JsonNode node = objectMapper.readTree(builder.toString());
JsonNode resource = node.get("resource");
String ciphertext = resource.get("ciphertext").textValue().replace("\"","");
//解密密文
String xmlResult = PayUtil.decryptOrder(builder.toString());
logger.info("处理腾讯支付平台的订单支付:{}", JSONObject.toJSONString(xmlResult));
//验证订单 验证订单号是否存在
String orderSn = JacksonUtil.parseString(xmlResult,"out_trade_no");
String transactionId = JacksonUtil.parseString(xmlResult,"transaction_id");
Map<String,Object> map = JsonMapUtil.jsonToMap(xmlResult);
Map<String,Object> payer = (HashMap<String,Object>)map.get("payer");
String openId = payer.get("openid").toString();
//验证订单是否存在 改变订单状态
PanPayOrder order = panPayOrderService.selectByOrderSn(orderSn);
if (order == null){
result.put("message","订单不存在");
return result;
}
order.setPayId(transactionId);
order.setPayTime(new Date());
order.setOrderStatus(1);
panPayOrderService.updateByPrimaryKeySelective(order);
//增加会员到期时长
PanMember panMember = panMemberService.selectByUser(order.getUserId());
Date time = panMember.getEndTime();
Calendar cal = Calendar.getInstance();
cal.setTime(time);
switch (order.getTypeId()){
case 1:{
cal.add(Calendar.MONTH, 1);
break;
}
case 2:{
cal.add(Calendar.MONTH, 3);
break;
}
case 3:{
cal.add(Calendar.MONTH, 6);
break;
}
case 4:{
cal.add(Calendar.YEAR, 1);
break;
}
default:{
break;
}
}
panMember.setEndTime(cal.getTime());
panMemberService.updateByPrimaryKeySelective(panMember);
result.put("code","SUCCESS");
}catch (IOException e){
e.printStackTrace();
}
logger.info("【请求结束】微信回调接口,result:{}", JSONObject.toJSONString(result));
return result;
}验证签名
public static boolean signVerify(String serial,String message,String signature){
PrivateKey merchantPrivateKey = PemUtil.loadPrivateKey(new ByteArrayInputStream(PayConstants.PRIVATE_KEY.getBytes(StandardCharsets.UTF_8)));
// 使用定时更新的签名验证器,不需要传入证书
ScheduledUpdateCertificatesVerifier verifier = new ScheduledUpdateCertificatesVerifier(
new WechatPay2Credentials(PayConstants.MCH_ID, new PrivateKeySigner(PayConstants.MCH_SERIAL_NO, merchantPrivateKey)),
PayConstants.API_V3KEY.getBytes(StandardCharsets.UTF_8));
return verifier.verify(serial, message.getBytes(StandardCharsets.UTF_8), signature);
}解密密文
public static String decryptOrder(String body) throws IOException {
try {
AesUtil util = new AesUtil(PayConstants.API_V3KEY.getBytes(StandardCharsets.UTF_8));
ObjectMapper objectMapper = new ObjectMapper();
JsonNode node = objectMapper.readTree(body);
JsonNode resource = node.get("resource");
String ciphertext = resource.get("ciphertext").textValue();
String associatedData = resource.get("associated_data").textValue();
String nonce = resource.get("nonce").textValue();
return util.decryptToString(associatedData.getBytes(StandardCharsets.UTF_8),nonce.getBytes(StandardCharsets.UTF_8),ciphertext);
} catch (JsonProcessingException | GeneralSecurityException e) {
e.printStackTrace();
}
return null;
}版权声明:本文为weixin_51168459原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。