在此更正,以前的微信支付借用了网上其他一些帖子,要么半桶水,要么有所隐藏,根本没法用。
当你发现百度已经帮不了你的时候,其实你自身已经有一定的高度了。
前面本文浏览次数在100多,可能坑了一些新手,我自己也被坑。再次抱歉!
下面是我自己实际微信扫码支付的过程记录,以供分享!微信扫码支付也称为万金油支付方式,适用很多场合。
首先前提条件得申请微信公众号,需要花一个星期以上的时间。
1、注册公众号(必须选择服务号),注册类型必须(企业/公司,政府,媒体)三选一。
2、认证,必须认真填写材料。认证300一次,不保证成功。被驳回钱打水漂了。
3、提交申请资料:微信支付,1-5个工作日。
4、开户成功,登录商户平台验证。进行测试转账1毛钱。
5、在线签收协议。
其他一些参数的设置可以参考我另一篇文章《微信支付的5个参数获取》
接入正题,开始开发。
前面使用了其他一些三方jar包,其实后来自己做,感觉根本没必要。一个map和xml的转换以及签名,官方的微信SDK都有。感觉根本没必要,再说也不安全,其次是可用性差。
讲讲开发者要做的事:
1、商户后台调用微信接口统一下单,并返回一个code_url。
2、后台把这个code_url发送给前端,前端生成二维码。与支付宝不同,这个二维码要我们自己生成。
3、支付结果微信会通过回调地址返回给系统,系统再返回给前端。
就这么点事,就这么简单、好多文章要么只写前端要么后台,要么简单变复杂化。所以很多新手因此而懵逼。
下面直接上步骤:
第一步:加入微信支付jar包。
这个要自己编译到maven仓库:第三方开源的不安全,参见微信支付官方提示。
怎么整呢?
把官方下载的SDK打包成jar,然后编译到maven仓库就好了。Dfile就是你打包成jar的存放地址
嫌麻烦,你把SDK那些代码拷到你的项目里直接用也是一样的。
<!-- 微信公众号支付依赖 最新版本--> <!--install:install-file -Dfile=E:wxpay-sdk-0.0.3.jar -DgroupId=com.weixin -DartifactId=alipay-sdk-weixin -Dversion=1.0 -Dpackaging=Jar--> <dependency> <groupId>com.weixin</groupId> <artifactId>alipay-sdk-weixin</artifactId> <version>1.0</version> </dependency>
第二步:编写微信支付配置类PayConfig
import org.springframework.stereotype.Component;
/**
* 微信支付配置类
*/
@Component
public class PayConfig {
//初始化
public final static String APP_ID = "123456"; //公众账号appid(改为自己实际的)
public final static String APP_PATH = "";//安全证书路径,没用到
public final static String MCH_ID = "123"; //商户号(改为自己实际的)
public final static String API_KEY = "pass"; //(改为自己实际的)key设置路径:微信商户平台(pay.weixin.qq.com)-->账户设置-->API安全-->密钥设置
//code_url请求地址
public final static String UFDODER_URL = "https://api.mch.weixin.qq.com/pay/unifiedorder";
public final static String NOTIFY_URL = "http://www.a.com/weixinPay/notify"; //微信支付回调接口,就是微信那边收到(改为自己实际的),需要跟微信公众号微信支付设置的一致
//企业向个人账号付款的URL
public final static String SEND_EED_PACK_URL = "https://api.mch.weixin.qq.com/mmpaymkttransfers/promotion/transfers";
//查询订单请求URL
private static final String ORDER_QUERY_REQUEST_URL = "https://api.mch.weixin.qq.com/pay/orderquery";
}
第三步:微信支付控制类
(这个跟前端存在一个交互)service层的一些代码也写在了这里,有点乱。绿色部分是个人业务,不是核心。可以无视
import com.github.wxpay.sdk.WXPayUtil; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.web.bind.annotation.*; import javax.annotation.Resource; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.BufferedOutputStream; import java.io.BufferedReader; import java.io.InputStream; import java.io.InputStreamReader; import java.util.*; /** * 微信支付 */ @Controller @RequestMapping("/weixinPay") public class PayController { final static Logger log = LoggerFactory.getLogger(PayController.class); @Resource private RentingtoolsBiz rentingtoolsBiz; //出租工具订单接口 @Resource private CustomerOrderBiz customerOrderBiz;//客户订单接口 @Resource private BrowseRecordsCommonUtil browseRecordsCommonUtil;//缓存类 @Resource private WebSocketServer webSocketServer;//socket @Resource private PsUserUtils psUserUtils;//缓存类 /** * 跳转到微信支付页面 * @param request * @param model * @return */ @RequestMapping("/payCode") public String payCode(HttpServletRequest request, Model model){ BrowseRecordsUtil browseRecordsUtil= browseRecordsCommonUtil.getBrowseRecords(request); RentingToosOrder order = (RentingToosOrder)browseRecordsUtil.getPayOrder(); model.addAttribute("order",order); return "business/payWeiXin"; } /** * 获取微信支付二维码(前端根据这个返回的数据生成二维码) * @param request */ @ResponseBody @RequestMapping("/weixinCode") public RestObject qrcode(HttpServletRequest request) { try { String data = weixinPay(request); return RestObject.newOk("ok",data); } catch (Exception e) { e.printStackTrace(); } return null; } /** * 微信平台发起的回调方法, * 调用我们这个系统的这个方法接口,将扫描支付的处理结果告知我们系统 * @throws * @throws Exception */ @RequestMapping(value = "/notify") public void weixinNotify(HttpServletRequest request, HttpServletResponse response) throws Exception{ //读取参数 InputStream inputStream ; StringBuffer sb = new StringBuffer(); inputStream = request.getInputStream(); String s ; BufferedReader in = new BufferedReader(new InputStreamReader(inputStream, "UTF-8")); while ((s = in.readLine()) != null){ sb.append(s); } in.close(); inputStream.close(); //解析xml成map Map<String, String> map = WXPayUtil.xmlToMap(sb.toString()); // 账号信息 String key = PayConfig.API_KEY; //key String userId = psUserUtils.getUserId(request); //判断签名是否正确 if(WXPayUtil.isSignatureValid(sb.toString(),key)) { //------------------------------ //处理业务开始 //------------------------------ String resXml = ""; if("SUCCESS".equals((String)map.get("result_code"))){ // 这里是支付成功 //////////执行自己的业务逻辑//////////////// //String mch_id = (String)map.get("mch_id"); //String openid = (String)map.get("openid"); //String is_subscribe = (String)map.get("is_subscribe"); //String out_trade_no = (String)map.get("out_trade_no"); String total_fee = (String)map.get("total_fee");//注意这个金额单位是分 //通知微信.异步确认成功.必写.不然会一直通知后台.八次之后就认为交易失败了. resXml = "<xml>" + "<return_code><![CDATA[SUCCESS]]></return_code>" + "<return_msg><![CDATA[OK]]></return_msg>" + "</xml> "; //这里处理更新数据库订单支付成功的信息####################### } else { resXml = "<xml>" + "<return_code><![CDATA[FAIL]]></return_code>" + "<return_msg><![CDATA[报文为空]]></return_msg>" + "</xml> "; } //------------------------------ //处理业务完毕 //------------------------------ BufferedOutputStream out = new BufferedOutputStream(response.getOutputStream()); out.write(resXml.getBytes()); out.flush(); out.close(); webSocketServer.sendInfo("微信支付失败!","service"+userId); } else{ System.out.println("通知签名验证失败"); } } /** * 发起微信支付 * @param request * @param * @return * @throws Exception */ public String weixinPay(HttpServletRequest request) throws Exception { BrowseRecordsUtil browseRecordsUtil= browseRecordsCommonUtil.getBrowseRecords(request); Order order=browseRecordsUtil.getPayOrder();//获取缓存里的订单信息 Map packageParams=new HashMap(); //这里暂时只处理A类型的业务 if(order instanceof RentingToosOrder){ RentingToosOrder order1=(RentingToosOrder)order; //注意这里的参数都是String类型,否则会报类型转换错误 packageParams.put("appid", PayConfig.APP_ID);//公众账号ID packageParams.put("mch_id", PayConfig.MCH_ID);//商户ID packageParams.put("nonce_str", WXPayUtil.generateNonceStr());//随机字符串 packageParams.put("body", "腾讯视频"); //(调整为自己的名称) packageParams.put("out_trade_no", order1.getId());//订单编号 DecimalFormat decimalFormat = new DecimalFormat("###################.###########"); packageParams.put("total_fee",decimalFormat.format(order1.getTotalPrice() * 100)); //价格的单位为分 packageParams.put("spbill_create_ip",request.getLocalAddr());//请求ip packageParams.put("notify_url", PayConfig.NOTIFY_URL);//异步回调地址 packageParams.put("trade_type", "NATIVE");//交易类型 } try { //支付请求参数,WXPayUtil生成签名并转成xml String xmlParam = WXPayUtil.generateSignedXml(packageParams, PayConfig.API_KEY); //2.发送请求,HttpClientUtil类是封装的一个HttpClient类包含了Https请求兼容的处理方法 HttpClientUtil httpClient=new HttpClientUtil(PayConfig.UFDODER_URL); httpClient.setHttps(true); httpClient.setXmlParam(xmlParam); httpClient.post(); //3.获取结果。这里做一个说明,微信支付jsapi支付授权目录必须跟请求页面地址匹配:例如请求页面是www.a.com/weixinPay/weixin.html // 那么jsapi支付授权目录必须要有www.a.com/weixinPay/的授权地址。其次回调地址要跟设置的一样 // 否则返回的数据为空 String xmlResult = httpClient.getContent(); //log.error("打印微信支付返回的xml"+xmlResult); Map<String, String> mapResult = WXPayUtil.xmlToMap(xmlResult); //log.error("打印微信支付返回的map"+mapResult); log.error("打印微信支付返回的map"+mapResult); String urlCode = mapResult.get("code_url"); log.error(urlCode); //对应链接格式:weixin://wxpay/bizpayurl?sr=XXXXX return urlCode; } catch (Exception e) { e.printStackTrace(); } return null; } }
第四步:前端
前端主要是生成了一个二维码,这里用的是纯前端技术qrious.js。没有后台生成,减少了后台的压力。
再者前端和后台建了socket连接,因此前台也不用轮询请求后台支付是否成功。支付成功后台会告诉前台,且只有一次。
没有建立socket连接的只用后台把支付结果保存,然后前端setInterval()轮询ajax请求返回即可。
HTML
<div id="tab-page"> <img id="codeImg" alt="微信支付二维码" width="300px" height="300px"> </div>
获取二维码
$.ajax({
type: "POST",//请求类型
url: path + "/weixinPay/weixinCode",//请求的url
dataType: "json",//ajax接口(请求url)返回的数据类型
success: function (data) {//data:返回数据(json对象)
if(data.data!=""){
var qr = new QRious({
element:document.getElementById("codeImg"),
size:300,
level:'L',
value:data.data
});
}else {
errerInformation("获取微信支付二维码失败!","javascript:void(0);");//弹窗告诉前台下单失败!
}
}
});
socket通知
//获得消息事件
socket.onmessage = function(msg) {
console.log(msg.data);
//发现消息进入 开始处理前端触发逻辑,连接成功不提示,烦
if(msg.data!="连接成功"){
errerInformation(msg.data,"javascript:void(0);");//alert弹窗socket信息
setTimeout(function () {
if(msg.data=="微信支付成功!"){
window.location.href=path+"/index";//成功返回首页
}
},2000);
}
};