微信支付(JSAPI) - Java

最近客栈订房,当然是需要微信支付的,官方微信支付文档什么的,只想说 去你妈的文档

so, 经过两天不懈的努力和网上大牛文档,终于做出来了,下面具体来说说,希望能对各位看客有点帮助

 

放大招,直接上代码

1. Configure.java 文件

微信支付(JSAPI) - Java
  1 package com.kzb.website.core.wechat.common;
  2 
  3 import java.util.Calendar;
  4 import java.util.Date;
  5 
  6 import org.apache.commons.lang3.StringUtils;
  7 
  8 public class Configure {
  9 
 10     private static String token = null;
 11     private static Date tokenTime = null;
 12     private static String jsapiTicket = null;
 13     private static Date jsapiTicketTime = null;
 14 
 15     public static String MD5 = "MD5";
 16     public static String EMPTY = "";
 17     public static String SUCCESS = "SUCCESS";
 18     public static String HEX_FORMAT = "%02x";
 19     public static String TRADE_TYPE = "JSAPI";
 20     public static String MIDDLE_LINE = "-";
 21     public static String CHARTSET_UTF8 = "UTF-8";
 22 
 23     public static String NOTIFY_SUCCESS = "<xml>\n<return_code><![CDATA[SUCCESS]]></return_code>\n<return_msg><![CDATA[OK]]></return_msg>\n</xml>";
 24     public static String NOTIFY_FAIL = "<xml>\n<return_code><![CDATA[FAIL]]></return_code>\n<return_msg><![CDATA[ERROR]]></return_msg>\n</xml>";
 25 
 26     private static String key = "API密钥(32位,在微信商户平台下的API安全栏下)";
 27     // 微信分配的公众号ID(开通公众号之后可以获取到)
 28     private static String appID = "XXXXXXXXXXXXXX";
 29     private static String appSecret = "XXXXXXXXXXXXXX";
 30     // 微信支付分配的商户号ID(开通公众号的微信支付功能之后可以获取到)
 31     private static String mchID = "1349019501";
 32     // 机器IP
 33     private static String ip = "127.0.0.1";
 34 
 35     // 以下是几个API的路径:
 36     // 统一下单
 37     public static String UNIFIEDORDER_API = "https://api.mch.weixin.qq.com/pay/unifiedorder";
 38     //  access_token API
 39     public static String TOKEN_API = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential";
 40     // 临时票据API
 41     public static String TICKET_API = "https://api.weixin.qq.com/cgi-bin/ticket/getticket";
 42     // 微信OPENID API
 43     public static String OPENID_API = "https://api.weixin.qq.com/sns/oauth2/access_token";
 44 
 45     public static void setKey(String key) {
 46         Configure.key = key;
 47     }
 48 
 49     public static void setAppID(String appID) {
 50         Configure.appID = appID;
 51     }
 52 
 53     public static void setMchID(String mchID) {
 54         Configure.mchID = mchID;
 55     }
 56 
 57     public static void setIp(String ip) {
 58         Configure.ip = ip;
 59     }
 60 
 61     public static String getKey(){
 62         return key;
 63     }
 64     
 65     public static String getAppid(){
 66         return appID;
 67     }
 68     
 69     public static String getMchid(){
 70         return mchID;
 71     }
 72 
 73     public static String getIP(){
 74         return ip;
 75     }
 76 
 77     public static String getAppSecret() {
 78         return appSecret;
 79     }
 80 
 81     public static void setAppSecret(String appSecret) {
 82         Configure.appSecret = appSecret;
 83     }
 84 
 85     public static String getToken() {
 86         return token;
 87     }
 88 
 89     public static void setToken(String token) {
 90         Configure.token = token;
 91         Configure.tokenTime = new Date();
 92     }
 93 
 94     public static String getJsapiTicket() {
 95         return jsapiTicket;
 96     }
 97 
 98     public static void setJsapiTicket(String jsapiTicket) {
 99         Configure.jsapiTicket = jsapiTicket;
100         Configure.jsapiTicketTime = new Date();
101     }
102 
103     public static boolean checkToken() {
104         if (!StringUtils.isEmpty(Configure.token)) {
105             Calendar calendar = Calendar.getInstance();
106             calendar.setTime(tokenTime);
107             calendar.add(Calendar.SECOND, 7200);
108             return calendar.before(new Date());
109         }
110         return true;
111     }
112 
113     public static boolean checkJsapiTicket() {
114         if (!StringUtils.isEmpty(Configure.jsapiTicket)) {
115             Calendar calendar = Calendar.getInstance();
116             calendar.setTime(jsapiTicketTime);
117             calendar.add(Calendar.SECOND, 7200);
118             return calendar.before(new Date());
119         }
120         return true;
121     }
122 }
View Code

 

