在此更正,以前的微信支付借用了网上其他一些帖子,要么半桶水,要么有所隐藏,根本没法用。
当你发现百度已经帮不了你的时候,其实你自身已经有一定的高度了。
前面本文浏览次数在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);
}
};