欢迎大家来到IT世界,在知识的湖畔探索吧!
首先要申请微信的应用,在微信开放平台https://open.weixin.qq.com/中建立移动应用,并在“接口信息”里面开通“微信支付”。
随后,把api证书、apiv3密钥申请好并把回调地址设置好
接下来直接上代码!
这里是用maven引用微信支付的依赖
<!-- 微信支付 -->
<dependency>
<groupId>com.github.wechatpay-apiv3</groupId>
<artifactId>wechatpay-apache-httpclient</artifactId>
<version>0.4.4</version>
</dependency>
欢迎大家来到IT世界,在知识的湖畔探索吧!
这里是获取预支付交易会话标识的代码部分
欢迎大家来到IT世界,在知识的湖畔探索吧! private CloseableHttpClient httpClient;
private AutoUpdateCertificatesVerifier verifier;
@Autowired
private WxPayConfigServiceImpl wxPayConfigService;
public void setup(String mchId, String appV3Key, String serialNo, String keyPath, String keyAlias) {
try {
KeyPair keyPair = WXKeyPairFactory.createPKCS12(keyPath, keyAlias, mchId);
PrivateKey merchantPrivateKey = keyPair.getPrivate();
//使用自动更新的签名验证器,不需要传入证书
verifier = new AutoUpdateCertificatesVerifier(
new WechatPay2Credentials(mchId, new PrivateKeySigner(serialNo, merchantPrivateKey)),
appV3Key.getBytes(StandardCharsets.UTF_8));
httpClient = WechatPayHttpClientBuilder.create()
.withMerchant(mchId, serialNo, merchantPrivateKey)
.withValidator(new WechatPay2Validator(verifier))
.build();
} catch (Exception e) {
System.out.println(e.getMessage());
e.printStackTrace();
}
}
/**
* 微信APP支付
*
* @param desc 订单描述
* @param outTradeNo 订单号
* @param total 金额(单位为分)
* @return Client
* @throws Exception
*/
@Override
public String createOrder(String desc, String outTradeNo, int total) throws Exception {
// 用于判断商户平台或商家服务
String appId = "";// 应用ID
String mchId = "";// 商户号
String serialNo = "";// 商户证书序列号
String appV3Key = "";// API V3密钥
String keyPath = "";// 商家平台证书路径
String keyAlias = "Tenpay Certificate";// 证书的别名,这里是固定值
String notifyUrl = "";// 回调地址
setup(mchId, appV3Key, serialNo, keyPath, keyAlias);
try {
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", mchId)
.put("appid", appId)
.put("notify_url", notifyUrl)
.put("description", desc)
.put("out_trade_no", outTradeNo);
rootNode.putObject("amount")
.put("total", total);
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());
JSONObject jsonObject = JSON.parseObject(bodyAsString);
return (String) jsonObject.get("prepay_id");
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
生成签名部分
/**
* APP支付 V3 SHA256withRSA 签名.
*
* @param AppId 应用id
* @param timestamp 当前时间戳 因为要配置到TOKEN 中所以 签名中的要跟TOKEN 保持一致
* @param nonceStr 随机字符串 要和TOKEN中的保持一致
* @param prepayId 预支付交易会话ID
* @param mchId 商户号
* @param keyPath 支付证书
* @param keyAlias 证书的别名
* @return the string
*/
@SneakyThrows
public static String generateAPPSignRSA(String AppId, long timestamp, String nonceStr, String prepayId,String mchId, String keyPath, String keyAlias) {
KeyPair keyPair = WXKeyPairFactory.createPKCS12(keyPath, keyAlias, mchId);
String signatureStr = Stream.of(AppId, String.valueOf(timestamp), nonceStr, prepayId)
.collect(Collectors.joining("\n", "", "\n"));
Signature sign = Signature.getInstance("SHA256withRSA");
sign.initSign(keyPair.getPrivate());
sign.update(signatureStr.getBytes(StandardCharsets.UTF_8));
return Base64Utils.encodeToString(sign.sign());
}
回调验证部分代码
欢迎大家来到IT世界,在知识的湖畔探索吧! // 微信支付回调
@PostMapping("/notify")
public Map<String, String> wechatCallback(HttpServletRequest request, HttpServletResponse response) {
Map<String, String> map = new HashMap<>(2);
try {
//微信返回的请求体
String body = WXPayUtil.getRequestBody(request);
//如果验证签名序列号通过
if (wxAppPayService.verifiedSign(request, body)) {
//微信支付通知实体类
WxPayNotify payNotify = JSONObject.parseObject(body, WxPayNotify.class);
//如果支付成功
if ("TRANSACTION.SUCCESS".equals(payNotify.getEventType())) {
//通知资源数据
WxResourceVo resource = payNotify.getResource();
//解密后资源数据
String apiV3Key = wxPayConfigService.selectWechatMerchantApiV3Key();
String notifyResourceStr = WXPayUtil.decryptResponseBody(resource.getAssociatedData(), resource.getNonce(), resource.getCiphertext(), apiV3Key);
//通知资源数据对象
WxNotifyResourceVo notifyResourceVo = JSONObject.parseObject(notifyResourceStr, WxNotifyResourceVo.class);
String outTradeNo = notifyResourceVo.getOutTradeNo();
String transactionId = notifyResourceVo.getTransactionId();
//逻辑实现
//do something
int res = 1;
if (res == 1){
//通知微信正常接收到消息,否则微信会轮询该接口
map.put("code", "SUCCESS");
map.put("message", "成功");
}else{
map.put("code", "FAIL");
map.put("message", "失败");
response.setStatus(416);
}
} else {
map.put("code", "FAIL");
map.put("message", "失败");
response.setStatus(416);
}
//通知微信正常接收到消息,否则微信会轮询该接口
return map;
}
} catch (Exception e) {
e.printStackTrace();
}
map.put("code", "FAIL");
map.put("message", "失败");
response.setStatus(416);
return map;
}
验证部分代码
/**
* 验签
* @param request request请求
* @param body 微信返回请求体
* @return true,false
*/
@Override
public boolean verifiedSign(HttpServletRequest request,String body){
boolean result = false;
try{
String appId = "";// 应用ID
String mchId = "";// 商户号
String serialNo = "";// 商户证书序列号
String appV3Key = "";// API V3密钥
String keyPath = "";// 商家平台证书路径
String keyAlias = "Tenpay Certificate";// 证书的别名,这里是固定值
//微信返回的证书序列号
String resSerialNo = request.getHeader("Wechatpay-Serial");
//微信返回的随机字符串
String nonceStr = request.getHeader("Wechatpay-Nonce");
//微信返回的时间戳
String timestamp = request.getHeader("Wechatpay-Timestamp");
//微信返回的签名
String wechatSign = request.getHeader("Wechatpay-Signature");
KeyPair keyPair = WXKeyPairFactory.createPKCS12(keyPath, keyAlias, mchId);
PrivateKey merchantPrivateKey = keyPair.getPrivate();
//组装签名字符串
String signStr = Stream.of(timestamp, nonceStr, body)
.collect(Collectors.joining("\n", "", "\n"));
//使用自动更新的签名验证器,不需要传入证书
verifier = new AutoUpdateCertificatesVerifier(
new WechatPay2Credentials(mchId, new PrivateKeySigner(serialNo, merchantPrivateKey)),
appV3Key.getBytes(StandardCharsets.UTF_8));
result = verifier.verify(resSerialNo, signStr.getBytes(StandardCharsets.UTF_8), wechatSign);
}catch (Exception e){
e.printStackTrace();
System.out.println("e:" + e);
}
return result;
}
封装的函数
/**
* 获取请求报文
* @param request
* @return
* @throws IOException
*/
public static String getRequestBody(HttpServletRequest request) throws IOException {
ServletInputStream stream = null;
BufferedReader reader = null;
StringBuffer sb = new StringBuffer();
try {
stream = request.getInputStream();
// 获取响应
reader = new BufferedReader(new InputStreamReader(stream));
String line;
while ((line = reader.readLine()) != null) {
sb.append(line);
}
} catch (IOException e) {
throw new IOException("读取返回支付接口数据流出现异常!");
} finally {
reader.close();
}
return sb.toString();
}
解码部分代码
/**
* 解密
* @param associatedData 附加数据包
* @param nonce 加密使用的随机串
* @param ciphertext Base64编码后的密文
* @param apiV3Key 支付apiV3秘钥
* @return
*/
public static String decryptResponseBody(String associatedData, String nonce, String ciphertext, String apiV3Key) {
try {
Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
SecretKeySpec key = new SecretKeySpec(apiV3Key.getBytes("UTF-8"), "AES");
GCMParameterSpec spec = new GCMParameterSpec(128, nonce.getBytes("UTF-8"));
cipher.init(Cipher.DECRYPT_MODE, key, spec);
cipher.updateAAD(associatedData.getBytes("UTF-8"));
byte[] bytes;
try {
bytes = cipher.doFinal(Base64Utils.decodeFromString(ciphertext));
} catch (GeneralSecurityException e) {
throw new IllegalArgumentException(e);
}
return new String(bytes, StandardCharsets.UTF_8);
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
免责声明:本站所有文章内容,图片,视频等均是来源于用户投稿和互联网及文摘转载整编而成,不代表本站观点,不承担相关法律责任。其著作权各归其原作者或其出版社所有。如发现本站有涉嫌抄袭侵权/违法违规的内容,侵犯到您的权益,请在线联系站长,一经查实,本站将立刻删除。 本文来自网络,若有侵权,请联系删除,如若转载,请注明出处:https://itzsg.com/17551.html