java微信扫码支付(模式二)

Posted wentaokyle

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了java微信扫码支付(模式二)相关的知识,希望对你有一定的参考价值。

微信扫码支付——模式二

  代码:

  PayCommonUtil.java  微信支付常用方法

  1 import java.text.SimpleDateFormat;
  2 import java.util.Date;
  3 import java.util.Iterator;
  4 import java.util.Map;
  5 import java.util.Set;
  6 import java.util.SortedMap;
  7 
  8 public class PayCommonUtil
  9 {
 10     /** 
 11      * 是否签名正确,规则是:按参数名称a-z排序,遇到空值的参数不参加签名。 
 12      * @return boolean 
 13      */  
 14     public static boolean isTenpaySign(String characterEncoding, SortedMap<Object, Object> packageParams, String API_KEY) {  
 15         StringBuffer sb = new StringBuffer();  
 16         Set es = packageParams.entrySet();  
 17         Iterator it = es.iterator();  
 18         while(it.hasNext()) {  
 19             Map.Entry entry = (Map.Entry)it.next();  
 20             String k = (String)entry.getKey();  
 21             String v = (String)entry.getValue();  
 22             if(!"sign".equals(k) && null != v && !"".equals(v)) {  
 23                 sb.append(k + "=" + v + "&");  
 24             }  
 25         }  
 26           
 27         sb.append("key=" + API_KEY);  
 28           
 29         //算出摘要  
 30         String mysign = MD5Util.MD5Encode(sb.toString(), characterEncoding).toLowerCase();  
 31         String tenpaySign = ((String)packageParams.get("sign")).toLowerCase();  
 32           
 33         //System.out.println(tenpaySign + "    " + mysign);  
 34         return tenpaySign.equals(mysign);  
 35     }  
 36   
 37     /** 
 38      * @author 
 39      * @date 2016-4-22 
 40      * @Description:sign签名 
 41      * @param characterEncoding 
 42      *            编码格式 
 43      * @param parameters 
 44      *            请求参数 
 45      * @return 
 46      */  
 47     public static String createSign(String characterEncoding, SortedMap<Object, Object> packageParams, String API_KEY) {  
 48         StringBuffer sb = new StringBuffer();  
 49         Set es = packageParams.entrySet();  
 50         Iterator it = es.iterator();  
 51         while (it.hasNext()) {  
 52             Map.Entry entry = (Map.Entry) it.next();  
 53             String k = (String) entry.getKey();  
 54             String v = (String) entry.getValue();  
 55             if (null != v && !"".equals(v) && !"sign".equals(k) && !"key".equals(k)) {  
 56                 sb.append(k + "=" + v + "&");  
 57             }  
 58         }  
 59         sb.append("key=" + API_KEY);  
 60         String sign = MD5Util.MD5Encode(sb.toString(), characterEncoding).toUpperCase();  
 61         return sign;  
 62     }  
 63   
 64     /** 
 65      * @author 
 66      * @date 2016-4-22 
 67      * @Description:将请求参数转换为xml格式的string 
 68      * @param parameters 
 69      *            请求参数 
 70      * @return 
 71      */  
 72     public static String getRequestXml(SortedMap<Object, Object> parameters) {  
 73         StringBuffer sb = new StringBuffer();  
 74         sb.append("<xml>");  
 75         Set es = parameters.entrySet();  
 76         Iterator it = es.iterator();  
 77         while (it.hasNext()) {  
 78             Map.Entry entry = (Map.Entry) it.next();  
 79             String k = (String) entry.getKey();  
 80             String v = (String) entry.getValue();  
 81             if ("attach".equalsIgnoreCase(k) || "body".equalsIgnoreCase(k) || "sign".equalsIgnoreCase(k)) {  
 82                 sb.append("<" + k + ">" + "<![CDATA[" + v + "]]></" + k + ">");  
 83             } else {  
 84                 sb.append("<" + k + ">" + v + "</" + k + ">");  
 85             }  
 86         }  
 87         sb.append("</xml>");  
 88         return sb.toString();  
 89     }  
 90   
 91     /** 
 92      * 取出一个指定长度大小的随机正整数. 
 93      *  
 94      * @param length 
 95      *            int 设定所取出随机数的长度。length小于11 
 96      * @return int 返回生成的随机数。 
 97      */  
 98     public static int buildRandom(int length) {  
 99         int num = 1;  
100         double random = Math.random();  
101         if (random < 0.1) {  
102             random = random + 0.1;  
103         }  
104         for (int i = 0; i < length; i++) {  
105             num = num * 10;  
106         }  
107         return (int) ((random * num));  
108     }  
109   
110     /** 
111      * 获取当前时间 yyyyMMddHHmmss 
112      *  
113      * @return String 
114      */  
115     public static String getCurrTime() {  
116         Date now = new Date();  
117         SimpleDateFormat outFormat = new SimpleDateFormat("yyyyMMddHHmmss");  
118         String s = outFormat.format(now);  
119         return s;  
120     }  
121 }

  XMLUtil.java   将支付参数转换为xml格式

 1 import java.io.ByteArrayInputStream;
 2 import java.io.IOException;
 3 import java.io.InputStream;
 4 import java.util.HashMap;
 5 import java.util.Iterator;
 6 import java.util.List;
 7 import java.util.Map;
 8 
 9 import org.jdom.Document;
