赞
踩
1.了解微信H5支付 流程
1、用户在商户侧完成下单,使用微信支付进行支付
2、由商户后台向微信支付发起下单请求(调用统一下单接口)注:交易类型trade_type=MWEB
3、统一下单接口返回支付相关参数给商户后台,如支付跳转url(参数名“mweb_url”),商户通过mweb_url调起微信支付中间页
4、中间页进行H5权限的校验,安全性检查(此处常见错误请见下文)
5、如支付成功,商户后台会接收到微信侧的异步通知
6、用户在微信支付收银台完成支付或取消支付,返回商户页面(默认为返回支付发起页面)
7、商户在展示页面,引导用户主动发起支付结果的查询
8,9、商户后台判断是否接到收微信侧的支付结果通知,如没有,后台调用我们的订单查询接口确认订单状态
10、展示最终的订单支付结果给用户
- <dependency>
- <groupId>com.thoughtworks.xstream</groupId>
- <artifactId>xstream</artifactId>
- <version>1.4.8</version>
- </dependency>
- <dependency>
- <groupId>commons-fileupload</groupId>
- <artifactId>commons-fileupload</artifactId>
- <version>1.2.2</version>
- </dependency>
- <dependency>
- <groupId>commons-io</groupId>
- <artifactId>commons-io</artifactId>
- <version>2.0.1</version>
- </dependency>
- <dependency>
- <groupId>commons-codec</groupId>
- <artifactId>commons-codec</artifactId>
- <version>1.10</version>
- </dependency>
- <dependency>
- <groupId>net.sf.json-lib</groupId>
- <artifactId>json-lib</artifactId>
- <version>2.4</version>
- <classifier>jdk15</classifier>
- </dependency>
- <dependency>
- <groupId>org.jdom</groupId>
- <artifactId>jdom</artifactId>
- <version>2.0.2</version>
- </dependency>
- <dependency>
- <groupId>org.apache.httpcomponents</groupId>
- <artifactId>httpcore</artifactId>
- <version>4.4.10</version>
- </dependency>
- <dependency>
- <groupId>org.apache.httpcomponents</groupId>
- <artifactId>httpmime</artifactId>
- <version>4.5.2</version>
- </dependency>
- <dependency>
- <groupId>commons-httpclient</groupId>
- <artifactId>commons-httpclient</artifactId>
- <version>3.1</version>
- </dependency>
-
- //回调地址
- String notifyUrl = PropUtil.getString("notifyurl", "", Constant.H5PAY_FILE);
- if (notifyUrl.endsWith("/")){
- notifyUrl+="h5";
- }else{
- notifyUrl+="/h5";
- }
-
- String APPID = PropUtil.getString("h5payAPPID");//商户号取配置;
- String MERID = PropUtil.getString("h5payMERID");//;
- String SIGNKEY = "&^$&())^%3124";//;
- String h5payurl=PropUtil.getString("h5payurl");
- logger.info("APPID="+APPID);
- String spbill_create_ip = getIpAddr(request);//生产
- // System.out.println("spbill_create_ip="+spbill_create_ip);
- logger.info("spbill_create_ip="+spbill_create_ip);
- //String spbill_create_ip = "";//测试地址,也就是本地真是ip,用于本地测试用
- String scene_info = "{\"h5_info\": {\"type\":\"Wap\",\"wap_url\": \""+h5payurl+"\",\"wap_name\": \"代理购钻\"}}";//我这里是网页入口,app入口参考文档的安卓和ios写法 授权地址 和购买信息
- String tradeType = "MWEB";//H5支付标记
- String MD5 = "MD5";//虽然官方文档不是必须参数,但是不送有时候会验签失败
- JSONObject result = new JSONObject();
- String subject = "代理购钻";//前端上送的支付主题
- String total_amount = String.valueOf(orderAmount);//前端上送的支付金额
- String timestamp = String.valueOf(System.currentTimeMillis() / 1000);
- //金额转化为分为单位 微信支付以分为单位
-
- BigDecimal b1 = new BigDecimal(Double.valueOf(total_amount));
- BigDecimal b2 = new BigDecimal(Double.toString(0.01));
- logger.info("b1:"+b1.toString());
- logger.info("b2:"+b2.toString());
- BigDecimal b3= new BigDecimal(b1.multiply(b2).doubleValue()).setScale(0, BigDecimal.ROUND_HALF_UP);
-
- logger.info(b3.toString());
- String finalmoney = StringUtil.getMoney(b3.toString());//;
- logger.info(finalmoney);
- int randomNum = (int) (Math.random() * 1999+5000);
- /*String out_trade_no = Util.getSysTime("yyyyMMddHHmmss") + randomNum;*/
- //随机数
- String nonce_str= MD5Utils.getMessageDigest(String.valueOf(new Random().nextInt(10000)).getBytes());
- // String nonce_str = RandomStringUtils.randomAlphabetic(10);
- //签名数据
- StringBuilder sb = new StringBuilder();
- sb.append("appid="+APPID);
- sb.append("&body="+subject);
- sb.append("&mch_id="+MERID);
- sb.append("&nonce_str="+nonce_str);
- sb.append("¬ify_url="+notifyUrl);
- sb.append("&out_trade_no="+out_trade_no);
- sb.append("&scene_info="+scene_info);
- sb.append("&sign_type="+"MD5");
- sb.append("&spbill_create_ip="+spbill_create_ip);
- sb.append("&total_fee="+finalmoney);
- sb.append("&trade_type="+tradeType);
- sb.append("&key="+SIGNKEY);
- System.out.println("sb="+sb);
- logger.info("sb="+sb);
- //签名MD5加密
- String sign = MD5Utils.md5Encode(sb.toString()).toUpperCase();
- System.out.println("sign="+sign);
- logger.info("签名数据:"+sign);
- //封装xml报文
- String xml="<xml>"+
- "<appid>"+ APPID+"</appid>"+
- "<mch_id>"+ MERID+"</mch_id>"+
- "<nonce_str>"+nonce_str+"</nonce_str>"+
- "<sign>"+sign+"</sign>"+
- "<body>"+subject+"</body>"+//
- "<out_trade_no>"+out_trade_no+"</out_trade_no>"+
- "<total_fee>"+finalmoney+"</total_fee>"+//
- "<trade_type>"+tradeType+"</trade_type>"+
- "<notify_url>"+notifyUrl+"</notify_url>"+
- "<sign_type>MD5</sign_type>"+
- "<scene_info>"+scene_info+"</scene_info>"+
- "<spbill_create_ip>"+spbill_create_ip+"</spbill_create_ip>"+
- "</xml>";
-
- String createOrderURL = "https://api.mch.weixin.qq.com/pay/unifiedorder";//微信统一下单接口
- String mweb_url = "";
- Map map = new HashMap();
- logger.info("报文:"+xml);
- try {
- //预下单 获取接口地址
- map = WebUtils.getMwebUrl(createOrderURL, xml);
- logger.info("请求返回结果:"+map);
- String return_code = (String) map.get("return_code");
- String return_msg = (String) map.get("return_msg");
- if("SUCCESS".equals(return_code) && "OK".equals(return_msg)){
- mweb_url = (String) map.get("mweb_url");//调微信支付接口地址
- // System.out.println("mweb_url="+mweb_url);
-
- logger.info("create order url:"+mweb_url);
- //操作自己的业务逻辑
-
- OutputUtil.output(MessageBuilder.newInstance()
- .builderCodeMessage(1000, "OK").builder("body","代理购钻").builder("pay_info",mweb_url).builder("type","微信支付")
- .builder("out_trade_no", orderInfo.getOrderId()).builder("total_fee", orderInfo.getOrderAmount())
- , request, response, null, false);
- return;
-
- }else{
- OutputUtil.output(1002, "购钻失败,请稍后再试", request, response, false);
- return;
- }
- } catch (Exception e) {
- logger.error("Exception:" + e.getMessage(), e);
- }
- /**
- * Project Name:pay-protocol
- * File Name:Xml.java
- * Package Name:cn.swiftpass.pay.protocol
- * Date:2014-8-10下午10:48:21
- *
- */
-
- package com.sy.util;
-
- import org.dom4j.Document;
- import org.dom4j.Element;
- import org.dom4j.io.SAXReader;
- import org.xml.sax.InputSource;
-
- import javax.servlet.ServletInputStream;
- import javax.servlet.http.HttpServletRequest;
- import java.io.*;
- import java.util.*;
-
- /**
- * ClassName:Xml
- * Function: XML的工具方法
- * Date: 2014-8-10 下午10:48:21
- * @author
- */
- public class XmlUtils {
-
- /** <一句话功能简述>
- * <功能详细描述>request转字符串
- * @param request
- * @return
- * @see [类、类#方法、类#成员]
- */
- public static String parseRequst(HttpServletRequest request){
- String body = "";
- try {
- ServletInputStream inputStream = request.getInputStream();
- BufferedReader br = new BufferedReader(new InputStreamReader(inputStream));
- while(true){
- String info = br.readLine();
- if(info == null){
- break;
- }
- if(body == null || "".equals(body)){
- body = info;
- }else{
- body += info;
- }
- }
- } catch (UnsupportedEncodingException e) {
- e.printStackTrace();
- } catch (IOException e) {
- e.printStackTrace();
- }
- return body;
- }
-
- public static String parseXML(SortedMap<String, String> 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 (null != v && !"".equals(v) && !"appkey".equals(k)) {
- sb.append("<" + k + ">" + parameters.get(k) + "</" + k + ">\n");
- }
- }
- sb.append("</xml>");
- return sb.toString();
- }
-
- /**
- * 从request中获得参数Map,并返回可读的Map
- *
- * @param request
- * @return
- */
- public static SortedMap getParameterMap(HttpServletRequest request) {
- // 参数Map
- Map properties = request.getParameterMap();
- // 返回值Map
- SortedMap returnMap = new TreeMap();
- Iterator entries = properties.entrySet().iterator();
- Map.Entry entry;
- String name = "";
- String value = "";
- while (entries.hasNext()) {
- entry = (Map.Entry) entries.next();
- name = (String) entry.getKey();
- Object valueObj = entry.getValue();
- if(null == valueObj){
- value = "";
- }else if(valueObj instanceof String[]){
- String[] values = (String[])valueObj;
- for(int i=0;i<values.length;i++){
- value = values[i] + ",";
- }
- value = value.substring(0, value.length()-1);
- }else{
- value = valueObj.toString();
- }
- returnMap.put(name, value.trim());
- }
- return returnMap;
- }
-
- /**
- * 转XMLmap
- * @author
- * @param xmlBytes
- * @param charset
- * @return
- * @throws Exception
- */
- public static Map<String, String> toMap(byte[] xmlBytes,String charset) throws Exception{
- SAXReader reader = new SAXReader(false);
- InputSource source = new InputSource(new ByteArrayInputStream(xmlBytes));
- source.setEncoding(charset);
- Document doc = reader.read(source);
- Map<String, String> params = XmlUtils.toMap(doc.getRootElement());
- return params;
- }
-
- /**
- * 转MAP
- * @author
- * @param element
- * @return
- */
- public static Map<String, String> toMap(Element element){
- Map<String, String> rest = new HashMap<String, String>();
- List<Element> els = element.elements();
- for(Element el : els){
- rest.put(el.getName().toLowerCase(), el.getTextTrim());
- }
- return rest;
- }
-
- public static String toXml(Map<String, String> params){
- StringBuilder buf = new StringBuilder();
- List<String> keys = new ArrayList<String>(params.keySet());
- Collections.sort(keys);
- buf.append("<xml>");
- for(String key : keys){
- buf.append("<").append(key).append(">");
- buf.append("<![CDATA[").append(params.get(key)).append("]]>");
- buf.append("</").append(key).append(">\n");
- }
- buf.append("</xml>");
- return buf.toString();
- }
- }
-
- package com.sy.util;
-
- import com.alibaba.fastjson.JSON;
- import com.sy.mainland.util.HttpsUtil;
- import com.sy.mainland.util.SHAUtil;
-
- import com.alibaba.fastjson.JSON;
- import com.sy.mainland.util.HttpsUtil;
- import com.sy.mainland.util.SHAUtil;
-
- import org.apache.commons.httpclient.HttpClient;
- import org.apache.commons.httpclient.methods.PostMethod;
- import org.apache.commons.httpclient.methods.StringRequestEntity;
- import org.slf4j.Logger;
- import org.slf4j.LoggerFactory;
- import org.springframework.http.RequestEntity;
-
- import java.io.BufferedInputStream;
- import java.util.HashMap;
- import java.util.LinkedHashMap;
- import java.util.Map;
-
- public class WebUtils {
-
- public static Map getMwebUrl(String url,String xmlParam){
- String jsonStr = null;
- HttpClient httpClient = new HttpClient();
- Map map = new HashMap();
- try {
- PostMethod method = null;
- StringRequestEntity reqEntity = new StringRequestEntity(xmlParam,"text/json","UTF-8");
- method = new PostMethod(url);
- method.setRequestEntity(reqEntity);
- method.addRequestHeader("Content-Type","application/json;charset=utf-8");
- httpClient.executeMethod(method);
- StringBuffer resBodyBuf = new StringBuffer();
- byte[] responseBody = new byte[1024];
- int readCount = 0;
- BufferedInputStream is = new BufferedInputStream(method.getResponseBodyAsStream());
- while((readCount = is.read(responseBody,0,responseBody.length))!=-1){
- resBodyBuf.append(new String(responseBody,0,readCount,"utf-8"));
- }
- jsonStr = resBodyBuf.toString();
- System.out.println(jsonStr);
- // map = XmlUtils.parseXmlToList(jsonStr);
- map = XmlUtils.toMap(jsonStr.getBytes(), "utf-8");
- } catch (Exception e) {
- e.printStackTrace();
- }
- return map;
- }
- }
-
- package com.sy.util;
-
- import java.io.UnsupportedEncodingException;
- import java.security.MessageDigest;
-
- /**
- * 采用MD5加密
- *
- * @author relax
- */
- public class MD5Utils {
-
- public static String md5U(String inStr) {
- return md5Encode(inStr).toUpperCase();
- }
-
- /***
- * MD5加密 生成32位md5码
- *
- * @param 待加密字符串
- * @return 返回32位md5码
- */
- public static String md5Encode(String inStr) {
- MessageDigest md5 = null;
- try {
- md5 = MessageDigest.getInstance("MD5");
- } catch (Exception e) {
- System.out.println(e.toString());
- e.printStackTrace();
- return "";
- }
-
- byte[] byteArray;
- StringBuffer hexValue = new StringBuffer();
- try {
- byteArray = inStr.getBytes("UTF-8");
- byte[] md5Bytes = md5.digest(byteArray);
-
- for (int i = 0; i < md5Bytes.length; i++) {
- int val = ((int) md5Bytes[i]) & 0xff;
- if (val < 16) {
- hexValue.append("0");
- }
- hexValue.append(Integer.toHexString(val));
- }
- } catch (UnsupportedEncodingException e) {
- e.printStackTrace();
- }
-
- return hexValue.toString();
- }
-
- public static String md5For16U(String inStr) {
- return md5For16(inStr).toUpperCase();
- }
-
- public static String md5For16(String inStr) {
- MessageDigest md5 = null;
- try {
- md5 = MessageDigest.getInstance("MD5");
- } catch (Exception e) {
- System.out.println(e.toString());
- e.printStackTrace();
- return "";
- }
-
- byte[] byteArray;
- StringBuffer hexValue = new StringBuffer();
- try {
- byteArray = inStr.getBytes("UTF-8");
- byte[] md5Bytes = md5.digest(byteArray);
-
- for (int i = 0; i < md5Bytes.length; i++) {
- int val = ((int) md5Bytes[i]) & 0xff;
- if (val < 16) {
- hexValue.append("0");
- }
- hexValue.append(Integer.toHexString(val));
- }
- } catch (UnsupportedEncodingException e) {
- e.printStackTrace();
- }
-
- return hexValue.toString().substring(8, 24);
- }
-
- /**
- * 测试主函数
- *
- * @param args
- * @throws Exception
- */
- public static void main(String args[]) throws Exception {
- String str = new String("amigoxiexiexingxing");
- System.out.println("原始:" + str);
- System.out.println("MD5后:" + md5Encode(str));
- }
-
- public final static String getMessageDigest(byte[] buffer) {
- char hexDigits[] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };
- try {
- MessageDigest mdTemp = MessageDigest.getInstance("MD5");
- mdTemp.update(buffer);
- byte[] md = mdTemp.digest();
- int j = md.length;
- char str[] = new char[j * 2];
- int k = 0;
- for (int i = 0; i < j; i++) {
- byte byte0 = md[i];
- str[k++] = hexDigits[byte0 >>> 4 & 0xf];
- str[k++] = hexDigits[byte0 & 0xf];
- }
- return new String(str);
- } catch (Exception e) {
- return null;
- }
- }
-
-
-
- }
- /**
- * 元转换成分
- * @param money
- * @return
- */
- public static String getMoney(String amount) {
- if(amount==null){
- return "";
- }
- // 金额转化为分为单位
- String currency = amount.replaceAll("\\$|\\¥|\\,", ""); //处理包含, ¥ 或者$的金额
- int index = currency.indexOf(".");
- int length = currency.length();
- Long amLong = 0l;
- if(index == -1){
- amLong = Long.valueOf(currency+"00");
- }else if(length - index >= 3){
- amLong = Long.valueOf((currency.substring(0, index+3)).replace(".", ""));
- }else if(length - index == 2){
- amLong = Long.valueOf((currency.substring(0, index+2)).replace(".", "")+0);
- }else{
- amLong = Long.valueOf((currency.substring(0, index+1)).replace(".", "")+"00");
- }
- return amLong.toString();
- }
- @RequestMapping(value = "/notify/h5")
- public void weixinPayNotify(HttpServletRequest req, HttpServletResponse resp) throws Exception {
- String respString = "fail";
- try {
- BufferedReader reader = req.getReader();
- String line = "";
- Map map = new HashMap();
- String xml = "<xml><return_code><![CDATA[FAIL]]></xml>";;
- JSONObject dataInfo = new JSONObject();
- StringBuffer inputString = new StringBuffer();
- while ((line = reader.readLine()) != null) {
- inputString.append(line);
- }
- req.getReader().close();
- // System.out.println("----接收到的报文---"+inputString.toString());
- logger.info("----接收到的报文---"+inputString.toString());
- if(inputString.toString().length()>0){
- // map = XmlUtils.parseXmlToList(inputString.toString());
- map = XmlUtils.toMap(inputString.toString().getBytes(), "utf-8");
- }else{
- System.out.println("接受微信报文为空");
- }
- // System.out.println("map="+map);
- logger.info("map="+map);
- if(map!=null && "SUCCESS".equals(map.get("result_code"))){
- //成功的业务。。。
- xml = "<xml><return_code><![CDATA[SUCCESS]]></return_code><return_msg><![CDATA[OK]]></return_msg></xml>";
- }
- } catch (Exception e) {
- logger.error("Exception:" + e.getMessage(), e);
- }finally {
- resp.getWriter().write(respString);
- resp.getWriter().flush();
- resp.getWriter().close();
- }
- }
注:伸手党仔细看一下
支付常见错误
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。