当前位置: 移动技术网 > IT编程>开发语言>Java > 微信支付之二维码支付(native)

微信支付之二维码支付(native)

2019年12月24日  | 移动技术网IT编程  | 我要评论

fm152海城之声,疯狂雷电,湘湘人体

hoje
男孩子你要加油阿

. 准备材料

首先肯定是要有微信的开发文档

再然后就是一些必的参数


注意:回调地址异步接收微信支付结果通知的回调地址,通知url必须为外网可访问的url,不能携带参数。

再然后就是微信的sdk

. 微信支付需要的参数

上面的开发文档你肯定看熟了吧,流程肯定会了吧,代码怎么写呢?先来看看需要哪些参数吧.



好了知道流程了知道需要哪些参数了那咱们动手吧!

. 统一下单

首页你得有统一下单是url:https://api.mch.weixin.qq.com/pay/unifiedorder

 1@controller
2@requestmapping("/wxpay")
3public class wxpaycontroller {
4    @autowired
5    private payorderservice payorderservice;
6
7    /**
8     * 微信二维码支付
9     */
10    @requestmapping(value = "/nativepay")
11    public map<string, string> createqrcode(httpservletrequest request, httpservletresponse response, string orderid) {
12        payorderdo payorderdo = this.payorderservice.getoder(orderid);//订单信息
13        //生成订单对象
14        map<string, string> request_data = new hashmap<>();
15        try {
16            map<string, string> data = new hashmap<string, string>();
17            data.put("appid", wxconstants.app_id);//公众账号id
18            data.put("mch_id",wxconstants.partner);//商户号
19            data.put("body", "测试");//商品详情
20            data.put("out_trade_no",orderid);//订单号
21            data.put("nonce_str", uuidutil.get32uuid());//32位字符串
22            //转换微信中存在最小计算单位是分的问题
23            bigdecimal paymoney = payorderdo.getpaymoney();
24            bigdecimal bigdecimal = new bigdecimal(100);
25            bigdecimal amount = paymoney.multiply(bigdecimal).setscale(0, bigdecimal.round_down);
26            data.put("total_fee", string.valueof(amount));//总金额
27            data.put("spbill_create_ip", iputils.getipaddr(request));//用户终端ip
28            data.put("trade_type", "native");  // h5支付的交易类型为mweb
29            data.put("notify_url", wxconstants.notify_url);//通知地址
30            data.put("product_id",orderid ); 
31            string sign = createsign(data, wxconstants.partner_key, wxconstants.charset);
32            //调用生成签名的方法,用以map集合中的相关参数生成签名 需要签名密钥
33            data.put("sign", sign);//签名
34            string xml = wxpayutil.generatesignedxml(data, wxconstants.partner_key);//转xml格式 微信sdk自带的
35
36            system.out.println("request - xml:" + xml);
37
38            string resultxml = httpsclientutil.dopost(wxconstants.bause_url, xml);//发送post请求   返回的是微信给我们的xml格式的数据
39
40            system.out.println("result - xml:" + resultxml);
41
42                map<string,string> result_map = xmltomap(resultxml);
43                //xml转map 微信sdk自带的
44                string return_msg = result_map.get("return_msg");//返回信息
45                string return_code = result_map.get("return_code");//状态码
46                string result_code = result_map.get("result_code");//业务结果
47                if (null != result_map && "success".equals(return_code) && "success".equals(result_code)) {
48                    request_data.put("url", result_map.get("code_url"));
49                }else{
50                request_data.put("url", "");
51            }
52
53        }catch (exception e){
54            request_data.put("url", "");
55        }
56        return request_data;
57    }

本人自己写的也可能不是很完美欢迎你们指出 送上更完美的demo 谢谢!!!

. 二维码

qr码是一种矩阵码,或二维空间的条码,1994年由日本denso-wave公司发明。qr是英文quick response的缩写,即快速反应的意思,源自发明者希望qr码可让其内容快速被解码。qr码常见於日本,并为目前日本最流行的二维空间条码。qr码比普通条码可储存更多资料,亦无需像普通条码般在扫描时需直线对准扫描器。
qr码呈正方形,只有黑白两色。在4个角落的其中3个,印有较小,像「回」字的的正方图案。这3个是供解码软体作定位用的图案,使用者无需对准,无论以任何角度扫描,资料仍可正确被读取。
qr code条码的特点
1.高密度编码,信息容量大:   
可容纳多达1850个大写字母或2710个数字或1108个字节,或500多个汉字,比普通条码信息容量约高几十倍。   
2.编码范围广:   
该条码可以把图片、声音、文字、签字、指纹等可以数字化的信息进行编码,用条码表示出来;可以表示多种语言文字;可表示图像数据。   
3.容错能力强,具有纠错功能:   
这使得二维条码因穿孔、污损等引起局部损坏时,照样可以正确得到识读,损毁面积达50%仍可恢复信息。   
4.译码可靠性高:   
它比普通条码译码错误率百万分之二要低得多,误码率不超过千万分之一。   
5.可引入加密措施:   
保密性、防伪性好。   
6.成本低,易制作,持久耐用。
本人百度粘贴的阿!!!
废话不多说了微信二维码支付关键不就是个二维码嘛!


当统一下单成功了返回的结果"code_url"就是我们要的二维码的链接
有很多种生成二位码的方法我知道的就两种
1丶第一种是前端的js插件qrious



使用该二维码生成插件需要在页面中引入qrious.js文件。
<script src="https://cdn.bootcss.com/qrious/4.0.2/qrious.js"></script>
使用一个img元素来作为二维码图片的容器。
<img id="qr"></img>
可以通过qrious()方法来实例化一个对象实例。

1(function() {
2  const qr = new qrious({
3    element: document.getelementbyid('qr'),
4    value: 'http://www.baidu.com/'
5  })
6})()

效果如图


好了前端代码怎么写看你怎么做了
2丶zxing是google提供的关于条码(一维码、二维码)的解析工具,提供了二维码的生成与解析的方法,现在我简单介绍一下使用java利用zxing生成与解析二维码
这种方法得写一个工具类百度网上有的我是用的qrious就不多说了

. 回调接口


我踩的坑阿!
注意:
1丶回调url必须得填写正确要不然微信访问不到会一直调用,就是支付成功后微信异步通知我们的服务器地址加项目加路径.
2丶一定要验证签名,要不然微信不知道是那个商户的会觉得不合法.
3丶给微信的数据一定是xml格式的,要不然微信解析不到就会一直调用(这就是微信比支付宝坑的地方)
话不多说上代码

 1/**
2     * 微信支付回调函数
3     * 支付成功后微信服务器会调用此方法,修改数据库订单状态
4     */
5    @requestmapping(value = "/notify")
6    public void wxpaycallback(httpservletrequest request, httpservletresponse response) {
7        try {
8            inputstream instream = request.getinputstream();
9            bytearrayoutputstream outsteam = new bytearrayoutputstream();
10            byte[] buffer = new byte[1024];
11            int len = 0;
12            while ((len = instream.read(buffer)) != -1) {
13                outsteam.write(buffer, 0, len);
14            }
15            outsteam.close();
16            instream.close();
17            string result = new string(outsteam.tobytearray(), wxconstants.charset);
18            map<string, string> map = xmltomap(result);
19            // 判断签名是否正确 微信sdk自带的方法
20            if (wxpayutil.issignaturevalid(map, wxconstants.partner_key)) {
21                 logger.info("微信支付成功回调");
22                // ------------------------------
23                // 处理业务开始
24                // ------------------------------
25                string resxml = "";
26                if ("success".equals((string) map.get("result_code"))) {
27                    // 这里是支付成功
28                    string orderno = (string) map.get("out_trade_no");
29                    logger.info("微信订单号{}付款成功",orderno);
30                    //这里 根据实际业务场景 做相应的操作 我们这里是更改数据库订单状态
31                    // 通知微信.异步确认成功.必写.不然会一直通知后台.八次之后就认为交易失败了.
32                    resxml = "<xml>" + "<return_code><![cdata[success]]></return_code>" + "<return_msg><![cdata[ok]]></return_msg>" + "</xml> ";
33                } else {
34                    logger.info("支付失败,错误信息:{}",packageparams.get("err_code"));
35                    resxml = "<xml>" + "<return_code><![cdata[fail]]></return_code>" + "<return_msg><![cdata[报文为空]]></return_msg>" + "</xml> ";
36                }
37                // ------------------------------
38                // 处理业务完毕
39                // ------------------------------
40                bufferedoutputstream out = new bufferedoutputstream(response.getoutputstream());
41                out.write(resxml.getbytes());
42                out.flush();
43                out.close();
44            } else {
45                system.out.println("通知签名验证失败");
46            }
47
48
49        } catch (exception e) {
50           e.printstacktrace();
51           logger.info("通知签名验证失败");
52        }
53
54    }

. 用到的工具类

1丶32位字符串

1public class uuidutil {
2
3    public static string get32uuid() {
4        string uuid = uuid.randomuuid().tostring().trim().replaceall("-", "");
5        return uuid;
6    }
7}

2丶获取用户的终端ip

 1/**
2 * ip地址
3 *
4 * @author hoje
5 */
6public class iputils {
7    private static logger logger = loggerfactory.getlogger(iputils.class);
8
9    /**
10     * 获取ip地址
11     *
12     * 使用nginx等反向代理软件, 则不能通过request.getremoteaddr()获取ip地址
13     * 如果使用了多级反向代理的话,x-forwarded-for的值并不止一个,而是一串ip地址,x-forwarded-for中第一个非unknown的有效ip字符串,则为真实ip地址
14     */
15    public static string getipaddr(httpservletrequest request) {
16        string ip = null;
17        try {
18            ip = request.getheader("x-forwarded-for");
19            if (stringutils.isempty(ip) || "unknown".equalsignorecase(ip)) {
20                ip = request.getheader("proxy-client-ip");
21            }
22            if (stringutils.isempty(ip) || ip.length() == 0 || "unknown".equalsignorecase(ip)) {
23                ip = request.getheader("wl-proxy-client-ip");
24            }
25            if (stringutils.isempty(ip) || "unknown".equalsignorecase(ip)) {
26                ip = request.getheader("http_client_ip");
27            }
28            if (stringutils.isempty(ip) || "unknown".equalsignorecase(ip)) {
29                ip = request.getheader("http_x_forwarded_for");
30            }
31            if (stringutils.isempty(ip) || "unknown".equalsignorecase(ip)) {
32                ip = request.getremoteaddr();
33            }
34        } catch (exception e) {
35            logger.error("iputils error ", e);
36        }
37
38        //使用代理,则获取第一个ip地址
39        if(stringutils.isempty(ip) && ip.length() > 15) {
40            if(ip.indexof(",") > 0) {
41                ip = ip.substring(0, ip.indexof(","));
42            }
43        }
44
45        return ip;
46    }
47
48}

3丶生成签名

 1/**
2     * 生成签名
3     * 这个方法是从微信sdk里copy过来的,自己也可以写,要注意生成签名后utf-8的转换,要不然容易报签名body utf-8错误
4     *
5     * @param data 待签名数据
6     * @param key  api密钥
7     * @param charset utf-8
8     */
9    public static string createsign(final map<string, string> data, string key, string charset) throws exception {
10        return createsign(data, key, wxpayconstants.signtype.md5, charset);
11    }
12
13    /**
14     * 生成签名. 注意,若含有sign_type字段,必须和signtype参数保持一致。
15     *
16     * @param data     待签名数据
17     * @param key      api密钥
18     * @param signtype 签名方式
19     * @param charset utf-8
20     * @return 签名
21     */
22    private static string createsign(final map<string, string> data, string key, wxpayconstants.signtype signtype, string charset) throws exception {
23        //根据规则创建可排序的map集合
24        set<string> keyset = data.keyset();
25        string[] keyarray = keyset.toarray(new string[keyset.size()]);
26        arrays.sort(keyarray);
27        stringbuilder sb = new stringbuilder();
28        for (string k : keyarray) {
29            if (k.equals(wxpayconstants.field_sign)) {
30                continue;
31            }
32            if (data.get(k).trim().length() > 0){
33                sb.append(k).append("=").append(data.get(k).trim()).append("&");
34            } // 参数值为空,则不参与签名
35        }
36        sb.append("key=").append(key);
37        //转换utf-8
38        string str = new string(sb.tostring().getbytes(charset));
39        if (wxpayconstants.signtype.md5.equals(signtype)) {
40            return md5(sb.tostring()).touppercase();
41        } else if (wxpayconstants.signtype.hmacsha256.equals(signtype)) {
42            return hmacsha256(sb.tostring(), key);
43        } else {
44            throw new exception(string.format("invalid sign_type: %s", signtype));
45        }
46    }
47}