2. SignMD5.java文件

微信支付(JSAPI) - Java
 1 package com.kzb.website.core.wechat.common;
 2 
 3 import java.io.UnsupportedEncodingException;
 4 import java.security.MessageDigest;
 5 import java.security.NoSuchAlgorithmException;
 6 import java.util.Formatter;
 7 import java.util.UUID;
 8 
 9 import org.springframework.security.crypto.password.PasswordEncoder;
10 
11 public class SignMD5 implements PasswordEncoder {
12     public static String byteToHex(final byte[] hash) {
13         Formatter formatter = new Formatter();
14         for (byte b : hash) {
15             formatter.format(Configure.HEX_FORMAT, b);
16         }
17         String result = formatter.toString();
18         formatter.close();
19         return result;
20     }
21 
22     @Override
23     public String encode(CharSequence charSequence) {
24         try {
25             MessageDigest crypt = MessageDigest.getInstance(Configure.MD5);
26             crypt.reset();
27             crypt.update(charSequence.toString().getBytes(Configure.CHARTSET_UTF8));
28             return byteToHex(crypt.digest());
29         } catch (NoSuchAlgorithmException e) {
30             e.printStackTrace();
31         } catch (UnsupportedEncodingException e) {
32             e.printStackTrace();
33         }
34         return Configure.EMPTY;
35     }
36 
37     @Override
38     public boolean matches(CharSequence charSequence, String encodedPassword) {
39         return encode(charSequence).equals(encodedPassword);
40     }
41 
42     public String createNonceStr() {
43         return UUID.randomUUID().toString().replaceAll(Configure.MIDDLE_LINE,Configure.EMPTY);
44     }
45 
46     public String createTimeStamp() {
47         return Long.toString(System.currentTimeMillis() / 1000);
48     }
49 
50 }
View Code

 

3. WechatNotify.java文件

