本编为原创,如需转载,请注明出处。
微信支付开发过程中,如果没有遇到签名错误这个问题或者一直请求回调方法问题,那么感觉你开发了一个假对接,网上也有许多列子,以及官网也有微信团队demo,但是还是有解决不了的各种签名问题,demo需要手动修改因为他的加密方式会不尽如人意,还有排序问题。好了,话不多说,直接进入步骤中。
注意:如果遇到签名错误,一定要查看参数顺序
比较坑的是,
1:官网商户key填写的时候提示你8位数还是6位数以上的数字加字母组成就可以,但是你必须在设定完之后,再次修改成32位加密字符串!!!
2:回调地址,如果你是http://www.xxx.cn/txxxr/wxpay/wxpay.do的方式,你的地址需要写成http://www.xxx.cn/txxxr/wxpay/ !!!
好了,以上两个问题如果都没问题了,那么我们进入正式代码开发。(具体工具类以及全部代码,会在本文的末尾中。)
在此只介绍重点步骤,开发可以在demo中修改我的路径以及自己的逻辑就可以。
controller方法:
package cn.teacher.wxpay.controller;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
import javax.servlet.http.HttpServletRequest;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import cn.teacher.weiXin.dao.BasWxUserForStuDao;
import cn.teacher.wxpay.sdk.WXPay;
import cn.teacher.wxpay.sdk.WXPayUtil;
import cn.teacher.wxpay.util.WXPayConfigImpl;
@Controller
@RequestMapping("wxpay")
public class WXPayController {
private WXPay wxpay;
private WXPayConfigImpl config;
private String out_trade_no;
@Autowired
private BasWxUserForStuDao basWxUserForStuDao;
@RequestMapping(value="/wxpay_memberManagement")
public String memberManagement(HttpServletRequest request,Model model){
String openid ="ogcMwwuHoHeMG5Mp_cPkmYYdY6CU";
return "memberManagement";
}
@RequestMapping(value="/wxpay_packageInfo")
public String packageInfo(HttpServletRequest request){
return "packageInfo";
}
public WXPayController() throws Exception {
config = WXPayConfigImpl.getInstance();
wxpay = new WXPay(config);
out_trade_no = UUID.randomUUID().toString().replaceAll("-", "").substring(0, 32);
}
/**
* 扫码支付 下单
* @throws Exception
*/
@RequestMapping(value = "/wxpay_unifiedOrder", produces = "application/json;charset=UTF-8")//这一步必须有!!
@Transactional
public @ResponseBody String doUnifiedOrder(String bodyname,String fee) throws Exception {//bodyname例如:腾讯支付中心,fee为价格
JSONObject result = new JSONObject();
Map<String, String> resdata = new HashMap<String, String>();
//获取到用户的openid
String openid ="ogcMwwuHoHeMG5Mp_cPkmYYdY6CU";
Map<String, String> data = new HashMap<String, String>();
data.put("body", bodyname);
data.put("out_trade_no", out_trade_no);//生成的订单编号
data.put("fee_type", "CNY");
data.put("total_fee", fee);
data.put("spbill_create_ip", "58.87.76.30");//请求ip地址
data.put("notify_url", "http://xxx.mmath.cn/teacher/uploadwx/paytest");//请求成功返回路径
data.put("trade_type", "JSAPI");//公众号支付类型
data.put("openid", openid);
try {
//统一下单,得到prepay_id
Map<String, String> r = wxpay.unifiedOrder(data);
//得到带预支付prepay_id
String prepay_id= r.get("prepay_id");
//拼接组成新的sign并加密
String timestamp = String.valueOf(new Date().getTime()/1000);
String stringA =""+"appId="+config.getAppID()+"&nonceStr="+r.get("nonce_str") +"&package=prepay_id="+prepay_id+"&signType=MD5"+"&timeStamp=" + timestamp + "&key="+config.getKey();
String sign=WXPayUtil.MD5(stringA).toUpperCase();
//返回页面数据供调用H5使用
result.put("appId", config.getAppID());//appid
result.put("timeStamp", timestamp);//时间戳精确到秒
result.put("nonceStr", r.get("nonce_str"));//订单编号
result.put("paySign", sign);//sign
result.put("signType", "MD5");//加密方式
result.put("packageStr", "prepay_id=" + prepay_id); //预支付id
result.put("flag", true);//支付方法状态
//可以在此处添加一个临时的订单步骤,状态为支付中,在回调接口中修改支付状态为支付成功或者失败
} catch (Exception e) {
e.printStackTrace();
}
return JSON.toJSONString(result);
}
}
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<% String path = request.getContextPath(); %>
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
<title>个人中心</title>
<script type="text/javascript" src="<%=path %>/js/jquery.js"></script>
<script type="text/javascript" src="http://res.wx.qq.com/open/js/jweixin-1.2.0.js"></script>
<body>
<div>
<div style=" width: 100%;">
<ul >
<li style="width: 80%;float: left;"><p><strong id="bodyname">99元套餐</strong></p><p>六年级下学期下载</p></li>
<li style="width: 20%;float: left;"><p><input type="button" value="结算" οnclick="pay();" style="background-color: yellow;"></li>
<li style="width: 100%;float: left;" >
<input name="tab" type="checkbox" value="" οnclick="money();"/>赵小小
<input name="tab" type="checkbox" value="" οnclick="money();"/>陈大
<input name="tab" type="checkbox" value="" οnclick="money();"/>辰辰
合计¥<strong id="m">0</strong> </li>
</ul>
</div>
</div>
<script type="text/javascript">
var prepay_id ,paySign,appId ,timeStamp, nonceStr,packageStr ,signType ;
/**
* 点击支付按钮进行方法调用
*/
function pay(){
var fee="20";
var bodyname="XXX支付界面";
var url = "http://XXX.mmath.cn/teacher/wxpay/wxpay_unifiedOrder";
$.ajax({
type:"post",
url:url,
data: "bodyname="+bodyname+"&fee="+fee,
success:function(data) {
if(data.flag){
appId = data.appId;
paySign = data.paySign;
timeStamp = data.timeStamp;
nonceStr = data.nonceStr;
packageStr = data.packageStr;
signType = data.signType;
callpay();
}else{
alert("统一下单失败");
}
}
});
}
/*
* 调用支付h5页面
*/
function onBridgeReady(){
WeixinJSBridge.invoke(
'getBrandWCPayRequest', {
"appId":appId, //公众号名称,由商户传入
"timeStamp":timeStamp, //时间戳,自1970年以来的秒数
"nonceStr":nonceStr , //随机串
"package":packageStr, //预支付交易会话标识
"signType":signType, //微信签名方式
"paySign":paySign //微信签名
},
function(res){
if(res.err_msg == "get_brand_wcpay_request:ok" ) {
alert('支付成功');
}else if(res.err_msg == "get_brand_wcpay_request:cancel"){
alert('支付取消');
}else if(res.err_msg == "get_brand_wcpay_request:fail" ){
alert('支付失败');
} //使用以上方式判断前端返回,微信团队郑重提示:res.err_msg将在用户支付成功后返回 ok,但并不保证它绝对可靠。
}
);
}
/**
* 判断是否进入支付步骤
*/
function callpay(){
if (typeof WeixinJSBridge == "undefined"){
if( document.addEventListener ){
document.addEventListener('WeixinJSBridgeReady', onBridgeReady, false);
}else if (document.attachEvent){
document.attachEvent('WeixinJSBridgeReady', onBridgeReady);
document.attachEvent('onWeixinJSBridgeReady', onBridgeReady);
}
}else{
onBridgeReady();
}
}
</script>
</body>
</html>
其余的文件以及工具类
由于上次上传的文件没有声明以下内容,导致码农下载完资源后看到个官方demo基本一致,直接弃置不用,所以在此特别声明。如果介意,不要下载。
(本文项目是在微信官方demo的基础上进行修改开发的,所以类名方法名和框架结构和官方demo基本一致,但是部分内容会进行修改,请下载前仔细阅读)
http://download.csdn.net/download/qq_37581708/10198124
好吧,我不知道怎么弄成免费的,你们可以联系我,我私发给你们,或者留下你的QQ~
下面是最后一步处理:回调接口
/**
* 支付成功后,接收微信返回的回调方法
*/
@RequestMapping(value="/order", produces = "application/json;charset=UTF-8")
@ResponseBody
public void order(HttpServletRequest request, HttpServletResponse response) throws Exception{
String msg = "success";
response.setContentType("text/xml");
String resXml = "";
BufferedReader reader = null;
reader = request.getReader();
String line = "";
String xmlString = null;
StringBuffer inputString = new StringBuffer();
while ((line = reader.readLine()) != null) {
inputString.append(line);
}
xmlString = inputString.toString();
request.getReader().close();
Document doc = null;
try {
// 下面的是通过解析xml字符串的
doc = DocumentHelper.parseText(xmlString); // 将字符串转为XML
Element rootElt = doc.getRootElement(); // 获取根节点
Element recordEle = (Element)rootElt;
String result_code = recordEle.elementTextTrim("result_code");
String return_code = recordEle.elementTextTrim("return_code");
String out_trade_no = recordEle.elementTextTrim("out_trade_no");
String stuNo =out_trade_no.split("_ms_")[1];
//在此处开始进行数据库订单记录状态插入与修改
if(return_code.indexOf("SUCCESS")!=-1){
if(result_code.indexOf("SUCCESS")!=-1){
//支付成功
wXPayService.updateOrder(out_trade_no, "1",stuNo);
}else{
//支付失败
wXPayService.updateOrder(out_trade_no, "2","1");
}
//这一步非常重要:返回给微信成功通知,否则会一直回调。
resXml = "<xml>" + "<return_code><![CDATA[SUCCESS]]></return_code>"
+ "<return_msg><![CDATA[OK]]></return_msg>" + "</xml> ";
BufferedOutputStream out = new BufferedOutputStream(
response.getOutputStream());
out.write(resXml.getBytes());
out.flush();
out.close();
response.getWriter().println(msg);
}
} catch (DocumentException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
}