4丶http请求的工具 实际没有用到很多方法有的是退款需要用到的

  1/**
2 * http请求工具
3 *
4 *
5 *
6 *
7 */
8public class httpsclientutil {
9    private static poolinghttpclientconnectionmanager connmgr;
10    private static requestconfig requestconfig;
11    private static final int max_timeout = 7000;
12
13    static {
14        // 设置连接池
15        connmgr = new poolinghttpclientconnectionmanager();
16        // 设置连接池大小
17        connmgr.setmaxtotal(100);
18        connmgr.setdefaultmaxperroute(connmgr.getmaxtotal());
19
20        requestconfig.builder configbuilder = requestconfig.custom();
21        // 设置连接超时
22        configbuilder.setconnecttimeout(max_timeout);
23        // 设置读取超时
24        configbuilder.setsockettimeout(max_timeout);
25        // 设置从连接池获取连接实例的超时
26        configbuilder.setconnectionrequesttimeout(max_timeout);
27        // 在提交请求之前 测试连接是否可用
28        configbuilder.setstaleconnectioncheckenabled(true);
29        requestconfig = configbuilder.build();
30    }
31
32    /**
33     * 发送 get 请求(http),不带输入数据
34     *
35     * @param url
36     * @return
37     */
38    public static string doget(string url) {
39        return doget(url, new hashmap<string, object>());
40    }
41
42    /**
43     * 发送 get 请求(http),k-v形式
44     *
45     * @param url
46     * @param params
47     * @return
48     */
49    public static string doget(string url, map<string, object> params) {
50        string apiurl = url;
51        stringbuffer param = new stringbuffer();
52        int i = 0;
53        for (string key : params.keyset()) {
54            if (i == 0)
55                param.append("?");
56            else
57                param.append("&");
58            param.append(key).append("=").append(params.get(key));
59            i++;
60        }
61        apiurl += param;
62        string result = null;
63        httpclient httpclient = new defaulthttpclient();
64        try {
65            httpget httppost = new httpget(apiurl);
66            httpresponse response = httpclient.execute(httppost);
67            int statuscode = response.getstatusline().getstatuscode();
68
69            system.out.println("执行状态码 : " + statuscode);
70
71            httpentity entity = response.getentity();
72            if (entity != null) {
73                inputstream instream = entity.getcontent();
74                result = ioutils.tostring(instream);
75            }
76        } catch (ioexception e) {
77            e.printstacktrace();
78        }
79        return result;
80    }
81
82    /**
83     * 发送 post 请求(http),不带输入数据
84     *
85     * @param apiurl
86     * @return
87     */
88    public static string dopost(string apiurl) {
89        return dopost(apiurl, new hashmap<string, object>());
90    }
91
92    /**
93     * 发送 post 请求(http),k-v形式
94     *
95     * @param apiurl api接口url
96     * @param params 参数map
97     * @return
98     */
99    public static string dopost(string apiurl, map<string, object> params) {
100        closeablehttpclient httpclient = httpclients.createdefault();
101        string httpstr = null;
102        httppost httppost = new httppost(apiurl);
103        closeablehttpresponse response = null;
104
105        try {
106            httppost.setconfig(requestconfig);
107            list<namevaluepair> pairlist = new arraylist<>(params.size());
108            for (map.entry<string, object> entry : params.entryset()) {
109                namevaluepair pair = new basicnamevaluepair(entry.getkey(), entry
110                        .getvalue().tostring());
111                pairlist.add(pair);
112            }
113            httppost.setentity(new urlencodedformentity(pairlist, charset.forname("utf-8")));
114            response = httpclient.execute(httppost);
115            system.out.println(response.tostring());
116            httpentity entity = response.getentity();
117            httpstr = entityutils.tostring(entity, "utf-8");
118        } catch (ioexception e) {
119            e.printstacktrace();
120        } finally {
121            if (response != null) {
122                try {
123                    entityutils.consume(response.getentity());
124                } catch (ioexception e) {
125                    e.printstacktrace();
126                }
127            }
128        }
129        return httpstr;
130    }
131
132    /**
133     * 发送 post 请求(http),json形式
134     *
135     * @param apiurl
136     * @param json   json对象
137     * @return
138     */
139    public static string dopost(string apiurl, object json) {
140        closeablehttpclient httpclient = httpclients.createdefault();
141        string httpstr = null;
142        httppost httppost = new httppost(apiurl);
143        closeablehttpresponse response = null;
144
145        try {
146            httppost.setconfig(requestconfig);
147            stringentity stringentity = new stringentity(json.tostring(), "utf-8");//解决中文乱码问题
148            stringentity.setcontentencoding("utf-8");
149            stringentity.setcontenttype("application/json");
150            httppost.setentity(stringentity);
151            response = httpclient.execute(httppost);
152            httpentity entity = response.getentity();
153            system.out.println(response.getstatusline().getstatuscode());
154            httpstr = entityutils.tostring(entity, "utf-8");
155        } catch (ioexception e) {
156            e.printstacktrace();
157        } finally {
158            if (response != null) {
159                try {
160                    entityutils.consume(response.getentity());
161                } catch (ioexception e) {
162                    e.printstacktrace();
163                }
164            }
165        }
166        return httpstr;
167    }
168
169    /**
170     * 发送 ssl post 请求(https),k-v形式
171     *
172     * @param apiurl api接口url
173     * @param params 参数map
174     * @return
175     */
176    public static string dopostssl(string apiurl, map<string, object> params) {
177        closeablehttpclient httpclient = httpclients.custom().setsslsocketfactory(createsslconnsocketfactory()).setconnectionmanager(connmgr).setdefaultrequestconfig(requestconfig).build();
178        httppost httppost = new httppost(apiurl);
179        closeablehttpresponse response = null;
180        string httpstr = null;
181
182        try {
183            httppost.setconfig(requestconfig);
184            list<namevaluepair> pairlist = new arraylist<namevaluepair>(params.size());
185            for (map.entry<string, object> entry : params.entryset()) {
186                namevaluepair pair = new basicnamevaluepair(entry.getkey(), entry
187                        .getvalue().tostring());
188                pairlist.add(pair);
189            }
190            httppost.setentity(new urlencodedformentity(pairlist, charset.forname("utf-8")));
191            response = httpclient.execute(httppost);
192            int statuscode = response.getstatusline().getstatuscode();
193            if (statuscode != httpstatus.sc_ok) {
194                return null;
195            }
196            httpentity entity = response.getentity();
197            if (entity == null) {
198                return null;
199            }
200            httpstr = entityutils.tostring(entity, "utf-8");
201        } catch (exception e) {
202            e.printstacktrace();
203        } finally {
204            if (response != null) {
205                try {
206                    entityutils.consume(response.getentity());
207                } catch (ioexception e) {
208                    e.printstacktrace();
209                }
210            }
211        }
212        return httpstr;
213    }
214
215    /**
216     * 发送 ssl post 请求(https),json形式
217     *
218     * @param apiurl api接口url
219     * @param json   json对象
220     * @return
221     */
222    public static string dopostssl(string apiurl, object json) {
223        closeablehttpclient httpclient = httpclients.custom().setsslsocketfactory(createsslconnsocketfactory()).setconnectionmanager(connmgr).setdefaultrequestconfig(requestconfig).build();
224        httppost httppost = new httppost(apiurl);
225        closeablehttpresponse response = null;
226        string httpstr = null;
227
228        try {
229            httppost.setconfig(requestconfig);
230            stringentity stringentity = new stringentity(json.tostring(), "utf-8");//解决中文乱码问题
231            stringentity.setcontentencoding("utf-8");
232            stringentity.setcontenttype("application/json");
233            httppost.setentity(stringentity);
234            response = httpclient.execute(httppost);
235            int statuscode = response.getstatusline().getstatuscode();
236            if (statuscode != httpstatus.sc_ok) {
237                return null;
238            }
239            httpentity entity = response.getentity();
240            if (entity == null) {
241                return null;
242            }
243            httpstr = entityutils.tostring(entity, "utf-8");
244        } catch (exception e) {
245            e.printstacktrace();
246        } finally {
247            if (response != null) {
248                try {
249                    entityutils.consume(response.getentity());
250                } catch (ioexception e) {
251                    e.printstacktrace();
252                }
253            }
254        }
255        return httpstr;
256    }
257
258    /**
259     * 创建ssl安全连接
260     *
261     * @return
262     */
263    private static sslconnectionsocketfactory createsslconnsocketfactory() {
264        sslconnectionsocketfactory sslsf = null;
265        try {
266            sslcontext sslcontext = new sslcontextbuilder().loadtrustmaterial(null, new truststrategy() {
267
268                public boolean istrusted(x509certificate[] chain, string authtype) throws certificateexception {
269                    return true;
270                }
271            }).build();
272            sslsf = new sslconnectionsocketfactory(sslcontext, new x509hostnameverifier() {
273
274                @override
275                public boolean verify(string arg0, sslsession arg1) {
276                    return true;
277                }
278
279                @override
280                public void verify(string host, sslsocket ssl) throws ioexception {
281                }
282
283                @override
284                public void verify(string host, x509certificate cert) throws sslexception {
285                }
286
287                @override
288                public void verify(string host, string[] cns, string[] subjectalts) throws sslexception {
289                }
290            });
291        } catch (generalsecurityexception e) {
292            e.printstacktrace();
293        }
294        return sslsf;
295    }

我这个人比较懒还有查询,退款,jsapi支付,h5支付慢慢更新总结.
今天就到这里了,拜拜

如对本文有疑问,请在下面进行留言讨论,广大热心网友会与你互动!! 点击进行留言回复

相关文章:

验证码:
移动技术网