微信支付(JSAPI) - Java
  1 package com.kzb.website.core.wechat.common;
  2 
  3 import java.io.Serializable;
  4 
  5 import javax.xml.bind.annotation.XmlRootElement;
  6 
  7 @XmlRootElement(name="xml")
  8 public class WechatNotify implements Serializable{
  9 
 10     private static final long serialVersionUID = 8047707600433551023L;
 11     private String appid;
 12     private String attach;
 13     private String bank_type;
 14     private String fee_type;
 15     private String is_subscribe;
 16     private String mch_id;
 17     private String nonce_str;
 18     private String openid;
 19     private String out_trade_no;
 20     private String result_code;
 21     private String return_code;
 22     private String sign;
 23     private String sub_mch_id;
 24     private String time_end;
 25     private String total_fee;
 26     private String trade_type;
 27     private String transaction_id;
 28 
 29     public String getAppid() {
 30         return appid;
 31     }
 32 
 33     public void setAppid(String appid) {
 34         this.appid = appid;
 35     }
 36 
 37     public String getAttach() {
 38         return attach;
 39     }
 40 
 41     public void setAttach(String attach) {
 42         this.attach = attach;
 43     }
 44 
 45     public String getBank_type() {
 46         return bank_type;
 47     }
 48 
 49     public void setBank_type(String bank_type) {
 50         this.bank_type = bank_type;
 51     }
 52 
 53     public String getFee_type() {
 54         return fee_type;
 55     }
 56 
 57     public void setFee_type(String fee_type) {
 58         this.fee_type = fee_type;
 59     }
 60 
 61     public String getIs_subscribe() {
 62         return is_subscribe;
 63     }
 64 
 65     public void setIs_subscribe(String is_subscribe) {
 66         this.is_subscribe = is_subscribe;
 67     }
 68 
 69     public String getMch_id() {
 70         return mch_id;
 71     }
 72 
 73     public void setMch_id(String mch_id) {
 74         this.mch_id = mch_id;
 75     }
 76 
 77     public String getNonce_str() {
 78         return nonce_str;
 79     }
 80 
 81     public void setNonce_str(String nonce_str) {
 82         this.nonce_str = nonce_str;
 83     }
 84 
 85     public String getOpenid() {
 86         return openid;
 87     }
 88 
 89     public void setOpenid(String openid) {
 90         this.openid = openid;
 91     }
 92 
 93     public String getOut_trade_no() {
 94         return out_trade_no;
 95     }
 96 
 97     public void setOut_trade_no(String out_trade_no) {
 98         this.out_trade_no = out_trade_no;
 99     }
100 
101     public String getResult_code() {
102         return result_code;
103     }
104 
105     public void setResult_code(String result_code) {
106         this.result_code = result_code;
107     }
108 
109     public String getReturn_code() {
110         return return_code;
111     }
112 
113     public void setReturn_code(String return_code) {
114         this.return_code = return_code;
115     }
116 
117     public String getSign() {
118         return sign;
119     }
120 
121     public void setSign(String sign) {
122         this.sign = sign;
123     }
124 
125     public String getSub_mch_id() {
126         return sub_mch_id;
127     }
128 
129     public void setSub_mch_id(String sub_mch_id) {
130         this.sub_mch_id = sub_mch_id;
131     }
132 
133     public String getTime_end() {
134         return time_end;
135     }
136 
137     public void setTime_end(String time_end) {
138         this.time_end = time_end;
139     }
140 
141     public String getTotal_fee() {
142         return total_fee;
143     }
144 
145     public void setTotal_fee(String total_fee) {
146         this.total_fee = total_fee;
147     }
148 
149     public String getTrade_type() {
150         return trade_type;
151     }
152 
153     public void setTrade_type(String trade_type) {
154         this.trade_type = trade_type;
155     }
156 
157     public String getTransaction_id() {
158         return transaction_id;
159     }
160 
161     public void setTransaction_id(String transaction_id) {
162         this.transaction_id = transaction_id;
163     }
164 }
View Code

 

4. WechatPayModel.java文件

