1、接入前的准备
官方文档地址 jsapi下单官方文档地址:https://pay.weixin.qq.com/wiki/doc/apiv3/apis/chapter3_1_1.shtml
jsapi调起支付官方文档地址:https://pay.weixin.qq.com/wiki/doc/apiv3/apis/chapter3_1_4.shtml
jsapi支付通知回调文档地址:https://pay.weixin.qq.com/wiki/doc/apiv3/apis/chapter3_1_5.shtml
接入前的准备:https://pay.weixin.qq.com/wiki/doc/apiv3/open/pay/chapter2_1.shtml
公众号绑定商户号(略)
登录商户号配置v3秘钥
登录商户号配置商户证书 流程比较多,可以看官方提供的步骤操作,操作完后本地会生成三个证书文件
登录商户号设置支付授权目录
登录公众号后台设置授权域名
2、引入jar
我这里用的是gradle
implementation 'com.github.wechatpay-apiv3:wechatpay-apache-httpclient:0.4.2'
implementation group: 'com.github.binarywang', name: 'weixin-java-common', version: '3.3.0'
3、创建三个工具方法
构造jsApi下单请求参数
public static JSONObject buildWxJsApiPayJson(String appid , String mchid , String description , String out_trade_no , String notify_url , String amount, String openId){
JSONObject amountJson = new JSONObject();
amountJson.put("total",Integer.valueOf(amount));
amountJson.put("currency","CNY");
JSONObject payerJson = new JSONObject();
payerJson.put("openid",openId);
JSONObject json = new JSONObject();
json.put("appid",appid);
json.put("mchid",mchid);
json.put("description",description);
json.put("out_trade_no",out_trade_no);
json.put("notify_url",notify_url);
json.put("amount",amountJson);
json.put("payer",payerJson);
return json;
}
创建下单httpClient方法:
public static JSONObject doPostWexinV3(String wxMchid,String wxCertno,String wxCertPath,String wxPaternerKey,String url, String body) {
AutoUpdateCertificatesVerifier verifier = null;
try {
verifier = new AutoUpdateCertificatesVerifier(
new WechatPay2Credentials(wxMchid, new PrivateKeySigner(wxCertno,
PemUtil.loadPrivateKey(new FileInputStream(wxCertPath)))),
wxPaternerKey.getBytes("utf-8"));
} catch (FileNotFoundException e) {
System.err.println("证书未找到!=====================");
e.printStackTrace();
} catch (UnsupportedEncodingException e) {
System.err.println("文件流错误!=====================");
e.printStackTrace();
}
WechatPayHttpClientBuilder builder = null;
try {
builder = WechatPayHttpClientBuilder.create()
.withMerchant(wxMchid,wxCertno, PemUtil.loadPrivateKey(new FileInputStream(wxCertPath)))
.withValidator(new WechatPay2Validator(verifier));
} catch (FileNotFoundException e) {
System.err.println("证书未找到!=====================");
e.printStackTrace();
}
HttpClient httpClient = builder.build();
HttpPost httpPost = new HttpPost(url);
httpPost.addHeader("Content-Type","application/json;chartset=utf-8");
httpPost.addHeader("Accept", "application/json");
try{
if(body==null){
throw new IllegalArgumentException("data参数不能为空");
}
StringEntity stringEntity = new StringEntity(body,"utf-8");
httpPost.setEntity(stringEntity);
HttpResponse httpResponse = httpClient.execute(httpPost);
HttpEntity httpEntity = httpResponse.getEntity();
if(httpResponse.getStatusLine().getStatusCode() == 200){
String jsonResult = EntityUtils.toString(httpEntity);
return JSONObject.parseObject(jsonResult);
}else{
System.err.println("微信支付错误信息"+EntityUtils.toString(httpEntity));
}
}catch (Exception e){
e.printStackTrace();
}
return null;
}
获取签名方法
public static JSONObject getTokenWeixin (String appId,String wxCertPath, String prepay_id) throws IOException, SignatureException, NoSuchAlgorithmException, InvalidKeyException, java.security.InvalidKeyException {
String nonceStr = getNonceStr();
String packagestr = "prepay_id=" + prepay_id;
long timestamp = System.currentTimeMillis() / 1000;
String message = buildMessageTwo(appId,timestamp,nonceStr,packagestr);
String signature = sign(wxCertPath,message.getBytes("utf-8"));
JSONObject json = new JSONObject();
json.put("timeStamp", String.valueOf(timestamp));
json.put("nonceStr", nonceStr);
json.put("package", packagestr);
json.put("signType", "RSA");
json.put("paySign", signature);
json.put("appId", appId);
return json;
}
public static String getNonceStr(){
return UUID.randomUUID().toString()
.replaceAll("-", "")
.substring(0, 32);
}
private static String buildMessageTwo(String appId, long timestamp, String nonceStr, String packag) {
return appId + "\n"
+ timestamp + "\n"
+ nonceStr + "\n"
+ packag + "\n";
}
private static String sign(String wxCertPath,byte[] message) throws NoSuchAlgorithmException, SignatureException, IOException, InvalidKeyException, java.security.InvalidKeyException {
Signature sign = Signature.getInstance("SHA256withRSA");
sign.initSign(PemUtil.loadPrivateKey(new FileInputStream(wxCertPath)));
sign.update(message);
return Base64.getEncoder().encodeToString(sign.sign());
}
4、获取微信加密签名控制层接口
给当前url鉴权,否则前端无法唤起支付窗口
@PostMapping("getSignPackage")
public ResponseResult getSignPackage(String url) {
ResponseResult result = new ResponseResult<>();
WxJsapiSignature jsapiSignature;
if (StringUtils.isEmpty(url)) {
return result.error(500,"缺少参数!");
}
try{
jsapiSignature = createJsapiSignature(url);
}catch (Exception e){
logger.error("getSignPackage_error:"+e.getMessage());
return result.error(500,"请求异常!");
}
return result.success(jsapiSignature);
}
public WxJsapiSignature createJsapiSignature(String url) throws Exception {
long timestamp = System.currentTimeMillis() / 1000L;
String randomStr = RandomUtils.getRandomStr();
String jsapiTicket =getAccessToken();
String signature = SHA1.genWithAmple(new String[]{"jsapi_ticket=" + jsapiTicket, "noncestr=" + randomStr, "timestamp=" + timestamp, "url=" + url});
WxJsapiSignature jsapiSignature = new WxJsapiSignature();
jsapiSignature.setAppId(wxAppid);
jsapiSignature.setTimestamp(timestamp);
jsapiSignature.setNonceStr(randomStr);
jsapiSignature.setUrl(url);
jsapiSignature.setSignature(signature);
return jsapiSignature;
}
5、创建下单控制层接口
JSONObject requestJson = buildWxJsApiPayJson(wxAppid,wxMchid,rechargeType.getMealName(),orderNo,notifyUrl,amount,openid);
JSONObject stringObjectJson = doPostWexinV3(wxMchid,wxCertno,wxCertPath,wxPaternerKey,wxJsApiurl, requestJson.toJSONString());
JSONObject resJson = getTokenWeixin(wxAppid,wxCertPath, String.valueOf(stringObjectJson.get("prepay_id")));
return result.success(resJson);
6、创建支付回调控制层接口
@RequestMapping("wxJsApiCallback")
public Map wxJsApiCallback(@RequestBody Map body, HttpServletRequest request) {
Map<String, Object> result = new HashMap();
String timestamp = request.getHeader("Wechatpay-Timestamp");
String nonce = request.getHeader("Wechatpay-Nonce");
ObjectMapper objectMapper = new ObjectMapper();
try {
String data = objectMapper.writeValueAsString(body);
String message = timestamp + "\n" + nonce + "\n" + data + "\n";
String sign = request.getHeader("Wechatpay-Signature");
String serialNo = request.getHeader("Wechatpay-Serial");
Map<String, String> resource = (Map) body.get("resource");
AesUtil aesUtil = new AesUtil(wxPaternerKey.getBytes());
String decryptToString = aesUtil.decryptToString(
resource.get("associated_data").getBytes(),
resource.get("nonce").getBytes(),
resource.get("ciphertext"));
com.alibaba.fastjson.JSONObject jsonData = com.alibaba.fastjson.JSONObject.parseObject(decryptToString);
logger.info("wxJsApiCallback responseJson:" + jsonData.toJSONString());
if ("SUCCESS".equals(jsonData.get("trade_state"))) {
String out_trade_no = jsonData.get("out_trade_no").toString();
String transaction_id = jsonData.get("transaction_id").toString();
com.alibaba.fastjson.JSONObject amount = jsonData.getJSONObject("amount");
int payMoney = amount.getIntValue("payer_total");
}else{
}
result.put("code", "SUCCESS");
result.put("message", "成功");
} catch (Exception e) {
result.put("code", "fail");
result.put("message", "系统错误");
e.printStackTrace();
}
return result;
}
|