微信支付 订阅
微信支付是集成在微信客户端的支付功能,用户可以通过手机完成快速的支付流程。微信支付以绑定银行卡的快捷支付为基础,向用户提供安全、快捷、高效的支付服务。 [1]  自2017年11月23日起,微信支付服务功能在中国铁路客户服务中心12306网站上线运行。 [2]  2018年4月1日,消费者在使用微信钱包扫描静态条码支付时,单日使用零钱包支付的上限不超过500元,同时微信关联的所有银行卡还可以再独立获得500元的支付上限。 [3]  2018年3月,车牌=付款码,微信直接推出“高速e行”。 [4]  2018年6月29日,微信支付与米其林指南在广州宣布达成战略合作。 [5]  2020年2月,微信支付取得了尼泊尔央行的运营牌照。 [6] 展开全文
微信支付是集成在微信客户端的支付功能,用户可以通过手机完成快速的支付流程。微信支付以绑定银行卡的快捷支付为基础,向用户提供安全、快捷、高效的支付服务。 [1]  自2017年11月23日起,微信支付服务功能在中国铁路客户服务中心12306网站上线运行。 [2]  2018年4月1日,消费者在使用微信钱包扫描静态条码支付时,单日使用零钱包支付的上限不超过500元,同时微信关联的所有银行卡还可以再独立获得500元的支付上限。 [3]  2018年3月,车牌=付款码,微信直接推出“高速e行”。 [4]  2018年6月29日,微信支付与米其林指南在广州宣布达成战略合作。 [5]  2020年2月,微信支付取得了尼泊尔央行的运营牌照。 [6]
信息
发布时间
2013年8月5日
所属企业
腾讯
平    台
微信第三方平台
所属用户
微信app使用者
中文名
微信支付
注册用户
8亿(2017年12月) [7]
支持系统
IOS,安卓
外文名
WeChat Pay
微信支付发展历程
2013年8月5日,财付通与微信合作推出微信支付。 [8]  微信支付正式上线。 [9]  2014年1月4日,滴滴打车接入微信支付,3天突破10万单。 [10]  2014年1月27日,微信正式推出微信红包,并迅速流行开来。 [8]  2014年08月28日,智慧生活全行业解决方案正式公布。 [11]  2015年02月18日,开创春晚红包,10.1亿次收发创新了春节全民红包互动的新高潮。 [12]  2015年05月,零钱用户突破3亿。 [12]  2016年01月,微信支付接入线下门店超30万家。 [13]  2016年08月8日,提出“无现金生活”理念,打造全球首个移动支付节日“无现金日”,倡导低碳、高效的生活方式。 [14]  2018年6月29日,微信支付与米其林指南在广州宣布达成战略合作。 [5]  2018年10月1日起,微信香港钱包正式为香港用户提供内地移动支付服务。用户于内地商户消费时,微信香港钱包会将所需支付的人民币金额,自动换算为对应的港币金额。服务推广期间,用户使用微信香港钱包在内地商户消费,无需支付手续费。 [15]  2019年10月,微信支付钱包入口上线银行储蓄(仅部分用户可见)服务,点击银行储蓄可跳转至工商银行存款产品。用户同意“工商银行定存相关协议”可免费开通工商银行存款账户,选择存入存款,三年期利率3.85%,随时可取,并且不需要跳转到工商银行就可以操作。 [16]  2019年5月,尼泊尔中央银行出台一项命令:在尼境内使用支付宝支付、微信支付及跨境POS机等国际支付系统(获得尼官方授权的除外)的行为是非法的,有关人员将会根据有关法令受到惩处。2020年2月上旬,微信支付取得了尼泊尔央行的运营牌照。 [6] 
收起全文
精华内容
下载资源
问答
  • 课程讲解了Unity如何接入微信登录 微信分享 微信支付 支付宝支付
  • 微信支付

    千次阅读 2015-05-26 08:03:13
    所有的支付都大同小异,借助微信支付,可以一览所有支付系统的原貌
    所有的支付都大同小异,借助微信支付,可以一览所有支付系统的原貌
    展开全文
  • 手把手教你--JAVA微信支付(公众号支付JSAPI)

    万次阅读 多人点赞 2018-03-07 17:38:53
    写这篇文章的目的有2个,一是自己的项目刚开发完微信支付功能,趁热回个炉温习一下,二也是帮助像我这样对微信支付不熟悉,反复看了多天文档还是一知半解,原理都没摸清,更不要说实现了。本以为网上的微信开发教程会和...

    自己的第一篇博客,请各位看官海涵!

    JAVA开发微信支付-公众号支付/微信浏览器支付(JSAPI)

        写这篇文章的目的有2个,一是自己的项目刚开发完微信支付功能,趁热回个炉温习一下,二也是帮助像我这样对微信支付不熟悉,反复看了多天文档还是一知半解,原理都没摸清,更不要说实现了。本以为网上的微信开发教程会和“java的重写与重载”一样铺天盖地,可搜出来的结果,要么是PHP的教程(微信支付官网推荐就是PHP),要么星星点点就那么几篇,想对比的看看思路都成问题,官网下载的JAVA-SDK-DEMO也恕我技术低下,看的糊里糊涂。等自己开发完的那一刻,才豁然开朗,才知道走通完支付这条路的过程走了多少弯路,我是第一次接触支付,想必大部分能看这篇文章的兄弟也是被微信官方文档给绕的出不来才出此下策,内容有误请指正。好了这回真正的正题了:

    步骤一:获取微信支付四大参数

        首先要想支持微信支付,必须拥有两个账号:①微信公众已认证的服务号,并且需要开通微信支付该能(必须是企业才有资格申请,请你找你家产品去申请吧),②微信商户平台账号;这两个账号一个不能少。此处已默认你已有上两个账号。

        此处是账号模板,请参考:

        微信公众平台:账户:con*******om 登录密码 ******

        公众APPID:wx15*********a8

        APPSECEPT : c210***************892d7

        微信商户平台:账户:149**********6742 登录密码:******

        商户ID:14******42

        API密钥:5d5************b35b

    其中比较不好找的是商户的API密钥:在商户平台的账户中心下:需要用户自行下载证书及安装,(略)

        至此我们需要的APPID(appid),APPSECEPT(appsecret),商户ID(mch_id),API密钥(paternerKey),四个重要参数已拿到,括号中是我们代码所用的变量名称请提前熟悉。

    步骤二:平台配置

    1.配置支付目录:商户平台:

        配置此目录是代码中“微信支付”所在页面的地址,可以是目录不一定是全路径-如http://www.wangtao.com/order/-----此一级域名需要ICP备案。

    点击添加

     

    2.配置授权域名:微信公众平台:

        支付过程需要获取用户openid,必须经过网页授权配置才可以,要不然获取不到openid。

    点击设置,按说明设置

    步骤三:开发流程:

        微信支付原理(说白了就是调用官方文档的“统一下单”接口,之后将微信服务器返回的参数做个加工后,返回到前台(JSP页面),就OK了。咱们要做的就是想方设法的凑齐统一下单的所有参数“而已”,“而已”,“而已”,这个而已也就是最大的挑战)。所有参数解释请参考:官方文档:https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=9_1

        咱们只考虑必填参数,其他参数可以就看你的了。

        先来看看所有参数:

    其中的必填参数有:

    1.        appid APPID (已有)

    2.        mch_id 商户ID (已有)

    3.        nonce_str 随机字符串

    4.        sign 签名

    5.        body 所支付的名称

    6.        out_trade_no 咱们自己所提供的订单号,需要唯一

    7.        total_fee 支付金额

    8.        spbill_create_ip IP地址

    9.        notify_url 回调地址

    10.       trade_type 支付类型

    11.       openid 支付人的微信公众号对应的唯一标识

        只要把这11个凑齐就齐活,现在咱们从第3个开始一个一个的获取;在这之前先从官网把公众号支付的sdk下载下来,如图

        主要是用其中的WXPayUtil工具类中的一些方法。当然其他的类我看不懂,要是看懂了,就不至于这么费劲了。

    好了开始咱们的取值之旅了:

    1.        appid APPID (已有)

    2.        mch_id 商户ID (已有)

    3.        nonce_str 随机字符串用WXPayUtil中的generateNonceStr()即可,就是生成UUID的方法;

    4.        sign 签名 用WXPayUtil中的generateSignature(finalMap<String, String> data, String key)方法,data是将除了sign外,其他10个参数放到map中,key是四大配置参数中的API秘钥(paternerKey)(这里不要着急管它,最后处理它);

    5.        body 所支付的名称

    6.        out_trade_no 自己后台生成的订单号,只要保证唯一就好:如“2018013000001”

    7.        total_fee 支付金额 单位:分,为了测试此值给1,表示支付1分钱

    8.        spbill_create_ip IP地址 网上很多ip的方法,自己找,此处测试给“127.0.0.1”

    9.        notify_url 回调地址:这是微信支付成功后,微信那边会带着一大堆参数(XML格式)请求这个地址多次,这个地址做我们业务处理如:修改订单状态,赠送积分等。Ps:支付还没成功还想这么远干嘛,最后再说。地址要公网可以访问。

    10.    trade_type 支付类型 咱们是公众号支付此处给“JSAPI”

    11.    openid 支付人的微信公众号对应的唯一标识,每个人的openid在不同的公众号是不一样的,这11个参数里,最费劲的就是他了,其他的几乎都已经解决,现在开发得到这个参数。

        获得openid的部分内容应该不属于微信支付的范畴,属于微信公众号网页授权的东西,详情请参考微信网页授权:

    https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1421140842

    获得openid步骤:

    第一步:用户同意授权,获取code

    https://open.weixin.qq.com/connect/oauth2/authorize?appid=APPID&redirect_uri=REDIRECT_URI&response_type=code&scope=SCOPE&state=STATE#wechat_redirect

    注意:1. redirect_uri参数:授权后重定向的回调链接地址, 请使用 urlEncode 对链接进行处理。

    2. scope:用snsapi_base 

        通过此链接可以获取code,可以在一个空页面设置一个a标签,链接至其redirect_uri的地址。点击a标签,即可链接到redirect_uri的地址,并携带code。

    <a href="https://open.weixin.qq.com/connect/oauth2/authorize?
    appid=wx15c*********&redirect_uri=http%3a%2f%2fwww.***.com%2fpay.jsp&response_type=code&
    scope=snsapi_base#wechat_redirect">去支付页面pay.jsp并携带code</a>

    第二步:通过code换取网页授权access_token(其实微信支付就没有必要获取access_token,咱们只要其中openid,不是要用户信息,此步结果已经就含有咱们需要的openid了)

    获取code,请求以下链接获取access_token https://api.weixin.qq.com/sns/oauth2/access_token?appid=APPID&secret=SECRET&code=CODE&grant_type=authorization_code

    上一步的code有了,对于此链接的参数就容易了。可是在页面上如何处理是个问题,我是在pay.jsp页面加载完成后将获取code当做参数传异步到后台,在后台中用http相关类发送get请求(可以自行网上查找)。返回的JSON结果为:

    { "access_token":"ACCESS_TOKEN",
    "expires_in":7200,
    "refresh_token":"REFRESH_TOKEN",
    "openid":"OPENID",//就是它,只要这个值
    "scope":"SCOPE" }
    

        好了,access_token是有了,不过咱们不关心它,咱们关心的是openid,有了它一就回到咱们“统一下单”接口里,所有的参数已经就位就等发送了。在回顾下11个必填参数:

    1.        appid APPID (已有)

    2.        mch_id 商户ID (已有)

    3.        nonce_str 随机字符串用WXPayUtil中的generateNonceStr()即可,就是生成UUID的方法;

    4.        sign 签名 用WXPayUtil中的publicstatic String generateSignature(final Map<String, String> data, Stringkey)方法,data是将除了sign外,其他10个参数放到map中,key是四大配置参数中的API秘钥(paternerKey)(此时可以处理它了,不过其他10个参数都有了,它就easy,new一个map,依次put其他10个参数,就可以用generateSignature方法了,得到了sign,不要忘记再将sign put到只有10个参数的map,这样才能凑齐最后的第11个参数。准备召唤神龙吧。);

    5.        body 所支付的名称

    6.        out_trade_no 自己后台生成的订单号,只要保证唯一就好:如“2018013000001”

    7.        total_fee 支付金额 单位:分,为了测试此值给1,表示支付1分钱

    8.        spbill_create_ip IP地址 网上很多ip的方法,自己找,此处测试给“127.0.0.1”

    9.        notify_url 回调地址:这是微信支付成功后,微信那边会带着一大堆参数(XML格式)请求这个地址多次,这个地址做我们业务处理如:修改订单状态,赠送积分等。Ps:支付还没成功还想这么远干嘛,最后再说。地址要公网可以访问。

    10.    trade_type 支付类型 咱们是公众号支付此处给“JSAPI”

    11.    openid (已有)

        好了,准备工作完成,开始发送POST请求吧,上面提到网上找到的get请求的方法,此处用到post请求的方法,请求微信"统一下单接口https://api.mch.weixin.qq.com/pay/unifiedorder。发送前先用WXPayUtil工具类中的public static String mapToXml(Map<String,String> data)方法将有11个参数的map转成XML格式。发送后会返回String类型的返回值,如果你够幸运的话应该会得到XML的字符串:

    <xml>
      <return_code><![CDATA[SUCCESS]]></return_code>
      <return_msg><![CDATA[OK]]></return_msg>
      <appid><![CDATA[wx2421b1c4370ec43b]]></appid>
      <mch_id><![CDATA[10000100]]></mch_id>
      <nonce_str><![CDATA[IITRi8Iabbblz1Jc]]></nonce_str>
      <openid><![CDATA[oUpF8uMuAJO_M2pxb1Q9zNjWeS6o]]></openid>
      <sign><![CDATA[7921E432F65EB8ED0CE9755F0E86D72F]]></sign>
      <result_code><![CDATA[SUCCESS]]></result_code>
      <prepay_id><![CDATA[wx201411101639507cbf6ffd8b0779950874]]></prepay_id>
      <trade_type><![CDATA[JSAPI]]></trade_type>
    </xml>

        如果你得到了以上的字符串,那么先恭喜你,坚持看到这,说明你的耐心还是不错的,因为“统一下单”接口调用完毕,可是并没有什么实际的效果,因为微信里想出现支付的界面是在前台完成的现在咱们还在后台玩耍,前面提到的我是页面加载完成时异步到后台的,咱们要返回异步的结果了,好了趁热继续吧。“统一下单”这么费劲的完成其实搞那么麻烦,就是为了得到上面红色的prepay_id(丫的,就这么一个参数给咱们搞的都想说***了)。

        先用WXPayUtil类中的public static Map<String, String> xmlToMap(String strXML)方法,将刚才返回的XML格式的字符串转成map(为了方便取值)。map.get(“prepay_id”)就得到了prepay_id的值(比如得到的是:“wx2018…250…9981…666”),记住它,先保留此值。

    看看前台都需要接收哪些值吧。

    6个参数,咱们还是一个一个分析:

    1.        appId:四大参数之一的APPID;

    2.        timestamp:时间戳(newDate()即可)

    3.        nonceStr:随机字符串,再次用WXPayUtil中的generateNonceStr()即可;

    4.        package:就tm是它用到了prepay_id,但是还不是直接取值,还非要固定格式的,值的格式例如:”prepay_id= wx2018…250…9981…666”

    5.        signType:写MD5就好

    6.        paySign:又来了还是签名算法 ,按照上面的方法,用WXPayUtil中的publicstatic String generateSignature(final Map<String, String> data, Stringkey)方法,data是将除了paySign外,其他5个参数放到map中,key是四大配置参数中的API秘钥(paternerKey),得到了paySign,不要忘记再将paySign put到只有5个参数的map,这样才能凑齐最后的第6个参数。);

    注意:此处有个小bug,很多人会被坑的很惨,不注意就掉坑里,我是掉进去了,就是最关键的第4个参数package,眼熟不眼熟,这tm是JAVA的关键字,不能用来当变量名。

    所有的参数有了,返回给前端的方法有很多,简易用springMVC的@ResponseBody注解,即可将这个有6个参数的map按json格式传给前端。好了,后台工作完成。

        前端的工作就容易多了,格式比较固定因为是微信固定格式,所以直接贴出我的代码,你只要更换触发支付的事件和异步的地址即可.

    前端简单来说:1.一个空jsp页面上有个a标签,用来获取code,并跳转到pay.jsp(上面提到过)。

                            2.pay.jsp中需要异步到后台需要带code参数,pay.jsp中页面的地址上带着code,想获取code的方法很多,抛砖引引玉:(定义一个按钮,按钮上绑定一个code的属性值是页面链接的code的值,用EL表达式取的参数值,点击按钮触发点击事件)。

                            3.接收后台传过来值,调用固定方法。

    Pay.jsp中内容只有一个”微信支付”的按钮,和js的代码,以下是js内容(获取code方法可以修改),其它内容不要修改

    <!—pay.jsp中点击”微信支付”按钮执行pay()方法>
    
    <input id="code"type="button" value="微信支付"onclick="pay()" code="${param.code }"/>
    <script type="text/javascript">
    var appId,timeStamp,nonceStr,package,signType,paySign;  
     function pay(){
    	var code = $("#code").attr("code");//页面链接上的code参数
    	if(code){
    		var url = "http://异步地址?code="+code+";
    	  	$.get(url,function(result) {
      				appId = result.appId;
    				timeStamp = result.timeStamp;
    				nonceStr = result.nonceStr;
    				package = result.package;
    				signType = result.signType;
    				paySign = result.paySign;
    				
    				if (typeof WeixinJSBridge == "undefined") {
    					if (document.addEventListener) {
    						document.addEventListener('WeixinJSBridgeReady',
    								onBridgeReady, false);
    					} else if (document.attachEvent) {
    						document.attachEvent('WeixinJSBridgeReady',
    								onBridgeReady);
    						document.attachEvent('onWeixinJSBridgeReady',
    								onBridgeReady);
    					}
    				} else {
    					onBridgeReady();
    				}
    			});
    		} else {
    			alert(“服务器错误”)
    		}
    	}
    
    function onBridgeReady(){
    	  WeixinJSBridge.invoke( 'getBrandWCPayRequest', {
    		  "appId":appId,     //公众号名称,由商户传入     
              "timeStamp":timeStamp,         //时间戳,自1970年以来的秒数     
              "nonceStr":nonceStr, //随机串     
              "package":package,     
              "signType":signType,         //微信签名方式:     
              "paySign":paySign //微信签名 
             }, 
             function(res){      
          	   if(res.err_msg == "get_brand_wcpay_request:ok" ) {
                     console.log('支付成功');
                     //支付成功后跳转的页面
                 }else if(res.err_msg == "get_brand_wcpay_request:cancel"){
              	   console.log('支付取消');
                 }else if(res.err_msg == "get_brand_wcpay_request:fail"){
              	   console.log('支付失败');
                     WeixinJSBridge.call('closeWindow');
                 } //使用以上方式判断前端返回,微信团队郑重提示:res.err_msg将在用户支付成功后返回ok,但并不保证它绝对可靠。
       });   
    }
    </script>
    

    以下是后台部分

    /**
    	 * @Description 微信浏览器内微信支付/公众号支付(JSAPI)
    	 * @param request
    	 * @param code
    	 * @return Map
    	 */
    	@RequestMapping(value="orders", method = RequestMethod.GET)
    	@ResponseBody
    	public Map orders(HttpServletRequest request,String code) {
    		try {
    			//页面获取openId接口
    			String getopenid_url = https://api.weixin.qq.com/sns/oauth2/access_token;
    			String  param= 
    "appid="+你appid+"&secret="+你secret+"&code="+code+"&grant_type=authorization_code";
    			//向微信服务器发送get请求获取openIdStr
    String openIdStr = HttpRequest.sendGet(getopenid_url, param);
    			JSONObject json = JSONObject.parseObject(openIdStr);//转成Json格式
    			String openId = json.getString("openid");//获取openId
    			
    			//拼接统一下单地址参数
    			Map<String, String> paraMap = new HashMap<String, String>();
    			//获取请求ip地址
    			String ip = request.getHeader("x-forwarded-for");
    		    if(ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)){
    		        ip = request.getHeader("Proxy-Client-IP");
    		    }
    		    if(ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)){
    		        ip = request.getHeader("WL-Proxy-Client-IP");
    		    }
    		    if(ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)){
    		        ip = request.getRemoteAddr();
    		    }
    		    if(ip.indexOf(",")!=-1){
    		    	String[] ips = ip.split(",");
    		    	ip = ips[0].trim();
    		    }
    			
    			paraMap.put("appid", 你appid);  
    			paraMap.put("body", "尧舜商城-订单结算");  
    			paraMap.put("mch_id", 你mchId);  
    			paraMap.put("nonce_str", WXPayUtil.generateNonceStr());  
    			paraMap.put("openid", openId);
    			paraMap.put("out_trade_no", 你的订单号);//订单号
    			paraMap.put("spbill_create_ip", ip);  
    			paraMap.put("total_fee",”1”);  
    			paraMap.put("trade_type", "JSAPI");  
    			paraMap.put("notify_url",www.*******.com/***/**);// 此路径是微信服务器调用支付结果通知路径随意写
    			String sign = WXPayUtil.generateSignature(paraMap, paternerKey);
    			paraMap.put("sign", sign);
    			String xml = WXPayUtil.mapToXml(paraMap);//将所有参数(map)转xml格式
    						
    			// 统一下单 https://api.mch.weixin.qq.com/pay/unifiedorder
    			String unifiedorder_url = https://api.mch.weixin.qq.com/pay/unifiedorder;
    	
    			String xmlStr = HttpRequest.sendPost(unifiedorder_url, xml);//发送post请求"统一下单接口"返回预支付id:prepay_id
    			
    			//以下内容是返回前端页面的json数据
    			String prepay_id = "";//预支付id
    			if (xmlStr.indexOf("SUCCESS") != -1) {  
    				Map<String, String> map = WXPayUtil.xmlToMap(xmlStr);  
    				prepay_id = (String) map.get("prepay_id");  
    			}
    			Map<String, String> payMap = new HashMap<String, String>();
    			payMap.put("appId", appid);  
    			payMap.put("timeStamp", WXPayUtil.getCurrentTimestamp()+"");  
    			payMap.put("nonceStr", WXPayUtil.generateNonceStr());  
    			payMap.put("signType", "MD5");  
    			payMap.put("package", "prepay_id=" + prepay_id);  
    			String paySign = WXPayUtil.generateSignature(payMap, paternerKey);  
    			payMap.put("paySign", paySign);
    			return payMap;
    		} catch (Exception e) {  
    			e.printStackTrace();
    		}  
    		return null;
    	}

     

    以下是网上找的一个发送get和post的类.仅供参考:提前导入相关jar包可网上查找(很容易)

    import java.io.BufferedReader;
    import java.io.IOException;
    import java.io.InputStreamReader;
    import java.io.PrintWriter;
    import java.net.URL;
    import java.net.URLConnection;
    import java.util.List;
    import java.util.Map;
    
    public class HttpRequest {
        /**
         * 向指定URL发送GET方法的请求
         * 
         * @param url
         *            发送请求的URL
         * @param param
         *            请求参数,请求参数应该是 name1=value1&name2=value2 的形式。
         * @return URL 所代表远程资源的响应结果
         */
        public static String sendGet(String url, String param) {
            String result = "";
            BufferedReader in = null;
            try {
                String urlNameString = url + "?" + param;
                System.out.println(urlNameString);
                URL realUrl = new URL(urlNameString);
                // 打开和URL之间的连接
                URLConnection connection = realUrl.openConnection();
                // 设置通用的请求属性
                connection.setRequestProperty("accept", "*/*");
                connection.setRequestProperty("connection", "Keep-Alive");
                connection.setRequestProperty("user-agent",
                        "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)");
                // 建立实际的连接
                connection.connect();
                // 获取所有响应头字段
                Map<String, List<String>> map = connection.getHeaderFields();
                // 遍历所有的响应头字段
                for (String key : map.keySet()) {
                    System.out.println(key + "--->" + map.get(key));
                }
                // 定义 BufferedReader输入流来读取URL的响应
                in = new BufferedReader(new InputStreamReader(
                        connection.getInputStream()));
                String line;
                while ((line = in.readLine()) != null) {
                    result += line;
                }
            } catch (Exception e) {
                System.out.println("发送GET请求出现异常!" + e);
                e.printStackTrace();
            }
            // 使用finally块来关闭输入流
            finally {
                try {
                    if (in != null) {
                        in.close();
                    }
                } catch (Exception e2) {
                    e2.printStackTrace();
                }
            }
            return result;
        }
    
        /**
         * 向指定 URL 发送POST方法的请求
         * 
         * @param url
         *            发送请求的 URL
         * @param param
         *            请求参数,请求参数应该是 name1=value1&name2=value2 的形式。
         * @return 所代表远程资源的响应结果
         */
        public static String sendPost(String url, String param) {
            PrintWriter out = null;
            BufferedReader in = null;
            String result = "";
            try {
                URL realUrl = new URL(url);
                // 打开和URL之间的连接
                URLConnection conn = realUrl.openConnection();
                // 设置通用的请求属性
                conn.setRequestProperty("accept", "*/*");
                conn.setRequestProperty("connection", "Keep-Alive");
                conn.setRequestProperty("user-agent",
                        "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)");
                // 发送POST请求必须设置如下两行
                conn.setDoOutput(true);
                conn.setDoInput(true);
                // 获取URLConnection对象对应的输出流
                out = new PrintWriter(conn.getOutputStream());
                // 发送请求参数
                out.print(param);
                // flush输出流的缓冲
                out.flush();
                // 定义BufferedReader输入流来读取URL的响应
                in = new BufferedReader(
                        new InputStreamReader(conn.getInputStream()));
                String line;
                while ((line = in.readLine()) != null) {
                    result += line;
                }
            } catch (Exception e) {
                System.out.println("发送 POST 请求出现异常!"+e);
                e.printStackTrace();
            }
            //使用finally块来关闭输出流、输入流
            finally{
                try{
                    if(out!=null){
                        out.close();
                    }
                    if(in!=null){
                        in.close();
                    }
                }
                catch(IOException ex){
                    ex.printStackTrace();
                }
            }
            return result;
        }    
    }
    

        ----------------------------------------------------------------------------------

    以下是微信支付成功后,向自己项目发送请求,自己来做一些业务处理。

    /**
     * @ClassName WxPayController
     * @Description 微信支付成功后回调次接口
     * @author wtao wangtao@eyaoshun.com
     * @date 2018年1月11日 下午3:10:59
     */
    //回调路径是自己在之前已经填写过的
    @RequestMapping("/pay/")
    @Controller
    public class WxPayController {
    	@Autowired
    	private OrdersService ordersService;
    	@Autowired
    	private AccountService accountService;
    	@Autowired
    	private PointService pointService;
    	
    	@RequestMapping("callback")
    	public String callBack(HttpServletRequest request,HttpServletResponse response){
    		//System.out.println("微信支付成功,微信发送的callback信息,请注意修改订单信息");
    		InputStream is = null;
    		try {
    			is = request.getInputStream();//获取请求的流信息(这里是微信发的xml格式所有只能使用流来读)
    			String xml = WXPayUtil.inputStream2String(is, "UTF-8");
    			Map<String, String> notifyMap = WXPayUtil.xmlToMap(xml);//将微信发的xml转map
    						
    			if(notifyMap.get("return_code").equals("SUCCESS")){  
    	                if(notifyMap.get("result_code").equals("SUCCESS")){  
    	                String ordersSn = notifyMap.get("out_trade_no");//商户订单号 
    	                String amountpaid = notifyMap.get("total_fee");//实际支付的订单金额:单位 分
    	                BigDecimal amountPay = (new BigDecimal(amountpaid).divide(new BigDecimal("100"))).setScale(2);//将分转换成元-实际支付金额:元
    	                //String openid = notifyMap.get("openid");  //如果有需要可以获取
    	                //String trade_type = notifyMap.get("trade_type");  
    	                
    	                /*以下是自己的业务处理------仅做参考
    	                 * 更新order对应字段/已支付金额/状态码
    	                 */
    	                Orders order = ordersService.selectOrdersBySn(ordersSn);
    	                if(order != null) {
    	                	order.setLastmodifieddate(new Date());
    	                	order.setVersion(order.getVersion().add(BigDecimal.ONE));
    	                	order.setAmountpaid(amountPay);//已支付金额
    	                	order.setStatus(2L);//修改订单状态为待发货
    	                	int num = ordersService.updateOrders(order);//更新order
    	                	
    	                	String amount = amountPay.setScale(0, BigDecimal.ROUND_FLOOR).toString();//实际支付金额向下取整-123.23--123
    	                	/*
    	                	 * 更新用户经验值
    	                	 */
    	                	Member member = accountService.findObjectById(order.getMemberId());
    	                	accountService.updateMemberByGrowth(amount, member);
    	                	
    	                	/*
    	                	 * 添加用户积分数及添加积分记录表记录
    	                	 */
    	                	pointService.updateMemberPointAndLog(amount, member, "购买商品,订单号为:"+ordersSn);
    	                	
    	                }
    	                  
    	            }  
    	        }
    			
    	        //告诉微信服务器收到信息了,不要在调用回调action了========这里很重要回复微信服务器信息用流发送一个xml即可
    	        response.getWriter().write("<xml><return_code><![CDATA[SUCCESS]]></return_code></xml>");  
    			is.close();
    		} catch (Exception e) {
    			e.printStackTrace();
    		}
    		return null;
    	}
    }
    

     

        以上纯手写,如有疏漏请联系,请大神勿喷.谢谢,以上是公众号支付(在微信里),有时间的话我再写一个H5页面的微信支付,请期待.

     

    展开全文
  • 微信支付微信支付之 Native 支付

    千次阅读 2019-07-05 16:08:03
      Native支付是商户系统按微信支付协议生成支付二维码,用户再用微信“扫一扫”完成支付的模式。该模式适用于PC网站支付、实体店单品或订单支付、媒体广告支付等场景。   详情见开发文档。 前期准备   注册...

    概述

      Native支付是商户系统按微信支付协议生成支付二维码,用户再用微信“扫一扫”完成支付的模式。该模式适用于PC网站支付、实体店单品或订单支付、媒体广告支付等场景。详情见开发文档

    前期准备

    1. 注册微信支付商户号,获取商户号 mch_id、key;
    2. 申请微信认证的服务号、政府或媒体类订阅号、小程序、APP、企业微信其中之一,并与商户号绑定。获取 appid。

    开发步骤

    Native支付可分为两种模式,商户根据支付场景选择相应模式。本文仅介绍模式二。

    业务流程时序图

    原生支付模式二时序图

    业务流程说明:

    (1)商户后台系统根据用户选购的商品生成订单。
    (2)用户确认支付后调用微信支付【统一下单API】生成预支付交易;
    (3)微信支付系统收到请求后生成预支付交易单,并返回交易会话的二维码链接code_url。
    (4)商户后台系统根据返回的code_url生成二维码。
    (5)用户打开微信“扫一扫”扫描二维码,微信客户端将扫码内容发送到微信支付系统。
    (6)微信支付系统收到客户端请求,验证链接有效性后发起用户支付,要求用户授权。
    (7)用户在微信客户端输入密码,确认支付后,微信客户端提交授权。
    (8)微信支付系统根据用户授权完成支付交易。
    (9)微信支付系统完成支付交易后给微信客户端返回交易结果,并将交易结果通过短信、微信消息提示用户。微信客户端展示支付交易结果页面。
    (10)微信支付系统通过发送异步消息通知商户后台系统支付结果。商户后台系统需回复接收情况,通知微信后台系统不再发送该单的支付通知。
    (11)未收到支付通知的情况,商户后台系统调用【查询订单API】。
    (12)商户确认订单已支付后给用户发货。

    统一下单

    SDK

    API 详见统一下单API
    下载官方 SDK ,或通过 maven 获取依赖。推荐使用后者。

    <!-- wxpay-sdk -->
    <dependency>
        <groupId>com.github.wxpay</groupId>
        <artifactId>wxpay-sdk</artifactId>
        <version>0.0.3</version>
    </dependency>
    

    SDK 中集成了一个 WXPayConfig.java 的接口,我们需要写一个实现类,存放配置信息。

    public class WXPayConfigImpl implements WXPayConfig {
        // 设置证书,没有的话注释掉
        // private byte[] certData;
        // public WXPayConfigImpl() throws Exception {
        //    String certPath = "/path/to/apiclient_cert.p12";
        //    File file = new File(certPath);
        //    InputStream certStream = new FileInputStream(file);
        //    this.certData = new byte[(int) file.length()];
        //    certStream.read(this.certData);
        //    certStream.close();
        // }
        // set appid
        public static void setAppId(String appId) {
            WXPayConfigImpl.appId = "";
        }
        // set mch_id
        public static void setMchId(String mchId) {
            WXPayConfigImpl.mchId = "";
        }
        // set key
        public static void setKey(String key) {
            WXPayConfigImpl.key = "";
        }
    
        public InputStream getCertStream() {
            ByteArrayInputStream certBis = new ByteArrayInputStream(this.certData);
            return certBis;
        }
        // 异步通知地址
        public String getNotifyUrl() {
            return "http://www.xxx.com/wxNotify";
        }
    
        public int getHttpConnectTimeoutMs() {
            return 8000;
        }
    
        public int getHttpReadTimeoutMs() {
            return 10000;
        }
    
    //    IWXPayDomain getWXPayDomain() {
    //        return null;
    //    }
    }
    

    获取 code_url

    核心代码如下:

    public class WXPayService {
        /**
         * 微信扫码下单 native
         * @param outTradeNo
         * @param totalFee
         * @param body
         * @param productId
         * @param attach 自定义参数,通知中原样返回。
         * @return
         * @throws Exception
         */
        public static String wxUnifiedOrder(String outTradeNo, 
                                            String totalFee, 
                                            String body,
                                            String productId, 
                                            String attach) throws Exception {
            WXPayConfigImpl config = null;
            WXPay wxpay = null;
            config = new WXPayConfigImpl();
            // 异步通知地址
            String notifyUrl = config.getNotifyUrl();
            // 使用沙箱环境
            // wxpay = new WXPay(config, WXPayConstants.SignType.MD5, true);
            // 默认使用MD5,不使用沙箱环境
            wxpay = new WXPay(config); 
            Map<String, String> data = new HashMap<String, String>();
            // 商品描述
            data.put("body", body); 
            // 商户订单号
            data.put("out_trade_no", outTradeNo); 
            // 标价金额
            data.put("total_fee", totalFee); 
            // 产品id
            data.put("product_id", productId);
            // 终端IP:调用微信支付API的机器IP
            data.put("spbill_create_ip", "221.12.4.52"); 
            // 交易类型:此处指定为扫码支付
            data.put("trade_type", "NATIVE"); 
            // 异步通知 url
            data.put("notify_url", notifyUrl);
            // 自定义参数
            data.put("attach", attach);
            Map<String, String> resp = null;
            try {
                resp = wxpay.unifiedOrder(data);
            } catch (Exception e) {
                e.printStackTrace();
            }
            String codeUrl = resp.get("code_url");
            System.out.println("============= 微信返回结果 =============");
            System.out.println(resp);
            return codeUrl;
        }
    }
    

    将获取得到的 codeUrl 通过第三方库转为二维码,供用户扫码。

    异步通知

    异步通知的请求路径在统一下单接口中设置。

    @RequestMapping("wxNotify")
    public class WXController {
        public void notify(HttpServletRequest request, HttpServletResponse response) throws Exception {
            // 拿到微信回调信息
            InputStream inputStream = request.getInputStream();
            BufferedReader in = new BufferedReader(new InputStreamReader(inputStream, "UTF-8"));
            StringBuffer sb = new StringBuffer();
            // 将微信回调信息转为字符串
            String line;
            while ((line = in.readLine()) != null) {
                sb.append(line);
            }
            in.close();
            inputStream.close();
            String strXml = sb.toString();
            WXPayConfigImpl config = new WXPayConfigImpl();
            Map<String, String> map = WXPayUtil.xmlToMap(strXml);
            System.out.println(strXml);
    
            // 获取业务信息
            String outTradeNo = map.get("out_trade_no");
            String totalFee = map.get("total_fee");
            String appId = map.get("appid");
            String mchId = map.get("mch_id");
            String transactionId = map.get("transaction_id");
            String resultCode = map.get("result_code");
            String attach = map.get("attach");
            
            // 验签
            boolean signatureValid = WXPayUtil.isSignatureValid(strXml, config.getKey());
            // todo 这里写代码
            /* 实际验证过程建议商户务必添加以下校验:
                1、需要验证该通知数据中的 out_trade_no 是否为商户系统中创建的订单号
                2、判断 total_fee 是否确实为该订单的实际金额(即商户订单创建时的金额)
            */
            PrintWriter writer = response.getWriter();
            // 判断签名是否正确
            if (signatureValid) {
                // 判断回调信息是否成功
                if ("SUCCESS".equals(map.get("result_code"))) {
                    // todo 根据不同业务类型处理不同业务
                    
                    // 通知微信订单处理成功
                    String noticeStr = setXML("SUCCESS", "");
                    writer.write(noticeStr);
                    writer.flush();
                }
            } else {
                // 通知微信订单处理失败
                String noticeStr = setXML("FAIL", "");
                writer.write(noticeStr);
                writer.flush();
            }
        }
    
        private static String setXML(String return_code, String return_msg) {
            return "<xml><return_code><![CDATA[" + return_code + "]]></return_code><return_msg><![CDATA[" + return_msg + "]]></return_msg></xml>";
        }
    }
    

    沙箱测试

      编写完代码,我们就要开始沙箱测试了。
      微信的流程是,写完代码之后,必须使用沙箱测试,对测试结果进行验收,验收通过才可以使用正式的微信商户号,否则会返回“商户无此接口权限”。
      沙箱验收过程可查看支付验收指引

    1. 使用正式的 mch_id,商户key 来获取沙箱密钥 sandbox_signkey。传送门
      沙箱密钥获取

    2. 通过调用接口https://api.mch.weixin.qq.com/sandboxnew/pay/getsignkey,获取验签密钥。请求方式为 POST,发送 json 字符串。可以使用 Postman 调用此接口,获取验签密钥。
      通过Postman获取验签密钥
      返回的结果如下

    <xml>
      <return_code><![CDATA[SUCCESS]]></return_code>
      <retmsg><![CDATA[ALSDFJASLDFKJASLDFKJASDLFJ]]></retmsg>
      <retcode><![CDATA[0]]></retcode>
    </xml>
    
    1. 使用沙箱环境
    // 使用沙箱环境
    wxpay = new WXPay(config, WXPayConstants.SignType.MD5, true);
    
    1. 测试结果
      • 微信的沙箱测试 不会 发送异步通知,等待5s左右后,会在控制台打印出模拟异步通知的结果。若无通知,调用 查询订单接口进行查询。
      • 必须按照微信的支付验收用例来设置金额,否则会返回错误信息,“金额不合法”。
      • 各项支付验收用例测试结束后,按照要求调用【查询订单】进行查询,查询结束后验收结束。
      • 在官方微信号查询验收结果。验收通过后,即可使用正式账号。

    查询订单

    controller 层

    public class WXController {
        public void orderQuery(String key, String appid, String mchId, String outTradeNo, String transactionId) throws Exception {
            WXPayConfigImpl.setKey(key);
            WXPayConfigImpl.setAppId(appid);
            WXPayConfigImpl.setMchId(mchId);
            WXPayConfigImpl config = new WXPayConfigImpl();
            
            Map<String, String> map = WXPayService.orderQuery(outTradeNo, transactionId);
            String attach = map.get("attach");
            String appId = map.get("appid");
            String totalFee = map.get("total_fee");
            String strXml = WXPayUtil.mapToXml(map);
            String resultCode = map.get("result_code");
            transactionId = map.get("transaction_id");
            System.out.println("strXml: " + strXml);
        }
    }
    

    service 层

        /**
         * 微信订单查询
         *
         * @param outTradeNo
         * @param transactionId
         * @return
         * @throws Exception
         */
        public static Map<String, String> orderQuery(String outTradeNo, String transactionId) throws Exception {
            WXPayConfigImpl config = null;
            WXPay wxpay = null;
            config = new WXPayConfigImpl();
            // wxpay = new WXPay(config, WXPayConstants.SignType.MD5, true); // 使用沙箱
            wxpay = new WXPay(config);// 默认使用MD5,不使用沙箱环境
    
            Map<String, String> data = new HashMap<String, String>();
            if (!StringUtils.isEmpty(outTradeNo)) {
                data.put("out_trade_no", outTradeNo);
            }
            if (!StringUtils.isEmpty(transactionId)) {
                data.put("transaction_id", transactionId);
            }
            return wxpay.orderQuery(data);
        }
    

    遇到的问题

    1. appid 与商户号绑定:
        问题描述:调用微信统一下单接口时,返回失败。错误信息为:appid 与 mch_id 不匹配。
        原因分析:appid 与 mch_id 不匹配,在 mch_id 没错的情况下,自然是 appid 出了问题。如果 appid 不合法,或者没有与 mch_id 绑定,就会报这个错。在微信商户账号界面绑定一个 appid 到 mch_id 下。
        解决方法:在微信商户账号界面绑定一个 appid 到 mch_id 下。“申请微信认证的服务号、政府或媒体类订阅号、小程序、APP、企业微信其中之一,并与商户号绑定。”
    2. 商户订单号重复:
        问题描述:在微信支付页面,用户获取了二维码之后并没有付款,或是关闭了页面,或是暂时不想支付等原因,这很常见。此时再次对同一订单进行微信支付,统一下单接口可能会报“INVALID_REQUEST 商户订单号重复”的错误。
        原因分析:同一订单号调用微信的统一下单接口时,若其他参数与首次不同,则微信认为是两个订单。两个订单使用了同一个订单号,这是不被允许的。
        解决方法:订单重入时,要求参数值与原请求一致,请确认参数问题。包括 attach 这种商户自定义参数,都必须一致。

    [end]

    展开全文
  • Java调用微信支付

    万次阅读 多人点赞 2020-06-17 02:04:46
    Java 使用微信支付 一. 准备工作 1.

    Java 使用微信支付

    前言百度搜了一下微信支付,都描述的不太好,于是乎打算自己写一个案例,希望以后拿来直接改造使用。
    因为涉及二维码的前端显示,所以有前端的内容

    一. 准备工作

    所需微信公众号信息配置

    • APPID:绑定支付的APPID(必须配置)
    • MCHID:商户号(必须配置)
    • KEY:商户支付密钥,参考开户邮件设置(必须配置)
    • APPSECRET:公众帐号secert(仅JSAPI支付的时候需要配置)

    我这个案例用的是尚硅谷一位老师提供的,这里不方便提供出来,需要大家自己找,或者公司提供

    二. 构建项目架构

    1.新建maven项目

    在这里插入图片描述

    2.导入依赖

        <parent>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-parent</artifactId>
            <version>2.2.1.RELEASE</version>
        </parent>
        <dependencies>
            <!--spring boot -->
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-web</artifactId>
            </dependency>
            <!--微信提供的sdk-->
            <dependency>
                <groupId>com.github.wxpay</groupId>
                <artifactId>wxpay-sdk</artifactId>
                <version>0.0.3</version>
            </dependency>
            <!--发送http请求-->
            <dependency>
                <groupId>org.apache.httpcomponents</groupId>
                <artifactId>httpclient</artifactId>
            </dependency>
            <!--模板引擎-->
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-freemarker</artifactId>
            </dependency>
        </dependencies>
    

    在这里插入图片描述
    依赖中需要注意的是我导入了微信提供的sdk,以及freemarker模板引擎

    3.编写配置文件application.properties

    # 服务端口
    server.port=8081
    # 微信开放平台 appid
    wx.pay.app_id=
    #商户号
    wx.pay.partner=
    #商户key
    wx.pay.partnerkey=
    #回调地址
    wx.pay.notifyurl:
    
    spring.freemarker.tempalte-loader-path=classpath:/templates
    #        关闭缓存,及时刷新,上线生产环境需要修改为true
    spring.freemarker.cache=false
    spring.freemarker.charset=UTF-8
    spring.freemarker.check-template-location=true
    spring.freemarker.content-type=text/html
    spring.freemarker.expose-request-attributes=true
    spring.freemarker.expose-session-attributes=true
    spring.freemarker.request-context-attribute=request
    spring.freemarker.suffix=.ftl
    spring.mvc.static-path-pattern: /static/**
    

    在这里插入图片描述

    4.编写启动类

    @SpringBootApplication
    @ComponentScan(basePackages = {"com.haiyang.wxpay"})
    public class Application {
    
        public static void main(String[] args) {
            SpringApplication.run(Application.class, args);
        }
    }
    
    

    在这里插入图片描述

    5.创建常用包controller,service,impl,utils

    在这里插入图片描述

    6.创建两个前端需要的文件夹 static和templates

    在这里插入图片描述

    三. 代码实现

    1. 创建工具类读取配置文件的参数

    @Component
    public class WxPayUtils implements InitializingBean {
    
        @Value("${wx.pay.app_id}")
        private String appId;
    
        @Value("${wx.pay.partner}")
        private String partner;
    
        @Value("${wx.pay.partnerkey}")
        private String partnerKey;
        @Value("${wx.pay.notifyurl}")
        private String notifyUrl;
    
    
        public static String WX_PAY_APP_ID;
        public static String WX_PAY_PARTNER;
        public static String WX_PAY_PARTNER_KEY;
        public static String WX_OPEN_NOTIFY_URL;
    
        @Override
        public void afterPropertiesSet() throws Exception {
            WX_PAY_APP_ID = appId;
            WX_PAY_PARTNER = partner;
            WX_PAY_PARTNER_KEY = partnerKey;
            WX_OPEN_NOTIFY_URL = notifyUrl;
        }
    
    }
    

    在这里插入图片描述

    2. 构建工具类发送http请求

    /**
     * http请求客户端
     * 
     * @author qy
     * 
     */
    public class HttpClient {
    	private String url;
    	private Map<String, String> param;
    	private int statusCode;
    	private String content;
    	private String xmlParam;
    	private boolean isHttps;
    
    	public boolean isHttps() {
    		return isHttps;
    	}
    
    	public void setHttps(boolean isHttps) {
    		this.isHttps = isHttps;
    	}
    
    	public String getXmlParam() {
    		return xmlParam;
    	}
    
    	public void setXmlParam(String xmlParam) {
    		this.xmlParam = xmlParam;
    	}
    
    	public HttpClient(String url, Map<String, String> param) {
    		this.url = url;
    		this.param = param;
    	}
    
    	public HttpClient(String url) {
    		this.url = url;
    	}
    
    	public void setParameter(Map<String, String> map) {
    		param = map;
    	}
    
    	public void addParameter(String key, String value) {
    		if (param == null)
    			param = new HashMap<String, String>();
    		param.put(key, value);
    	}
    
    	public void post() throws ClientProtocolException, IOException {
    		HttpPost http = new HttpPost(url);
    		setEntity(http);
    		execute(http);
    	}
    
    	public void put() throws ClientProtocolException, IOException {
    		HttpPut http = new HttpPut(url);
    		setEntity(http);
    		execute(http);
    	}
    
    	public void get() throws ClientProtocolException, IOException {
    		if (param != null) {
    			StringBuilder url = new StringBuilder(this.url);
    			boolean isFirst = true;
    			for (String key : param.keySet()) {
    				if (isFirst)
    					url.append("?");
    				else
    					url.append("&");
    				url.append(key).append("=").append(param.get(key));
    			}
    			this.url = url.toString();
    		}
    		HttpGet http = new HttpGet(url);
    		execute(http);
    	}
    
    	/**
    	 * set http post,put param
    	 */
    	private void setEntity(HttpEntityEnclosingRequestBase http) {
    		if (param != null) {
    			List<NameValuePair> nvps = new LinkedList<NameValuePair>();
    			for (String key : param.keySet())
    				nvps.add(new BasicNameValuePair(key, param.get(key))); // 参数
    			http.setEntity(new UrlEncodedFormEntity(nvps, Consts.UTF_8)); // 设置参数
    		}
    		if (xmlParam != null) {
    			http.setEntity(new StringEntity(xmlParam, Consts.UTF_8));
    		}
    	}
    
    	private void execute(HttpUriRequest http) throws ClientProtocolException,
    			IOException {
    		CloseableHttpClient httpClient = null;
    		try {
    			if (isHttps) {
    				SSLContext sslContext = new SSLContextBuilder()
    						.loadTrustMaterial(null, new TrustStrategy() {
    							// 信任所有
    							public boolean isTrusted(X509Certificate[] chain,
    									String authType)
    									throws CertificateException {
    								return true;
    							}
    						}).build();
    				SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(
    						sslContext);
    				httpClient = HttpClients.custom().setSSLSocketFactory(sslsf)
    						.build();
    			} else {
    				httpClient = HttpClients.createDefault();
    			}
    			CloseableHttpResponse response = httpClient.execute(http);
    			try {
    				if (response != null) {
    					if (response.getStatusLine() != null)
    						statusCode = response.getStatusLine().getStatusCode();
    					HttpEntity entity = response.getEntity();
    					// 响应内容
    					content = EntityUtils.toString(entity, Consts.UTF_8);
    				}
    			} finally {
    				response.close();
    			}
    		} catch (Exception e) {
    			e.printStackTrace();
    		} finally {
    			httpClient.close();
    		}
    	}
    
    	public int getStatusCode() {
    		return statusCode;
    	}
    
    	public String getContent() throws ParseException, IOException {
    		return content;
    	}
    
    }
    
    

    额~有点长就不放图片了 代码都一样

    3. 新建controller

    @Controller
    @RequestMapping("/wxpay")
    public class WxPayController {
        @RequestMapping("/pay")
        public String createPayQRcode(Model model) throws Exception{
    
            String price = "0.01";
            String no = getOrderNo();
            Map m = new HashMap();
            m.put("appid", WxPayUtils.WX_PAY_APP_ID);
            m.put("mch_id", WxPayUtils.WX_PAY_PARTNER);
            m.put("nonce_str", WXPayUtil.generateNonceStr());
            m.put("body","微信支付测试"); //主体信息
            m.put("out_trade_no", no); //订单唯一标识
            m.put("total_fee", getMoney(price));//金额
            m.put("spbill_create_ip", "127.0.0.1");//项目的域名
            m.put("notify_url", WxPayUtils.WX_OPEN_NOTIFY_URL);//回调地址
            m.put("trade_type", "NATIVE");//生成二维码的类型
    
            //3 发送httpclient请求,传递参数xml格式,微信支付提供的固定的地址
            HttpClient client = new HttpClient("https://api.mch.weixin.qq.com/pay/unifiedorder");
            //设置xml格式的参数
            //把xml格式的数据加密
            client.setXmlParam(WXPayUtil.generateSignedXml(m, WxPayUtils.WX_PAY_PARTNER_KEY));
            client.setHttps(true);
            //执行post请求发送
            client.post();
            //4 得到发送请求返回结果
            //返回内容,是使用xml格式返回
            String xml = client.getContent();
            //把xml格式转换map集合,把map集合返回
            Map<String,String> resultMap = WXPayUtil.xmlToMap(xml);
            //最终返回数据 的封装
            Map map = new HashMap();
            map.put("no", no);
            map.put("price", price);
            map.put("result_code", resultMap.get("result_code"));
            map.put("code_url", resultMap.get("code_url"));
    
            model.addAttribute("map",map);
            return "pay";
    
        }
    
        @GetMapping("queryorder/{no}")
        @ResponseBody
        public String queryPayStatus(@PathVariable String no) throws Exception{
            //1、封装参数
            Map m = new HashMap<>();
            m.put("appid", WxPayUtils.WX_PAY_APP_ID);
            m.put("mch_id", WxPayUtils.WX_PAY_PARTNER);
            m.put("out_trade_no", no);
            m.put("nonce_str", WXPayUtil.generateNonceStr());
    
            //2 发送httpclient
            HttpClient client = new HttpClient("https://api.mch.weixin.qq.com/pay/orderquery");
            client.setXmlParam(WXPayUtil.generateSignedXml(m, WxPayUtils.WX_PAY_PARTNER_KEY));
            client.setHttps(true);
            client.post();
    
            //3.得到订单数据
            String xml = client.getContent();
            Map<String, String> resultMap = WXPayUtil.xmlToMap(xml);
    
            //4.判断是否支付成功
            if(resultMap.get("trade_state").equals("SUCCESS")) {
                /*
                      改变数据库中的数据等操作
                 */
                return "支付成功";
            }
            return "支付中";
        }
    
        @GetMapping("success")
        public String success(){
            return "success";
        }
        @RequestMapping("test")
        public String test(){
            return "pay";
        }
        /**
         * 生成订单号
         * @return
         */
        public static String getOrderNo() {
            SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmss");
            String newDate = sdf.format(new Date());
            String result = "";
            Random random = new Random();
            for (int i = 0; i < 3; i++) {
                result += random.nextInt(10);
            }
            return newDate + result;
        }
        /**
         * 元转换成分
         * @param amount
         * @return
         */
        public static String getMoney(String amount) {
            if(amount==null){
                return "";
            }
            // 金额转化为分为单位
            // 处理包含, ¥ 或者$的金额
            String currency =  amount.replaceAll("\\$|\\¥|\\,", "");
            int index = currency.indexOf(".");
            int length = currency.length();
            Long amLong = 0l;
            if(index == -1){
                amLong = Long.valueOf(currency+"00");
            }else if(length - index >= 3){
                amLong = Long.valueOf((currency.substring(0, index+3)).replace(".", ""));
            }else if(length - index == 2){
                amLong = Long.valueOf((currency.substring(0, index+2)).replace(".", "")+0);
            }else{
                amLong = Long.valueOf((currency.substring(0, index+1)).replace(".", "")+"00");
            }
            return amLong.toString();
        }
    }
    

    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    值得一提的是 这里我们用的是controller而不是restcontroller,因为我们需要展示二维码

    4. 在templates文件中新建 订单支付页面(二维码生成的页面)

    注意:文件名必须和生成二维码方法中返回的字符串名称一样 我这里叫 pay

    先新建html页面,然后再将后缀改成ftl(freemarker模板引擎的后缀名)

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
        <script src="/static/qrcode.js"></script>
        <script src="https://cdn.bootcss.com/jquery/3.4.1/jquery.js"></script>
    </head>
    <center>
        <div id="qrcode"></div>
    </center>
    <script type="text/javascript">
        new QRCode(document.getElementById("qrcode"), "${map.code_url}");  // 设置要生成二维码的链接
    </script>
    <script type="text/javascript">
        var int=self.setInterval("querystatus()",3000);
        function querystatus() {
            $.get("/wxpay/queryorder/${map.no}",function(data,status){
                if (data==="支付中"){
                    console.log("支付中");
                } else {
                    clearInterval(int)
                    window.location.href="/wxpay/success"
                }
            })
        }
    </script>
    </body>
    </html>
    

    在这里插入图片描述
    再创建支付成功跳转的页面 文件名要与支付成功方法返回的文件名一样

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
    </head>
    <body>
    <h1>支付成功</h1>
    </body>
    </html>
    

    在这里插入图片描述
    引入 qrcode 生成二维码的依赖,放入static文件中
    这里我提供下载链接
    链接: https://pan.baidu.com/s/15-E3KpRCenAewh0ZaBLnjQ 提取码: xhs9 复制这段内容后打开百度网盘手机App,操作更方便哦

    引入完成后
    在这里插入图片描述

    最后 我们启动项目来测试一下

    浏览器输入地址
    http://localhost:8081/wxpay/pay
    发现二维码生成成功,并且定时器也没问题
    在这里插入图片描述
    之后我们扫码支付
    成功跳转到支付成功页面 ~nice
    在这里插入图片描述

    四. 总结

    1. 首先就是生成二维码,需要的几个主要的参数,订单号,金额,购买的信息(主体信息),其余的参数除了一些可以不写的都是固定的
    2. 生成二维码然后展示在页面上,用的qrcode插件,生成
    3. 然后设置定时器,来实时查询订单是否支付
    4. 查询订单信息的写法和生成二维码的方式差不多 无非就是请求时少了几个参数,必须得带上订单号
    5. 微信提供的查询订单接口返回数据中 trade_state 代表支付状态 notpay没有支付,seccess表示已成功
    6. 定时器检测到订单支付成功就清除定时器,并且执行支付成功之后的操作

    实际项目中远没有这么简单,并且所有的数据都要从数据库中获取,在这里我为了方便把价格固定写死的

    展开全文
  • 哪些年微信支付遇到的坑,蛋蛋的忧伤。。。 本人小白一枚,第一次写微信支付“湿鞋”的经历。。。话说微信这个“坑”啊!!! 好了进入正题:先说一下我遇到的坑!!(发现一个很让人无奈的事情,无论支付缺少啥...
  • 微信支付系列文章 微信支付-java后端实现 微信支付-vue 前端实现 vue demo: 下载地址文章底部 技术栈 vue vue-cli weixin-js-sdk (微信jsSdk) 微信支付术语 微信jsSdk需要提前初始化完成 初始化加密参数需要...
  • 微信支付分为以下几步: 官网api地址:https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=7_7&amp;index=6 1,登录的时候,静默获取用户code,再用code获取用户openId,获取code的链接也是由微信提供...
  • 微信支付-java实现微信支付-后端篇

    万次阅读 多人点赞 2018-08-11 14:19:15
    四 Java 实现微信支付 — 后端篇 技术栈 Spring boot java XML (微信在http协议中数据传输方案) MD5 签名 微信支付术语 openid (OpenID是公众号一对一对应用户身份的标识) app_id (公众号id,登录微信...
  • vue 微信支付 支付宝支付

    千次阅读 多人点赞 2020-01-17 13:59:07
    需求:vue页面嵌套在安卓或者苹果app里面 在vue页面完成支付宝 或者 微信的支付 ...微信支付 saveWechat(){//微信支付 let _this = this; _this.common.ajax({ method: 'post', ...
  • Java微信支付-微信App支付服务端源代码

    千次下载 热门讨论 2016-11-18 10:46:35
    微信支付-微信app支付java服务器端代码 实现功能:微信支付 支付查询 申请退款 退款查询 微信服务器端异步支付结果通知 参考博文:http://blog.csdn.net/fengshizty/article/details/53199356
  • 请确保实际支付时的请求目录与后台配置的目录一致,否则将无法成功唤起微信支付。 在微信商户平台(pay.weixin.qq.com)设置您的公众号支付支付目录,设置路径:商户平台-->产品中心-->开发配置,如下图所...
  • 求能用的案例 java微信支付jsapi的java微信支付jsapi的
  • 微信支付开发——公众号支付

    万人学习 2016-10-27 14:33:09
    微信已经融入到人们的生活中,很多企业也...这是一部中课程,需要有学习的开发者拥有微信开发和PHP的相关基础:微信支付在项目中的位置、微信支付类型、微信支付涉及内容、微信公众号支付功能实现、微信支付安全建议。
  • 微信公众平台开发之微信支付开发是子恒老师《微信公众平台开发》视频教程的第12部。详细讲解了用php进行微信支付的开发。内容包含获取支付密钥,微信公众号支付开发,扫码支付,微信刷卡支付,异步处理支付结果等等...
  • 如果你不会微信支付开发,你微信公众号开发白学了!现在微商城越来越火,微信支付开发是的技术技能,也是众多网络技术公司招聘技术的条件。本课程将一步一步带你实现微信支付开发网页版。让你的公众号变现不再是梦
  • 微信支付工具包

    千次下载 热门讨论 2015-01-12 21:46:48
    本人微信支付代码中相关的工具包,方便大家结合我的博客更方便的测试成功。
  • 要实现微信支付要满足几个条件: 一、有一个服务号,菜单栏里面有微信支付菜单的公众号 二、需要开通商户号
  • 微信支付之原路退款

    万次阅读 2018-05-10 17:06:31
    1.场景还原 最近项目要求上线微信支付原路退款功能,今天笔者就微信支付原路退款的流程梳理下,方便有需要的伙伴借阅2.准备工作①获取微信支付的相关配置WECHATPAY_PARTNER = "150xxxxxxx"; //商户号 ...
  • 安卓实现微信支付,怎么调不出微信支付的页面。 目前没有请求后台 只是测试 微信支付测试demo需要哪些条件
  • JavaEE项目接入H5微信支付WAPJava项目接入H5微信支付开发环境前期准备准备过程申请微信公众平台及微信支付准备内网穿透域名微信支付开发配置撸代码部分重要pom文件前端代码微信支付统一下单Controller支付成功后接收...
  • 集成微信支付的时候会遇到很多问题,此文章只介绍处理【能调启微信为何调启不了微信支付】问题。 1、微信能调启来,说明你的集成已经成功。但还是注意商户的微信id是否统一,因为在调启支付接口的时候需要注册微信...
  • 一、对于微信支付(引入微信支付类) 由于微信支付文件比较多,一个文件可能有很多类,所以使用Tp框架的时候 使用Vendor()来引入第三方的类库 该微信支付类文件放在ThinkPHP\Library\Vendor目录下: 引入方法:...
  • 微信小程序微信支付

    千次阅读 多人点赞 2018-07-24 18:10:51
    - -微信支付之小程序- - 哈喽 我是你们的KingYiFan,一直说把微信支付给分享出来一直没有机会。终于闲下来了。听着音乐给你们分享一下。不懂可以随时联系我。。 -~~ 本文介绍小程序微信支付的java服务端~~。 ...
  • 用户的账户里面有余额但是不足,需要剩余的部分调用微信支付来完成,而微信支付需要等待异步的通知才知道是否成功,现在的问题是用户的余额何时扣除,如果通知前扣除,在支付失败的情况怎么处理,要是在通知的时候...
  • Android的Webview中H5支付调起微信支付

    万次阅读 热门讨论 2017-08-14 15:21:55
    之前在app中集成过微信支付,此种微信支付方式为app支付,即在我们自己的应用中嵌入微信支付SDK,由Native代码调起微信支付。 后来由于业务需要在我们app的WebView中打开自己的网页版商城的网页,在商城网页中有...
  • Vue微信网页微信支付

    2020-10-15 11:01:59
    基于Vue框架的微信网页进行微信支付导语一、微信后台配置接口1.配置微信支付的合法地址2.配置JS接口安全域名二、安装微信SDK依赖1.安装2.在需要的页面导入三、在页面中配置SDK四、使用微信支付接口 导语 作为一个先...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 39,929
精华内容 15,971
关键字:

微信支付