微支付jsapi巨坑 微支付 jsapi java
(你必须是服务号并且申请各种认证通过后才能往下走,否则请回炉!)
String timestamp = Long.toString(System.currentTimeMillis() / 1000);//生成时间
* @category 第一个签名,前台的config配置签名
* @param code
* @param state
* @return 返回签名map,前台要用
*/
public static Map<String, Object> configSign(String code,String state) {
String nonce_str = UUID.randomUUID().toString().replaceAll("-", "");//32位随机码
String timestamp = Long.toString(System.currentTimeMillis() / 1000);//生成时间
String url = WxConfig.getUrl()+"/wxtest?code="+code+"&state="+state;//微支付页面url
String jsapiTicket;
try {
jsapiTicket = WxpayUtil.getJsapiTicket();
//注意这里参数名必须全部小写,且必须有序
String string1 = "jsapi_ticket=" + jsapiTicket +
"&noncestr=" + nonce_str +
"×tamp=" + timestamp +
"&url=" + url;
//加密算法
MessageDigest crypt = MessageDigest.getInstance("SHA-1");
crypt.reset();
crypt.update(string1.getBytes("UTF-8"));
String signature = byteToHex(crypt.digest());//生成签名
Map<String, Object> returnMap = new HashMap<String, Object>();
returnMap.put("url", url);
returnMap.put("jsapi_ticket", jsapiTicket);
returnMap.put("nonceStr", nonce_str);
returnMap.put("timestamp", timestamp);
returnMap.put("signature", signature); //这是万恶的config配置签名,就是他!!!
return returnMap;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
String code = request.getParameter("code");//这个code码在下面会用到,到时不要问我code码从哪里来,他的故乡在远方。。。
String state = request.getParameter("state");//报名ID
//第一个签名,用于第一个JS配置
Map<String,Object> signatureMap = WxpaySign.configSign(code,state);
%>
<script type="text/javascript" src="${ctx}/js/jquery/jquery-1.9.1.min.js"></script>
debug: false, // 开启调试模式,调用的所有api的返回值会在客户端alert出来
appId: '<%=WxConfig.getAppID()%>', // 必填,公众号的唯一标识
timestamp: '<%=signatureMap.get("timestamp")%>', // 必填,生成签名的时间戳
nonceStr: '<%=signatureMap.get("nonceStr")%>', // 必填,生成签名的随机串
signature: '<%=signatureMap.get("signature")%>',// 必填,签名,见附录1
sApiList: ['chooseWXPay'] // 必填,需要使用的JS接口列表,所有JS接口列表见附录2
});
wx.error(function(res){
for(i in res){
alert(i+":"+res[i]);
}
alert("微支付调用失败,请截图给管理人员,谢谢");
window.close();
});
wx.ready(function(){
alert("hello world...");
});
Map<String,Object> paramSignMap = new LinkedHashMap();//按顺序来的
paramSignMap.put("appid", WxConfig.getAppID());
paramSignMap.put("attach", "aaa");//附加数据,在查询API和支付通知中原样返回,该字段主要用于商户携带订单的自定义数据
paramSignMap.put("body", "逐风者祝福之剑"); //支付的时候给用户看的商品描述,直接写中文,不用转义。
paramSignMap.put("mch_id", WxConfig.getMchID());//商户号
paramSignMap.put("nonce_str", UUID.randomUUID().toString().replaceAll("-", ""));//随机码
paramSignMap.put("notify_url", WxConfig.getUrl()+"/wxnotify");//监听地址,支付成功或失败微信会回调这个url通知你。
paramSignMap.put("openid",openId); //之前拿到的oepnid
paramSignMap.put("out_trade_no", "1231231231231");//自己的订单号,这里跟你的业务逻辑要挂钩了。
paramSignMap.put("spbill_create_ip", request.getRemoteAddr());//请求者IP
paramSignMap.put("total_fee", signMap.get("money")+"00");//钱数
paramSignMap.put("trade_type", "JSAPI");//固定写法
paramSignMap.put("sign", WxpaySign.preFormSign(paramSignMap));//生成预订单签名
* @category 预提交表单签名
* @param url
* @return
*/
public static String preFormSign(Map<String,Object> paramSignMap) {
StringBuffer tempStr = new StringBuffer(1024);
for (String key : paramSignMap.keySet()) {
tempStr.append(key+"="+paramSignMap.get(key)+"&");
}
System.out.println(tempStr.toString());
String returnStr = MD5.GetMD5Code(tempStr.substring(0,tempStr.length()-1)+"&key="+WxConfig.getSecret()).toUpperCase();
logger.info("preFormSign==========================================>"+returnStr);
return returnStr;
}
// 全局数组
private final static String[] strDigits = { "0", "1", "2", "3", "4", "5",
"6", "7", "8", "9", "a", "b", "c", "d", "e", "f" };
public MD5() {
}
// 返回形式为数字跟字符串
private static String byteToArrayString(byte bByte) {
int iRet = bByte;
// System.out.println("iRet="+iRet);
if (iRet < 0) {
iRet += 256;
}
int iD1 = iRet / 16;
int iD2 = iRet % 16;
return strDigits[iD1] + strDigits[iD2];
}
// 返回形式只为数字
private static String byteToNum(byte bByte) {
int iRet = bByte;
System.out.println("iRet1=" + iRet);
if (iRet < 0) {
iRet += 256;
}
return String.valueOf(iRet);
}
// 转换字节数组为16进制字串
private static String byteToString(byte[] bByte) {
StringBuffer sBuffer = new StringBuffer();
for (int i = 0; i < bByte.length; i++) {
sBuffer.append(byteToArrayString(bByte[i]));
}
return sBuffer.toString();
}
public static String GetMD5Code(String strObj) {
String resultString = null;
try {
resultString = new String(strObj);
MessageDigest md = MessageDigest.getInstance("MD5");
// md.digest() 该函数返回值为存放哈希值结果的byte数组
resultString = byteToString(md.digest(strObj.getBytes()));
} catch (NoSuchAlgorithmException ex) {
ex.printStackTrace();
}
return resultString;
}
public static void main(String[] args) {
System.out.println(MD5.GetMD5Code("qqqqqq"));
}
}
* @category 生成请求xml,用于微支付
* @param parameters
* @return
*/
public static String getRequestXml(Map<String,Object> parameters){
StringBuffer sb = new StringBuffer(1024);
sb.append("<xml>");
for (String key : parameters.keySet()) {
System.out.println("key= "+ key + " and value= " + parameters.get(key));
String k = key;
String v = parameters.get(key)+"";
sb.append("<"+k+">"+"<![CDATA["+v+"]]></"+k+">");
}
sb.append("</xml>");
return sb.toString();
}
URL url = new URL("https://api.mch.weixin.qq.com/pay/unifiedorder");
URLConnection con = url.openConnection();
con.setDoOutput(true); // POST方式
out = new OutputStreamWriter(con.getOutputStream(), "UTF-8");
out.write(xmlInfo);
if(out!=null){
out.flush();
out.close();
}
StringBuffer returnStr = new StringBuffer(1024);
String sCurrentLine = "";
InputStream l_urlStream = con.getInputStream();
BufferedReader l_reader = new BufferedReader(new InputStreamReader(l_urlStream));
while ((sCurrentLine = l_reader.readLine()) != null) {
returnStr.append(sCurrentLine);
}
// System.out.println("xmlInfo=" + xmlInfo);
// System.out.println("-------------预订单返回--------------"+returnStr.toString());
Map<String, String> returnMap = XMLUtil.doXMLParse(returnStr.toString());//解析微信返回的信息,以Map形式存储便于取值
// System.out.println("最后的结果111----->"+returnMap.get("return_code"));
// System.out.println("最后的结果222----->"+returnMap.get("return_msg"));
if("SUCCESS".equals(returnMap.get("return_code"))){
* 解析xml,返回第一级元素键值对。如果第一级元素有子节点,则此节点的值是子节点的xml数据。
* @param strxml
* @return
* @throws JDOMException
* @throws IOException
*/
public static Map doXMLParse(String strxml) throws JDOMException, IOException {
strxml = strxml.replaceFirst("encoding=\".*\"", "encoding=\"UTF-8\"");
if(null == strxml || "".equals(strxml)) {
return null;
}
Map m = new HashMap();
InputStream in = new ByteArrayInputStream(strxml.getBytes("UTF-8"));
SAXBuilder builder = new SAXBuilder();
Document doc = builder.build(in);
Element root = doc.getRootElement();
List list = root.getChildren();
Iterator it = list.iterator();
while(it.hasNext()) {
Element e = (Element) it.next();
String k = e.getName();
String v = "";
List children = e.getChildren();
if(children.isEmpty()) {
v = e.getTextNormalize();
} else {
v = XMLUtil.getChildrenText(children);
}
m.put(k, v);
}
//关闭流
in.close();
return m;
}
//自己的业务
return 返回给前台prepay_id以及你自己的业务id;
return 错误信息;
}
* @category 真实表单签名生成
* @param request
* @param response
* @return String
*/
@ResponseBody
@RequestMapping("getRealFormSignature")
public JsonMessage getRealFormSignature(HttpServletRequest request, String prepay_id,String timestamp,String nonceStr) throws Exception{
Map<String,Object> readFormParamMap = new HashMap();
readFormParamMap.put("appId",WxConfig.getAppID());
readFormParamMap.put("timeStamp",timestamp);
readFormParamMap.put("nonceStr",nonceStr);
readFormParamMap.put("package","prepay_id="+prepay_id);
readFormParamMap.put("signType","MD5");
String realFormSign = WxpaySign.getSign(readFormParamMap);
return 把签名返回给前台
}
public static String getSign(Map<String,Object> map){
ArrayList<String> list = new ArrayList<String>();
for(Map.Entry<String,Object> entry:map.entrySet()){
if(entry.getValue()!=""){
list.add(entry.getKey() + "=" + entry.getValue() + "&");
}
}
int size = list.size();
String [] arrayToSort = list.toArray(new String[size]);
Arrays.sort(arrayToSort, String.CASE_INSENSITIVE_ORDER);
StringBuilder sb = new StringBuilder();
for(int i = 0; i < size; i ++) {
sb.append(arrayToSort[i]);
}
String result = sb.toString();
result += "key=" + WxConfig.getKey();
//Util.log("Sign Before MD5:" + result);
result = MD5Util.MD5Encode(result).toUpperCase();
//Util.log("Sign Result:" + result);
return result;
}
wx.chooseWXPay({
timestamp: '<%=signatureMap.get("timestamp")%>',
nonceStr: '<%=signatureMap.get("nonceStr")%>',
package: 'prepay_id='+prepay_id,
signType: 'MD5',//SHA1
paySign: realFormSignature,
success:function(res1) {
//alert(res1);
//修改交易状态,这是我自己的逻辑,你换成你的。就是需要更新你的逻辑,告诉自己的数据库,交易成功了。
$.ajax({
type:"POST", //post提交方式默认是get
dataType:'json',
url:'${ctx}/wxPaySaveSuccess',
data : {
key_id : payLogUUID, //这是我自己的业务ID
trade_status :'TRADE_SUCCESS'//我自己的业务参数
},
error:function(data) {// 设置表单提交出错
alert('系统出现异常,请联系管理员');
},
success:function(result) {//提交成功
if(result.success){
alert("哇!成功啦,快去领取您的号码牌吧~");
window.location.href="${ctx}/sign/phoneSignSuccess/<%=state%>"; //跳转到成功页面
}else{
alert(result.msg);
alert("更新交易记录失败!");
}
}
});
},fail:function(res) {
//alert(res);
alert("本次支付失败,请联系客服人员,谢谢您的支持与理解。");
}
});
* @category 监听通知,微信服务器调用闭环
* @param request
* @param response
* @return String
*/
@RequestMapping("wxnotify")
public void wxnotify(HttpServletRequest request, HttpServletResponse response) throws Exception{
System.out.println("微支付回调.1111111111111111111111111111111...");
InputStream inputStream = null;
try {
// 解析结果存储在HashMap
Map<String, String> map = new HashMap<String, String>();
inputStream = request.getInputStream();
// 读取输入流
SAXReader reader = new SAXReader();
Document document = reader.read(inputStream);
// 得到xml根元素
Element root = document.getRootElement();
// 得到根元素的所有子节点
List<Element> elementList = root.elements();
// 遍历所有子节点
for (Element e : elementList){
map.put(e.getName(), e.getText());
}
//遍历MAP
for (String key : map.keySet()) {
System.out.println("key= "+ key + " and value= " + map.get(key));
}
if(map!=null&&"SUCCESS".equals(map.get("return_code"))){
Map logMap = tPayLogService.findOneByUUID(map.get("out_trade_no"));
if(logMap!=null&&"".equals(logMap.get("trade_status"))){//如果已经状态是成功则无视,否则UPDATE一下状态
Map paramMap = new HashMap();
logMap.put("trade_status", "TRADE_SUCCESS");
Map signMap = signService.findOneByKeyId(logMap.get("sign_id"));
Map userMap = tClientService.findOneByKeyId(signMap.get("client_id"));
Map activityMap = tActivityService.findOneByKeyId(signMap.get("activity_id"));
paramMap.put("social_type", userMap.get("social_type"));
paramMap.put("price_model", signMap.get("price_model"));
//支付成功
signMap.put("s_status", 2);//状态(0:免费;1:未付费;2:已付费)
signMap.put("sign_num", signService.findMaxSignNum(paramMap, activityMap));
signService.saveLogAndSignTransaction(logMap,signMap);
Map<String,Object> paramSignMap = new LinkedHashMap();//按顺序来的
paramSignMap.put("return_code","SUCCESS");
// paramSignMap.put("return_msg",);
String xmlInfo = XMLUtil.getRequestXml(paramSignMap);//生成xml,这个xml要post请求到微信的服务端
PrintWriter out = null;
try {
// 转码
// response.setContentType("text/html;charset=UTF-8");
out = response.getWriter();
out.write(xmlInfo);
out.flush();
} catch (final IOException e) {
e.printStackTrace();
} finally {
if (out != null) {
out.close();
}
}
}
}
} catch (Exception e) {
e.printStackTrace();
}finally{
if(inputStream!=null){
// 释放资源
inputStream.close();
inputStream = null;
}
}
}
<%@ include file="/jsp/common/taglib.jsp"%>
<%@ page import="com.mingyisoft.bean.wxpay.WxpayUtil"%>
<%@ page import="com.mingyisoft.bean.wxpay.WxConfig"%>
<%@ page import="com.mingyisoft.bean.wxpay.WxpaySign"%>
<%@ page import="java.util.Map"%>
<html>
<head>
<meta charset="utf-8">
<script src="http://res.wx.qq.com/open/js/jweixin-1.0.0.js"></script>
<script type="text/javascript" src="${ctx}/js/jquery/jquery-1.9.1.min.js"></script>
<script>
<%
String code = request.getParameter("code");//页面获取的code码
String state = request.getParameter("state");//报名ID
//第一个签名,用于第一个JS配置
Map<String,Object> signatureMap = WxpaySign.configSign(code,state);
%>
wx.config({
debug: false, // 开启调试模式,调用的所有api的返回值会在客户端alert出来,若要查看传入的参数,可以在pc端打开,参数信息会通过log打出,仅在pc端时才会打印。
appId: '<%=WxConfig.getAppID()%>', // 必填,公众号的唯一标识
timestamp: '<%=signatureMap.get("timestamp")%>', // 必填,生成签名的时间戳
nonceStr: '<%=signatureMap.get("nonceStr")%>', // 必填,生成签名的随机串
signature: '<%=signatureMap.get("signature")%>',// 必填,签名,见附录1
jsApiList: ['chooseWXPay'] // 必填,需要使用的JS接口列表,所有JS接口列表见附录2
});
wx.error(function(res){
for(i in res){
alert(i+":"+res[i]);
}
// config信息验证失败会执行error函数,如签名过期导致验证失败,具体错误信息可以打开config的debug模式查看,也可以在返回的res参数中查看,对于SPA可以在这里更新签名。
alert("微支付调用失败,请截图给管理人员,谢谢");
window.close();
});
// config信息验证后会执行ready方法,所有接口调用都必须在config接口获得结果之后,config是一个客户端的异步操作,所以如果需要在页面加载时就调用相关接口,则须把相关接口放在ready函数中调用来确保正确执行。对于用户触发时才调用的接口,则可以直接调用,不需要放在ready函数中。
wx.ready(function(){
//调用统一下单接口
$.ajax({
type:"POST", //post提交方式默认是get
dataType:'json',
url:basePath+'/wxpostpreform',
data : {
openId :'<%=WxpayUtil.getOpenid(code)%>',
state : '<%=state%>'
},error:function(data) {// 设置表单提交出错
alert('系统出现异常,请联系管理员');
},success:function(result) {//提交成功
if(result.success){
var prepay_id = result.msg;//这个就是预订单ID
var payLogUUID = result.data;//自己的业务逻辑ID
//alert("预订单编号===>"+prepay_id);
$.ajax({
type:"POST", //post提交方式默认是get
dataType:'json',
url:basePath+'/getRealFormSignature',
data : {
prepay_id :prepay_id,
timestamp :'<%=signatureMap.get("timestamp")%>',
nonceStr :'<%=signatureMap.get("nonceStr")%>'
},error:function(data) {// 设置表单提交出错
alert('系统出现异常,请联系管理员');
},success:function(result3) {//提交成功
if(result3.success){
var realFormSignature = result3.msg;
//alert("最后订单的签名===>"+result3.msg);
//提交支付订单
wx.chooseWXPay({
timestamp: '<%=signatureMap.get("timestamp")%>',
nonceStr: '<%=signatureMap.get("nonceStr")%>',
package: 'prepay_id='+prepay_id,
signType: 'MD5',//SHA1
paySign: realFormSignature,
success:function(res1) {
//alert(res1);
//修改交易状态
$.ajax({
type:"POST", //post提交方式默认是get
dataType:'json',
url:'${ctx}/wxPaySaveSuccess',
data : {
key_id : payLogUUID,
trade_status :'TRADE_SUCCESS'//参数
},
error:function(data) {// 设置表单提交出错
alert('系统出现异常,请联系管理员');
},
success:function(result) {//提交成功
if(result.success){
alert("哇!成功啦,快去领取您的号码牌吧~");
window.location.href="${ctx}/sign/phoneSignSuccess/<%=state%>";
}else{
alert(result.msg);
alert("更新交易记录失败!");
}
}
});
},fail:function(res) {
//alert(res);
alert("本次支付失败,请联系客服人员,谢谢您的支持与理解。");
}
});
}else{
alert(result3.msg);
}
}
});
}else{
alert(result.msg);
}
}
});
});
</script>
</head>
<body>
<h1>系统正在提交订单,请勿跳转页面。</h1>
</body>
</html>
微支付jsapi巨坑 微支付 jsapi java相关推荐
- 微信Jsapi支付实战踩坑
准备 需求 需求就是最简单的对接微信网页支付接口 方案心路历程 一开始是对接的H5,后面才发现H5支付是一定要在微信环境外才可以调用并跳转支付的 这是H5支付对接实操过程 下面称为P1 上文H5支付对 ...
- php接入微信JSAPI支付,微信内拉起支付,基于thinkPHP框架 WeChatDeveloper支付类包
文章:php接入微信支付,扫码支付和H5支付(非微信浏览器),基于thinkPHP框架 WeChatDeveloper支付类包 踩坑指南 文章:php快速接入支付宝即时支付,PC网站支付和手机网站支付 ...
- jsapi支付签名_PHP实现微信支付(jsapi支付)流程步骤详解
最近接触到一个项目,涉及到微信支付,搞微信开发这么久以来,还没搞过支付,之前也就搞过公众号发红包,感谢前辈们的探索,我看了他们的博文,让我少走了很多弯路. 前期准备: 1.微信认证服务号,并且开通了微 ...
- php如何接入微信支付接口,PHP实现微信支付(jsapi支付)流程的方法
最近接触到一个项目,涉及到微信支付,搞微信开发这么久以来,还没搞过支付,之前也就搞过公众号发红包,感谢前辈们的探索,我看了他们的博文,让我少走了很多弯路. 前期准备: 1.微信认证服务号,并且开通了微 ...
- php微信jsapi支付小结,ThinkPHP接入微信支付 - JSAPI支付
一.支付准备 二.获取用户openid 首先,到微信公众平台后台 - 设置 - 网页授权域名(别忘了添加开发者) // 在头部引入WechatPubService.php文件,见附录一 use app ...
- 微信app支付和公众号内支付JSAPI
微信app支付和公众号内支付 以下为微信app和JSAPI支付 package cn.xizhi.until.pay;import cn.xizhi.until.GetIp; import cn.xi ...
- 微信小程序服务商模式支付巨坑解决!
今日有个在同一个小程序支付 款项需要付到不同的银行卡里去??? 于是找了下微信小程序支付文档,只有个requestPayment方法 emmm 去看看小程序后台吧 ok 有个微信支付 但是只能绑定一 ...
- php微信支付jsapi,ThinkPHP实现微信支付(jsapi支付)
这篇文章主要介绍了ThinkPHP实现微信支付(jsapi支付)流程教程详解,需要的朋友可以参考下 之前写过一篇文章讲了PHP实现微信支付(jsapi支付)流程 ,详见文章:PHP实现微信支付(jsa ...
- JAVA微信支付(微信公众号支付JSAPI)
JAVA开发微信支付-公众号支付/微信浏览器支付(JSAPI) 写本篇博客其一是因为最近做的项目在用这个功能,通过本篇博客进行一个全局的梳理,其二呢,也就是想趁着思路清晰,把心得记录下来,分享给大家, ...
最新文章
- jquery控制只监听数字_jQuery老矣,尚能饭否
- [OS复习]进程管理3
- opencv-python将视频帧还原成视频
- 支持nvme的linux_Linux nvme驱动初探
- 蓝奏网盘直链转换器 v1.1
- springboot怎么杀进程_头疼,springboot进程总是自己退出
- javascript无限请求_JAVASCRIPT事件循环
- 解决算法问题的思路总结
- 【神经网络】单层感知器
- 神经网络与深度学习(六)卷积神经网络(4)ResNet18实现MNIST
- android跳转QQ陌生人聊天或者加入QQ群
- 宣传单印刷价格明细报价的影响因素有哪些?
- L'Hospital法则
- 多张图片合成一张jpg工具_简单实用!3个手机拼图APP,让多张图片变为1张!
- 图形界面介绍Create Pin Blockage
- Micropython——关于I2C和SoftI2C以及SPI和SoftSPI的区别
- 圆柱体积怎么算立方公式_四个计算圆柱的体积常用公式(附例题)
- C++编程验证费马小定律
- 关于NP与co-NP、RP与coRP的理解
- 《偶像练习生》、《创造101》现象级的爆发还能在中国出现吗?【文末有彩蛋】...
热门文章
- Python基础知识(二进制与字符编码、Python中的标识符和保留字、变量的定义和使用、变量的多次赋值)
- 集成学习中的Boosting和Bagging
- 初中数学503个必考知识点_初中生物必考知识点总结_生物必考知识点指南
- 软件工程复习重点知识
- Android播放器实现视频窗口实时放大缩小功能
- 工程师应该掌握的电子电路-1
- 《惢客创业日记》2019.10.28(周一)放纵的代价
- 欧几里德算法,扩展算法
- 基于小程序的微信学习平台设计与实现+源码
- 32岁学python有前途吗_学Python做爬虫有前途吗?老男孩IT教育