微信支付–Native支付(PC网页扫码支付)
一.准备工作
1.申请微信商户号,在微信的开放平台创建一个公众号应用并和商户进行绑定,在这一步你会获得:AppID(公众号的appID),mchid(商户号)
2.配置API key,登录微信商户平台,进入【账户中心 > API安全 > API安全】目录,点击【APIV3密钥】,也可以只配置API密钥。
在这一步你会获取到到一个新的参数:APi_Key(api密钥)
注意:申请微信材料可以查看微信接入引导:https://pay.weixin.qq.com/wiki/doc/apiv3/open/pay/chapter2_1.shtml
进行配置申请。
二.代码开发
1.完成以上步骤可获取到参数:AppID(公众号的appID),mchid(商户号),APi_Key(api密钥)。
2.java服务端代码。
(1).引入依赖
<!--微信的工具依赖-->
<dependency>
<groupId>com.github.wxpay</groupId>
<artifactId>wxpay-sdk</artifactId>
<version>0.0.3</version>
</dependency>
<!-- 二维码生成依赖 -->
<dependency>
<groupId>com.google.zxing</groupId>
<artifactId>core</artifactId>
<version>2.1</version>
</dependency>
<dependency>
<groupId>com.google.zxing</groupId>
<artifactId>javase</artifactId>
<version>2.1</version>
</dependency>
微信工具依赖只是将微信订单的参数进行map转成XmL格式,或者将xml转成map,因为微信统一下单需要将订单信息转成xml格式。
二维码依赖是将微信下单成功后微信官方返回的code_url
你可以将这个参数个前端让他们去生成二维码。也可以自己生成给前端访问。
(2).功能代码
支付需要使用的常量配置
WxConfig – (自定以一个类名也行)
/**
* 微信公众账号
*/
public final static String APPID = "wxxxxxxxxxxxxx";
/**
* 商户号
*/
public final static String MCH_ID = "xxxxxxxx";
/**
* API密钥
*/
public final static String API_KEY = "xxxxxxxxxxxxxxxxxxxx";
/**
*异步回调地址
* */
public final static String notify_url = "http://htk5yt.natappfree.cc/wxpaycontroller/wxPayBynotify";
注:以上参数的异步回调地址不能使用IP去做,需要使用域名可以自己搞一个端口穿孔。
统一下单
一下自己封装的工具类
/**
* 微信的Pc统一支付(Native)
* (非证书模式)
*
* @param orderId 订单号
* @param price 金额(分)--格式:0.01
* @param body 商品描述
*/
public static JsonResult createNative(
String orderId,
String price,
String body,
HttpServletRequest request
) {
JsonResult jsonResult = new JsonResult();
try {
log.info("微信创建统一支付订单! 订单号:" + orderId + " 支付金额: " + price + " 商品描述: " + body);
//todo 创建请求参数
SortedMap<String, String> req = new TreeMap<String, String>();
req.put("appid", WxPayConfig.APPID); //公众号appID -- 引入上面的参数
req.put("mch_id", WxPayConfig.MCH_ID); // 商户号
req.put("nonce_str", WXPayUtil.generateNonceStr()); // 32位随机字符串
req.put("body", body); // 商品描述
req.put("out_trade_no", orderId); // 商户订单号
req.put("total_fee", df.format(Double.parseDouble(price) * 100)); // 标价金额(分)
req.put("spbill_create_ip", WxPayHttpUtil.getIp(request)); // 终端IP
req.put("notify_url", WxPayConfig.notify_url); // 回调地址
req.put("trade_type", "NATIVE"); // 交易类型
req.put("sign", WXPayUtil.generateSignature(req, WxPayConfig.API_KEY, WXPayConstants.SignType.MD5)); // 签名
//todo 生成要发送的 xml
String xmlBody = WXPayUtil.generateSignedXml(req, WxPayConfig.API_KEY);
System.err.println(String.format("微信支付预下单请求 xml 格式:\n%s", xmlBody));
//todo 发送 POST 请求 统一下单 API 并携带 xmlBody 内容,然后获得返回接口结果
String result = WxPayHttpUtil.httpsRequest("https://api.mch.weixin.qq.com/pay/unifiedorder", "POST", xmlBody);
System.err.println(String.format("%s", result));
//todo 将返回结果从 xml 格式转换为 map 格式
Map<String, String> resultMap = WXPayUtil.xmlToMap(result);
Map<String, String> map = new HashMap<>();
map.put("code_url", resultMap.get("code_url")); // 支付地址
map.put("total_fee", price); // 总金额
map.put("out_trade_no", orderId); // 订单号
//后台生成二维码,建议给前台生成
String codeurl = resultMap.get("code_url");
String destpath = "E:/wximg";
log.info("微信统一下单成功: codeurl " + codeurl);
jsonResult.setSuccess(true);
jsonResult.setObj(map);
jsonResult.setMsg("微信统一下单成功");
return jsonResult;
} catch (Exception e) {
e.printStackTrace();
log.error("微信统一下单失败! 异常:" + e.getMessage());
jsonResult.setSuccess(false);
jsonResult.setObj(e.getMessage());
jsonResult.setMsg("微信统一下单失败");
return jsonResult;
}
}
/**
* 微信异步回调处理
*/
public static JsonResult wxNotify(HttpServletRequest request) {
JsonResult jsonResult = new JsonResult();
WXPayConfig mywxpay = new WXPayConfig() {
@Override
public String getAppID() {
return WxPayConfig.APPID;
}
@Override
public String getMchID() {
return WxPayConfig.MCH_ID;
}
@Override
public String getKey() {
return WxPayConfig.API_KEY;
}
@Override
public InputStream getCertStream() {
return null;
}
@Override
public int getHttpConnectTimeoutMs() {
return 0;
}
@Override
public int getHttpReadTimeoutMs() {
return 0;
}
};
WXPay wxPay = new WXPay(mywxpay);
String returnXmlMessage = null;
String notifyXmlData = null;
try {
notifyXmlData = readXmlFromStream(request);
Map<String, String> notifyMapData = WXPayUtil.xmlToMap(notifyXmlData);
log.info("解析微信支付回调map成功"+ JSON.toJSONString(notifyMapData));
// 验证签名
boolean signatureValid = wxPay.isPayResultNotifySignatureValid(notifyMapData);
if (signatureValid) {
log.info("验签成功!");
// TODO:订单支付成功之后相关业务逻辑...
// 支付成功
log.info("微信支付成功回调!");
//商品订单号
String out_trade_no = notifyMapData.get("out_trade_no"); // 商品订单号
log.info("微信商品订单号: " + out_trade_no);
// 当前交易状态
String tradeStatus = notifyMapData.get("return_code"); //当前交易状态
log.info("微信当前交易状态: " + tradeStatus);
// 支付金额
String totalAmount = notifyMapData.get("total_fee"); //支付金额
log.info("微信支付金额: " + totalAmount);
// 支付时间
String payDate = notifyMapData.get("time_end"); //支付时间
log.info("微信支付时间: " + payDate);
//流水号--支付宝交易号。支付宝交易凭证号。
String tradeNo = notifyMapData.get("transaction_id"); //流水号
log.info("微信交易号: " + tradeNo);
Map<String, String> map = new HashMap<>();
map.put("tradeNo", tradeNo);
map.put("out_trade_no", out_trade_no);
map.put("tradeStatus", tradeStatus);
map.put("totalAmount", totalAmount);
map.put("payDate", payDate);
jsonResult.setSuccess(true);
jsonResult.setMsg("微信支付成功");
jsonResult.setObj(map);
return jsonResult;
} else {
//支付其他状态
log.info("微信支付回调其他状态");
return jsonResult.setSuccess(false).setMsg("微信支付回调其他状态");
}
} catch (IOException e) {
log.error("微信回调异常:解析网络参数异常:" + e.getMessage());
return jsonResult.setSuccess(false).setMsg("微信回调异常:解析网络参数异常:" + e.getMessage());
} catch (Exception e) {
log.error("微信回调异常:" + e.getMessage());
return jsonResult.setSuccess(false).setMsg("微信回调异常:" + e.getMessage());
}
}
/**
* 微信订单状态查询
* @param orderId
**/
public static Map<String,String> wxOrderStart(String orderId){
try {
//todo 创建请求参数
SortedMap<String, String> req = new TreeMap<String, String>();
req.put("appid", WxPayConfig.APPID); // 公众号ID
req.put("mch_id", WxPayConfig.MCH_ID); // 商户号
req.put("out_trade_no", orderId); // 订单号
req.put("nonce_str", WXPayUtil.generateNonceStr()); // 随机字符串
req.put("sign", WXPayUtil.generateSignature(req, WxPayConfig.API_KEY, WXPayConstants.SignType.MD5));
//todo 生成要发送的 xml
String xmlBody = WXPayUtil.generateSignedXml(req, WxPayConfig.API_KEY);
System.err.println(String.format("查询订单支付状态 xml 格式:\n%s", xmlBody));
//todo 调用查询订单支付状态 API
String result = WxPayHttpUtil.httpsRequest("https://api.mch.weixin.qq.com/pay/orderquery", "POST", xmlBody);
//todo 返回解析后的 map 数据
Map<String, String> map = WXPayUtil.xmlToMap(result);
System.out.println(String.format("%s", map));
return map;
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
注:以上用的WxPayConfig是上面代码自己定义的微信支付参数
自己在也一个Controller接口去调用就行
异步回调:service层
@Override
public void wxPayBynNotify(HttpServletRequest request) {
//微信异步回调
JsonResult jsonResult = new JsonResult();
jsonResult = WxPayUtil.wxNotify(request);
boolean orderstart = jsonResult.getSuccess();
if (orderstart) {
Map<String, String> map = (Map) jsonResult.getObj();
//商品订单号
String out_trade_no = map.get("out_trade_no"); // 商品订单号
// 当前交易状态
String tradeStatus = map.get("tradeStatus"); //当前交易状态
// 支付金额
String totalAmount = map.get("totalAmount"); //支付金额
// 支付时间
String payDate = map.get("payDate"); //支付时间
//流水号--微信交易号。微信交易凭证号。
String tradeNo = map.get("tradeNo"); //流水号
log.info("微信参数取出: out_trade_no: " + out_trade_no + " tradeStatus: " + tradeStatus + " totalAmount: " + totalAmount + " payDate: " + payDate + " tradeNo: " + tradeNo);
//自己处理业务
} else {
log.error("订单不存在");
}
} else {
log.info("微信回调处理异常待处理");
}
}
因为PC端是生成二维码,要写一个获取订单状态的接口去查订单状态
状态查询:service层
@Override
public JsonResult wxPayByOrderStart(String orderId) {
JsonResult jsonResult = new JsonResult();
int x = 0;
// 调用查询微信支付订单状态方法
Map<String, String> map = WxPayUtil.wxOrderStart(orderId);
Map<String,Integer> startmap = new HashMap<>();
// startmap的状态说明:1不要刷新二维码等待支付,2刷新二维码就是重新调用下单,3,订单支付成功前端跳转页面
try {
log.info("微信状态查询:" + JSON.toJSONString(map));
if (map.isEmpty()) {
//支付出错
return jsonResult.setSuccess(false).setMsg("支付出错,重新调用统一下单,刷新二维密码。");
}
if (map.get("trade_state").equals("SUCCESS")) {
//支付成功
startmap.put("start",3);
return jsonResult.setSuccess(true).setMsg("订单支付成功!").setObj(startmap);
}else if(map.get("trade_state").equals("NOTPAY")){
//订单未支付
startmap.put("start",1);
return jsonResult.setSuccess(true).setMsg("订单等待支付中!").setObj(startmap);
}
} catch (Exception e) {
//进入其中的话就说明账号没有问题,是订单有问题,处理map里面返回的错误码
String err_code = map.get("err_code");
String err_msg = map.get("err_code_des");
if(err_code.equals("USERPAYING")){
// USERPAYING--用户支付中,需要输入密码
startmap.put("start",1);
return jsonResult.setSuccess(true).setMsg(err_msg).setObj(startmap);
}else if(err_code.equals("TRADE_ERROR")){
// TRADE_ERROR--交易错误
startmap.put("start",2);
return jsonResult.setSuccess(true).setMsg(err_msg).setObj(startmap);
}else if(err_code.equals("SYSTEMERROR")){
// SYSTEMERROR--系统错误
startmap.put("start",2);
return jsonResult.setSuccess(true).setMsg(err_msg).setObj(startmap);
}else if(err_code.equals("OUT_TRADE_NO_USED")){
// OUT_TRADE_NO_USED--订单号重复
startmap.put("start",2);
return jsonResult.setSuccess(true).setMsg(err_msg).setObj(startmap);
}else if(err_code.equals("ORDERNOTEXIST")){
// ORDERNOTEXIST--订单不存在
startmap.put("start",2);
return jsonResult.setSuccess(true).setMsg(err_msg).setObj(startmap);
}else if(err_code.equals("ORDER_CLOSED")){
// ORDER_CLOSED--订单已关闭,当前订单已关闭,请重新下单
startmap.put("start",2);
return jsonResult.setSuccess(true).setMsg(err_msg).setObj(startmap);
}else{
startmap.put("start",2);
return jsonResult.setSuccess(true).setMsg(err_msg).setObj(startmap);
}
}
return jsonResult.setSuccess(false).setMsg("重新");
}