微信支付(JSAPI) - Java
  1 package com.kzb.website.core.wechat.common;
  2 
  3 import javax.xml.bind.annotation.XmlRootElement;
  4 
  5 import org.springframework.security.crypto.password.PasswordEncoder;
  6 
  7 @XmlRootElement(name = "XML")
  8 public class WechatPayModel {
  9 
 10     private String appid;
 11     private String mch_id;
 12     private String nonce_str;
 13     private String body;
 14     private String out_trade_no;
 15     private String total_fee;
 16     private String spbill_create_ip;
 17     private String notify_url;
 18     private String trade_type;
 19     private String openid;
 20     private String sign;
 21 
 22     public String getAppid() {
 23         return appid;
 24     }
 25 
 26     public void setAppid(String appid) {
 27         this.appid = appid;
 28     }
 29 
 30     public String getMch_id() {
 31         return mch_id;
 32     }
 33 
 34     public void setMch_id(String mch_id) {
 35         this.mch_id = mch_id;
 36     }
 37 
 38     public String getNonce_str() {
 39         return nonce_str;
 40     }
 41 
 42     public void setNonce_str(String nonce_str) {
 43         this.nonce_str = nonce_str;
 44     }
 45 
 46     public String getOut_trade_no() {
 47         return out_trade_no;
 48     }
 49 
 50     public void setOut_trade_no(String out_trade_no) {
 51         this.out_trade_no = out_trade_no;
 52     }
 53 
 54     public String getTotal_fee() {
 55         return total_fee;
 56     }
 57 
 58     public void setTotal_fee(String total_fee) {
 59         this.total_fee = total_fee;
 60     }
 61 
 62     public String getSpbill_create_ip() {
 63         return spbill_create_ip;
 64     }
 65 
 66     public void setSpbill_create_ip(String spbill_create_ip) {
 67         this.spbill_create_ip = spbill_create_ip;
 68     }
 69 
 70     public String getNotify_url() {
 71         return notify_url;
 72     }
 73 
 74     public void setNotify_url(String notify_url) {
 75         this.notify_url = notify_url;
 76     }
 77 
 78     public String getTrade_type() {
 79         return trade_type;
 80     }
 81 
 82     public void setTrade_type(String trade_type) {
 83         this.trade_type = trade_type;
 84     }
 85 
 86     public String getBody() {
 87         return body;
 88     }
 89 
 90     public void setBody(String body) {
 91         this.body = body;
 92     }
 93 
 94     public String getSign() {
 95         return sign;
 96     }
 97 
 98     public void setSign(String sign) {
 99         this.sign = sign;
100     }
101 
102     public String getOpenid() {
103         return openid;
104     }
105 
106     public void setOpenid(String openid) {
107         this.openid = openid;
108     }
109 
110     public void sign(PasswordEncoder encoder) {
111         StringBuilder stringBuilder = new StringBuilder();
112         stringBuilder.append("appid=").append(getAppid());
113         stringBuilder.append("&body=").append(getBody());
114         stringBuilder.append("&mch_id=").append(getMch_id());
115         stringBuilder.append("&nonce_str=").append(getNonce_str());
116         stringBuilder.append("&notify_url=").append(getNotify_url());
117         stringBuilder.append("&openid=").append(getOpenid());
118         stringBuilder.append("&out_trade_no=").append(getOut_trade_no());
119         stringBuilder.append("&spbill_create_ip=").append(getSpbill_create_ip());
120         stringBuilder.append("&total_fee=").append(getTotal_fee());
121         stringBuilder.append("&trade_type=").append(getTrade_type());
122         stringBuilder.append("&key=").append(Configure.getKey());
123         this.sign = encoder.encode(stringBuilder.toString());
124     }
125 
126     @Override
127     public String toString() {
128         return "<xml>" +
129                 "<appid><![CDATA[" + appid + "]]></appid>" +
130                 "<body><![CDATA[" + body + "]]></body>" +
131                 "<mch_id><![CDATA[" + mch_id + "]]></mch_id>" +
132                 "<nonce_str><![CDATA[" + nonce_str + "]]></nonce_str>" +
133                 "<notify_url><![CDATA[" + notify_url + "]]></notify_url>" +
134                 "<openid><![CDATA[" + openid + "]]></openid>" +
135                 "<out_trade_no><![CDATA[" + out_trade_no + "]]></out_trade_no>" +
136                 "<spbill_create_ip><![CDATA[" + spbill_create_ip + "]]></spbill_create_ip>" +
137                 "<trade_type><![CDATA[" + trade_type + "]]></trade_type>" +
138                 "<total_fee><![CDATA[" + total_fee + "]]></total_fee>" +
139                 "<sign><![CDATA[" + sign + "]]></sign>" +
140                 "</xml>";
141     }
142 }
View Code

 

5. WechatUtil.java文件

微信支付(JSAPI) - Java
 1 package com.kzb.website.core.wechat.common;
 2 
 3 import java.io.DataInputStream;
 4 import java.io.IOException;
 5 
 6 import javax.servlet.http.HttpServletRequest;
 7 
 8 import com.kzb.website.core.utils.XMLUtil;
 9 
10 public class WechatUtil {
11 
12     /**
13      * 微信回调成功后 将 xml 转换为  WechatNotify 对象
14      * 
15      * @param request
16      * @return WechatNotify 对象
17      */
18     public static WechatNotify getNotifyBean(HttpServletRequest request){
19         try {
20             DataInputStream in = new DataInputStream(request.getInputStream());
21             byte[] dataOrigin = new byte[request.getContentLength()];
22             // 根据长度,将消息实体的内容读入字节数组dataOrigin中
23             in.readFully(dataOrigin); 
24             // 关闭数据流
25             in.close();
26             // 从字节数组中得到表示实体的字符串
27             String xml = new String(dataOrigin);
28             // 将 xml 转换为  WechatNotify 对象
29             Object object = XMLUtil.xmlToBean(WechatNotify.class, xml);
30             if (object != null && object instanceof WechatNotify) {
31                 WechatNotify notify = (WechatNotify) object;
32                 return notify;
33             } else {return null;}
34         } catch (IOException e) {
35             e.printStackTrace();
36             return null;
37         }
38     }
39 }
View Code

 

