这篇来讲下微信支付的开发
上面那张图偷字微信开发文档,微信支付方式有很多种,我们今天主要说的是JSAPI,你问其他的咋整,等我做完了再说
啥事JSAPI呢,就是下图这种,通俗的讲就是输入密码的
大家可以先康康这个,微信支付的文档,图太大了,扣成了两幅
https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=7_4
看了上面的图,你的想法应该是,give up,我们从代码一点点来,我会在代码中写注解,对应上面那个步骤,如果你懂,只是想cv 代码,那你你直接把代码里的注解删了吧。
1.先做准备工作,看到那个SDK和DEMO下载了吗,我们是java 当然得选java咯。里面提供了各种封装好的,比如xml 转json啥的方法,如果你是大牛,你想自己写,也…也行。不过相信我你又会来下载的。
先写核心代码,工具类贴在下面,我把注解写的很详细很详细了,如果少了哪个类,留言
//支付购买商品 单件
@RequestMapping(value = "/url")
public Map JsApi(String ip, String openid,Integer commodityId) {
//前面你可以写逻辑,判断是否要开启支付啥的
//这里正式开始支付
//这是个MyConfig类,里面主要配置了APPID MCHID 还有密匙 类贴在下面
WXPayConfig config = new MyConfig(ConstantsWechat.APP_ID, ConstantsWechat.MCH_ID, ConstantsWechat.KEY);
//这是个SDK里面的类
WXPay wxPay;
try {
//下面填的是回调地址,记住一定要填域名+回调的Url ,我的回调是/weChatReturnCommodity
wxPay = new WXPay(config,"域名/weChatReturnCommodity");
wxPay.setSignType(SignType.HMACSHA256);
} catch (Exception e) {
e.printStackTrace();
logger.error("初始化微信支付失败", e);
return null;
}
//微信要进行两次签名,这里是第一次
Map<String, String> payMap = new HashMap<>();
payMap.put("device_info", "LibraryCommodity");//机器号 可写项目名称
//WXPayConstants 这个也是SDK里的
payMap.put("sign_type", WXPayConstants.HMACSHA256);//签名类型 默认 HMACSHA256 类型 可以MD5 类型
payMap.put("body", "Commodity");
payMap.put("attack", "");//附加数据 //0表示不用从购物车里清除数据 1表示从购物车中来需要清除数据
payMap.put("nonce_str", WXPayUtil.generateNonceStr()); //获取随机字符串
//这里测试 id如果你写死了,付一次有用,第二次无效了,id应不能重复
payMap.put("out_trade_no", id);
//下面填的是回调地址,记住一定要填域名+回调的Url ,我的回调是/weChatReturnCommodity
payMap.put("notify_url", "https://1194.shuntun.com/weChatReturnCommodity");
payMap.put("fee_type", "CNY"); //货币类型
//记住单位是分,传过去要字符串
payMap.put("total_fee", (int)(commodity.getMoney()*100)+"");
//这个经过测试,无用处,可直接写死127.0.0.1 进入登录界面,获取
payMap.put("spbill_create_ip", ip);
//支付类型
payMap.put("trade_type", "JSAPI");
//可根据微信网页授权获取openid 能看到这里你总不会不知道咋拿openid吧
payMap.put("openid", openid);
//数据转换
String jsonString = JSON.toJSONString(payMap);
logger.info("【微信支付】上送:" + jsonString);
Map<String, String> payData;
try {
payData = wxPay.unifiedOrder(payMap);
String toJSONString = JSON.toJSONString(payData);
logger.info("【微信支付】结果:" + toJSONString);
} catch (Exception e) {
e.printStackTrace();
logger.error("发起微信支付失败", e);
return null;
}
String returnCode = payData.get("return_code");
logger.info("【微信支付】返回状态码:" + returnCode);
if (returnCode.equals("FAIL")) {
String returnMsg = payData.get("return_msg");
logger.info("【微信支付】返回信息:" + returnMsg);
logger.info("【微信支付】保存下单结果:发送失败");
return null;
} else {
//时间戳 这里开始第二次签名
long currentTimestamp = WXPayUtil.getCurrentTimestamp();
String nonce_str = WXPayUtil.generateNonceStr();
String prepayId = payData.get("prepay_id");
Map<String, String> singData = new HashMap<>();
singData.put("appId", ConstantsWechat.APP_ID);
singData.put("timeStamp", "" + currentTimestamp);//时间戳
singData.put("nonceStr", nonce_str); //随机字符串
singData.put("package", "prepay_id=" + prepayId); //注意参数
singData.put("signType", WXPayConstants.HMACSHA256);
String paySign = null;
try {
paySign = WXPayUtil.generateSignature(singData, ConstantsWechat.KEY, SignType.HMACSHA256);
} catch (Exception e) {
e.printStackTrace();
}
singData.put("paySign", paySign);
//这里返回后是个xml格式的,就能在小程序中唤起支付程序,就那个输入密码的那个界面
//用户支付成功后,微信平台会根据你的回调地址,来告诉你,这个订单他成功了
return singData;
}
}
回调函数
//单件商品回调 回调地址千万别写错,不然你就gg 还要要把你的域名配置到微信小程序注册的那个地方
@RequestMapping(value = "/weChatReturnCommodity")
public void weChatReturnCommodity(HttpServletRequest request, HttpServletResponse response) throws Exception {
System.out.println("开始回调----------------------------------------");
try {
request.setCharacterEncoding("UTF-8");
response.setCharacterEncoding("UTF-8");
int totalBytes = request.getContentLength();
DataInputStream in = new DataInputStream(request.getInputStream());
byte[] data = new byte[totalBytes];
in.readFully(data);
// 支付结果通知的xml格式数据
String notifyData = new String(data);
// 转换成map
Map<String, String> notifyMap = WXPayUtil.xmlToMap(notifyData);
if (notifyMap.get("return_code").equals(WXPayConstants.SUCCESS) && notifyMap.get("result_code").equals(WXPayConstants.SUCCESS)) {
//到这里说明,这个人钱已经付成功了,你可以根据订单号来写自己对应的逻辑
//获取订单号
String oId = notifyMap.get("out_trade_no");
//逻辑
//逻辑
//逻辑
}
logger.info("支付成功" + notifyMap);
//这里你收到回调消息后你要告诉下微信平台,不然微信平台好像隔一段时间就会来问候你一下,你收到了吗?你收到了吗?你收到了吗?
String responseXml = "<xml><return_code><![CDATA[SUCCESS]]></return_code><return_msg><![CDATA[OK]]></return_msg></xml>";
response.getWriter().write(responseXml);
} catch (Exception e) {
logger.error(e.toString(), e);
}
System.out.println("结束回调----------------------------------------");
}
//到这里就结束了,其实在有SDK封装的情况下,如果理解大致流程就不难。应该没忘记啥工具类了,网上很多教程都不放工具类,本人深受其害,如果我忘了,死命call我。
工具类
MyConfig 主要配置参数
import org.springframework.stereotype.Component;
import java.io.ByteArrayInputStream;
import java.io.InputStream;
@Component
public class MyConfig extends WXPayConfig {
private byte[] certData;
private String appId;
private String mchId;
private String key;
public MyConfig() {
}
public MyConfig(String appId, String mchId, String key) {
this.appId = appId;
this.mchId = mchId;
this.key = key;
}
public MyConfig(String appId, String mchId, String key, byte[] certData) {
this.appId = appId;
this.mchId = mchId;
this.key = key;
this.certData = certData;
}
@Override
String getAppID() {
return appId;
}
@Override
String getMchID() {
return mchId;
}
@Override
String getKey() {
return key;
}
@Override
InputStream getCertStream() {
return new ByteArrayInputStream(this.certData);
}
@Override
IWXPayDomain getWXPayDomain() {
return new IWXPayDomain() {
@Override
public void report(String domain, long elapsedTimeMillis, Exception ex) {
}
@Override
public DomainInfo getDomain(WXPayConfig config) {
return new DomainInfo(WXPayConstants.DOMAIN_API, true);
}
};
}
}