微信 支付(H5) (七) --基于Spring
发布日期:2022-01-11 03:09:52
浏览次数:3
分类:技术文章
本文共 17754 字,大约阅读时间需要 59 分钟。
Controller:
/** * 获取支付 */ @RequestMapping(params={"getPayInfo"}) @ResponseBody public Map getPayInfo(HttpServletRequest request) { Mapresult = new HashMap(); int i=1; try { Map dataMap=new HashMap(); String weiXinId=request.getParameter("weiXinId"); String amount=request.getParameter("amount"); String ordersid=request.getParameter("ordersid"); String ip= request.getRemoteAddr(); dataMap.put("ordersid", ordersid); dataMap.put("ip", ip); dataMap.put("opendid", weiXinId); dataMap.put("amount", amount); JSONObject jsonObject= rewardService.payReward(dataMap); if(null==jsonObject){ result.put("responsecode", "0"); result.put("responsemsg", "获取支付信息失败"); } else{ // 新增支付数据 result.put("payinfo", jsonObject); result.put("responsecode", "1"); result.put("responsemsg", "获取支付信息成功"); } } catch (Exception e) { result.put("responsecode", "0"); result.put("responsemsg", "获取支付信息失败"); e.printStackTrace(); } return result; }
service:
private static String NOTIFY_URL="http://"+Constants.url+"/DDKX/WXRewardController/payNotify.do"; //回调地址 /** * 支付 打赏 */ @Override public JSONObject payReward(Mapmap) { //要获取 订单号 , 用户id ,金额 ,spbill_create_ip String ordersid=map.get("ordersid"); String amount=map.get("amount"); String ip=map.get("ip"); String opendid=map.get("opendid"); String notify_url=NOTIFY_URL; //-----------------------------------回调地址 String nonce_str=Sign.create_nonce_str().toUpperCase(); SortedMap parameters = new TreeMap (); parameters.put("appid", Constants.appid); parameters.put("mch_id", Constants.mch_id); parameters.put("device_info", "WEB"); parameters.put("nonce_str", nonce_str); parameters.put("body", "打赏"); parameters.put("out_trade_no", ordersid); parameters.put("total_fee", amount); parameters.put("spbill_create_ip", ip); parameters.put("notify_url", notify_url); parameters.put("trade_type", "JSAPI"); parameters.put("openid", opendid); PayUtil payUtil=PayUtil.getInstance(); String prepay_id=payUtil.getPrepay_id(parameters); System.out.println(">>>>>>>>>>prepay_id:"+prepay_id); if(prepay_id==null) return null; return payUtil.getPayInfo4JSON(prepay_id,nonce_str); }
(帮助类)PayUtil:
import java.io.BufferedReader;import java.io.FileInputStream;import java.io.InputStreamReader;import java.util.Map;import java.util.Set;import java.util.SortedMap;import java.util.TreeMap;import net.sf.json.JSONObject;public class PayUtil { private static final String goUrl="https://api.mch.weixin.qq.com/pay/unifiedorder"; //private static MappayModel=new HashMap (); private static String payplate1=null; private PayUtil (){}; private static volatile PayUtil instance=null; public static PayUtil getInstance(){ if(instance==null){ synchronized(PayUtil.class){ if(instance==null){ instance=new PayUtil(); //payModel.put("payplate1", loadxml("/payplate/payplate1.xml")); payplate1=loadxml("/payplate/payplate1.xml"); } } } return instance; } /** * 加载模版 * @param xmlurl * @return */ private static String loadxml(String xmlurl){ String path=PayUtil.class.getResource("/").getPath()+xmlurl; String xmlString=""; try { FileInputStream fileInputStream=new FileInputStream(path); InputStreamReader inputStreamReader=new InputStreamReader(fileInputStream,"UTF-8"); BufferedReader reader=new BufferedReader(inputStreamReader); String tempString=null; while((tempString=reader.readLine())!=null) xmlurl+=tempString; reader.close(); } catch (Exception e) { e.printStackTrace(); } return xmlurl; } /** * 获取Prepay_id 顺带附加 SIGN 字段 * @param parameters * @return */ public String getPrepay_id(SortedMap parameters){ String mysign1=Sign.createSign("UTF-8", parameters); String xmlparam=payplate1; parameters.put("SIGN", mysign1); xmlparam=strReplaceXML(xmlparam, parameters); String data= HttpClientUtil.httpRequestComm(goUrl, EnumMethod.POST.name(),xmlparam); if(null==data) return null; JSONObject jsonObject= Xml2JsonUtil.xml2JSON(data).getJSONObject("xml"); System.out.println(">>>>>>>>>>服务器回复:"+jsonObject.toString()); return jsonObject.containsKey("prepay_id")?jsonObject.getJSONArray("prepay_id").getString(0):null; } /** * 替换 模版里的xml 大写标识内容 * @param xml * @param parameters * @return */ public String strReplaceXML(String xml,SortedMap parameters){ Set es = parameters.keySet(); for(String ss:es){ xml=xml.replace(ss.toUpperCase(), parameters.get(ss)); } return xml; } /** * 生成 网页支付所需 参数包 * @param prepay_id * @return */ public JSONObject getPayInfo4JSON(String prepay_id,String nonce_str){ SortedMap dataMap = new TreeMap (); dataMap.put("appId", Constants.appid); dataMap.put("timeStamp", System.currentTimeMillis() / 1000+""); dataMap.put("nonceStr",nonce_str); dataMap.put("package", "prepay_id="+prepay_id); dataMap.put("signType", "MD5"); String mysign2=Sign.createSign("UTF-8", dataMap); dataMap.put("paySign", mysign2); JSONObject jsonObject=JSONObject.fromObject(dataMap); return jsonObject; } }
(帮助模板)payplate1.xml:
(帮助类)Xml2JsonUtil:APPID MCH_ID DEVICE_INFO NONCE_STR BODYOUT_TRADE_NO TOTAL_FEE SPBILL_CREATE_IP NOTIFY_URL TRADE_TYPE OPENID SIGN
package com.gzkit.ddkx.util;import java.io.ByteArrayInputStream;import java.io.InputStream;import java.io.StringReader;import java.util.HashMap;import java.util.Iterator;import java.util.LinkedList;import java.util.List;import java.util.Map;import org.dom4j.Document;import org.dom4j.Element;import org.dom4j.io.SAXReader;import net.sf.json.JSONArray;import net.sf.json.JSONObject;public class Xml2JsonUtil { /** * 解析xml,返回第一级元素键值对。如果第一级元素有子节点,则此节点的值是子节点的xml数据。 */ public static MapXMLParse2Map(String strxml){ Map m = new HashMap (); try { if(null == strxml || "".equals(strxml)) { return null; } SAXReader sb = new SAXReader(); Document doc = sb.read(new StringReader(strxml)); Element root = doc.getRootElement(); List list =root.elements(); Iterator it = list.iterator(); while(it.hasNext()) { Element e = (Element) it.next(); String k = e.getName(); String v = ""; List children = e.elements(); if(children.isEmpty()) { v = e.getTextTrim(); } else { v = getChildrenText(children); } m.put(k, v); } } catch (Exception e) { // TODO: handle exception } return m; } /** * 解析xml,返回第一级元素键值对。如果第一级元素有子节点,则此节点的值是子节点的xml数据。 */ public static JSONObject XMLParse2JSON(String strxml){ return JSONObject.fromObject(XMLParse2Map(strxml)); } /** * 获取子结点的xml * @param children * @return String */ public static String getChildrenText(List children) { StringBuffer sb = new StringBuffer(); if(!children.isEmpty()) { Iterator it = children.iterator(); while(it.hasNext()) { Element e = (Element) it.next(); String name = e.getName(); String value = e.getTextTrim(); List list = e.elements(); sb.append("<" + name + ">"); if(!list.isEmpty()) { sb.append(getChildrenText(list)); } sb.append(value); sb.append(" "); } } return sb.toString(); } /** * 转换一个xml格式的字符串到json格式 获取的值都是 jsonarray 要解多层 */ @SuppressWarnings("unchecked") public static JSONObject xml2JSON(InputStream is) { JSONObject obj = new JSONObject(); try { SAXReader sb = new SAXReader(); Document doc = sb.read(is); Element root = doc.getRootElement(); obj.put(root.getName(), iterateElement(root)); return obj; } catch (Exception e) { return null; } } /** * 转换一个xml格式的字符串到json格式 */ @SuppressWarnings("unchecked") public static JSONObject xml2JSON(String is) { JSONObject obj = new JSONObject(); try { SAXReader sb = new SAXReader(); Document doc = sb.read(new StringReader(is)); Element root = doc.getRootElement(); obj.put(root.getName(), iterateElement(root)); return obj; } catch (Exception e) { return null; } } /** * 一个迭代方法 * * @param element * : org.jdom.Element * @return java.util.Map 实例 */ @SuppressWarnings("unchecked") private static Map iterateElement(Element element) { List jiedian = element.elements() ; Element et = null; Map obj = new HashMap(); List list = null; for (int i = 0; i < jiedian.size(); i++) { list = new LinkedList(); et = (Element) jiedian.get(i); if (et.getTextTrim().equals("")) { if (et.elements().size() == 0) continue; if (obj.containsKey(et.getName())) { list = (List) obj.get(et.getName()); } list.add(iterateElement(et)); obj.put(et.getName(), list); } else { if (obj.containsKey(et.getName())) { list = (List) obj.get(et.getName()); } list.add(et.getTextTrim()); obj.put(et.getName(), list); } } return obj; } public static void main(String[] args) { String str1=" "; JSONObject array=Xml2JsonUtil.xml2JSON(str1).getJSONObject("xml"); System.out.println(array.getJSONArray("prepay_id").get(0)); }}
(帮助类)Sign:
/*** * * @author yuki_ho * */public class Sign { public static Map sign(String url) { Map ret = new HashMap (); String nonce_str = create_nonce_str(); String timestamp = create_timestamp(); String signature = null; if(null==Constants.jsapi_ticket) { WXListener.getJsapi_ticket(WXListener.accessToken.getAccessToken()); } //注意这里参数名必须全部小写,且必须有序 String[] paramArr = new String[] { "jsapi_ticket=" + Constants.jsapi_ticket, "timestamp=" + timestamp, "noncestr=" + nonce_str, "url=" + url }; Arrays.sort(paramArr); String content = paramArr[0].concat("&"+paramArr[1]).concat("&"+paramArr[2]) .concat("&"+paramArr[3]); System.out.println(content); try { MessageDigest md = MessageDigest.getInstance("SHA-1"); // 对拼接后的字符串进行 sha1 加密 byte[] digest = md.digest(content.toString().getBytes()); signature = MD5Util.byteArrayToHexString(digest); } catch (NoSuchAlgorithmException e) { e.printStackTrace(); } ret.put("url", url); ret.put("jsapi_ticket", Constants.jsapi_ticket); ret.put("nonceStr", nonce_str); ret.put("timestamp", timestamp); ret.put("signature", signature); System.out.println(url); ret.put("appId", Constants.appid); return ret; } /** * 微信支付签名算法sign * @param characterEncoding * @param parameters * @return */ @SuppressWarnings("unchecked") public static String createSign(String characterEncoding,SortedMap parameters){ StringBuffer sb = new StringBuffer(); Set es = parameters.entrySet();//所有参与传参的参数按照accsii排序(升序) Iterator it = es.iterator(); while(it.hasNext()) { Map.Entry entry = (Map.Entry)it.next(); String k = (String)entry.getKey(); Object v = entry.getValue(); if(null != v && !"".equals(v) && !"sign".equals(k) && !"key".equals(k)) { sb.append(k + "=" + v + "&"); } } sb.append("key=" +Constants.key); String sign = MD5Util.MD5Encode(sb.toString(), characterEncoding).toUpperCase(); return sign; } private static String create_nonce_str() { return RandomStringGenerator.getRandomStringByLength(32); } private static String create_timestamp() { return String.valueOf(System.currentTimeMillis()).substring(0, 10); } }前端页面:
wx.config({ debug: false, // 开启调试模式,调用的所有api的返回值会在客户端alert出来,若要查看传入的参数,可以在pc端打开,参数信息会通过log打出,仅在pc端时才会打印。 appId: '${appid}', // 必填,公众号的唯一标识 timestamp: '${timestamp}', // 必填,生成签名的时间戳 nonceStr: '${nonceStr}', // 必填,生成签名的随机串 signature: '${signature}',// 必填,签名,见附录1 jsApiList: [ 'chooseWXPay' ] // 必填,需要使用的JS接口列表,所有JS接口列表见附录2 });
function pay(){ wx.chooseWXPay({ timestamp: ${paytimestamp}, // 支付签名时间戳,注意微信jssdk中的所有使用timestamp字段均为小写。但最新版的支付后台生成签名使用的timeStamp字段名需大写其中的S字符 nonceStr: '${paynonceStr}', // 支付签名随机串,不长于 32 位 package: '${paypackage}', // 统一支付接口返回的prepay_id参数值,提交格式如:prepay_id=***) signType: '${paysignType}', // 签名方式,默认为'SHA1',使用新版支付需传入'MD5' paySign: '${paySign}', // 支付签名 success: function (res) { if(res.errMsg == "chooseWXPay:ok") {}else if(res.errMsg == "chooseWXPay:fail"){ $.toast("支付失败请刷新重试!","cancel"); } // 支付成功后的回调函数 } }); } 微信回调后台:// 支付成功后的回调函数
// -----报文-----// {is_subscribe=Y, // appid=xxxxxxxxxxxx, // fee_type=CNY, // nonce_str=5FMGNBEUY0W1RFNBMHGINYUN8MF6W6CE, // out_trade_no=xxxxxxxxxxxxxxxxx, // device_info=WEB, // transaction_id=xxxxxxxxxxxxxxx, // trade_type=JSAPI, // sign=0C869ED5882C641960798CD2DDDC0F7C, // result_code=SUCCESS,// mch_id=xxxxxxxxxxx, // total_fee=1, // time_end=20160908143148, // openid=xxxxxxxxxxxxxxxxxxxx, // bank_type=CMB_CREDIT, // return_code=SUCCESS, // cash_fee=1} /** * 获取支付 * */ @RequestMapping(value={"payNotify"}) @ResponseBody public void payNotify(HttpServletRequest request,HttpServletResponse response) { String resultStr=null; try { InputStream inStream = request.getInputStream(); ByteArrayOutputStream outSteam = new ByteArrayOutputStream(); byte[] buffer = new byte[1024]; int len = 0; while ((len = inStream.read(buffer)) != -1) { outSteam.write(buffer, 0, len); } outSteam.close(); inStream.close(); resultStr = new String(outSteam.toByteArray(),"utf-8"); Mapresponse.getWriter().write("<xml><return_code><![CDATA[SUCCESS]]></return_code></xml>"); } }else { String err_code= resultMap.get("err_code"); System.out.println("打赏出错:"+err_code);} } catch (IOException e) {e.printStackTrace();}catch(Exception e){e.printStackTrace();}}resultMap = Xml2JsonUtil.XMLParse2Map(resultStr); System.out.println(resultMap.toString()); //---------------获取的参数 String result_code = resultMap.get("result_code"); System.out.println("result_code:"+result_code); String out_trade_no = resultMap.get("out_trade_no"); System.out.println("out_trade_no:"+out_trade_no); String sign = resultMap.get("sign"); String time_end = resultMap.get("time_end"); String total_fee= resultMap.get("total_fee"); String transaction_id=resultMap.get("transaction_id"); String return_code = resultMap.get("return_code"); System.out.println("return_code:"+return_code); //验证签名------------------------------------------------ System.out.println("微信回传:"+sign); resultMap.remove("sign"); SortedMap sortMap=new TreeMap (resultMap); String mysign= Sign.createSign("UTF-8", sortMap); System.out.println("我的签名:"+mysign); //--------------------------------------------------------- if("SUCCESS".equals(return_code)){ if("SUCCESS".equals(result_code)){ //业务 } } //通知微信.异步确认成功.必写.不然会一直通知后台.八次之后就认为交易失败了.
转载地址:https://yuki-ho.blog.csdn.net/article/details/52312502 如侵犯您的版权,请留言回复原文章的地址,我们会给您删除此文章,给您带来不便请您谅解!
发表评论
最新留言
哈哈,博客排版真的漂亮呢~
[***.90.31.176]2024年04月10日 22时42分02秒
关于作者
喝酒易醉,品茶养心,人生如梦,品茶悟道,何以解忧?唯有杜康!
-- 愿君每日到此一游!
推荐文章
POJ 1703 Find them, Catch them【种类并查集】
2019-04-28
POJ 2492 A Bug‘s Life【种类并查集】
2019-04-28
POJ 2236 Wireless Network【并查集】
2019-04-28
LeetCode C++ 214. Shortest Palindrome【字符串】困难
2019-04-28
洛谷 P2580 于是他错误的点名开始了【字典树/Map】
2019-04-28
HDU 3336 Count the string【KMP的next数组性质】
2019-04-28
洛谷 P1196 [NOI2002]银河英雄传说【带权并查集】
2019-04-28
HDU 4825 Xor Sum【01字典树/贪心】(两数最大/最小异或和)
2019-04-28
洛谷 P4551 最长异或路径【01字典树/贪心】
2019-04-28
LeetCode 921. 使括号有效的最少添加(栈)
2019-04-28
LeetCode 1018. 可被 5 整除的二进制前缀
2019-04-28
LeetCode 961. 重复 N 次的元素
2019-04-28
LeetCode 925. 长按键入(双指针)
2019-04-28
LeetCode 1309. 解码字母到整数映射
2019-04-28
动态规划应用--最长递增子序列 LeetCode 300
2019-04-28
LeetCode 53. 最大子序和(动态规划)
2019-04-28
图Graph--拓扑排序(Topological Sorting)
2019-04-28
图Graph--最短路径算法(Shortest Path Algorithm)
2019-04-28