10 import org.jdom.Element;
11 import org.jdom.JDOMException;
12 import org.jdom.input.SAXBuilder;
13 
14 public class XMLUtil
15 {
16     /** 
17      * 解析xml,返回第一级元素键值对。如果第一级元素有子节点,则此节点的值是子节点的xml数据。 
18      * @param strxml 
19      * @return 
20      * @throws JDOMException 
21      * @throws IOException 
22      */  
23     public static Map doXMLParse(String strxml) throws JDOMException, IOException {  
24         strxml = strxml.replaceFirst("encoding=\".*\"", "encoding=\"UTF-8\"");  
25   
26         if(null == strxml || "".equals(strxml)) {  
27             return null;  
28         }  
29           
30         Map m = new HashMap();  
31           
32         InputStream in = new ByteArrayInputStream(strxml.getBytes("UTF-8"));  
33         SAXBuilder builder = new SAXBuilder();  
34         Document doc = builder.build(in);  
35         Element root = doc.getRootElement();  
36         List list = root.getChildren();  
37         Iterator it = list.iterator();  
38         while(it.hasNext()) {  
39             Element e = (Element) it.next();  
40             String k = e.getName();  
41             String v = "";  
42             List children = e.getChildren();  
43             if(children.isEmpty()) {  
44                 v = e.getTextNormalize();  
45             } else {  
46                 v = XMLUtil.getChildrenText(children);  
47             }  
48               
49             m.put(k, v);  
50         }  
51           
52         //关闭流  
53         in.close();  
54           
55         return m;  
56     }  
57       
58     /** 
59      * 获取子结点的xml 
60      * @param children 
61      * @return String 
62      */  
63     public static String getChildrenText(List children) {  
64         StringBuffer sb = new StringBuffer();  
65         if(!children.isEmpty()) {  
66             Iterator it = children.iterator();  
67             while(it.hasNext()) {  
68                 Element e = (Element) it.next();  
69                 String name = e.getName();  
70                 String value = e.getTextNormalize();  
71                 List list = e.getChildren();  
72                 sb.append("<" + name + ">");  
73                 if(!list.isEmpty()) {  
74                     sb.append(XMLUtil.getChildrenText(list));  
75                 }  
76                 sb.append(value);  
77                 sb.append("</" + name + ">");  
78             }  
79         }  
80           
81         return sb.toString();  
82     }  
83 }

  HttpUtil.java  用http连接提交支付信息参数

 1 import java.io.BufferedReader;
 2 import java.io.IOException;
 3 import java.io.InputStreamReader;
 4 import java.io.OutputStreamWriter;
 5 import java.net.URL;
 6 import java.net.URLConnection;
 7 
 8 import org.apache.commons.logging.Log;
 9 import org.apache.commons.logging.LogFactory;
