首先需要自己在微信平台申请账户,将openid与key放入配置文件中进行读取,在公众平台配置支付回调地址,还需要下载好加密的证书,对信息进行加密
编写代码按照微信提供的文档进行拼接自己的参数,进行加密处理后请求微信提供的地址,因为我写的是小程序,在登陆时候就保存用户的openid了,直接获取即可。同时配置的回调地址需要外网能够访问。
@RequestMapping(value = "do", method = RequestMethod.POST)
public R payVip(@RequestBody WxVo vo) throws Exception {
User user = userService.getById(vo.getUserid());
String userOpenid = user.getOpenid();
if (StringUtils.isEmpty(userOpenid)){
StringBuffer baseAccessTokenUrl = new StringBuffer()
.append("https://api.weixin.qq.com/sns/jscode2session")
.append("?appid=%s")
.append("&secret=%s")
.append("&js_code=%s")
.append("&grant_type=authorization_code");
String accessTokenUrl = String.format(baseAccessTokenUrl.toString(),
ConstantPropertiesUtil.WX_OPEN_APP_ID,
ConstantPropertiesUtil.WX_OPEN_APP_SECRET,
vo.getCode());
OkHttpClient client = new OkHttpClient();
Request request = new Request.Builder().url(accessTokenUrl).build();
Response response = client.newCall(request).execute();
if (response.isSuccessful()) {
String body = response.body().string();
JSONObject jsonObject = JSONObject.parseObject(body);
String session_key = jsonObject.getString("session_key");
String openid = jsonObject.getString("openid");
userOpenid=openid;
}else {
return R.error().message("微信授权失败");
}
}
//判断自己的业务逻辑
//开始支付,创建数据体
JSONObject order = new JSONObject();
order.put("appid", ConstantPropertiesUtil.WX_OPEN_APP_ID);
order.put("mchid",ConstantPropertiesUtil.PARTNER);
order.put("description","支付");
String str_no = new DateTime().toString("yyyyMMddHHmmssSSS");
order.put("out_trade_no",str_no);
System.out.println(str_no);
order.put("notify_url","https://www.dsxssd.com/api/dsxs/wx/payNotice");
JSONObject amount = new JSONObject();
amount.put("total",(long)(companyClass.getMoney()*100));
amount.put("currency","CNY");
order.put("amount",amount);
JSONObject payer = new JSONObject();
payer.put("openid",userOpenid);
order.put("payer",payer);
//放在服务器上的v3证书
PrivateKey merchantPrivateKey = PemUtil.loadPrivateKey(new FileInputStream(ResourceUtils.getFile("/www/zs/apiclient_key.pem")));
AutoUpdateCertificatesVerifier verifier = new AutoUpdateCertificatesVerifier(
new WechatPay2Credentials(ConstantPropertiesUtil.PARTNER,new PrivateKeySigner(ConstantPropertiesUtil.NUM,merchantPrivateKey)),
ConstantPropertiesUtil.MY.getBytes(StandardCharsets.UTF_8));
WechatPayHttpClientBuilder builder = WechatPayHttpClientBuilder.create()
.withMerchant(ConstantPropertiesUtil.PARTNER, ConstantPropertiesUtil.NUM, merchantPrivateKey)
.withValidator(new WechatPay2Validator(verifier));
HttpClient httpClient = builder.build();
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");
httpPost.setEntity(new StringEntity(order.toJSONString(),"UTF-8"));
HttpResponse response = httpClient.execute(httpPost);
String body = EntityUtils.toString(response.getEntity());
JSONObject jsonObject = JSONObject.parseObject(body);
if(jsonObject.containsKey("code")) {
System.out.println(jsonObject.getString("message"));
return null;
}
final String prepay_id = jsonObject.getString("prepay_id");
final String timeStamp = System.currentTimeMillis()+"";
final String nonceStr = RandomStringGenerator.getRandomStringByLength(32);
StringBuffer stringBuffer = new StringBuffer();
stringBuffer.append(ConstantPropertiesUtil.WX_OPEN_APP_ID+"\n");
stringBuffer.append(timeStamp+"\n");
stringBuffer.append(nonceStr+"\n");
stringBuffer.append("prepay_id="+prepay_id+"\n");
Signature signature = Signature.getInstance("SHA256withRSA");
signature.initSign(merchantPrivateKey);
signature.update(stringBuffer.toString().getBytes(StandardCharsets.UTF_8));
byte[] signBytes = signature.sign();
String paySign = Base64.encodeBytes(signBytes);
//处理自己业务逻辑
corderService.saveCorder(user,companyClass,str_no);
JSONObject params = new JSONObject();
params.put("appId",ConstantPropertiesUtil.WX_OPEN_APP_ID);
params.put("timeStamp",timeStamp);
params.put("nonceStr",nonceStr);
params.put("package","prepay_id="+prepay_id);
params.put("signType","RSA");
params.put("paySign",paySign);
return R.ok().data("weixinMap",params);
}
/**
* 买课支付通知(api)
*/
@RequestMapping(value = "payNotice", method = RequestMethod.POST)
public R payNotice(
HttpServletRequest request,
HttpServletResponse response){
System.out.println("支付回调执行");
try {
String reqParams = StreamUtil.read(request.getInputStream());
logger.info("-------支付结果:"+reqParams);
JSONObject json = JSONObject.parseObject(reqParams);
if(json.getString("event_type").equals("TRANSACTION.SUCCESS")){
logger.info("-------支付成功");
}
String ciphertext = json.getJSONObject("resource").getString("ciphertext");
final String associated_data = json.getJSONObject("resource").getString("associated_data");
final String nonce = json.getJSONObject("resource").getString("nonce");
AesUtil aesUtil = new AesUtil(ConstantPropertiesUtil.MY.getBytes(StandardCharsets.UTF_8));
ciphertext = aesUtil.decryptToString(associated_data.getBytes(), nonce.getBytes(), ciphertext);
logger.info(JSONObject.parseObject(ciphertext).getString("out_trade_no"));
//商户单号
String out_trade_no = JSONObject.parseObject(ciphertext).getString("out_trade_no");
//交易单号
String transaction_id = JSONObject.parseObject(ciphertext).getString("transaction_id");
//金额
String total =JSONObject.parseObject(ciphertext).getString("total");
String openid =JSONObject.parseObject(ciphertext).getString("openid");
System.out.println("更新数据库");
UpdateWrapper wrapper = new UpdateWrapper<>();
wrapper.eq("orderid",out_trade_no).set("status",1).set("paytype",2);
boolean b = corderService.update(wrapper);
System.out.println(b+"=============");
} catch (Exception e) {
e.printStackTrace();
logger.error(e.toString());
}
return R.ok();
}
由于服务器上的jre对v3秘钥进行加密解密的长度超过128,会报异常需要我们自己下载jrc将其中的jar覆盖掉原有的。
@RequestMapping(value="/refund")
public void refund(
String out_trade_no,
String reason){
System.out.println("退款接口执行");
Integer totalFee = 1;
Integer total = 1;
Orderr orderr = orderrService.getById(out_trade_no);
if (!StringUtils.isEmpty(orderr)){
total = orderr.getPayment();
totalFee = orderr.getPayment();
}else {
Corder corder = corderService.getCorderByNo(out_trade_no);
totalFee = corder.getPayment();
total = corder.getPayment();
}
String out_refund_no = new DateTime().toString("yyyyMMddHHmmssSSS");
try {
JSONObject order = new JSONObject();
order.put("out_trade_no", out_trade_no);//商户订单号
order.put("out_refund_no", out_refund_no);//商户退款单号
order.put("reason", reason);//退款原因
order.put("notify_url","https://www.dsxssd.com/api/dsxs/wx/refundNotice/");//退款通知
JSONObject amount = new JSONObject();
amount.put("refund", (long)(totalFee*100));//退款金额
amount.put("currency", "CNY");
amount.put("total", (long)(total*100));//原订单金额
order.put("amount", amount);
PrivateKey merchantPrivateKey = PemUtil.loadPrivateKey(new FileInputStream(ResourceUtils.getFile("/www/zs/apiclient_key.pem")));
// 使用定时更新的签名验证器,不需要传入证书
ScheduledUpdateCertificatesVerifier verifier = new ScheduledUpdateCertificatesVerifier(
new WechatPay2Credentials(ConstantPropertiesUtil.PARTNER, new PrivateKeySigner( ConstantPropertiesUtil.NUM, merchantPrivateKey)),
ConstantPropertiesUtil.MY.getBytes(StandardCharsets.UTF_8));
WechatPayHttpClientBuilder builder = WechatPayHttpClientBuilder.create()
.withMerchant(ConstantPropertiesUtil.PARTNER, ConstantPropertiesUtil.NUM, merchantPrivateKey)
.withValidator(new WechatPay2Validator(verifier));
// ... 接下来,你仍然可以通过builder设置各种参数,来配置你的HttpClient
// 通过WechatPayHttpClientBuilder构造的HttpClient,会自动的处理签名和验签,并进行证书自动更新
HttpClient httpClient = builder.build();
HttpPost httpPost = new HttpPost("https://api.mch.weixin.qq.com/v3/refund/domestic/refunds");
httpPost.addHeader("Accept", "application/json");
httpPost.addHeader("Content-type","application/json; charset=utf-8");
httpPost.setEntity(new StringEntity(order.toJSONString(), "UTF-8"));
// 后面跟使用Apache HttpClient一样
HttpResponse response = httpClient.execute(httpPost);
String bodyAsString = EntityUtils.toString(response.getEntity());
JSONObject bodyAsJSON = JSONObject.parseObject(bodyAsString);
logger.info(bodyAsJSON.toJSONString());
final String status = bodyAsJSON.getString("status");
if(status.equals("SUCCESS")){
logger.info("退款成功");
}else if(status.equals("CLOSED")){
logger.info("退款关闭");
}else if(status.equals("PROCESSING")){
logger.info("退款处理中");
}else if(status.equals("ABNORMAL")){
logger.info("退款异常");
}
} catch (Exception e) {
// TODO Auto-generated catch block
logger.info(e.toString());
e.printStackTrace();
}
}
/**
* 买课退款通知(api)
*/
@RequestMapping(value="/refundNotice")
public void refundNotice(
HttpServletRequest request,
HttpServletResponse response){
try {
String reqParams = StreamUtil.read(request.getInputStream());
logger.info("-------退款回调结果:"+reqParams);
JSONObject json = JSONObject.parseObject(reqParams);
final String event_type = json.getString("event_type");
if(event_type.equals("REFUND.SUCCESS")){
logger.info("-------退款成功");
}else if(event_type.equals("REFUND.ABNORMAL")){
logger.info("-------退款异常");
}else if(event_type.equals("REFUND.CLOSED")){
logger.info("-------退款关闭");
}
String ciphertext = json.getJSONObject("resource").getString("ciphertext");
final String associated_data = json.getJSONObject("resource").getString("associated_data");
final String nonce = json.getJSONObject("resource").getString("nonce");
AesUtil aesUtil = new AesUtil(ConstantPropertiesUtil.MY.getBytes());
ciphertext = aesUtil.decryptToString(associated_data.getBytes(), nonce.getBytes(), ciphertext);
logger.info("-------ciphertext:"+ciphertext);
String out_trade_no = JSONObject.parseObject(ciphertext).getString("out_trade_no");
//处理自己的业务逻辑
} catch (Exception e) {
e.printStackTrace();
logger.error(e.toString());
}
}
复制改改就能用