1.初始化jsapi
后台
/**
* 获取微信JSAPI初始化配置
* @return
*/
@GetMapping("/getWxconfig")
public Result getWxconfig(@RequestParam String url) throws NoSuchAlgorithmException {
log.info("前端url:"+url);
String appid = "";
String timestamp = String.valueOf(new Date().getTime());
String nonceStr = "";
String signature = "";
List jsApiList = new ArrayList();
//获取随机字符串
String str="abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
Random random = new Random();
StringBuffer sb=new StringBuffer();
for(int i=0;i<32;i++){
int number=random.nextInt(62);
sb.append(str.charAt(number));
}
nonceStr = sb.toString();
//获取支付access_token
String access_tokenurl = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=&secret=&code";
RestTemplate restTemplate = new RestTemplate();
Gson gson = new Gson();
Map<String,String> response = gson.fromJson(restTemplate.getForObject(access_tokenurl, String.class),new TypeToken<Map<String,String>>(){}.getType());
log.info(response.toString());
redisUtil.set("yygh_pay_access_token",response.get("access_token"),7000);
//获取jsapi_ticket
String jsapi_ticket = "";
String access_token = (String) redisUtil.get("yygh_pay_access_token");
String ticeturl = "https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token="+access_token+"&type=jsapi";
log.info(access_token);
restTemplate = new RestTemplate();
gson = new Gson();
response = gson.fromJson(restTemplate.getForObject(ticeturl, String.class),new TypeToken<Map<String,String>>(){}.getType());
log.info(response.toString());
jsapi_ticket = response.get("ticket");
redisUtil.set("yygh_jsapi_ticket",response.get("ticket"),7000);
//拼接签名字符串
String signatureStr = "jsapi_ticket="+jsapi_ticket+"&noncestr="+nonceStr+"×tamp"+timestamp+"=&url="+url;
signature = ShaUtils.getSHA1(signatureStr,false);
//设置需要使用的接口
jsApiList.add("chooseWXPay");
List openTagList = new ArrayList();
openTagList.add("wx-open-subscribe");
Map<String,Object> m = new HashMap<>();
m.put("debug",false);
m.put("appId",appid);
m.put("timestamp",timestamp);
m.put("nonceStr",nonceStr);
m.put("signature",signature);
m.put("jsApiList",jsApiList);
m.put("openTagList",openTagList);
return Result.OK(m);
}
前台
getWxconfig() {
console.log("haha");
var url = this.apiurl
uni.request({
method: "GET",
url: url + "/getWxconfig",
data: {
url: window.location.href
},
success(res) {
console.log(res);
var config = {}
config = res.data.result
jWeixin.config(config);
jWeixin.error(function(res) {
console.log(res);
});
jWeixin.ready(function(res) {
console.log("成功了", res);
})
}
})
},
2.支付签名
/**
* 获取微信支付的签名参数
*/
@GetMapping("/getChooseWXPay")
public Result getChooseWXPay(@RequestParam String prepayId){
String privateKey = WxConfig.getPrivateKey().replace("-----END PRIVATE KEY-----\n","").replace("-----BEGIN PRIVATE KEY-----\n","");
String timestamp = String.valueOf(new Date().getTime()/1000);
String nonceStr = "";
String packageStr = "prepay_id="+prepayId;
String signType = "RSA";
String paySign = "";
String appid = "";
//获取随机字符串
String str="abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
Random random = new Random();
StringBuffer sb=new StringBuffer();
for(int i=0;i<32;i++){
int number=random.nextInt(62);
sb.append(str.charAt(number));
}
nonceStr = sb.toString();
String paySignstr = appid+"\n"+timestamp+"\n"+nonceStr+"\n"+packageStr+"\n";
String chatSet = "UTF-8";
paySign = ShaUtils.signBySHA256WithRSA(paySignstr,privateKey,chatSet);
Map map = new HashMap();
map.put("timestamp",timestamp);
map.put("nonceStr",nonceStr);
map.put("package",packageStr);
map.put("signType",signType);
map.put("paySign",paySign);
return Result.OK(map);
}
3.微信支付下单
/**
* 微信支付下单
* @return
*/
@PostMapping("/getPrepayId")
@Transactional
public Result getPrepayId(@RequestBody Yuyue yuyue , HttpServletRequest request) throws Exception {
String privateKey = WxConfig.getPrivateKey();
PrivateKey merchantPrivateKey = PemUtil.loadPrivateKey(
new ByteArrayInputStream(privateKey.getBytes("utf-8")));
String apiV3Key = "";
String merchantId = "";
String merchantSerialNumber = "";
String appid = "";
Verifier verifier = this.getVerifier();
WechatPayHttpClientBuilder builder = WechatPayHttpClientBuilder.create()
.withMerchant(merchantId, merchantSerialNumber, merchantPrivateKey)
.withValidator(new WechatPay2Validator(verifier));
// ... 接下来,你仍然可以通过builder设置各种参数,来配置你的HttpClient
// 通过WechatPayHttpClientBuilder构造的HttpClient,会自动的处理签名和验签,并进行证书自动更新
CloseableHttpClient 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");
ByteArrayOutputStream bos = new ByteArrayOutputStream();
ObjectMapper objectMapper = new ObjectMapper();
String out_trade_no = "";
String time = String.valueOf(new Date().getTime());
String randn = String.valueOf(new Random().nextInt(90001)+1000);
String randntwo = String.valueOf(new Random().nextInt(9001)+1000);
String notifyUrl = WxConfig.getNotifyUrl();
String ip = request.getHeader("x-forwarded-for");
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
ip = request.getHeader("X-Real-IP");
}
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
ip = request.getHeader("http_client_ip");
}
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
ip = request.getRemoteAddr();
}
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
ip = request.getHeader("Proxy-Client-IP");
}
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
ip = request.getHeader("WL-Proxy-Client-IP");
}
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
ip = request.getHeader("HTTP_X_FORWARDED_FOR");
}
if (ip != null && ip.indexOf(",") != -1) {
ip = ip.substring(ip.lastIndexOf(",") + 1, ip.length()).trim();
}
log.info("当前用户ip:"+ip);
String resip = ip.replace(".","");
//获取预约单号
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd");
int num = iYuyueService.getMaxDayYuyueNum(simpleDateFormat.format(new Date()));
String yuyueNum = String.valueOf(num);
out_trade_no = time +""+yuyueNum+""+resip+""+randn;
ObjectNode rootNode = objectMapper.createObjectNode();
rootNode.put("mchid",merchantId)
.put("appid", appid)
.put("description", "挂号费用")
.put("notify_url", notifyUrl)
.put("out_trade_no", out_trade_no);
rootNode.putObject("amount")
.put("total", (int)(Double.parseDouble(yuyue.getPayMoney())*100));
rootNode.putObject("payer")
.put("openid", yuyue.getWxId());
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());
log.info(bodyAsString);
Gson gson = new Gson();
Map<String,String> map = gson.fromJson(bodyAsString,new TypeToken<Map<String,String>>(){}.getType());
System.out.println(map.toString());
//获取到微信支付信息后保存预约单信息
yuyue.setOrderNum(out_trade_no);
yuyue.setPrepayId(map.get("prepay_id"));
//yuyue.setYuyueNum(yuyueNum);
iYuyueService.save(yuyue);
//获取刚刚新增的订单返回到页面
QueryWrapper queryWrapper = new QueryWrapper();
queryWrapper.eq("jz_people",yuyue.getJzPeople());
queryWrapper.last("limit 1");
queryWrapper.orderByDesc("create_time");
Yuyue yuyue1 = (Yuyue) iYuyueService.list(queryWrapper).get(0);
return Result.OK(yuyue1);
}
前台
uni.request({
method: "POST",
url: url + "/getPrepayId",
data: data,
success(res) {
console.log(res);
uni.showLoading({
title: "预约中..."
})
that.clicked = false
if (res.data.success) {
var orderRes = res.data.result
// uni.redirectTo({
// url: "../success/success?data=" + JSON.stringify(res.data.result)
// })
data = {
prepayId: res.data.result.prepayId
}
uni.request({
method: "GET",
url: url + "/getChooseWXPay",
data: data,
success(res) {
console.log(res);
var resdata = res.data.result
jWeixin.chooseWXPay({
timestamp: resdata
.timestamp, // 支付签名时间戳,注意微信jssdk中的所有使用timestamp字段均为小写。但最新版的支付后台生成签名使用的timeStamp字段名需大写其中的S字符
nonceStr: resdata.nonceStr, // 支付签名随机串,不长于 32 位
package: resdata
.package, // 统一支付接口返回的prepay_id参数值,提交格式如:prepay_id=\*\*\*)
signType: resdata
.signType, // 微信支付V3的传入RSA,微信支付V2的传入格式与V2统一下单的签名格式保持一致
paySign: resdata.paySign, // 支付签名
success: function(res) {
uni.redirectTo({
url: "../success/success?orderNum=" +
orderRes.orderNum
})
// 支付成功后的回调函数
// console.log(res);
// uni.showLoading({
// title:"预约中..."
// })
// data = {
// orderNum: orderRes.orderNum
// }
// uni.request({
// method: "GET",
// url: url +
// "/updatePayStatus",
// data: data,
// success(res) {
// console.log(res);
// orderRes.payStatus = "已支付"
// if (res.data.success) {
// uni.hideLoading()
// uni.redirectTo({
// url: "../success/success?orderNum=" +orderRes.orderNum
// })
// }
// }
// })
},
cancel: function(res) {
uni.showModal({
content: "取消支付",
showCancel: false
});
},
fail: function(res) {
uni.showModal({
content: "支付失败",
showCancel: false
});
}
});
},
fail(res) {
uni.showModal({
content: "预约失败,请重试或到窗口挂号"
})
},
complete() {
uni.hideLoading()
that.clicked = false
}
})
} else {
uni.showModal({
content: "预约失败,请重试或到窗口挂号",
showCancel: false
})
}
},
fail(res) {
uni.showModal({
content: "预约失败,请重试或到窗口挂号"
})
},
complete() {
uni.hideLoading()
that.clicked = false
}
})
4.接受微信支付结果
/**
* 获取微信支付结果通知
* @return
*/
@PostMapping("/getPayNotify")
public Result getPayNotify(HttpServletRequest request,@RequestBody JSONObject jsonObject ) throws Exception {
String signature = request.getHeader("Wechatpay-Signature");
String timestamp = request.getHeader("Wechatpay-Timestamp");
String nonce = request.getHeader("Wechatpay-Nonce");
String wechatPaySerial = request.getHeader("Wechatpay-Serial");
log.info("签名信息:"+signature+"--"+timestamp+"--"+nonce+"--"+wechatPaySerial);
// 从证书管理器中获取verifier
Verifier verifier = this.getVerifier();
String apiV3Key = WxConfig.getApiV3Key();
String body = jsonObject.toJSONString();
Gson gson = new Gson();
Map<String,Object> mapMap = gson.fromJson(body,new TypeToken<Map<String,Object>>(){}.getType());
log.info("我通知了:"+body);
String associatedData = ((Map<String,String>)mapMap.get("resource")).get("associated_data");
String nonceres = ((Map<String,String>)mapMap.get("resource")).get("nonce");
String ciphertext = ((Map<String,String>)mapMap.get("resource")).get("ciphertext");
AesUtil aesUtil = new AesUtil(WxConfig.getApiV3Key().getBytes());
String res = aesUtil.decryptToString(associatedData.getBytes(),nonceres.getBytes(),ciphertext);
log.info("訂單信息:"+res);
Map<String,Object> resmap = gson.fromJson(res,new TypeToken<Map<String,Object>>(){}.getType());
String ordernum = (String) resmap.get("out_trade_no");
QueryWrapper queryWrapper = new QueryWrapper();
queryWrapper.eq("order_num",ordernum);
Yuyue yuyue = iYuyueService.getOne(queryWrapper);
yuyue.setPayStatus("已支付");
//获取预约单号
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd");
int num = iYuyueService.getMaxDayYuyueNum(simpleDateFormat.format(new Date()));
String yuyueNum = String.valueOf(num);
yuyue.setYuyueNum(yuyueNum);
iYuyueService.updateById(yuyue);
this.sendPaySuccessMsg(yuyue);
List<SysUser> sysUserList = iUserService.list();
log.info(sysUserList.toString());
List<String> stringList = new ArrayList<>();
for (SysUser sysUser:sysUserList) {
stringList.add(sysUser.getId());
}
sysBaseAPI.sendWebSocketMsg(stringList.toArray(new String[stringList.size()]), "新订单");
return Result.OK();
}
5.退款
@GetMapping("/payRefund")
public Result payRefund(@RequestParam String orderNum) throws Exception {
QueryWrapper queryWrapper = new QueryWrapper();
queryWrapper.eq("order_num",orderNum);
Yuyue yuyue = iYuyueService.getOne(queryWrapper);
if(!yuyue.getStatus().equals("未录入")){
return Result.error("当前订单无法退款");
}
if(yuyue.getStatus().equals("已录入")){
return Result.error("当前订单已完成不支持退款");
}
if(yuyue.getStatus().equals("已退款")){
return Result.error("非法操作");
}
String privateKey = WxConfig.getPrivateKey();
PrivateKey merchantPrivateKey = PemUtil.loadPrivateKey(
new ByteArrayInputStream(privateKey.getBytes("utf-8")));
String apiV3Key = "";
String merchantId = "";
String merchantSerialNumber = "";
String appid = "";
Verifier verifier = this.getVerifier();
WechatPayHttpClientBuilder builder = WechatPayHttpClientBuilder.create()
.withMerchant(merchantId, merchantSerialNumber, merchantPrivateKey)
.withValidator(new WechatPay2Validator(verifier));
// ... 接下来,你仍然可以通过builder设置各种参数,来配置你的HttpClient
// 通过WechatPayHttpClientBuilder构造的HttpClient,会自动的处理签名和验签,并进行证书自动更新
CloseableHttpClient httpClient = builder.build();
String url = "https://api.mch.weixin.qq.com/v3/refund/domestic/refunds";
HttpPost httpPost = new HttpPost(url);
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();
int money = (int)(Double.parseDouble(yuyue.getPayMoney())*100);
rootNode.put("out_trade_no",yuyue.getOrderNum())
.put("out_refund_no", yuyue.getOrderNum())
.put("reason", "用户申请退款");
rootNode.putObject("amount")
.put("refund", money)
.put("total", money)
.put("currency", "CNY");
objectMapper.writeValue(bos, rootNode);
log.info(String.valueOf(rootNode));
httpPost.setEntity(new StringEntity(bos.toString("UTF-8"), "UTF-8"));
CloseableHttpResponse response = httpClient.execute(httpPost);
log.info(String.valueOf( response.getStatusLine().getStatusCode()));
String bodyAsString = EntityUtils.toString(response.getEntity());
log.info(bodyAsString);
String code = String.valueOf(response.getStatusLine().getStatusCode());
if(code.equals("200")){
yuyue.setPayStatus("已退款");
iYuyueService.updateById(yuyue);
this.sendPayCancelMsg(yuyue);
return Result.OK();
}else{
return Result.error("退款失败");
}
}
- THE END -
最后修改:2022年11月27日
非特殊说明,本博所有文章均为博主原创。
如若转载,请注明出处:https://www.95app.top/1449/