10 
11 
12 public class HttpUtil
13 {
14     private static final Log logger = LogFactory.getLog("org.apache.catalina.tribes.MESSAGES" );
15     
16     private final static int CONNECT_TIMEOUT = 5000; // in milliseconds  
17     
18     private final static String DEFAULT_ENCODING = "UTF-8";  
19       
20     public static String postData(String urlStr, String data){  
21         return postData(urlStr, data, null);  
22     }  
23       
24     public static String postData(String urlStr, String data, String contentType){  
25         BufferedReader reader = null;  
26         try {  
27             URL url = new URL(urlStr);  
28             URLConnection conn = url.openConnection();  
29             conn.setDoOutput(true);  
30             conn.setConnectTimeout(CONNECT_TIMEOUT);  
31             conn.setReadTimeout(CONNECT_TIMEOUT);  
32             if(contentType != null)  
33                 conn.setRequestProperty("content-type", contentType);  
34             OutputStreamWriter writer = new OutputStreamWriter(conn.getOutputStream(), DEFAULT_ENCODING);  
35             if(data == null)  
36                 data = "";  
37             writer.write(data);   
38             writer.flush();  
39             writer.close();    
40   
41             reader = new BufferedReader(new InputStreamReader(conn.getInputStream(), DEFAULT_ENCODING));  
42             System.out.println(reader.toString());
43             StringBuilder sb = new StringBuilder();  
44             String line = null;  
45             while ((line = reader.readLine()) != null) {  
46                 sb.append(line);  
47                 sb.append("\r\n");  
48             }  
49             return sb.toString();  
50         } catch (IOException e) {  
51             logger.error("Error connecting to " + urlStr + ": " + e.getMessage());  
52         } finally {  
53             try {  
54                 if (reader != null)  
55                     reader.close();  
56             } catch (IOException e) {  
57             }  
58         }  
59         return null;  
60     }  
61 }

  MD5Util.java   md5加密

 1     private static String byteToHexString(byte b) {  
 2         int n = b;  
 3         if (n < 0)  
 4             n += 256;  
 5         int d1 = n / 16;  
 6         int d2 = n % 16;  
 7         return hexDigits[d1] + hexDigits[d2];  
 8     }  
 9   
