课程目标掌握二维码生成插件qrious的使用能够说出微信支付开发的整体思路能够调用微信支付接口(统一下单)生成支付二维码能够调用微信支付接口(查询订单)查询支付状态实现支付日志的生成与订单状态的修改一.二维码1.1什么是二维码1.二维码又称QRCode,QR全称QuickResponse,是一个近几年来移动设备上超流行的一种编码方式,它比传统的BarCode条形码能存更多的信息,也能表示更多的数据类型。
2.二维条码/二维码(2-dimensionalbarcode)是用某种特定的几何图形按一定规律在平面(二维方向上)分布的黑白相间的图形记录数据符号信息的;在代码编制上巧妙地利用构成计算机内部逻辑基础的“0”、“1”比特流的概念,使用若干个与二进制相对应的几何形体来表示文字数值信息,通过图象输入设备或光电扫描设备自动识读以实现信息自动处理:它具有条码技术的一些共性:每种码制有其特定的字符集;每个字符占有一定的宽度;具有一定的校验功能等。同时还具有对不同行的信息自动识别功能、及处理图形旋转变化点。
3.图示:
1.2二维码的优势:信息容量大,可以容纳多达1850个大写字母或2710个数字或500多个汉字应用范围广,支持文字,声音,图片,指纹等等…容错能力强,即使图片出现部分破损也能使用成本低,容易制作1.3二维码的容错级别:L级(低)7%的码字可以被恢复。M级(中)的码字的15%可以被恢复。Q级(四分)的码字的25%可以被恢复。H级(高)的码字的30%可以被恢复。二.二维码生成插件qrious:2.1qrious是一款基于HTML5Canvas的纯JS二维码生成插件。通过qrious.js可以快速生成各种二维码,你可以控制二维码的尺寸颜色,还可以将生成的二维码进行Base64编码。2.2qrious.js二维码插件的可用配置参数如下:4.方块确定方位,黑色代表1,白色代表0
三.微信扫码支付3.1介绍:微信扫码支付是商户系统按微信支付协议生成支付二维码,用户再用微信“扫一扫”完成支付的模式。该模式适用于PC网站支付、实体店单品或订单支付、媒体广告支付等场景。3.2申请步骤:(了解)5.第一步:注册公众号(类型须为:服务号)请根据营业执照类型选择以下主体注册:个体工商户|企业/公司|政府|媒体|其他类型。
6.第二步:认证公众号公众号认证后才可申请微信支付,认证费:300元/次。
7.第三步:提交资料申请微信支付登录公众平台,点击左侧菜单【微信支付】,开始填写资料等待审核,审核时间为1-5个工作日内。
8.第四步:开户成功,登录商户平台进行验证资料审核通过后,请登录联系人邮箱查收商户号和密码,并登录商户平台填写财付通备付金打的小额资金数额,完成账户验证。
9.第五步:在线签署协议本协议为线上电子协议,签署后方可进行交易及资金结算,签署完立即生效。
四.微信支付SDK4.1微信支付接口调用的整体思路:按API要求组装参数,以XML方式发送(POST)给微信支付接口(URL),微信支付接口也是以XML方式给予响应。程序根据返回的结果(其中包括支付URL)生成二维码或判断订单状态简单来讲:通过URL将一些参数告诉给微信,然后接受返回值生成二维码4.2释义:appid:微信公众账号或开放平台APP的唯一标识mch_id:商户号(配置文件中的partner)partnerkey:商户密钥sign:数字签名,根据微信官方提供的密钥和一套算法生成的一个加密信息,就是为了保证交易的安全性【每次都不同】4.3微信支付SDK微信支付提供了SDK,下载后打开源码,install到本地仓库;导入依赖:dependencygroupIdcom.github.wxpay/groupIdartifactIdwxpay-sdk/artifactIdversion0.0.3/version/dependency4.4我们主要会用到微信支付SDK的以下功能:10.获取随机字符串WXPayUtil.generateNonceStr()
11.MAP转换为XML字符串(自动添加签名)WXPayUtil.generateSignedXml(param,partnerkey)
12.XML字符串转换为MAPWXPayUtil.xmlToMap(result)
4.5HttpClient工具类13.介绍:
HttpClient是ApacheJakartaCommon下的子项目,用来提供高效的、最新的、功能丰富的支持HTTP协议的客户端编程工具包,并且它支持HTTP协议最新的版本和建议。HttpClient已经应用在很多的项目中,比如ApacheJakarta上很著名的另外两个开源项目Cactus和HTMLUnit都使用了HttpClient。HttpClient通俗的讲就是模拟了浏览器的行为,如果我们需要在后端向某一地址提交数据获取结果,就可以使用HttpClient.关于HttpClient(原生)具体的使用不属于我们本章的学习内容,我们这里这里为了简化HttpClient的使用,提供了工具类HttpClient(对原生HttpClient进行了封装)14.HttpClient工具类使用的步骤:
HttpClientclientnewHttpClient(请求的url地址);client.setHttps(true);//是否是https协议client.setXmlParam(xmlParam);//发送的xml数据client.post();//执行post请求Stringresultclient.getContent();//获取结果五.查询状态5.1思路:前端循环调用后端后端循环调用微信支付查询结果,前端调用后端5.2交易状态类型:SUCCESS:支付成功REFUND:转入退款NOTPAY:未支付CLOSED:已关闭REVOKED:已撤销USERPAYING:用户支付中PAYERROR:支付失败(其他原因,银行返回失败)支付状态机等可以查看相关文档六.支付日志需求6.1思路:15.在用户下订单时,判断如果为微信支付,就向支付日志表添加一条记录,信息包括支付总金额,订单id(多个),用户id,下单时间等信息,支付状态为0(未支付);
16.生成的支付日志对象放入reids中,以用户id作为key,这样在生成支付二维码时就可以从redis中提取支付日志对象中的金额和订单号;
17.当用户支付成功后,修改支付日志的支付状态为1(已支付),并记录微信传递给我们的交易流水号。根据订单id(多个)修改订单的状态为2(已付款).
七.微信支付准备:7.1业务流程:选择商品以及相应的规格和数量后点击"加入购物车"。当加入购物车后跳转到购物车列表页面,对收货地址,商品添加或者删除等操作后点击"结算"当带着参数进入结算页的时候,首先对使用微信支付和货到付款等方式进行判断,然后跳转到相应的页面页面通过与微信官方交互然后自动生成二维码,用户扫码之后显示"付款成功"或者"付款失败"等.7.2技术分析[准备阶段]:微信支付功能必须为服务号才能申请微信付款功能,这个由公司完成并提供给我们相关的账户和密码;查看微信支付SDK文档,获取大概的流程;首先应该在本地仓库中配好微信支付SDK的jar包,并引入微信支付SDK的依赖使用HttpClient工具类,方便向微信官方发送请求和接收请求;搭建工程,分为消费方和服务方,消费方应该直接放入用户加入购物车的消费项目里,服务方加入服务方,服务方分成interface和service解耦合;应该引入HttpClient.java工具类和添加依赖,添加properties配置文件[这里的配置文件应该为商户的信息,如appid,partner,partnerkey…等]八.支付流程图九.流程及代码9.1首先生成微信二维码:18.准备:
通过HttpClient工具类实现对远程支付接口的调用接口连接:https://api.mch.weixin.qq.com/pay/unifiedorder参考文档:统一下单API19.开始:
interface:接口服务层应该建立一个生成微信二维码的接口serviceimpl:注入properties中的配置文件,创建一个生成二维码的方法createNative创建一个map集合,将需要发送给微信的数据存入map集合内通过WXPayUtil工具类将集合内的数据转为XML格式数据通过HttpClient发送给微信获取XML结果后调用WXPayUtil工具类将它转为Map格式的数据创建一个新的Map集合,将获取的结果存入新建的map集合内【这里的数据是要展现给前端的,所以只存一些需要展示的,不必所有都存入,否则安全性有影响】将集合返回20.Controller:
21.通过@Reference注解注入Service的类:WeixinPayService
22.建立一个生成微信二维码的方法,调用雪花算法将订单号和支付类型作为方法参数调用Serivec的createNative,将得到的map集合返回上去;
23.payService.js:建立一个本地支付的方法,指向pay/createNative.do[Controller.java类的生成二维码方法]
24.payController.js:建立一个本地生成二维码的方法,前端页面调用此方法进行查询后端,获取结果后得到订单编号和金额大小,同时在这里生成二维码,将订单编号和金额大小都返回到前端页面;
25.pay.html:
26.首先引入js相关文件,qrious.min.js创建二维码的js文件,以及绑定ng-app,ng-controller,初始调用ng-init生成二维码功能将放置二维码图片的地方显示订单:订单号:{{out_trade_no}}显示金额:¥{{money}}元
9.2然后,检测支付状态:27.准备:
需求:当用户支付成功的时候我们应该跳转到成功页面,提示:恭喜您,付款成功啦!,支付方式:微信支付支付金额:xxxx元当用户支付失败的时候我们应该跳转到失败页面,提示:支付失败,请稍后再试!失败原因:…提供一个重新支付按钮以及跳转到品优购首页的功能28.实现思路:
我们可以通过HttpClient工具类实现对远程支付接口的调用微信接口链接:https://api.mch.weixin.qq.com/pay/orderquery参考文档:查询订单API思路:我们可以在后端建立查询状态方法,方法内通过循环查询,如果获取到结果则进行判断:如果结果为Null,则返回空map集合,如果有值,则返回给controller,再返回给前端前端进行循环调用查询状态方法。前端controller.js对返回的结果进行判断:如果mapnull,则提示支付出错,跳出循环判断,如果map.get(“trade_state”).equals(“SUCCESS”),那么则返回支付成功,同时程序可以使用Thread进行睡眠,Thread.sleep(3000),此方法可以使循环查询每三秒执行一次29.开始:
interface:创建查询状态方法,接收参数订单编号serviceImpl:实现查询状态方法,新建一个HashMap,然后存入公众号id,商户号id,订单号,随机字符串,以及查询订单状态的url地址;【URL地址是微信提供的,其他通过配置文件注入和参数接收】通过WXPayUtil将Map集合转为XML格式的字符串,然后通过HttpClient传入url地址发送获取状态;接收状态并将其转为Map集合,然后返回结果,如果获取失败则打印异常;30.controller:
创建queryPayStatus1.先定义一个实体类Resultresutlnull;2.循环调用Service层的查询订单状态方法并获取返回值;3.对返回值进行判断,如果null,则result:false,出错4.如果map.get(“trade_state”).equals(“SUCCESS”),则result:true,“支付成功”5.线程等待每3秒执行一次31.payService.js:
创建查询状态方法并指向查询状态的地址和方法,传给它订单编号;32.payController.js:
33.controller.js中创建查询状态方法,方法中对返回结果进行判断,-如果返回结果为true,则跳转到支付成功页面-如果返回结果为false,则跳转到失败页面
34.将该方法在createNative生成二维码的时候进行调用,这样在二维码生成的时候就完成了查询订单状态的功能;因为二维码是初始化init就进行调用,所以生成二维码开始起就可以对二维码状态进行查询;
9.3再然后,我们需要加一个查询时间限制准备:需求:35.如果用户到了二维码页面一直未支付,或是关掉了支付页面,我们的代码会一直循环调用微信接口,这样会对程序造成很大的压力。所以我们要加一个时间限制或是循环次数限制,当超过时间或次数时,跳出循环。
实现思路:36.可以在Contrller.java中的查询状态方法内定义一个计时器,intx0;然后再while(true){}循环查询状态的时候每次x++;如果x100时[可以自定义时间],然后resultnewResult(false,“二维码超时”);
37.在前端中payController.js中再添加一个判断,如果成功则跳转,如果失败则进行判断,如果返回的结果是二维码超时,则重新生成二维码,否则就跳转到失败页面;
38.、
9.4再然后,支付成功页面我们应该显示金额准备:需求:现在我们支付成功页面显示的是固定的值,怎么显示真正的支付金额呢?我们这里可以使用angularJS的页面传参来解决实现思路:payController.js中的查询支付状态方法内,如果返回的result是true,支付成功,那么我们在跳转到支付成功页面的时候应该传入参数:$scope.money[付款金额]开始:payController.js:-跳转页面传参,当支付成功后跳转到成功页面的时候传入付款金额*if(response.success){location.href"paysuccess.html#?money"+$scope.money;}-引入$location服务,新增获取金额的方法;return$location.search()['money'];paysuccess.html:-引入相关的js,并在body添加指令:ng-app,ng-controller-用表达式显示金额:39.支付金额:¥{{getMoney()}}元
9.5最后,我们应该添加一个支付日志的功能40.准备:
需求:-系统中无法查询到支付记录-支付后订单状态没有改变实现思路:在用户下订单时,判断如果为微信支付,就想支付日志表添加一条记录,信息包括支付总金额、订单ID(多个)、用户ID、下单时间等信息,支付状态为0(未支付)生成的支付日志对象放入redis中,以用户ID作为key,这样在生成支付二维码时就可以从redis中提取支付日志对象中的金额和订单号。当用户支付成功后,修改支付日志的支付状态为1(已支付),并记录微信传递给我们的交易流水号。根据订单ID(多个)修改订单的状态为2(已付款)。分析表结构:根据需求我们应该独立建立一个订单支付日志表,它应该包含:支付订单号,创建事件,支付完成时间,支付金额,交易流水,交易状态,支付类型,订单表id串41.具体思路[解决系统中无法查询到支付记录]:
interface:*首先我们在接口中创建一个通过用户id查询redis中订单的办法。service:然后在实现类中的生成二维码方法[createNative]中先获取当前用户,通过当前用户userid查询redis返回一个payLog日志对象,然后对其进行判断如果该日志不存在则返回一个newHashMap();【即这个值为null】如果该日志存在,则将日志中的订单编号和商品金额作为参数调用weixinPayService.createNative(…)返回;42.具体思路[解决支付后订单状态没有改变]
43.interface:
创建一个修改订单状态的方法,并传入订单编号,和交易号的的方法;44.serviceimpl:
45.首先要明确做的三件事情:
修改支付日志状态修改关联的订单的状态清除缓存中的支付日志对象46.实现接口新建的修改订单状态方法updateOrderStatus(Stringout_trade_no,Stringtransaction_id):
通过日志操作类通过订单编号查询到payLog对象,然后修改payLog对象内的属性,如交易状态,交易号等通过日志类payLog.getOrderList()获取订单号列表然后查询到orderList值,orderList的值为"xxx,xxx,xxx",我们可以通过spilt(",")方法获取到订单号数组。遍历订单编号,通过订单操作类orderMapper.selectByPrimaryKey方法查询id值获得订单,如果订单存在则修改状态,并orderMapper.updateByPrimaryKey(order)覆盖订单;通过redisTemplate查找"payLog".delete删除日志id;47.PayController.java:
在微信支付接口有成功返回状态时,调用修改状态的方法if(map.get("trade_state").equals("SUCCESS")){//如果成功resultnewResult(true,"支付成功");//修改订单状态orderService.updateOrderStatus(out_trade_no,map.get("transaction_id"));break;}十.interface:10.1pom.xml:?xmlversion"1.0"encoding"UTF-8"?projectxmlns"http://maven.apache.org/POM/4.0.0"xmlns:xsi"http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation"http://maven.apache.org/POM/4.0.0http://maven.apache.org/xsd/maven-4.0.0.xsd"parentartifactIdpinyougou-parent/artifactIdgroupIdcom.pinyougou/groupIdversion1.0-SNAPSHOT/version/parentmodelVersion4.0.0/modelVersionpackagingjar/packagingartifactIdpinyougou-pay-interface/artifactId/project10.2WeixinPayService.java[接口]packagecom.pinyougou.pay.service;importjava.util.Map;publicinterfaceWeixinPayService{/***生成二维码**/publicMapcreateNative(Stringout_trade_no,Stringtotal_fee);/***查询支付订单状态**/publicMapqueryPayStatus(Stringout_trade_no);}10.3serviceImpl1.pom.xml?xmlversion"1.0"encoding"UTF-8"?projectxmlns"http://maven.apache.org/POM/4.0.0"xmlns:xsi"http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation"http://maven.apache.org/POM/4.0.0http://maven.apache.org/xsd/maven-4.0.0.xsd"parentartifactIdpinyougou-parent/artifactIdgroupIdcom.pinyougou/groupIdversion1.0-SNAPSHOT/version/parentmodelVersion4.0.0/modelVersionpackagingwar/packagingartifactIdpinyougou-pay-service/artifactIdpropertiesproject.build.sourceEncodingUTF-8/project.build.sourceEncodingmaven.compiler.source1.7/maven.compiler.sourcemaven.compiler.target1.7/maven.compiler.target/propertiesdependencies!--Spring--dependencygroupIdorg.springframework/groupIdartifactIdspring-context/artifactId/dependencydependencygroupIdorg.springframework/groupIdartifactIdspring-beans/artifactId/dependencydependencygroupIdorg.springframework/groupIdartifactIdspring-webmvc/artifactId/dependencydependencygroupIdorg.springframework/groupIdartifactIdspring-jdbc/artifactId/dependencydependencygroupIdorg.springframework/groupIdartifactIdspring-aspects/artifactId/dependencydependencygroupIdorg.springframework/groupIdartifactIdspring-jms/artifactId/dependencydependencygroupIdorg.springframework/groupIdartifactIdspring-context-support/artifactId/dependencydependencygroupIdorg.springframework/groupIdartifactIdspring-test/artifactId/dependency!--dubbo相关--dependencygroupIdcom.alibaba/groupIdartifactIddubbo/artifactId/dependencydependencygroupIdorg.apache.zookeeper/groupIdartifactIdzookeeper/artifactId/dependencydependencygroupIdcom.github.sgroschupf/groupIdartifactIdzkclient/artifactId/dependencydependencygroupIdjunit/groupIdartifactIdjunit/artifactId/dependencydependencygroupIdcom.alibaba/groupIdartifactIdfastjson/artifactId/dependencydependencygroupIdjavassist/groupIdartifactIdjavassist/artifactId/dependencydependencygroupIdcommons-codec/groupIdartifactIdcommons-codec/artifactId/dependencydependencygroupIdjavax.servlet/groupIdartifactIdservlet-api/artifactIdscopeprovided/scope/dependencydependencygroupIdcom.pinyougou/groupIdartifactIdpinyougou-pay-interface/artifactIdversion1.0-SNAPSHOT/version/dependencydependencygroupIdcom.pinyougou/groupIdartifactIdpinyougou-common/artifactIdversion1.0-SNAPSHOT/version/dependencydependencygroupIdcom.github.wxpay/groupIdartifactIdwxpay-sdk/artifactIdversion0.0.3/version/dependency/dependenciesbuildpluginsplugingroupIdorg.apache.tomcat.maven/groupIdartifactIdtomcat7-maven-plugin/artifactIdversion2.2/versionconfiguration!--指定端口--port9000/port!--请求路径--path//path/configuration/plugin/plugins/build/project10.4WeinxinPayServiceImpl.java:packagecom.pinyougou.pay.service.impl;importcom.alibaba.dubbo.config.annotation.Service;importcom.github.wxpay.sdk.WXPayUtil;importcom.pinyougou.pay.service.WeixinPayService;importorg.springframework.beans.factory.annotation.Value;importutil.HttpClient;importjava.util.HashMap;importjava.util.Map;/***WeixinPayServiceImpl*hasee*2018/12/14*15:13**@Version1.0**/@ServicepublicclassWeixinPayServiceImplimplementsWeixinPayService{@Value("${appid}")privateStringappid;@Value("${partner}")privateStringpartner;@Value("${partnerkey}")privateStringpartnerkey;@OverridepublicMapcreateNative(Stringout_trade_no,Stringtotal_fee){//1.参数封装MapparamnewHashMap();param.put("appid",appid);//公众号idparam.put("mch_id",partner);//商户key值param.put("nonce_str",WXPayUtil.generateNonceStr());//商户密码,随机字符串param.put("body","品优购");//主体param.put("out_trade_no",out_trade_no);//交易订单param.put("total_fee",total_fee);//金额(分)param.put("spbill_create_ip","127.0.0.1");//终端ipparam.put("notify_url","http://www.itcast.cn");//回调地址param.put("trade_type","NATIVE");//交易类型try{StringxmlParamWXPayUtil.generateSignedXml(param,partnerkey);System.out.println("请求的参数:"+xmlParam);//2.发送请求HttpClienthttpClientnewHttpClient("https://api.mch.weixin.qq.com/pay/unifiedorder");httpClient.setHttps(true);httpClient.setXmlParam(xmlParam);httpClient.post();//获取结果StringxmlResulthttpClient.getContent();MapString,StringmapResultWXPayUtil.xmlToMap(xmlResult);System.out.println("接收到的结果"+mapResult);MapmapnewHashMap();map.put("code_url",mapResult.get("code_url"));//生成支付二维码连接map.put("out_trade_no",mapResult.get("out_trade_no"));map.put("total_fee",mapResult.get("total_fee"));returnmap;}catch(Exceptione){e.printStackTrace();returnnewHashMap();}}@OverridepublicMapqueryPayStatus(Stringout_trade_no){//1.封装参数MapparamnewHashMap();param.put("appid",appid);param.put("mch_id",partner);param.put("out_trade_no",out_trade_no);param.put("nonce_str",WXPayUtil.generateNonceStr());try{StringxmlParamWXPayUtil.generateSignedXml(param,partnerkey);//2.发送请求HttpClienthttpClientnewHttpClient("https://api.mch.weixin.qq.com/pay/orderquery");httpClient.setHttps(true);httpClient.setXmlParam(xmlParam);httpClient.post();//3.获取结果StringxmlResulthttpClient.getContent();MapString,StringmapWXPayUtil.xmlToMap(xmlResult);returnmap;}catch(Exceptione){e.printStackTrace();returnnewHashMap();}}}10.5resources/sping/applicationContext-service.xml?xmlversion"1.0"encoding"UTF-8"?beansxmlns"http://www.springframework.org/schema/beans"xmlns:xsi"http://www.w3.org/2001/XMLSchema-instance"xmlns:p"http://www.springframework.org/schema/p"xmlns:context"http://www.springframework.org/schema/context"xmlns:dubbo"http://code.alibabatech.com/schema/dubbo"xmlns:mvc"http://www.springframework.org/schema/mvc"xsi:schemaLocation"http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/mvchttp://www.springframework.org/schema/mvc/spring-mvc.xsdhttp://code.alibabatech.com/schema/dubbohttp://code.alibabatech.com/schema/dubbo/dubbo.xsdhttp://www.springframework.org/schema/contexthttp://www.springframework.org/schema/context/spring-context.xsd"dubbo:protocolname"dubbo"port"20880"/dubbo:protocoldubbo:applicationname"pinyougou-pay-service"/dubbo:registryaddress"zookeeper://192.168.25.128:2181"/dubbo:annotationpackage"com.pinyougou.pay.service.impl"//beans10.6webapp/WEB-INF/web.xml:?xmlversion"1.0"encoding"UTF-8"?web-appxmlns:xsi"http://www.w3.org/2001/XMLSchema-instance"xmlns"http://java.sun.com/xml/ns/javaee"xsi:schemaLocation"http://java.sun.com/xml/ns/javaeehttp://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"version"2.5"!--加载spring容器--context-paramparam-namecontextConfigLocation/param-nameparam-valueclasspath*:spring/applicationContext*.xml/param-value/context-paramlistenerlistener-classorg.springframework.web.context.ContextLoaderListener/listener-class/listener/web-app十一.Controller:11.1controller:packagecom.pinyougou.cart.controller;importcom.alibaba.dubbo.config.annotation.Reference;importcom.pinyougou.order.service.OrderService;importcom.pinyougou.pay.service.WeixinPayService;importcom.pinyougou.pojo.TbPayLog;importentity.Result;importorg.springframework.security.core.context.SecurityContextHolder;importorg.springframework.web.bind.annotation.RequestMapping;importorg.springframework.web.bind.annotation.RestController;importjava.util.HashMap;importjava.util.Map;/***PayController*hasee*2018/12/14*15:55**@Version1.0**/@RestController@RequestMapping("/pay")publicclassPayController{@ReferenceprivateWeixinPayServiceweixinPayService;@ReferenceprivateOrderServiceorderService;@RequestMapping("/createNative")publicMapcreateNative(){//获取当前登录用户StringusernameSecurityContextHolder.getContext().getAuthentication().getName();//从日志中提取缓存TbPayLogpayLogorderService.searchPayLogFromRedis(username);//调用微信支付接口if(payLog!null){returnweixinPayService.createNative(payLog.getOutTradeNo(),payLog.getTotalFee()+"");}else{returnnewHashMap();}}@RequestMapping("/queryPayStatus")publicResultqueryPayStatus(Stringout_trade_no){Resultresultnull;intx0;while(true){MapString,StringmapweixinPayService.queryPayStatus(out_trade_no);//调用查询if(mapnull){resultnewResult(false,"支付发生错误!");break;}if(map.get("trade_state").equals("SUCCESS")){resultnewResult(true,"支付成功");orderService.updateOrderStatus(out_trade_no,map.get("transaction_id"));//修改订单状态break;}try{Thread.sleep(3000);}catch(InterruptedExceptione){e.printStackTrace();}x++;//平时x100[三秒执行一次,每分钟执行20次,五分钟执行100次,大概5分钟左右二维码超时],这里方便测试我们可以直接大于4if(x4){resultnewResult(false,"二维码超时");break;}}returnresult;}}11.2pom.xml:?xmlversion"1.0"encoding"UTF-8"?projectxmlns"http://maven.apache.org/POM/4.0.0"xmlns:xsi"http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation"http://maven.apache.org/POM/4.0.0http://maven.apache.org/xsd/maven-4.0.0.xsd"parentartifactIdpinyougou-parent/artifactIdgroupIdcom.pinyougou/groupIdversion1.0-SNAPSHOT/version/parentmodelVersion4.0.0/modelVersionpackagingwar/packagingartifactIdpinyougou-cart-web/artifactIddependencies!--Spring--dependencygroupIdorg.springframework/groupIdartifactIdspring-context/artifactId/dependencydependencygroupIdorg.springframework/groupIdartifactIdspring-beans/artifactId/dependencydependencygroupIdorg.springframework/groupIdartifactIdspring-webmvc/artifactId/dependencydependencygroupIdorg.springframework/groupIdartifactIdspring-jdbc/artifactId/dependencydependencygroupIdorg.springframework/groupIdartifactIdspring-aspects/artifactId/dependencydependencygroupIdorg.springframework/groupIdartifactIdspring-jms/artifactId/dependencydependencygroupIdorg.springframework/groupIdartifactIdspring-context-support/artifactId/dependencydependencygroupIdorg.springframework/groupIdartifactIdspring-test/artifactId/dependency!--dubbo相关--dependencygroupIdcom.alibaba/groupIdartifactIddubbo/artifactId/dependencydependencygroupIdorg.apache.zookeeper/groupIdartifactIdzookeeper/artifactId/dependencydependencygroupIdcom.github.sgroschupf/groupIdartifactIdzkclient/artifactId/dependencydependencygroupIdjunit/groupIdartifactIdjunit/artifactId/dependencydependencygroupIdcom.alibaba/groupIdartifactIdfastjson/artifactId/dependencydependencygroupIdjavassist/groupIdartifactIdjavassist/artifactId/dependencydependencygroupIdcommons-codec/groupIdartifactIdcommons-codec/artifactId/dependencydependencygroupIdjavax.servlet/groupIdartifactIdservlet-api/artifactIdscopeprovided/scope/dependencydependencygroupIdorg.springframework.security/groupIdartifactIdspring-security-web/artifactIdversion4.1.0.RELEASE/version/dependencydependencygroupIdorg.springframework.security/groupIdartifactIdspring-security-config/artifactIdversion4.1.0.RELEASE/version/dependencydependencygroupIdorg.springframework.security/groupIdartifactIdspring-security-cas/artifactIdversion4.1.0.RELEASE/version/dependencydependencygroupIdorg.jasig.cas.client/groupIdartifactIdcas-client-core/artifactIdversion3.3.3/versionexclusionsexclusiongroupIdorg.slf4j/groupIdartifactIdlog4j-over-slf4j/artifactId/exclusion/exclusions/dependencydependencygroupIdcom.pinyougou/groupIdartifactIdpinyougou-common/artifactIdversion1.0-SNAPSHOT/version/dependencydependencygroupIdcom.pinyougou/groupIdartifactIdpinyougou-cart-interface/artifactIdversion1.0-SNAPSHOT/version/dependencydependencygroupIdcom.pinyougou/groupIdartifactIdpinyougou-user-interface/artifactIdversion1.0-SNAPSHOT/version/dependencydependencygroupIdcom.pinyougou/groupIdartifactIdpinyougou-order-interface/artifactIdversion1.0-SNAPSHOT/version/dependencydependencygroupIdcom.pinyougou/groupIdartifactIdpinyougou-pay-interface/artifactIdversion1.0-SNAPSHOT/version/dependency/dependenciesbuildpluginsplugingroupIdorg.apache.tomcat.maven/groupIdartifactIdtomcat7-maven-plugin/artifactIdversion2.2/versionconfiguration!--指定端口--port9107/port!--请求路径--path//path/configuration/plugin/plugins/build/project11.3resources/sping/spring-security.xml?xmlversion"1.0"encoding"UTF-8"?beans:beansxmlns"http://www.springframework.org/schema/security"xmlns:beans"http://www.springframework.org/schema/beans"xmlns:xsi"http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation"http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/securityhttp://www.springframework.org/schema/security/spring-security.xsd"httppattern"/css/**"security"none"/httphttppattern"/img/**"security"none"/httphttppattern"/js/**"security"none"/httphttppattern"/plugins/**"security"none"/httphttppattern"/cart.html"security"none"/http!--entry-point-ref入口点引用--!--登录不在自己本身的系统中进行登录,所以需要设置入口点--httpuse-expressions"false"entry-point-ref"casProcessingFilterEntryPoint"!--匿名角色IS_AUTHENTICATED_ANONYMOUSLY--!--如果用户登录了,则显示登录名,如果未登录则登录名:anonymousUser,必须要放在ROLE_USER前面--intercept-urlpattern"/cart/*.do"access"IS_AUTHENTICATED_ANONYMOUSLY"/intercept-urlintercept-urlpattern"/**"access"ROLE_USER"/csrfdisabled"true"/!--custom-filter为过滤器,position表示将过滤器放在指定的位置上,before表示放在指定位置之前,after表示放在指定的位置之后--custom-filterref"casAuthenticationFilter"position"CAS_FILTER"/custom-filterref"requestSingleLogoutFilter"before"LOGOUT_FILTER"/custom-filterref"singleLogoutFilter"before"CAS_FILTER"//http!--CAS只是单点登录的一种解决方案,所以这里不一定一定要接入CAS,也可以接入其他的;--!--CAS入口点开始--beans:beanid"casProcessingFilterEntryPoint"class"org.springframework.security.cas.web.CasAuthenticationEntryPoint"!--单点登录服务器登录URL--beans:propertyname"loginUrl"value"http://localhost:9100/cas/login"/beans:propertyname"serviceProperties"ref"serviceProperties"//beans:beanbeans:beanid"serviceProperties"class"org.springframework.security.cas.ServiceProperties"!--service配置自身工程的根地址+/login/cas--beans:propertyname"service"value"http://localhost:9107/login/cas"//beans:bean!--CAS入口点结束--!--认证过滤器开始--beans:beanid"casAuthenticationFilter"class"org.springframework.security.cas.web.CasAuthenticationFilter"beans:propertyname"authenticationManager"ref"authenticationManager"//beans:bean!--认证管理器--authentication-manageralias"authenticationManager"authentication-providerref"casAuthenticationProvider"/authentication-provider/authentication-manager!--认证提供者--beans:beanid"casAuthenticationProvider"class"org.springframework.security.cas.authentication.CasAuthenticationProvider"beans:propertyname"authenticationUserDetailsService"beans:beanclass"org.springframework.security.core.userdetails.UserDetailsByNameServiceWrapper"beans:constructor-argref"userDetailsService"//beans:bean/beans:propertybeans:propertyname"serviceProperties"ref"serviceProperties"/!--ticketValidator为票据验证器--beans:propertyname"ticketValidator"beans:beanclass"org.jasig.cas.client.validation.Cas20ServiceTicketValidator"beans:constructor-argindex"0"value"http://localhost:9100/cas"//beans:bean/beans:propertybeans:propertyname"key"value"an_id_for_this_auth_provider_only"//beans:bean!--认证类--beans:beanid"userDetailsService"class"com.pinyougou.user.service.UserDetailServiceImpl"/!--认证过滤器结束--!--单点登出开始--beans:beanid"singleLogoutFilter"class"org.jasig.cas.client.session.SingleSignOutFilter"/!--经过此配置,当用户在地址栏输入本地工程/logout/cas--beans:beanid"requestSingleLogoutFilter"class"org.springframework.security.web.authentication.logout.LogoutFilter"beans:constructor-argvalue"http://localhost:9100/cas/logout?servicehttp://localhost:9103"/beans:constructor-argbeans:beanclass"org.springframework.security.web.authentication.logout.SecurityContextLogoutHandler"//beans:constructor-argbeans:propertyname"filterProcessesUrl"value"/logout/cas"//beans:bean!--单点登出结束--/beans:beans11.4resources/springmvc.xml?xmlversion"1.0"encoding"UTF-8"?beansxmlns"http://www.springframework.org/schema/beans"xmlns:xsi"http://www.w3.org/2001/XMLSchema-instance"xmlns:p"http://www.springframework.org/schema/p"xmlns:context"http://www.springframework.org/schema/context"xmlns:dubbo"http://code.alibabatech.com/schema/dubbo"xmlns:mvc"http://www.springframework.org/schema/mvc"xsi:schemaLocation"http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/mvchttp://www.springframework.org/schema/mvc/spring-mvc.xsdhttp://code.alibabatech.com/schema/dubbohttp://code.alibabatech.com/schema/dubbo/dubbo.xsdhttp://www.springframework.org/schema/contexthttp://www.springframework.org/schema/context/spring-context.xsd"context:property-placeholderlocation"classpath:config/application.properties"/mvc:annotation-drivenmvc:message-convertersregister-defaults"true"beanclass"com.alibaba.fastjson.support.spring.FastJsonHttpMessageConverter"propertyname"supportedMediaTypes"value"application/json"/propertyname"features"arrayvalueWriteMapNullValue/valuevalueWriteDateUseDateFormat/value/array/property/bean/mvc:message-converters/mvc:annotation-driven!--引用dubbo服务--dubbo:applicationname"pinyougou-cart-web"/dubbo:registryaddress"zookeeper://192.168.25.128:2181"/dubbo:annotationpackage"com.pinyougou.cart.controller"//beans11.5js/controller.jsapp.controller('payController',function($scope,$location,payService){$scope.createNativefunction(){payService.createNative().success(function(response){//显示订单号和金额//toFixed是保留两位小数,total_fee单位是分除以100变为元$scope.money(response.total_fee/100).toFixed(2);$scope.out_trade_noresponse.out_trade_no;//生成二维码varqrnewQRious({element:document.getElementById('qrious'),size:250,value:response.code_url,level:'H'});queryPayStatus();//调用查询})};//调用查询queryPayStatusfunction(){payService.queryPayStatus($scope.out_trade_no).success(function(response){if(response.success){location.href"paysuccess.html#?money"+$scope.money;}else{if(response.message'二维码超时'){//这里调用重新生成二维码功能,当关闭浏览器,后端循环遍历查询订单状态即停止,如果不关闭浏览器和本支付页面的话,就可以实现每隔几秒重新生成一次二维码功能;$scope.createNative();//重新生成二维码}else{location.href"payfail.html";}}})}//获取金额$scope.getMoneyfunction(){return$location.search()['money'];}});11.6js/base.js:varappangular.module('pinyougou',[]);11.7js/service.js:app.controller('payController',function($scope,$location,payService){$scope.createNativefunction(){payService.createNative().success(function(response){//显示订单号和金额//toFixed是保留两位小数,total_fee单位是分除以100变为元$scope.money(response.total_fee/100).toFixed(2);$scope.out_trade_noresponse.out_trade_no;//生成二维码varqrnewQRious({element:document.getElementById('qrious'),size:250,value:response.code_url,level:'H'});queryPayStatus();//调用查询})};//调用查询queryPayStatusfunction(){payService.queryPayStatus($scope.out_trade_no).success(function(response){if(response.success){location.href"paysuccess.html#?money"+$scope.money;}else{if(response.message'二维码超时'){//这里调用重新生成二维码功能,当关闭浏览器,后端循环遍历查询订单状态即停止,如果不关闭浏览器和本支付页面的话,就可以实现每隔几秒重新生成一次二维码功能;$scope.createNative();//重新生成二维码}else{location.href"payfail.html";}}})}//获取金额$scope.getMoneyfunction(){return$location.search()['money'];}});~~~java###11.8webapp/WEB-INF/web.xml~~~java?xmlversion"1.0"encoding"UTF-8"?web-appxmlns:xsi"http://www.w3.org/2001/XMLSchema-instance"xmlns"http://java.sun.com/xml/ns/javaee"xsi:schemaLocation"http://java.sun.com/xml/ns/javaeehttp://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"version"2.5"!--解决post乱码--filterfilter-nameCharacterEncodingFilter/filter-namefilter-classorg.springframework.web.filter.CharacterEncodingFilter/filter-classinit-paramparam-nameencoding/param-nameparam-valueutf-8/param-value/init-paraminit-paramparam-nameforceEncoding/param-nameparam-valuetrue/param-value/init-param/filterfilter-mappingfilter-nameCharacterEncodingFilter/filter-nameurl-pattern/*/url-pattern/filter-mappingcontext-paramparam-namecontextConfigLocation/param-nameparam-valueclasspath:spring/spring-security.xml/param-value/context-paramlistenerlistener-classorg.springframework.web.context.ContextLoaderListener/listener-class/listenerfilterfilter-namespringSecurityFilterChain/filter-namefilter-classorg.springframework.web.filter.DelegatingFilterProxy/filter-class/filterfilter-mappingfilter-namespringSecurityFilterChain/filter-nameurl-pattern/*/url-pattern/filter-mappingservletservlet-namespringmvc/servlet-nameservlet-classorg.springframework.web.servlet.DispatcherServlet/servlet-class!--指定加载的配置文件,通过参数contextConfigLocation加载--init-paramparam-namecontextConfigLocation/param-nameparam-valueclasspath:spring/springmvc.xml/param-value/init-param/servletservlet-mappingservlet-namespringmvc/servlet-nameurl-pattern*.do/url-pattern/servlet-mappingwelcome-file-listwelcome-filecart.html/welcome-file/welcome-file-list/web-app十二.工具类:12.1HttpClient工具类:packageutil;importjava.io.IOException;importjava.security.GeneralSecurityException;importjava.security.cert.CertificateException;importjava.security.cert.X509Certificate;importjava.text.ParseException;importjava.util.HashMap;importjava.util.LinkedList;importjava.util.List;importjava.util.Map;importjavax.net.ssl.SSLContext;importjavax.net.ssl.SSLException;importjavax.net.ssl.SSLSession;importjavax.net.ssl.SSLSocket;importjavax.net.ssl.TrustManager;importjavax.net.ssl.X509TrustManager;importorg.apache.http.Consts;importorg.apache.http.HttpEntity;importorg.apache.http.NameValuePair;importorg.apache.http.client.ClientProtocolException;importorg.apache.http.client.config.RequestConfig;importorg.apache.http.client.entity.UrlEncodedFormEntity;importorg.apache.http.client.methods.CloseableHttpResponse;importorg.apache.http.client.methods.HttpEntityEnclosingRequestBase;importorg.apache.http.client.methods.HttpGet;importorg.apache.http.client.methods.HttpPost;importorg.apache.http.client.methods.HttpPut;importorg.apache.http.client.methods.HttpUriRequest;importorg.apache.http.conn.scheme.Scheme;importorg.apache.http.conn.ssl.SSLConnectionSocketFactory;importorg.apache.http.conn.ssl.SSLContextBuilder;importorg.apache.http.conn.ssl.SSLSocketFactory;importorg.apache.http.conn.ssl.TrustStrategy;importorg.apache.http.conn.ssl.X509HostnameVerifier;importorg.apache.http.entity.StringEntity;importorg.apache.http.impl.client.CloseableHttpClient;importorg.apache.http.impl.client.DefaultHttpClient;importorg.apache.http.impl.client.HttpClients;importorg.apache.http.impl.conn.PoolingHttpClientConnectionManager;importorg.apache.http.message.BasicNameValuePair;importorg.apache.http.util.EntityUtils;/***http请求客户端**@authorAdministrator**/publicclassHttpClient{privateStringurl;privateMapString,Stringparam;privateintstatusCode;privateStringcontent;privateStringxmlParam;privatebooleanisHttps;publicbooleanisHttps(){returnisHttps;}publicvoidsetHttps(booleanisHttps){this.isHttpsisHttps;}publicStringgetXmlParam(){returnxmlParam;}publicvoidsetXmlParam(StringxmlParam){this.xmlParamxmlParam;}publicHttpClient(Stringurl,MapString,Stringparam){this.urlurl;this.paramparam;}publicHttpClient(Stringurl){this.urlurl;}publicvoidsetParameter(MapString,Stringmap){parammap;}publicvoidaddParameter(Stringkey,Stringvalue){if(paramnull)paramnewHashMapString,String();param.put(key,value);}publicvoidpost()throwsClientProtocolException,IOException{HttpPosthttpnewHttpPost(url);setEntity(http);execute(http);}publicvoidput()throwsClientProtocolException,IOException{HttpPuthttpnewHttpPut(url);setEntity(http);execute(http);}publicvoidget()throwsClientProtocolException,IOException{if(param!null){StringBuilderurlnewStringBuilder(this.url);booleanisFirsttrue;for(Stringkey:param.keySet()){if(isFirst)url.append("?");elseurl.append("");url.append(key).append("").append(param.get(key));}this.urlurl.toString();}HttpGethttpnewHttpGet(url);execute(http);}/***sethttppost,putparam*/privatevoidsetEntity(HttpEntityEnclosingRequestBasehttp){if(param!null){ListNameValuePairnvpsnewLinkedListNameValuePair();for(Stringkey:param.keySet())nvps.add(newBasicNameValuePair(key,param.get(key)));//参数http.setEntity(newUrlEncodedFormEntity(nvps,Consts.UTF_8));//设置参数}if(xmlParam!null){http.setEntity(newStringEntity(xmlParam,Consts.UTF_8));}}privatevoidexecute(HttpUriRequesthttp)throwsClientProtocolException,IOException{CloseableHttpClienthttpClientnull;try{if(isHttps){SSLContextsslContextnewSSLContextBuilder().loadTrustMaterial(null,newTrustStrategy(){//信任所有publicbooleanisTrusted(X509Certificate[]chain,StringauthType)throwsCertificateException{returntrue;}}).build();SSLConnectionSocketFactorysslsfnewSSLConnectionSocketFactory(sslContext);httpClientHttpClients.custom().setSSLSocketFactory(sslsf).build();}else{httpClientHttpClients.createDefault();}CloseableHttpResponseresponsehttpClient.execute(http);try{if(response!null){if(response.getStatusLine()!null)statusCoderesponse.getStatusLine().getStatusCode();HttpEntityentityresponse.getEntity();//响应内容contentEntityUtils.toString(entity,Consts.UTF_8);}}finally{response.close();}}catch(Exceptione){e.printStackTrace();}finally{httpClient.close();}}publicintgetStatusCode(){returnstatusCode;}publicStringgetContent()throwsParseException,IOException{returncontent;}}12.2雪花算法工具类packageutil;importjava.lang.management.ManagementFactory;importj
支付解决方案_微信扫码支付附详细代码流程图-微信支付代码是什么-微信小程序支付代码
浏览量:2079
时间:
来源:暗余
版权声明
即速应用倡导尊重与保护知识产权。如发现本站文章存在版权问题,烦请提供版权疑问、身份证明、版权证明、联系方式等发邮件至197452366@qq.com ,我们将及时处理。本站文章仅作分享交流用途,作者观点不等同于即速应用观点。用户与作者的任何交易与本站无关,请知悉。
最新资讯
-

即速应用,赋能企业玩转微信小程序智慧经营
作为国内领军的智慧商业经营服务商,即速应用始终秉承“让每个企业都拥有自己的智慧店铺”的愿景,持续赋能更多企业玩转智慧经营。即速应用旗下拥有“小程序搭建工具-即速应用”、“私域流量专家-即客云”等产品,帮助商家打通互联网全生态营销闭环。 -

即客云2.0重磅更新,让微信小程序运营更简单!
即客云作为一款基于企业微信的第三方工具,现从多维度提供超过30种功能,自上线以来,已服务多家企业,受到一致好评。近期,我们根据客户反馈和市场调研正式推出升级版 即客云2.0!更新了私域运营SOP,群日历功能,批量拓客,客户雷达,消息推送,个人欢迎语,帮助企业更好运用企业微信;同时提升了社群运营工作标准化,提升运营效率,帮助企业实现客户增长,玩转私域流量。 -

零代码 + AI 双轮驱动|即速应用解锁人工智能小程序开发新范式
无需代码、无需 AI 算法功底,普通人也能快速搭建智能小程序。即速应用将人工智能与零代码开发深度融合,推出 AI 智能生成能力,用户通过自然语言描述需求,AI 自动生成小程序页面、功能模块与后台配置,覆盖商城、预约、同城、社区团购等全场景。平台内置 AI 智能推荐、智能客服、用户画像分析等能力,一键对接微信生态,打通视频号、企业微信、短信跳转,帮企业快速落地 AI 应用,抢占智慧经营先机,让每家企业都拥有 AI 驱动的智慧店铺。










