微信APP支付统一下单、加签、map转xml,java代码

流程:前端创建订单,后端保存订单并调用微信统一下单接口,将微信返回的预支付回话标识返回给客户端。

统一下单:

1.统一下单参数设置(map)


2.将参数加签,并将sign加入到map(这里注意,key是需要自己去设置的,设置路径:微信商户平台(pay.weixin.qq.com)-->账户设置-->API安全-->密钥设置。加签官方文档:https://pay.weixin.qq.com/wiki/doc/api/app/app.php?chapter=4_3)


3.map转xml然后转string


4.请求api(注意:请求方式POST,设置编码格式UTF-8)


5.解析微信返回的xml格式数据,并根据业务需求,格式化后返回给客户端




遇到的报错:
1.APP没有支付权限或者商户号和APP_ID不符合。这里是因为你的参数不是微信APP支付需要的参数,你用了微信其他的参数,建议关注微信官方公众号:WXPayService,里面有个接入指南,按照他的流程做,一次通过。公众号支付和扫码支付流程及技术指引也有。
2.签名错误。一方面可能是你的签名过程有问题,另一方面是可能你的参数(例如KEY有问题,他也会报签名错误),遇到这个错误建议用官方提供的 加签工具 验证你的签名是否正确,如果你的结果和他的结果一样,那应该就是你的参数有问题,加签工具地址:https://pay.weixin.qq.com/wiki/tools/signverify/。
2.time_expire时间过短。过期时间应该在当前系统时间之后。


附上代码:

加签
 public static String getSign(Map<String,String> map){ 	
    	String StringA =  util.StringUtil.formatUrlMap(map,true,true);
    	String stringSignTemp = MD5.MD5Encode(StringA+"&key="+AliPayConfig.weixin_key).toUpperCase();  
    	return stringSignTemp;   
    }
/**  
     *  
     * 方法用途: 对所有传入参数按照字段名的 ASCII 码从小到大排序(字典序),并且生成url参数串
     * 实现步骤: 
     * @param paraMap   要排序的Map对象  
     * @param urlEncode   是否需要URLENCODE  
     * @param keyToLower    是否需要将Key转换为全小写  
     *            true:key转化成小写,false:不转化  
     * @return  
     */  
    public static String formatUrlMap(Map<String,String> paraMap,boolean urlEncode,boolean keyToLower)  
    {  
        if(paraMap == null){  
            return "";  
        }  
        String buff = "";  
        Map<String,String> tmpMap = paraMap;  
        try  
        {  
            List<Map.Entry<String,String>> infoIds = new ArrayList<Map.Entry<String,String>>(tmpMap.entrySet());  
            // 对所有传入参数按照字段名的 ASCII 码从小到大排序(字典序)  
            Collections.sort(infoIds,new Comparator<Map.Entry<String,String>>()  
            {  
                @Override  
                public int compare(Map.Entry<String,String> o1,Map.Entry<String,String> o2)  
                {  
                    return (o1.getKey()).toString().compareTo(o2.getKey());  
                }  
            });  
            // 构造URL 键值对的格式  
            StringBuilder buf = new StringBuilder();  
            for (Map.Entry<String,String> item : infoIds)  
            {  
                    String key = item.getKey();  
                    String val = item.getValue();  
                    if (urlEncode)  
                    {  
			//如果是中文,则不参与编码
                       if(key.equals("package")){
          		
        }else if(key.equals("body")){
          		
        }else if(key.equals("notify_url")){
          		
       	}else{
         val = URLEncoder.encode(val,"utf-8"); 
        }
                    }  
                    if (keyToLower)  
                    {  
                        buf.append(key.toLowerCase() + "=" + val);  
                    } else  
                    {  
                        buf.append(key + "=" + val);  
                    }  
                    buf.append("&");  
            }  
            buff = buf.toString();  
            if (buff.equals("") == false)  
            {  
                buff = buff.substring(0,buff.length() - 1);  
            }  
        } catch (Exception e)  
        {  
            return null;  
        }  
        return buff;  
    }  

 /**
     * MD5编码
     * @param origin 原始字符串
     * @return 经过MD5加密之后的结果
     */
    public static String MD5Encode(String origin) {
        String resultString = null;
        try {
            resultString = origin;
            MessageDigest md = MessageDigest.getInstance("MD5");
            resultString = byteArrayToHexString(md.digest(resultString.getBytes()));
        } catch (Exception e) {
            e.printStackTrace();
        }
        return resultString;
    }

  /**
     * 转换字节数组为16进制字串
     * @param b 字节数组
     * @return 16进制字串
     */
    public static String byteArrayToHexString(byte[] b) {
        StringBuilder resultSb = new StringBuilder();
        for (byte aB : b) {
            resultSb.append(byteToHexString(aB));
        }
        return resultSb.toString();
    }
 /**
     * 转换byte到16进制
     * @param b 要转换的byte
     * @return 16进制格式
     */
    private static String byteToHexString(byte b) {
        int n = b;
        if (n < 0) {
            n = 256 + n;
        }
        int d1 = n / 16;
        int d2 = n % 16;
        return hexDigits[d1] + hexDigits[d2];
    }
===============================================================================
map转xml然后转string

private static final String PREFIX_XML = "<xml>";

	private static final String SUFFIX_XML = "</xml>";

	private static final String PREFIX_CDATA = "<![CDATA[";

	private static final String SUFFIX_CDATA = "]]>";

public static String xmlFormat(Map<String,String> parm,boolean isAddCDATA) {

		StringBuffer strbuff = new StringBuffer(PREFIX_XML);
		if (StringUtil.isNotEmpty(parm)) {
			for (Entry<String,String> entry : parm.entrySet()) {
				strbuff.append("<").append(entry.getKey()).append(">");
				//这里是用CDATA标签包起来,原本以为body和sign需要包起来,但是发现不需要,又懒得删了,就改成了body1,sign1
				//isNotNullOrEmptyStr是判断不为空的方法
				if("attach".equalsIgnoreCase(entry.getKey()) ||"body1".equalsIgnoreCase(entry.getKey()) ||"sign1".equalsIgnoreCase(entry.getKey()) ){
					strbuff.append(PREFIX_CDATA);
					if (StringUtil.isNotNullOrEmptyStr(entry.getValue())) {
						strbuff.append(entry.getValue());
					}
					strbuff.append(SUFFIX_CDATA);
				}else{
					if (StringUtil.isNotNullOrEmptyStr(entry.getValue())) {
						strbuff.append(entry.getValue());
					}
				}
				strbuff.append("</").append(entry.getKey()).append(">");
			}
		}
		return strbuff.append(SUFFIX_XML).toString();
	}
===============================================================================

请求api(注意:请求方式POST,设置编码格式UTF-8)

public static String httpsRequest(String requestUrl,String requestMethod,String outputStr) {    
      try {    
          URL url = new URL(requestUrl);    
          HttpURLConnection conn = (HttpURLConnection) url.openConnection();    
            
          conn.setDoOutput(true);    
          conn.setDoInput(true);    
          conn.setUseCaches(false);    
          // 设置请求方式(GET/POST)    
          conn.setRequestMethod(requestMethod);    
          conn.setRequestProperty("content-type","application/x-www-form-urlencoded");    
          // 当outputStr不为null时向输出流写数据    
          if (null != outputStr) {    
              OutputStream outputStream = conn.getOutputStream();    
              // 注意编码格式    
              outputStream.write(outputStr.getBytes("UTF-8"));    
              outputStream.close();    
          }    
          // 从输入流读取返回内容    
          InputStream inputStream = conn.getInputStream();    
          InputStreamReader inputStreamReader = new InputStreamReader(inputStream,"utf-8");    
          BufferedReader bufferedReader = new BufferedReader(inputStreamReader);    
          String str = null;  
          StringBuffer buffer = new StringBuffer();    
          while ((str = bufferedReader.readLine()) != null) {    
        	 // System.out.println("bf != null");
              buffer.append(str);    
          }    
          // 释放资源    
          bufferedReader.close();    
          inputStreamReader.close();    
          inputStream.close();    
          inputStream = null;    
          conn.disconnect();    
          return buffer.toString();    
      } catch (ConnectException ce) {    
          System.out.println("连接超时:{}"+ ce);    
      } catch (Exception e) {    
          System.out.println("https请求异常:{}"+ e);    
      }    
      return null;    
    }  
===============================================================================
解析微信返回的xml格式数据,并根据业务需求,格式化后返回给客户端
import org.jdom.Document;
import org.jdom.Element;
import org.jdom.input.SAXBuilder;
public static Map<String,String> doXMLParse(String strxml) throws Exception {    
          strxml = strxml.replaceFirst("encoding=\".*\"","encoding=\"UTF-8\"");    
          if(null == strxml || "".equals(strxml)) {    
              return null;    
          }          
          Map<String,String> m = new HashMap<String,String>();     
          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 = getChildrenText(children);    
              }      
              m.put(k,v);    
          }       
          in.close();     
          return m;    
    } 
    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.getTextNormalize();    
                List list = e.getChildren();    
                sb.append("<" + name + ">");    
                if(!list.isEmpty()) {    
                    sb.append(getChildrenText(list));    
                }    
                sb.append(value);    
                sb.append("</" + name + ">");    
            }    
        }     
        return sb.toString();    
  }

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


php输出xml格式字符串
J2ME Mobile 3D入门教程系列文章之一
XML轻松学习手册
XML入门的常见问题(一)
XML入门的常见问题(三)
XML轻松学习手册(2)XML概念
xml文件介绍及使用
xml编程(一)-xml语法
XML文件结构和基本语法
第2章 包装类
XML入门的常见问题(二)
Java对象的强、软、弱和虚引用
JS解析XML文件和XML字符串详解
java中枚举的详细使用介绍
了解Xml格式
XML入门的常见问题(四)
深入SQLite多线程的使用总结详解
PlayFramework完整实现一个APP(一)
XML和YAML的使用方法
XML轻松学习总节篇