6. XMLUtil.java文件

微信支付(JSAPI) - Java
 1 package com.kzb.website.core.utils;
 2 
 3 import java.io.StringReader;
 4 
 5 import javax.xml.bind.JAXBContext;
 6 import javax.xml.bind.JAXBException;
 7 import javax.xml.bind.Unmarshaller;
 8 
 9 public class XMLUtil {
10 
11     /**
12      * 将 XML 字符串转换为 Java 对象
13      * 
14      * @param clazz 要转换对象的 class
15      * @param xml 待转换的 xml
16      * @return 转换后的对象
17      */
18     public static Object xmlToBean(Class<?> clazz, String xml) {
19         try {
20             JAXBContext jc = JAXBContext.newInstance(clazz);
21             Unmarshaller us = jc.createUnmarshaller();
22             return us.unmarshal(new StringReader(xml));
23         } catch (JAXBException e) {
24             e.printStackTrace();
25             return null;
26         }
27     }
28 }
View Code

 

7. pay_choose.jsp 页面,这个页面是一个支付选择画面,用来获取code,和回调到支付画面

微信支付(JSAPI) - Java
 1 <%@ page language="java" contentType="text/html; charset=UTF-8"%>
 2 <!DOCTYPE html>
 3 <html>
 4 <head>
 5     <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
 6     <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no">
 7     <title>支付选择画面</title>
 8     <meta name="keywords" content="关键字,关键字">
 9     <meta name="description" content="">
