微信公众号支付(服务商模式)
来源:互联网 发布:颜值评分软件 编辑:程序博客网 时间:2024/05/22 09:49
微信公众号支付(服务商模式)
- 公众号支付官方文档地址
业务流程时序图:
第一步:
在H5页面点击支付后,生成订单,然后调用统一下单API后台生成预支付交易单
/** * 生成预支付交易单 * @author * @version 创建时间:2017年3月6日 下午5:20:23 * @return * @throws JDOMException * @throws IOException */ @SuppressWarnings("unchecked") public String weixinPay() throws JDOMException, IOException { if (state.indexOf(ServletActionContext.getRequest().getSession().getId()) == -1) { return ERROR; } else { //获取用户IP HttpServletRequest requests = ServletActionContext.getRequest(); String ip = requests.getHeader("X-Forwarded-For"); if(StringUtils.isNotEmpty(ip) && !"unKnown".equalsIgnoreCase(ip)){ int index = ip.indexOf(","); if(index != -1){ ip= ip.substring(0,index); } } //用code来获取用户的openid,替换为自己的获取用户openid的方法 JSONObject object = new JSONObject(); object = GetWxOpenId.codeGetWxOpenId(code, "gzh"); SortedMap<Object, Object> parameters = new TreeMap<Object, Object>(); String mch_id = mchId;//服务商的商户号 String sub_mch_id="绑定的子商户号";//绑定的子商户号(二者必须有匹配关系) String nonce_str = String.valueOf(System.currentTimeMillis()); String body = "商品描述";// body==商品描述==商品或支付单简要描述 String openid = object.getString("openid").toString();//替换为自己获取openid的方法 String code = PayUtil.createCode(5);//生成五位随机数 String out_trade_no =Long.toString(new Date().getTime())+code;// 商户订单号==商户系统内部的订单号,32个字符内、可包含字母 number=100;//替换为H5页面传来的支付金额 String total_fee = String.valueOf( (int)(Double.parseDouble(number)*100));// total_fee==总金额==订单总金额 String spbill_create_ip = ip;// APP和网页支付提交用户端ip,Native支付填调用微信支付API的机器IP。 String notify_url = "替换为自己项目的支付成功回调地址";// 通知地址,接收微信支付异步通知回调地址,通知url必须为直接可访问的url,不能携带参数。 String trade_type = "JSAPI";// trade_type,交易类型取值如下:JSAPI,NATIVE,APP。我们这里使用的JSAPI。标题已经说了,是微信公众号支付。 String key = paykey;//服务商的key(服务商商户平台配置的key) parameters.put("appid", appid); parameters.put("sub_mch_id", sub_mch_id); parameters.put("mch_id", mch_id); parameters.put("nonce_str", nonce_str); parameters.put("body", body); parameters.put("out_trade_no", out_trade_no); parameters.put("total_fee", total_fee); parameters.put("spbill_create_ip", spbill_create_ip); parameters.put("notify_url", notify_url); parameters.put("trade_type", trade_type); parameters.put("openid", openid); String sign = PayCommonUtil.createSign("UTF-8", parameters,key); parameters.put("sign", sign); String requestXML = PayCommonUtil.getRequestXml(parameters); String result = CommonUtils.httpsRequest("https://api.mch.weixin.qq.com/pay/unifiedorder", "POST",requestXML); Map<String, String> map = XMLUtil.doXMLParse(result);// 解析微信返回的预支付交易会话标识等信息,以Map形式存储便于取值 SortedMap<String, String> params = new TreeMap<String, String>(); params.put("appId", appid); params.put("timeStamp", String.valueOf(System.currentTimeMillis() / 1000)); params.put("nonceStr", nonce_str); params.put("package", "prepay_id=" + map.get("prepay_id")); params.put("signType", "MD5"); Map<String, String> sPara = PayUtil.paraFilter(params); String prestr = PayUtil.createLinkString(sPara); // 把数组所有元素,按照“参数=参数值”的模式用“&”字符拼接成字符串 String mykey = "&key=" + key; // 商户支付密钥 String paySign = PayUtil.sign(prestr, mykey, "utf-8").toUpperCase(); params.put("paySign", paySign); request.put("appId", appid); request.put("timeStamp", params.get("timeStamp")); request.put("nonceStr", nonce_str); request.put("signType", "MD5"); request.put("packageValue", "prepay_id=" + map.get("prepay_id")); request.put("paySign", paySign); // paySign的生成规则和Sign的生成规则一致 request.put("sendUrl", "付款成功后跳转的页面,我在这里没有用到"); // 付款成功后跳转的页面 request.put("detail", params); request.put("paySn", paySn); return SUCCESS; } }
第二步:
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%><!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"><html><head> <script type="text/javascript" src="http://res.wx.qq.com/open/js/jweixin-1.0.0.js"></script> <script src="//cdn.bootcss.com/jquery/3.1.1/jquery.min.js"></script> <script type="text/javascript"> function onBridgeReady(){ WeixinJSBridge.invoke( 'getBrandWCPayRequest', { "appId" : "${request.appId}", "timeStamp" : "${request.timeStamp}",//时间戳,自1970年以来的秒数 "nonceStr" : "${request.nonceStr}", //随机串 "package" : "${request.packageValue}", "signType" : "${request.signType}",//微信签名方式 "paySign" : "${request.paySign}" //微信签名 }, function(res){ // 使用以上方式判断前端返回,微信团队郑重提示:res.err_msg将在用户支付成功后返回 ok,但并不保证它绝对可靠。 if(res.err_msg == "get_brand_wcpay_request:ok") { //替换为自己支付成功后的处理代码 } else if(res.err_msg == "get_brand_wcpay_request:cancel"){ //替换为自己支付取消的处理代码 } else if(res.err_msg == "get_brand_wcpay_request:fail"){ //替换为自己支付失败的处理代码 } } ); } 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><title>微信支付</title> </head> <body> </body></html>
后台处理涉及到的工具类
public class PayCommonUtil { private static Logger log = LoggerFactory.getLogger(PayCommonUtil.class); public static String CreateNoncestr(int length) { String chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"; String res = ""; for (int i = 0; i < length; i++) { Random rd = new Random(); res += chars.indexOf(rd.nextInt(chars.length() - 1)); } return res; } public static String CreateNoncestr() { String chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"; String res = ""; for (int i = 0; i < 16; i++) { Random rd = new Random(); res += chars.charAt(rd.nextInt(chars.length() - 1)); } return res; } /** * @author * @date * @Description:sign签名 * @param characterEncoding 编码格式 * @param parameters 请求参数 * @return */ public static String createSign(String characterEncoding,SortedMap<Object,Object> parameters,String key){ StringBuffer sb = new StringBuffer(); Set es = parameters.entrySet(); 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=" + key); String sign = MD5Util.MD5Encode(sb.toString(), characterEncoding).toUpperCase(); return sign; } /** * @author * @date * @Description:将请求参数转换为xml格式的string * @param parameters 请求参数 * @return */ public static String getRequestXml(SortedMap<Object,Object> parameters){ StringBuffer sb = new StringBuffer(); sb.append("<xml>"); Set es = parameters.entrySet(); Iterator it = es.iterator(); while(it.hasNext()) { Map.Entry entry = (Map.Entry)it.next(); String k = (String)entry.getKey(); String v = (String)entry.getValue(); if ("attach".equalsIgnoreCase(k)||"body".equalsIgnoreCase(k)||"sign".equalsIgnoreCase(k)) { sb.append("<"+k+">"+"<![CDATA["+v+"]]></"+k+">"); }else { sb.append("<"+k+">"+v+"</"+k+">"); } } sb.append("</xml>"); return sb.toString(); } /** * @author * @date * @Description:返回给微信的参数 * @param return_code 返回编码 * @param return_msg 返回信息 * @return */ public static String setXML(String return_code, String return_msg) { return "<xml><return_code><![CDATA[" + return_code + "]]></return_code><return_msg><![CDATA[" + return_msg + "]]></return_msg></xml>"; }}public class CommonUtils{ /** * * @param requestUrl请求地址 * @param requestMethod请求方法 * @param outputStr参数 */ public static String httpRequest(String requestUrl,String requestMethod,String outputStr){ // 创建SSLContext StringBuffer buffer=null; try{ URL url = new URL(requestUrl); HttpURLConnection conn = (HttpURLConnection) url.openConnection(); conn.setRequestMethod(requestMethod); conn.setDoOutput(true); conn.setDoInput(true); conn.connect(); //往服务器端写内容 if(null !=outputStr){ OutputStream os=conn.getOutputStream(); os.write(outputStr.getBytes("utf-8")); os.close(); } // 读取服务器端返回的内容 InputStream is = conn.getInputStream(); InputStreamReader isr = new InputStreamReader(is, "utf-8"); BufferedReader br = new BufferedReader(isr); buffer = new StringBuffer(); String line = null; while ((line = br.readLine()) != null) { buffer.append(line); } }catch(Exception e){ e.printStackTrace(); } return buffer.toString(); } /** * * @param requestUrl请求地址 * @param requestMethod请求方法 * @param outputStr参数 */ public static String httpsRequest(String requestUrl,String requestMethod,String outputStr){ // 创建SSLContext StringBuffer buffer=null; try{ SSLContext sslContext = SSLContext.getInstance("SSL", "SunJSSE"); TrustManager[] tm = { new MyX509TrustManager() }; // 初始化 sslContext.init(null, tm, new java.security.SecureRandom()); // 获取SSLSocketFactory对象 SSLSocketFactory ssf = sslContext.getSocketFactory(); // TODO Auto-generated method stub URL url = new URL(requestUrl); HttpsURLConnection conn = (HttpsURLConnection) url.openConnection(); conn.setRequestMethod(requestMethod); conn.setSSLSocketFactory(ssf); conn.setDoOutput(true); conn.setDoInput(true); conn.connect(); //往服务器端写内容 if(null !=outputStr){ OutputStream os=conn.getOutputStream(); os.write(outputStr.getBytes("utf-8")); os.close(); } // 读取服务器端返回的内容 InputStream is = conn.getInputStream(); InputStreamReader isr = new InputStreamReader(is, "utf-8"); BufferedReader br = new BufferedReader(isr); buffer = new StringBuffer(); String line = null; while ((line = br.readLine()) != null) { buffer.append(line); } }catch(Exception e){ e.printStackTrace(); } return buffer.toString(); } //获取access_token 的请求地址 public final static String token_url="https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=APPID&secret=APPSECRET"; /** * 获取access_token 公众号的唯一凭证 * @param appid * @param appsecret * @return */ public static Token getAccessToken(String appid,String appsecret){ Token token=null; //拼接请求地址 String requestUrl=token_url.replace("APPID", appid).replaceAll("APPSECRET", appsecret); //调用接口 String jsonString=CommonUtil.httpsRequest(requestUrl, "GET", null); try{ //将json字符串转换成java对象 JSONObject jsonObject=JSONObject.fromObject(jsonString); String accessToken=jsonObject.getString("access_token"); int expiresIn=jsonObject.getInt("expires_in"); token=new Token(); token.setAccess_token(accessToken); token.setExpires_in(expiresIn); }catch(Exception e){ e.printStackTrace(); } return token; } public static String urlEncodeUTF8(String source){ String result=source; try { result=java.net.URLEncoder.encode(source, "UTF-8"); } catch (UnsupportedEncodingException e) { // TODO Auto-generated catch block e.printStackTrace(); } return result; }}
第三步:
支付成功后,微信服务器会向开发者设置的回调地址发送请求
/** * 微信支付成功回调处理 * @author * @version 创建时间:2017年3月8日 下午6:19:26 * @throws IOException * @throws DocumentException * @throws ParseException */ @SuppressWarnings("unchecked") public void acquire() throws IOException, DocumentException, ParseException { HttpServletRequest requests = ServletActionContext.getRequest(); // 解析结果存储在HashMap Map<String, String> map = new HashMap<String, String>(); InputStream inputStream = requests.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()); } // 释放资源 inputStream.close(); inputStream = null; // 返回状态码 String return_code = map.get("return_code"); // 返回信息 String return_msg = map.get("return_msg"); // 业务结果,判断交易是否成功 String result_code = map.get("result_code"); if(return_code=="SUCCESS"||return_code.equals("SUCCESS")){ if(result_code.equals("SUCCESS")){ //支付成功后的处理代码 } }
以上是微信支付服务商模式下的支付,其中涉及到的一些参数可以去微信商户平台找到
代码如有错误,欢迎大家批评指正,多多交流
0 0
- 微信公众号支付(服务商模式)
- 怎么申请微信支付服务商-微信公众号使用教程29
- 怎么认证微信支付服务商-微信公众号使用教程30
- 微信支付服务商开发能力说明文档范本-微信公众号使用教程31
- 微信支付(公众号支付)
- 微信支付服务商模式(受理机构模式)开发注意事项,jsapi支付
- 微信支付服务商模式(受理机构模式)开发注意事项,jsapi支付
- 微信支付服务商模式(受理机构模式)开发注意事项,jsapi支付
- 微信支付服务商APP支付申请
- 微信公众号支付
- 微信公众号支付
- 微信公众号支付
- 微信公众号支付
- 微信公众号支付
- 微信公众号支付
- 微信公众号支付
- 支付--微信公众号
- 微信公众号支付。
- DP两道关于递增非递增的题目
- SQL语句AND&OR
- 深度学习Imagenet caffe AlexNet 实验步骤
- 携程技术面试官素质。。。。。。哎
- 检查内存泄露
- 微信公众号支付(服务商模式)
- 见字如面,T3420为专业而生
- php 字符串
- 音乐会的等待【单调栈】
- 使用linux-c编程实现简单的ls命令
- redis数据库简介与安装
- mybatis中${}和#{}的区别?
- BFS最短路路径
- 自己写Ibatis,理解batis