10     public static String MD5Encode(String origin, String charsetname) {  
11         String resultString = null;  
12         try {  
13             resultString = new String(origin);  
14             MessageDigest md = MessageDigest.getInstance("MD5");  
15             if (charsetname == null || "".equals(charsetname))  
16                 resultString = byteArrayToHexString(md.digest(resultString  
17                         .getBytes()));  
18             else  
19                 resultString = byteArrayToHexString(md.digest(resultString  
20                         .getBytes(charsetname)));  
21         } catch (Exception exception) {  
22         }  
23         return resultString;  
24     }  
25   
26     private static final String hexDigits[] = { "0", "1", "2", "3", "4", "5",  
27             "6", "7", "8", "9", "a", "b", "c", "d", "e", "f" };  
28 } 
  GetWeixinUrlUtil.java   获取订单生成的二维码URL
 1 import java.io.UnsupportedEncodingException;
 2 import java.net.URLEncoder;
 3 import java.util.Map;
 4 import java.util.SortedMap;
 5 import java.util.TreeMap;
 6 
 7 public class GetWeixinUrlUtil
 8 {
 9     //获取二维码url  
10     public static String weixin_pay(String ip, VcWeixinPay vcWeixinPay) throws Exception {  
11     // 账号信息  
12         String appid = PayConfigUtil.APP_ID;  // appid  
13         String mch_id = PayConfigUtil.MCH_ID; // 商户号  
14         String key = PayConfigUtil.API_KEY; // key  
15         String currTime = PayCommonUtil.getCurrTime();  
16         String strTime = currTime.substring(8, currTime.length());  
17         String strRandom = PayCommonUtil.buildRandom(4) + "";  
18         String nonce_str = strTime + strRandom;          
19         int order_price = 1; // 商品价格   注意:价格的单位是分  
20         String body = "商品名称";   // 商品名称  
21         String out_trade_no = PayCommonUtil.getCurrTime() + PayCommonUtil.buildRandom(4); // 商户订单号  
22         // 获取发起电脑 ip  
23         String spbill_create_ip = ip;  
24         // 回调接口   
25         String notify_url = PayConfigUtil.NOTIFY_URL;  
26         String trade_type = "NATIVE";  //交易类型          
27         SortedMap<Object,Object> packageParams = new TreeMap<Object,Object>();  
28         packageParams.put("appid", appid);  
29         packageParams.put("mch_id", mch_id);  
30         packageParams.put("nonce_str", nonce_str);  
31         packageParams.put("body", body);  
32         packageParams.put("out_trade_no", out_trade_no);  
33         packageParams.put("total_fee", String.valueOf(order_price));  
34         packageParams.put("spbill_create_ip", spbill_create_ip);  
35         packageParams.put("notify_url", notify_url);  
36         packageParams.put("trade_type", trade_type);  
37         //生成签名
38         String sign = PayCommonUtil.createSign("UTF-8", packageParams,key);  
39         packageParams.put("sign", sign);  
40           
41         String requestXML = PayCommonUtil.getRequestXml(packageParams);  
42         System.out.println(requestXML);  
43    
44         String resXml = HttpUtil.postData(PayConfigUtil.UFDODER_URL, requestXML);       
45         Map map = XMLUtil.doXMLParse(resXml);  
48         String urlCode = (String) map.get("code_url");  
49           
50         return urlCode;   
51     } 
52     
53     // 特殊字符处理  
54     public static String UrlEncode(String src)  throws UnsupportedEncodingException {  
55         return URLEncoder.encode(src, "UTF-8").replace("+", "%20");  
56     }  
57 }    

  PayConfigUtil.java  微信支付参数

 1 import javax.servlet.http.HttpServletRequest;
 2 
 3 public class PayConfigUtil
 4 {
 5     public static final String APP_ID = "";//微信开发平台应用ID(公众号ID)
 6     public static final String MCH_ID = "";//商户号(商户号ID)
 7     public static final String API_KEY = "";//API key(商户号里面的)
 8     public static final String CREATE_IP = "";//发起支付的ip
 9     public static final String NOTIFY_URL = "";//回调地址
10     public static final String UFDODER_URL = "https://api.mch.weixin.qq.com/pay/unifiedorder";//微信统一下单接口
11     public static final String APP_SECRET = "";//应用对应的凭证(在公众号里面)
12     
13     //获取ip
14     public static String getIP(HttpServletRequest request)
15     {
16         String ip = request.getRemoteAddr();
17         return ip;
18     }
19     
  支付回调方法
  1 public void weixin_notify(HttpServletRequest request,HttpServletResponse response) throws Exception
  2     {  
  3         System.out.println("调用回调方法");
  4         //读取参数  
  5         InputStream inputStream ;  
  6         StringBuffer sb = new StringBuffer();  
  7         inputStream = request.getInputStream();  
  8         String s ;  
  9         BufferedReader in = new BufferedReader(new InputStreamReader(inputStream, "UTF-8"));  
 10         while ((s = in.readLine()) != null){  
 11             sb.append(s);  
 12         }  
 13         in.close();  
 14         inputStream.close();  
 15   
 16         //解析xml成map  
 17         Map<String, String> m = new HashMap<String, String>();  
 18         m = XMLUtil.doXMLParse(sb.toString());  
 19           
 20         //过滤空 设置 TreeMap  
 21         SortedMap<Object,Object> packageParams = new TreeMap<Object,Object>();        
 22         Iterator it = m.keySet().iterator();  
 23         while (it.hasNext()) {  
 24             String parameter = (String) it.next();  
 25             String parameterValue = m.get(parameter);  
 26               
 27             String v = "";  
 28             if(null != parameterValue) {  
 29                 v = parameterValue.trim();  
 30             }  
 31             packageParams.put(parameter, v);  
 32         }  
 33           
 34         // 账号信息  
 35         String key = PayConfigUtil.API_KEY; // key  
 36         
 37         logger.info(packageParams);  
 38         //判断签名是否正确  
 39         if(PayCommonUtil.isTenpaySign("UTF-8", packageParams,key)) {  
 40             //------------------------------  
 41             //处理业务开始  
 42             //------------------------------  
 44             String resXml = "";  
 45             if("SUCCESS".equals((String) packageParams.get("result_code"))){  
 46                 // 这里是支付成功  
 47                 //////////执行自己的业务逻辑////////////////  
 48                 String mch_id = (String) packageParams.get("mch_id");  
 49                 String openid = (String) packageParams.get("openid");  
 50                 String is_subscribe = (String) packageParams.get("is_subscribe");  
 51                 String out_trade_no = (String) packageParams.get("out_trade_no");  
 52                 String total_fee = (String) packageParams.get("total_fee"); 
 53                 String cash_fee_s = (String) packageParams.get("cash_fee");
 54                 String cash_fee = String.valueOf(Integer.parseInt(cash_fee_s) / 100);
 55                 String time_end = MctsUtils.numberDateToDate((String) packageParams.get("time_end"));
 56                 String transaction_id = (String) packageParams.get("transaction_id");
 57                     
 58                     //////////执行自己的业务逻辑(报存订单信息到数据库)////////////////  
 59                     System.out.println("支付成功 ,处理业务成功");
 60                     logger.info("支付成功");  
 61                     //通知微信.异步确认成功.必写.不然会一直通知后台.八次之后就认为交易失败了.  
 62                     resXml = "<xml>" + "<return_code><![CDATA[SUCCESS]]></return_code>"  
 63                             + "<return_msg><![CDATA[OK]]></return_msg>" + "</xml> ";  
 64                   //------------------------------  
 65                     //处理业务完毕  
 66                     //------------------------------  
              //向微信服务器发送确认信息,若不发送,微信服务器会间隔不同的时间调用回调方法 67 BufferedOutputStream out = new BufferedOutputStream( 68 response.getOutputStream()); 69 out.write(resXml.getBytes()); 70 out.flush(); 71 out.close(); 73 System.out.println("通知微信.异步确认成功"); 74 } else { 93 logger.info("支付失败,错误信息:" + packageParams.get("err_code")); 94 resXml = "<xml>" + "<return_code><![CDATA[FAIL]]></return_code>" 95 + "<return_msg><![CDATA[报文为空]]></return_msg>" + "</xml> "; 96 97 BufferedOutputStream out = new BufferedOutputStream( 98 response.getOutputStream()); 99 out.write(resXml.getBytes()); 100 out.flush(); 101 out.close(); 102 System.out.println("执行回调函数失败"); 103 } 105 } else{ 106 logger.info("通知签名验证失败"); 107 } 108 }
  根据GetWeixinUrlUtil.java获取到微信支付订单信息的二维码url,下载一个解析二维码的js插件(jquery.qrcode.min.js),把获取到二维码url在前端页面用jquery.qrcode.min.js解析,就能显示二维码了。
  前端页面简略代码:
 1 <script type="text/javascript" src="js/jquery.qrcode.min.js"></script>
 2 <script language="javascript">
 3     $(function(){
 4         var codeUrl = ${erWeiMa};//erWeiMa是后端传的二维码url
 5         $("#code").qrcode({ 
 6             render: "canvas", //table方式 
 7             width: 240, //宽度 
 8             height:240, //高度 
 9             text: codeUrl //任意内容 
10         }); 
11     });
12 </script>
13 
14 <div id="code" style="width: 240px;height: 240px;margin: 0px auto;"></div> 

  其中用到的jar包当时忘记记录了,不知道的可以根据报错信息搜下缺少的jar包。

  

以上是关于java微信扫码支付(模式二)的主要内容,如果未能解决你的问题,请参考以下文章

微信扫码支付模式二无法回调解决方案(转)

微信:微信扫码支付调用统一下单接口网站支付 + springmvc

PHP版本,微信扫码支付native模式二,扫码支付成功,页面静止不动,怎么可以支付回调URL?

PHP PC端微信扫码支付模式二详细教程-附带源码(转)

thinkphp5.0 微信扫码支付模式二

java实现微信支付之扫码支付