https://mp.weixin.qq.com/
https://mp.weixin.qq.com/
在小程序中的开发管理
-开发设置
-服务器域名
<!-- 微信支付 -->
<dependency>
<groupId>com.github.wechatpay-apiv3</groupId>
<artifactId>wechatpay-apache-httpclient</artifactId>
<version>0.2.2</version>
</dependency>
以下配置文件中的秘钥信息为模拟数据。
## weixin pay
# 商户号
weixin.merchantId=161000000
# 证书序列号
weixin.merchantSerialNumber=69AA2BEARNUV13B20A9CEBAAAAABBBBBCCCCCCDDDD
# 证书秘钥文件
weixin.privateKeyPath=/server/shenma/apiclient_key.pem
# v3密码
weixin.apiV3Key=ujn5kzjxjoe
# appid
weixin.appId=wx0999e67698231456
# 支付成功回调地址
weixin.notifyUrl=https://www.www.com/wxpay/orderPayNotify
public String prepayIdByOrderInfo(String orderId, String product, Long amount, String openId) throws IOException {
//--1 读取证书
PrivateKey merchantPrivateKey = PemUtil.loadPrivateKey(
new FileInputStream(privateKeyPath));
//--2 构建请求
AutoUpdateCertificatesVerifier verifier = new AutoUpdateCertificatesVerifier(
new WechatPay2Credentials(merchantId, new PrivateKeySigner(merchantSerialNumber, merchantPrivateKey)),
apiV3Key.getBytes("utf-8"));
WechatPayHttpClientBuilder builder = WechatPayHttpClientBuilder.create()
.withMerchant(merchantId, merchantSerialNumber, merchantPrivateKey)
.withValidator(new WechatPay2Validator(verifier));
//--3 通过WechatPayHttpClientBuilder构造的HttpClient,会自动的处理签名和验签,并进行证书自动更新
HttpClient httpClient = builder.build();
//--4 调用统一下单接口
// https://api.mch.weixin.qq.com/v3/pay/transactions/jsapi
HttpPost httpPost = new HttpPost("https://api.mch.weixin.qq.com/v3/pay/transactions/jsapi");
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",merchantId)
.put("appid", appId)
.put("description", product)
.put("notify_url", notifyUrl)
.put("out_trade_no", orderId);
rootNode.putObject("amount")
.put("total", amount);
rootNode.putObject("payer")
.put("openid", openId);
objectMapper.writeValue(bos, rootNode);
httpPost.setEntity(new StringEntity(bos.toString("UTF-8"), "UTF-8"));
CloseableHttpResponse response = (CloseableHttpResponse) httpClient.execute(httpPost);
String bodyAsString = EntityUtils.toString(response.getEntity());
System.out.println(bodyAsString);
return bodyAsString;
}
public String getSignString(String prepayId) throws FileNotFoundException, NoSuchAlgorithmException, InvalidKeyException, JsonProcessingException, UnsupportedEncodingException, SignatureException {
//--1 获取个人私钥
PrivateKey merchantPrivateKey = PemUtil.loadPrivateKey(
new FileInputStream(privateKeyPath));
//--2 组装支付签名消息
//wx8888888888888888
//1414561699
//5K8264ILTKCH16CQ2502SI8ZNMTM67VS
//prepay_id=wx201410272009395522657a690389285100
String nonceStr = UUID.randomUUID().toString().replace("-", "");
long timestamp = System.currentTimeMillis() / 1000;
String message = appId;
message += "\n";
message += timestamp;
message += "\n";
message += nonceStr;
message += "\n";
message += "prepay_id=";
message += prepayId;
message += "\n";
//--3 计算签名字符串
Signature sign = Signature.getInstance("SHA256withRSA");
sign.initSign(merchantPrivateKey);
sign.update(message.getBytes("utf-8"));
String paySign = Base64.getEncoder().encodeToString(sign.sign());
//--4 生产json字符串
HashMap<String, String> hashMap = new HashMap<>();
hashMap.put("timeStamp", String.valueOf(timestamp));
hashMap.put("nonceStr", nonceStr);
hashMap.put("package", "prepay_id="+prepayId);
hashMap.put("signType", "RSA");
hashMap.put("paySign", paySign);
ObjectMapper objectMapper = new ObjectMapper();
String data = objectMapper.writeValueAsString(hashMap);
//--5 返回json字符串
return data;
}
@Override
public ResponseResult orderPayNotify(WxSuccessCallBackObj body) {
String associated_data = body.getResource().getAssociated_data();
String nonce = body.getResource().getNonce();
String ciphertext = body.getResource().getCiphertext();
WeiXinAesUtil aesUtil = new WeiXinAesUtil(weiXinPayUtil.getApiV3Key().getBytes());
try {
//--1 解密数据
String json = aesUtil.decryptToString(associated_data.getBytes(), nonce.getBytes(), ciphertext);
log.info(json);
//--2 反序列化
ObjectMapper objectMapper = new ObjectMapper();
WxSuccessCallBackData wxSuccessCallBackData = objectMapper.readValue(json, WxSuccessCallBackData.class);
log.info("trade_no="+wxSuccessCallBackData.getOut_trade_no());
log.info("transaction_id="+wxSuccessCallBackData.getTransaction_id());
log.info("trade_state="+wxSuccessCallBackData.getTrade_state());
log.info("appid="+wxSuccessCallBackData.getAppid());
//--3 修改订单状态
if(!wxSuccessCallBackData.getTrade_state().equals("SUCCESS")) {
return ResponseResult.FAIL("订单失败");
}
TbOrder tbOrder = tbOrderMapper.selectById(wxSuccessCallBackData.getOut_trade_no());
if(tbOrder == null) {
return ResponseResult.FAIL("订单不存在");
}
if(!tbOrder.getOrderStatus().equals(OrderStatusEnum.NOPAY.getCode())) {
return ResponseResult.FAIL("订单状态错误");
}
tbOrder.setOrderStatus(OrderStatusEnum.PAYED.getCode());
tbOrderMapper.updateById(tbOrder);
//--4 修改用户积分
TbUser tbUser = tbUserMapper.selectById(tbOrder.getUserId());
Long score = tbOrder.getAmount()*100;
Long oldScore = tbUser.getUserScore();
Long newScore = oldScore + score;
tbUser.setUserScore(newScore);
tbUserMapper.updateById(tbUser);
//--5 记录积分变化
IdWorker idWorker = new IdWorker();
TbUserScoreRecord record = new TbUserScoreRecord();
record.setRecordId(idWorker.nextId());
record.setUserId(tbUser.getUserId());
record.setChangeScore(score);
record.setOldScore(oldScore);
record.setNewScore(newScore);
record.setChangeReason("充值");
tbUserScoreRecordMapper.insert(record);
return ResponseResult.SUCCESS();
} catch (GeneralSecurityException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return ResponseResult.FAIL("未知错误");
}
@Data
public class WxSuccessCallBackObj implements Serializable {
private static final long serialVersionUID = 3099698871017317731L;
private String summary;
private String event_type;
private String create_time;
private String resource_type;
private String id;
private WxResource resource;
}
@Data
@JsonIgnoreProperties(ignoreUnknown = true)
public class WxSuccessCallBackData {
private String transaction_id;
private String mchid;
private String trade_state;
private String bank_type;
private String success_time;
private String out_trade_no;
private String appid;
private String trade_state_desc;
private String trade_type;
}
package com.shenmazong.shenmacodeserver.util;
import javax.crypto.Cipher;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.spec.GCMParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.io.IOException;
import java.security.GeneralSecurityException;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.util.Base64;
/**
* @author 军哥
* @version 1.0
* @description: 微信支付回调函数解密
* @date 2021/8/25 12:15
*/
public class WeiXinAesUtil {
static final int KEY_LENGTH_BYTE = 32;
static final int TAG_LENGTH_BIT = 128;
private final byte[] aesKey;
public WeiXinAesUtil(byte[] key) {
if (key.length != KEY_LENGTH_BYTE) {
throw new IllegalArgumentException("无效的ApiV3Key,长度必须为32个字节");
}
this.aesKey = key;
}
public String decryptToString(byte[] associatedData, byte[] nonce, String ciphertext) throws GeneralSecurityException, IOException {
try {
Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
SecretKeySpec key = new SecretKeySpec(aesKey, "AES");
GCMParameterSpec spec = new GCMParameterSpec(TAG_LENGTH_BIT, nonce);
cipher.init(Cipher.DECRYPT_MODE, key, spec);
cipher.updateAAD(associatedData);
return new String(cipher.doFinal(Base64.getDecoder().decode(ciphertext)), "utf-8");
} catch (NoSuchAlgorithmException | NoSuchPaddingException e) {
throw new IllegalStateException(e);
} catch (InvalidKeyException | InvalidAlgorithmParameterException e) {
throw new IllegalArgumentException(e);
}
}
}
<button type="primary" bindtap="handleGetPrepayId">我要充值</button>
handleGetPrepayId(e) {
let that = this
let userId = wx.getStorageSync('userId')
console.log(userId)
wx.request({
url: 'https://www.xxx.com/wx/getOrderPrepayId',
method: 'POST',
data: {
userId: userId,
productId: 1
},
success (res) {
console.log(res.data)
if(res.data.code == 0) {
let prepay = JSON.parse(res.data.data)
console.log(prepay.prepay_id)
that.getPayOrderSign(prepay.prepay_id)
}
else {
console.log(res.message)
}
}
})
}
getPayOrderSign(prepayId) {
let that = this
let userId = wx.getStorageSync('userId')
console.log(userId)
wx.request({
url: 'https://www.xxx.com/wx/getOrderRequestSign',
method: 'POST',
data: {
prepayId: prepayId
},
success (res) {
console.log(res.data)
if(res.data.code == 0) {
let param = JSON.parse(res.data.data)
wx.requestPayment(
{
"timeStamp": param.timeStamp,
"nonceStr": param.nonceStr,
"package": param.package,
"signType": "RSA",
"paySign": param.paySign,
"success":function(res){
console.log(res)
},
"fail":function(res){
console.log(res)
},
"complete":function(res){
console.log(res)
}
})
}
else {
console.log(res.message)
}
}
})