10     <style type="text/css">
11         *{margin: 0;padding: 0;}
12         body{font-size:12px;font-family:"微软雅黑";color:#666;}
13     </style>
14 </head>
15 <body>
16     <div style="margin:40px auto;width:400px;">
17         <a href="javascript:wechat();">微信支付</a><br/><br/><br/>
18         <a href="javascript:ali();">支付宝支付</a>
19     </div>
20 <script type="text/javascript" src="http://apps.bdimg.com/libs/jquery/2.1.4/jquery.min.js"></script>
21 <script type="text/javascript">
22 function wechat(){
23     var redirect_uri = "http://www.xxxxx.com/wxpay/payment.htm?hotelId=14501";
24     var href = "https://open.weixin.qq.com/connect/oauth2/authorize?redirect_uri=" + encodeURIComponent(redirect_uri);
25     href += "&appid=wx73997299f6dba700&response_type=code&scope=snsapi_base";
26     window.location.href = href;
27 }
28 function ali(){
29     
30 }
31 </script>
32 </body>
33 </html>
View Code

 

8. wechat_pay.jsp 页面

 1 <%@ page language="java" contentType="text/html; charset=UTF-8"%>
 2 <%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
 3 <!DOCTYPE html>
 4 <html>
 5 <head>
 6     <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
 7     <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no">
 8     <title>微信支付</title>
 9     <meta name="keywords" content="关键字,关键字">
10     <meta name="description" content="">
11 <script type="text/javascript" src="http://apps.bdimg.com/libs/jquery/2.1.4/jquery.min.js"></script>
12 <script type="text/javascript" charset="UTF-8" src="https://res.wx.qq.com/open/js/jweixin-1.0.0.js"></script>
13 <script type="text/javascript">
14 function pay(){
15     //config
16     var appId = $(#appId).val();
17     var timeStamp = $(#timeStamp).val();
18     var nonceStr = $(#nonceStr).val();
19     var signature = $(#signature).val();
20     
21     var signType = $(#signType).val();
22     var pk = $(#package).val();
23     var paySign = $(#paySign).val();
24 
25     wx.config({
26         debug: false, // 开启调试模式,调用的所有api的返回值会在客户端alert出来,若要查看传入的参数,可以在pc端打开,参数信息会通过log打出,仅在pc端时才会打印。
27         appId: appId, // 必填,公众号的唯一标识
28         timestamp: timeStamp , // 必填,生成签名的时间戳
29         nonceStr: nonceStr, // 必填,生成签名的随机串
30         signature: signature,// 必填,签名,见附录1
31         jsApiList: [chooseWXPay] // 必填,需要使用的JS接口列表,所有JS接口列表见附录2
32     });
33 
34     wx.ready(function(res){
35         // config信息验证后会执行ready方法,所有接口调用都必须在config接口获得结果之后,config是一个客户端的异步操作,所以如果需要在页面加载时就调用相关接口,则须把相关接口放在ready函数中调用来确保正确执行。对于用户触发时才调用的接口,则可以直接调用,不需要放在ready函数中。
36         wx.chooseWXPay({
37             timestamp: timeStamp, // 支付签名时间戳,注意微信jssdk中的所有使用timestamp字段均为小写。但最新版的支付后台生成签名使用的timeStamp字段名需大写其中的S字符
38             nonceStr: nonceStr, // 支付签名随机串,不长于 32 位
39             package: pk, // 统一支付接口返回的prepay_id参数值,提交格式如:prepay_id=***)
40             signType: signType, // 签名方式,默认为‘SHA1‘,使用新版支付需传入‘MD5‘
41             paySign: paySign, // 支付签名
42             success: function (res) {
43                 location.href = http://www.xxxxxxx.net/success.htm;
44             },
45             cancel: function (res) {
46                 location.href = http://www.xxxxxxx.net/success.htm;
47             },
48             fail: function (res) {
49                 location.href = http://www.xxxxxxx.net/success.htm;
50             }
51         });
52     });
53 
54     wx.error(function (res) {
55         alert("error:" + JSON.stringify(res));
56     });
57 }
58 </script>
59 </head>
60 <body onload="pay()">
61     <h1>正在进行微信支付....
62         <br/>
63         <small>请不要关闭</small>
64     </h1>
65     <input id="appId" type="hidden" value="${start.appId}" /><br/>
66     <input id="timeStamp" type="hidden" value="${start.timestamp}" /><br/>
67     <input id="nonceStr" type="hidden" value="${start.nonceStr}" /><br/>
68     <input id="signature" type="hidden" value="${start.signature}" /><br/>
69     
70     <input id="signType" type="hidden" value="${pay.signType}" /><br/>
71     <input id="package" type="hidden" value="${pay.packageStr}" /><br/>
72     <input id="paySign" type="hidden" value="${pay.paySign}" /><br/>
73 </body>
74 </html>

 

9. WechatPayService.java 页面

  1 package com.kzb.website.web.wechat;
  2 
  3 import java.util.HashMap;
  4 import java.util.Map;
  5 
  6 import org.apache.commons.lang3.StringUtils;
  7 import org.springframework.stereotype.Service;
  8 import org.springframework.ui.Model;
  9 import org.springframework.web.client.RestTemplate;
 10 
 11 import com.alibaba.fastjson.JSONArray;
 12 import com.fasterxml.jackson.databind.JsonNode;
 13 import com.fasterxml.jackson.dataformat.xml.XmlMapper;
 14 import com.kzb.website.core.wechat.common.Configure;
 15 import com.kzb.website.core.wechat.common.SignMD5;
 16 import com.kzb.website.core.wechat.common.WechatPayModel;
 17 
 18 @Service
 19 public class WechatPayService {
 20     SignMD5 encoder = new SignMD5();
 21     RestTemplate restTemplate = new RestTemplate();
 22 
 23     /**
 24      * 微信支付统一下单接口
 25      * 
 26      * @param notifyUrl 支付成功后回调路径
 27      * @param openId 用户的 openId
 28      * @param body 商品描述
 29      * @param total 支付金额(单位分)
 30      * @param out_trade_no 订单唯一订单号
 31      * @return
 32      */
 33     public String unifiedorder(String notifyUrl, String openId, String body, String total, String out_trade_no) {
 34         WechatPayModel xml = new WechatPayModel();
 35         xml.setAppid(Configure.getAppid());
 36         xml.setMch_id(Configure.getMchid());
 37         xml.setNonce_str(encoder.createNonceStr());
 38         xml.setBody(body);
 39         xml.setOut_trade_no(out_trade_no);
 40         xml.setTotal_fee(total);
 41         xml.setSpbill_create_ip(Configure.getIP());
 42         xml.setNotify_url(notifyUrl);
 43         xml.setTrade_type(Configure.TRADE_TYPE);
 44         xml.setOpenid(openId);
 45         xml.sign(encoder);
 46         return restTemplate.postForObject(Configure.UNIFIEDORDER_API, xml, String.class);
 47     }
 48 
 49     /**
 50      * 调起微信支付
 51      * 
 52      * @param model
 53      * @param res 预支付订单 字符串
 54      * @param url 微信支付 url
 55      */
 56     public void wechatPay(Model model, String res,String url) {
 57         try {
 58             Map<String, String> start = new HashMap<>();
 59             StringBuilder startSign = new StringBuilder();
 60 
 61             Map<String, String> pay = new HashMap<>();
 62             StringBuilder paySign = new StringBuilder();
 63             XmlMapper xmlMapper = new XmlMapper();
 64             JsonNode node = xmlMapper.readTree(res);
 65             if (StringUtils.equals(node.get("return_code").asText(), Configure.SUCCESS)) {
 66                 // 得到的预支付订单,重新生成微信支付参数
 67                 String prepay_id = node.get("prepay_id").asText();
 68                 String jsapi_ticket = jsapiTicket();
 69                 // 生成 微信支付 config 参数
 70                 start.put("appId", Configure.getAppid());
 71                 start.put("nonceStr", encoder.createNonceStr());
 72                 start.put("timestamp", encoder.createTimeStamp());
 73                 // 生成 config 签名
 74                 startSign.append("jsapi_ticket=").append(jsapi_ticket);
 75                 startSign.append("&noncestr=").append(start.get("nonceStr"));
 76                 startSign.append("&timestamp=").append(start.get("timestamp"));
 77                 startSign.append("&url=").append(url);
 78                 start.put("signature", encoder.encode(startSign.toString()));
 79                 
 80                 // config信息验证后会执行ready方法的参数
 81                 pay.put("signType", Configure.MD5);
 82                 pay.put("packageStr", "prepay_id=" + prepay_id);
 83                 // 生成支付签名
 84                 paySign.append("appId=").append(start.get("appId"));
 85                 paySign.append("&nonceStr=").append(start.get("nonceStr"));
 86                 paySign.append("&package=").append(pay.get("packageStr"));
 87                 paySign.append("&signType=").append(pay.get("signType"));
 88                 paySign.append("&timeStamp=").append(start.get("timestamp"));
 89                 paySign.append("&key=").append(Configure.getKey());
 90                 pay.put("paySign", encoder.encode(paySign.toString()));
 91                 // 将微信支参数放入 model 对象中以便前端使用
 92                 model.addAttribute("start", start);
 93                 model.addAttribute("pay", pay);
 94             }
 95         } catch (Exception e) {
 96             model.addAttribute("wechatMessage", "微信授权失败!");
 97             e.printStackTrace();
 98         }
 99     }
100 
101     /**
102      * 微信授权,获取 access_token
103      * 
104      * @return access_token
105      */
106     public String getToken() {
107         if (Configure.checkToken()) {
108             // 声明 获取 access_token 路径
109             StringBuilder tokenBuilder = new StringBuilder();
110             tokenBuilder.append(Configure.TOKEN_API);
111             tokenBuilder.append("&appid=").append(Configure.getAppid());
112             tokenBuilder.append("&secret=").append(Configure.getAppSecret());
113             // 获取 token
114             Map<?, ?> token = restTemplate.getForObject(tokenBuilder.toString(), Map.class);
115             Configure.setToken((String) token.get("access_token"));
116         }
117         return Configure.getToken();
118     }
119 
120     /**
121      * 获取微信 JSAPI 支付的临时票据
122      * 
123      * @return 临时票据
124      */
125     public String jsapiTicket() {
126         if (Configure.checkJsapiTicket()) {
127             // 声明 获取临时票据路径
128             StringBuilder ticketBuilder = new StringBuilder();
129             ticketBuilder.append(Configure.TICKET_API);
130             ticketBuilder.append("?access_token=").append(getToken());
131             ticketBuilder.append("&type=jsapi");
132             // 获取 临时票据
133             Map<?, ?> jsapiTicket = restTemplate.getForObject(ticketBuilder.toString(), Map.class);
134             Configure.setJsapiTicket((String) jsapiTicket.get("ticket"));
135         }
136         return Configure.getJsapiTicket();
137     }
138 
139     /**
140      * 获取用的 OPENID
141      * 
142      * @param code 微信认证回调的 code
143      * @return
144      */
145     public String takeOpenId(String code) {
146         // 声明 获取OPENID路径
147         StringBuilder openidBuilder = new StringBuilder();
148         openidBuilder.append(Configure.OPENID_API);
149         openidBuilder.append("?appid=").append(Configure.getAppid());
150         openidBuilder.append("&secret=").append(Configure.getAppSecret());
151         openidBuilder.append("&code=").append(code);
152         openidBuilder.append("&grant_type=authorization_code");
153         // 获取 OPENID
154         String res = restTemplate.getForObject(openidBuilder.toString(), String.class);
155         Map<?, ?> map = JSONArray.parseObject(res, Map.class);
156         return String.valueOf(map.get("openid"));
157     }
158 }

 

10. WechatPayController.java 页面

 1 package com.kzb.website.web.wechat;
 2 
 3 import java.util.Date;
 4 
 5 import javax.servlet.http.HttpServletRequest;
 6 
 7 import org.apache.commons.lang3.StringUtils;
 8 import org.springframework.beans.factory.annotation.Autowired;
 9 import org.springframework.stereotype.Controller;
10 import org.springframework.ui.Model;
11 import org.springframework.web.bind.annotation.RequestMapping;
12 import org.springframework.web.bind.annotation.RequestMethod;
13 import org.springframework.web.bind.annotation.RequestParam;
14 import org.springframework.web.bind.annotation.ResponseBody;
15 
16 import com.kzb.website.core.wechat.common.Configure;
17 import com.kzb.website.core.wechat.common.WechatNotify;
18 import com.kzb.website.core.wechat.common.WechatUtil;
19 
20 @RequestMapping("wxpay")
21 @Controller
22 public class WechatPayController {
23 
24     @Autowired
25     private PayService payService;
26 
27     @RequestMapping("payment.htm")
28     public String payment(@RequestParam(required = false) String code, Model model, HttpServletRequest request){
29         String openId = payService.takeOpenId(code);
30         if (StringUtils.isEmpty(openId)) {
31             return "pay/wxpay_error";
32         }
33         String notify = "http://www.xxxxxx.net/wxpay/notify.htm";
34         String body = "商品支付内容";
35         String total = "1"; // 单位分
36         String out_trade_no = new Date().getTime() + "";
37         
38         String res = payService.unifiedorder(notify, openId, body, total, out_trade_no);
39 
40         String url = "http://www.xxxxxx.net/wxpay/payment.htm";
41         payService.wechatPay(model,res,url);
42         return "pay/wxpay";
43     }
44 
45     /**
46      * 微信支付成功后的回调函数
47      * 
48      * @param request
49      * @return
50      */
51     @RequestMapping(value="notify.htm",method=RequestMethod.POST)
52     @ResponseBody
53     public String wechatNotify(HttpServletRequest request){
54         // 从 request 对象中获取 WechatNotify 对象
55         WechatNotify notify = WechatUtil.getNotifyBean(request);
56         // 如果 notify 对象不为空 并且 result_code 和 return_code 都为 ‘SUCCESS‘ 则表示支付成功
57         if (notify != null
58                 && StringUtils.equals(notify.getResult_code(), Configure.SUCCESS)
59                 && StringUtils.equals(notify.getReturn_code(), Configure.SUCCESS)) {
60 
61             return Configure.NOTIFY_SUCCESS;
62         }
63         return Configure.NOTIFY_FAIL;
64     }
65 }

 

现在就只需要放入服务器测试啦,赶快行动起来,试试吧

下面还有几篇来说说微信支付中遇到的那些 操蛋 的问题吧

微信支付(JSAPI) - Java

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


下一篇:仿微信图片选择器