JAVA实现微信支付以及微信回调接口(Notify_url)问题处理
根据自己的业务需要选择支付方式,查看官方文档开发模式图和API列表
首先支持微信支付开发需要给商家后台绑定公众号/或者小程序,需要设置扫码回调链接地址/H5支付域名设置/JSAPI支付授权目录
private final String appid = “小程序ID/公众号ID”
private final String mch_id = ”小程序绑定商户ID“
private final String key = ”商户后台设置得key“
微信支付开发工具类POM文件:
<dependency>
<groupId>com.github.wxpay</groupId>
<artifactId>wxpay-sdk</artifactId>
<version>0.0.3</version>
</dependency>
Native支付:API列表
Java后台代码编写
Controller层代码:
/**
* 微信支付接口
* @param
* @param mobile 手机号
* @param money 付款金额(类型根据自己业务可选)
* @param type 购买类型
*/
@RequestMapping("/jnonly/wxPay")
public ModelAndView wxPay(HttpServletResponse response,String mobile,int money,String type){
Map<String, Object> data = new HashMap();
//此处需要将该订单存入到数据库用来记录数据以及后续其他业务使用
//微信支付的商户订单号
if (StringUtils.isNotEmpty(mobile) && StringUtils.isNotEmpty(String.valueOf(money)) && StringUtils.isNotEmpty(type)){
//唯一订单号
String out_trade_no = String.valueOf(idWorker.nextId());
System.out.println(out_trade_no);
System.out.println(mobile);
jnonlyService.addOrderMgtv(out_trade_no,mobile,money,type);
//总价格 单位:分
String total_fee = String.valueOf(money * 100);
Map map = mangGuoService.creatNative(out_trade_no,total_fee,String ip);
map.put("type",type);
map.put("mobile",mobile);
data.put("data",map);
return new ModelAndView().addObject(data);
}else {
data.put("message","参数不全,不能生成二维码!");
data.put("status","0");
return new ModelAndView().addObject(data);
}
}
Service层实现类代码:
/**
* 支付生成二维码扫描
* @param out_trade_no 商户订单号
* @param total_fee 总价格:单位分
* @param ip IP地址
* @return
*/
@Override
public Map creatNative(String out_trade_no, String total_fee ,String ip) {
//封装所需要的必须参数
Map<String,String> param = new HashMap();
//公众号ID
param.put("appid",appid);
//商户ID
param.put("mch_id",mch_id);
//随机字符串
param.put("nonce_str", WXPayUtil.generateNonceStr());
//商品描述
param.put("body","商品描述");
//商户订单号
param.put("out_trade_no",out_trade_no);
//订单总金额,单位为分
param.put("total_fee", total_fee);
//用户的客户端IP
param.put("spbill_create_ip",ip);
//异步接收微信支付结果通知的回调地址,通知url必须为外网可访问的url,不能携带参数。
param.put("notify_url","自己微信商家后台设置得回调地址");
//交易类型
param.put("trade_type","NATIVE");
try {
String xmlParam = WXPayUtil.generateSignedXml(param, key);
//参数封装完成然后发送POST请求
logger.info("微信支付所需要的参数:" + xmlParam);
HttpClientWx client = new HttpClientWx("https://api.mch.weixin.qq.com/pay/unifiedorder");
client.setHttps(true);
client.setXmlParam(xmlParam);
client.post();
String result = client.getContent();
Map<String, String> resultMap = WXPayUtil.xmlToMap(result);
logger.info("微信返回的结果:" + resultMap);
//加密参数
String sign = resultMap.get("sign");
String signedXml = WXPayUtil.generateSignedXml(resultMap, key);
//判断加密参数是否一致
if (signedXml.contains(sign)){
logger.info("签名一致!");
Map<String,String> map = new HashMap();
//支付地址,要生成二维码的地址
map.put("code_url",resultMap.get("code_url"));
//总金额(分)
map.put("total_fee",total_fee);
//订单号
map.put("out_trade_no",out_trade_no);
return map;
}
return new HashMap();
} catch (Exception e) {
e.printStackTrace();
return new HashMap();
}
}
获取IP地址接口
/**
* 获取IP地址接口
* @param request
* @return
*/
public static String getIpAddr(HttpServletRequest request) {
String ip = request.getHeader("X-Forwarded-For");
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_CLIENT_IP");
}
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
ip = request.getHeader("HTTP_X_FORWARDED_FOR");
}
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
ip = request.getRemoteAddr();
}
if(StringUtils.contains(ip, ",")){
ip = StringUtils.split(ip, ",")[1];
ip = StringUtils.trim(ip);
}
return ip;
}
微信查询订单接口(此处可以有两种实现方法,一种是前端定时轮询,另一种是后端代码实现)
- 第一种:前端定时轮询接口
@RequestMapping("/jnonly/cooperate/wxPaySearch")
public ModelAndView wxPaySearch(HttpServletResponse response,String out_trade_no) throws Exception {
logger.info("开始查询微信订单");
Map<String, Object> data = new HashMap();
Map map = jnonlyService.wxPaySearch(out_trade_no);
data.put("data",map);
if (map == null){
//出错
data.put("message","未支付");
data.put("status","0");
}
if (map.get("trade_state").equals("SUCCESS")){
data.put("message","支付成功");
//如果支付成功,修改订单状态 微信交易流水号 之后根据订单号修改订单信息
String transaction_id = (String) map.get("transaction_id");
jnonlyService.updateUUidMgtv(transaction_id,out_trade_no);
data.put("status","1");
}
if (map.get("trade_state").equals("NOTPAY")){
data.put("message","未支付");
data.put("status","0");
}
if(map.get("trade_state").equals("USERPAYING")){
data.put("message","用户支付中");
data.put("status","2");
}
if (map.get("trade_state").equals("PAYERROR")){
data.put("message","支付失败");
data.put("status","3");
}
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
return new ModelAndView().addObject(data);
}
- 第二种后端实现
@RequestMapping("/jnonly/cooperate/wxPaySearch")
public ModelAndView wxPaySearch(HttpServletResponse response,String out_trade_no) throws Exception {
int x = 0;
while (true){
Map map = jnonlyService.wxPaySearch(out_trade_no);
data.put("data",map);
if (map == null){
//出错
data.put("message","未支付");
data.put("status","0");
break;
}
if (map.get("trade_state").equals("NOTPAY")){
data.put("message","未支付");
data.put("status","0");
break;
}
if (map.get("trade_state").equals("SUCCESS")){
data.put("message","支付成功");
//如果支付成功,修改订单状态 微信交易流水号 之后根据订单号修改订单信息
String transaction_id = (String) map.get("transaction_id");
jnonlyService.updateUUidMgtv(transaction_id,out_trade_no);
data.put("status","1");
break;
}
if (map.get("trade_state").equals("NOTPAY")){
data.put("message","未支付");
data.put("status","0");
break;
}
if (map.get("trade_state").equals("USERPAYING")){
data.put("message","用户支付中");
data.put("status","2");
break;
}
if (map.get("trade_state").equals("PAYERROR")){
data.put("message","支付失败");
data.put("status","3");
break;
}
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
//为了不让循环无休止地运行,我们定义一个循环变量,如果这个变量超过了这个值则退出循环,设置时间为2分钟
x++;
if (x >= 40){
logger.info("第:"+ x + "次循环查询");
data.put("message","二维码超时");
data.put("status","-1");
break;
}
}
logger.info(data);
return new ModelAndView().addObject(data);
}
微信查询service层实现类代码
@Override
public Map wxPaySearch(String out_trade_no) {
//封装所需要的必须参数
Map<String,String> param = new HashMap();
//公众号ID
param.put("appid",appid);
//商户号
param.put("mch_id",mch_id);
//商户订单号
param.put("out_trade_no",out_trade_no);
//随机字符串
param.put("nonce_str",WXPayUtil.generateNonceStr());
try {
String xmlParam = WXPayUtil.generateSignedXml(param, key);
HttpClientWx clientWx = new HttpClientWx("https://api.mch.weixin.qq.com/pay/orderquery");
clientWx.setHttps(true);
clientWx.setXmlParam(xmlParam);
clientWx.post();
String resultContent = clientWx.getContent();
Map<String, String> resultMap = WXPayUtil.xmlToMap(resultContent);
return resultMap;
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
微信支付回调接口:
微信支付成功之后会对设置得回调接口发出结果通知注意事项
/**
* 微信支付回调信息接口
*/
@RequestMapping("notify_url")支付下单接口当中填写的对应回调接口
@ResponseBody
public String getRefund(HttpServletRequest request,HttpServletResponse response) throws Exception {
InputStream inputStream = request.getInputStream();
BufferedReader in = new BufferedReader(new InputStreamReader(inputStream,"UTF-8"));
StringBuffer sb = new StringBuffer();
//1、将微信回调信息转为字符串
String line ;
while ((line = in.readLine()) != null){
sb.append(line);
}
in.close();
inputStream.close();
Map<String, String> stringStringMap = WXPayUtil.xmlToMap(sb.toString());
String out_trade_no = stringStringMap.get("out_trade_no");
String total_fee = stringStringMap.get("total_fee");
String result_code =stringStringMap.get("result_code");
List<Map> map = mangGuoService.getParam(out_trade_no);
if (map.size() > 0 && result_code.equals("success")){
//支付成功之后所需要进行得业务性操作
}
Map<String, String> responseMap = new HashMap<>();
//此处一定要有响应的返回信息要不然回重复调用
String xmlBack = "<xml>" + "<return_code><![CDATA[SUCCESS]]></return_code>" + "<return_msg><![CDATA[SUCCESS]]></return_msg>" + "</xml> ";
return xmlBack;
}
JSAPI支付:业务流程
首先需要在微信商家后台设置支付配置:商家后台开发者配置
需要设置JSAPI授权目录,支付成功回调接口链接,H5支付域名
还需要在公众号里面设置网页授权域名(如果商家后台绑定的是小程序是没用这个功能的)
JSAPI支付是需要openid这个参数,所以我们要获取openid,此处用网页授权获取openid。
如果只需要openid的话到第二步骤就可以获取到,如果是需要用户的信息需要都实现每个操作步骤
获取code的时候最重要的就是作用域scope:
测试地址:https://open.weixin.qq.com/connect/oauth2/authorize?appid=wx520c15f417810387&redirect_uri=https%3A%2F%2Fchong.qq.com%2Fphp%2Findex.php%3Fd%3D%26c%3DwxAdapter%26m%3DmobileDeal%26showwxpaytitle%3D1%26vb2ctag%3D4_2030_5_1194_60&response_type=code&scope=snsapi_base&state=123#wechat_redirect
JSAPI支付接口
/**
* 微信JSAPI支付
* @param request
* @param response
* @param phone 要购买会员得手机号
* @param type 购买套餐类型
* @param code 用于获取openid得code知
* @return
*/
@RequestMapping("/jnonly/cooperate/getJhZfjsapi")
public ModelAndView getZfJsapi(HttpServletRequest request,HttpServletResponse response,String phone,String type,String code,Long money){
String total_fee = "";
String codeParam = request.getParameter("code");
Map<String, Object> orderJSAPI = new HashMap();
//根据获取的code值来获取用户ID
String query = "appid=关联appid&secret=密钥&code="+code + "&grant_type=authorization_code";
String url = "https://api.weixin.qq.com/sns/oauth2/access_token?";
String responseMessage = HttpClientUtil.sendGet(url, query);
Map<?, ?> responeMap = NuomiUtils.parseJson(responseMessage);
//获取用户ID
total_fee = String.valueOf(money);
String openid = (String) responeMap.get("openid");
if (StringUtils.isNotEmpty(phone) && StringUtils.isNotEmpty(String.valueOf(money)) && StringUtils.isNotEmpty(type) && StringUtils.isNotEmpty(openid)){
BigDecimal ch = new BigDecimal(100);
BigDecimal price = new BigDecimal(money);
price = price.divide(ch);
String mgPrice = jnonlyService.getMgPrice(type);
BigDecimal totalPrice = new BigDecimal(mgPrice);
int i = totalPrice.compareTo(price);
if (totalPrice.compareTo(price) == 0){
String out_trade_no = String.valueOf(idWorker.nextId());
orderJSAPI = jnonlyService.addOrderJSAPI(out_trade_no, total_fee,openid);
jnonlyService.addOrderMgtvJhZf(out_trade_no,phone,money,type);
orderJSAPI.put("total_fee",total_fee);
orderJSAPI.put("out_trade_no",out_trade_no);
}
}
return new ModelAndView().addObject(orderJSAPI);
}
JSAPI支付前端处理接口数据代码微信内H5调起支付
// 获取微信内支付 参数
function insideWxPay() {
$.ajax({
url: baseUrl+'jnonly/cooperate/getJhZfjsapi.json',
data: {
code: code,
phone: phoneNum,
money: totalPrice,
type: type
},
type: 'get',
dataType: 'json',
success: function (res) {
var weChatParameter = {
timeStamp: res.hashMap.timeStamp,
package: res.hashMap.package,
appId: res.hashMap.appId,
signType: res.hashMap.signType,
nonceStr: res.hashMap.nonceStr,
paySign: res.hashMap.paySign
}
orderId = res.hashMap.out_trade_no;
window.localStorage.setItem("orderId", orderId);
if (typeof WeixinJSBridge === 'undefined') {
if (document.addEventListener) {
document.addEventListener('WeixinJSBridgeReady', onBridgeReady(weChatParameter), false)
} else if (document.attachEvent) {
document.attachEvent('WeixinJSBridgeReady', onBridgeReady(weChatParameter))
document.attachEvent('onWeixinJSBridgeReady', onBridgeReady(weChatParameter))
}
} else {
onBridgeReady(weChatParameter)
}
},
error: function (err) {
alert('调取微信支付失败,请稍后再试')
}
})
}
// 微信内支付方法
function onBridgeReady(weChatParameter) {
WeixinJSBridge.invoke(
'getBrandWCPayRequest', {
"appId": weChatParameter.appId, //公众号名称,由商户传入
"timeStamp": weChatParameter.timeStamp, //时间戳,自1970年以来的秒数
"nonceStr": weChatParameter.nonceStr, //随机串
"package": weChatParameter.package,
"signType": weChatParameter.signType, //微信签名方式:
"paySign": weChatParameter.paySign //微信签名
},
function (res) {
// if (res.err_msg == "get_brand_wcpay_request:ok") {
// 使用以上方式判断前端返回,微信团队郑重提示:
//res.err_msg将在用户支付成功后返回ok,但并不保证它绝对可靠。
// 此处没有根据微信返回参数而进行判断,对接其他业务,此处无论支付是否成功都跳转到中间页,用于处理其他业务和在中间页对微信支付订单查询是否支付成功处理。
$(window).attr('location', '中间页URL地址');
// }
});
}
本代码仅仅为项目中抽取部分内容来写笔记文章。
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/77238.html