写这篇文章的目的有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。

  1. <a href="https://open.weixin.qq.com/connect/oauth2/authorize?appid=wx15c*********&redirect_uri=http%3a%2f%2fwww.***.com%2fpay.jsp&response_type=code&cope=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结果为:

  1. { "access_token":"ACCESS_TOKEN",
  2.  
  3. "expires_in":7200,
  4.  
  5. "refresh_token":"REFRESH_TOKEN",
  6.  
  7. "openid":"OPENID",//就是它,只要这个值
  8.  
  9. "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的字符串:

  1. <xml>
  2.  
  3. <return_code><![CDATA[SUCCESS]]></return_code>
  4.  
  5. <return_msg><![CDATA[OK]]></return_msg>
  6.  
  7. <appid><![CDATA[wx2421b1c4370ec43b]]></appid>
  8.  
  9. <mch_id><![CDATA[10000100]]></mch_id>
  10.  
  11. <nonce_str><![CDATA[IITRi8Iabbblz1Jc]]></nonce_str>
  12.  
  13. <openid><![CDATA[oUpF8uMuAJO_M2pxb1Q9zNjWeS6o]]></openid>
  14.  
  15. <sign><![CDATA[7921E432F65EB8ED0CE9755F0E86D72F]]></sign>
  16.  
  17. <result_code><![CDATA[SUCCESS]]></result_code>
  18.  
  19. <prepay_id><![CDATA[wx201411101639507cbf6ffd8b0779950874]]></prepay_id>
  20.  
  21. <trade_type><![CDATA[JSAPI]]></trade_type>
  22.  
  23. </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方法可以修改),其它内容不要修改

  1. <!—pay.jsp中点击”微信支付”按钮执行pay()方法>
  2.  
  3. <input id="code"type="button" value="微信支付"onclick="pay()" code="${param.code }"/>
  4.  
  5. <script type="text/javascript">
  6.  
  7. var appId,timeStamp,nonceStr,package,signType,paySign;
  8.  
  9. function pay(){
  10.  
  11. var code = $("#code").attr("code");//页面链接上的code参数
  12.  
  13. if(code){
  14.  
  15. var url = "http://异步地址?code="+code+";
  16.  
  17. $.get(url,function(result) {
  18.  
  19. appId = result.appId;
  20.  
  21. timeStamp = result.timeStamp;
  22.  
  23. nonceStr = result.nonceStr;
  24.  
  25. package = result.package;
  26.  
  27. signType = result.signType;
  28.  
  29. paySign = result.paySign;
  30.  
  31. if (typeof WeixinJSBridge == "undefined") {
  32.  
  33. if (document.addEventListener) {
  34.  
  35. document.addEventListener('WeixinJSBridgeReady',
  36.  
  37. onBridgeReady, false);
  38.  
  39. } else if (document.attachEvent) {
  40.  
  41. document.attachEvent('WeixinJSBridgeReady',
  42.  
  43. onBridgeReady);
  44.  
  45. document.attachEvent('onWeixinJSBridgeReady',
  46.  
  47. onBridgeReady);
  48.  
  49. }
  50.  
  51. } else {
  52.  
  53. onBridgeReady();
  54.  
  55. }
  56.  
  57. });
  58.  
  59. } else {
  60.  
  61. alert(“服务器错误”)
  62.  
  63. }
  64.  
  65. }
  66.  
  67. function onBridgeReady(){
  68.  
  69. WeixinJSBridge.invoke( 'getBrandWCPayRequest', {
  70.  
  71. "appId":appId, //公众号名称,由商户传入
  72.  
  73. "timeStamp":timeStamp, //时间戳,自1970年以来的秒数
  74.  
  75. "nonceStr":nonceStr, //随机串
  76.  
  77. "package":package,
  78.  
  79. "signType":signType, //微信签名方式:
  80.  
  81. "paySign":paySign //微信签名
  82.  
  83. },
  84.  
  85. function(res){
  86.  
  87. if(res.err_msg == "get_brand_wcpay_request:ok" ) {
  88.  
  89. console.log('支付成功');
  90.  
  91. //支付成功后跳转的页面
  92.  
  93. }else if(res.err_msg == "get_brand_wcpay_request:cancel"){
  94.  
  95. console.log('支付取消');
  96.  
  97. }else if(res.err_msg == "get_brand_wcpay_request:fail"){
  98.  
  99. console.log('支付失败');
  100.  
  101. WeixinJSBridge.call('closeWindow');
  102.  
  103. } //使用以上方式判断前端返回,微信团队郑重提示:res.err_msg将在用户支付成功后返回ok,但并不保证它绝对可靠。
  104.  
  105. });
  106.  
  107. }
  108.  
  109. </script>

以下是后台部分

  1. /**
  2.  
  3. * @Description 微信浏览器内微信支付/公众号支付(JSAPI)
  4.  
  5. * @param request
  6.  
  7. * @param code
  8.  
  9. * @return Map
  10.  
  11. */
  12.  
  13. @RequestMapping(value="orders", method = RequestMethod.GET)
  14.  
  15. @ResponseBody
  16.  
  17. public Map orders(HttpServletRequest request,String code) {
  18.  
  19. try {
  20.  
  21. //页面获取openId接口
  22.  
  23. String getopenid_url = https://api.weixin.qq.com/sns/oauth2/access_token;
  24.  
  25. String param=
  26.  
  27. "appid="+你appid+"&secret="+你secret+"&code="+code+"&grant_type=authorization_code";
  28.  
  29. //向微信服务器发送get请求获取openIdStr
  30.  
  31. String openIdStr = HttpRequest.sendGet(getopenid_url, param);
  32.  
  33. JSONObject json = JSONObject.parseObject(openIdStr);//转成Json格式
  34.  
  35. String openId = json.getString("openid");//获取openId
  36.  
  37. //拼接统一下单地址参数
  38.  
  39. Map<String, String> paraMap = new HashMap<String, String>();
  40.  
  41. //获取请求ip地址
  42.  
  43. String ip = request.getHeader("x-forwarded-for");
  44.  
  45. if(ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)){
  46.  
  47. ip = request.getHeader("Proxy-Client-IP");
  48.  
  49. }
  50.  
  51. if(ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)){
  52.  
  53. ip = request.getHeader("WL-Proxy-Client-IP");
  54.  
  55. }
  56.  
  57. if(ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)){
  58.  
  59. ip = request.getRemoteAddr();
  60.  
  61. }
  62.  
  63. if(ip.indexOf(",")!=-1){
  64.  
  65. String[] ips = ip.split(",");
  66.  
  67. ip = ips[0].trim();
  68.  
  69. }
  70.  
  71. paraMap.put("appid", appid);
  72.  
  73. paraMap.put("body", "尧舜商城-订单结算");
  74.  
  75. paraMap.put("mch_id", mchId);
  76.  
  77. paraMap.put("nonce_str", WXPayUtil.generateNonceStr());
  78.  
  79. paraMap.put("openid", openId);
  80.  
  81. paraMap.put("out_trade_no", 你的订单号);//订单号
  82.  
  83. paraMap.put("spbill_create_ip", ip);
  84.  
  85. paraMap.put("total_fee",”1”);
  86.  
  87. paraMap.put("trade_type", "JSAPI");
  88.  
  89. paraMap.put("notify_url",www.*******.com/***/**);// 此路径是微信服务器调用支付结果通知路径随意写
  90.  
  91. String sign = WXPayUtil.generateSignature(paraMap, paternerKey);
  92.  
  93. paraMap.put("sign", sign);
  94.  
  95. String xml = WXPayUtil.mapToXml(paraMap);//将所有参数(map)转xml格式
  96.  
  97. // 统一下单 https://api.mch.weixin.qq.com/pay/unifiedorder
  98.  
  99. String unifiedorder_url = https://api.mch.weixin.qq.com/pay/unifiedorder;
  100.  
  101. String xmlStr = HttpRequest.sendPost(unifiedorder_url, xml);//发送post请求"统一下单接口"返回预支付id:prepay_id
  102.  
  103. //以下内容是返回前端页面的json数据
  104.  
  105. String prepay_id = "";//预支付id
  106.  
  107. if (xmlStr.indexOf("SUCCESS") != -1) {
  108.  
  109. Map<String, String> map = WXPayUtil.xmlToMap(xmlStr);
  110.  
  111. prepay_id = (String) map.get("prepay_id");
  112.  
  113. }
  114.  
  115. Map<String, String> payMap = new HashMap<String, String>();
  116.  
  117. payMap.put("appId", appid);
  118.  
  119. payMap.put("timeStamp", WXPayUtil.getCurrentTimestamp()+"");
  120.  
  121. payMap.put("nonceStr", WXPayUtil.generateNonceStr());
  122.  
  123. payMap.put("signType", "MD5");
  124.  
  125. payMap.put("package", "prepay_id=" + prepay_id);
  126.  
  127. String paySign = WXPayUtil.generateSignature(payMap, paternerKey);
  128.  
  129. payMap.put("paySign", paySign);
  130.  
  131. return payMap;
  132.  
  133. } catch (Exception e) {
  134.  
  135. e.printStackTrace();
  136.  
  137. }
  138.  
  139. return null;
  140.  
  141. }

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

  1. import java.io.BufferedReader;
  2.  
  3. import java.io.IOException;
  4.  
  5. import java.io.InputStreamReader;
  6.  
  7. import java.io.PrintWriter;
  8.  
  9. import java.net.URL;
  10.  
  11. import java.net.URLConnection;
  12.  
  13. import java.util.List;
  14.  
  15. import java.util.Map;
  16.  
  17. public class HttpRequest {
  18.  
  19. /**
  20.  
  21. * 向指定URL发送GET方法的请求
  22.  
  23. *
  24.  
  25. * @param url
  26.  
  27. * 发送请求的URL
  28.  
  29. * @param param
  30.  
  31. * 请求参数,请求参数应该是 name1=value1&name2=value2 的形式。
  32.  
  33. * @return URL 所代表远程资源的响应结果
  34.  
  35. */
  36.  
  37. public static String sendGet(String url, String param) {
  38.  
  39. String result = "";
  40.  
  41. BufferedReader in = null;
  42.  
  43. try {
  44.  
  45. String urlNameString = url + "?" + param;
  46.  
  47. System.out.println(urlNameString);
  48.  
  49. URL realUrl = new URL(urlNameString);
  50.  
  51. // 打开和URL之间的连接
  52.  
  53. URLConnection connection = realUrl.openConnection();
  54.  
  55. // 设置通用的请求属性
  56.  
  57. connection.setRequestProperty("accept", "*/*");
  58.  
  59. connection.setRequestProperty("connection", "Keep-Alive");
  60.  
  61. connection.setRequestProperty("user-agent",
  62.  
  63. "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)");
  64.  
  65. // 建立实际的连接
  66.  
  67. connection.connect();
  68.  
  69. // 获取所有响应头字段
  70.  
  71. Map<String, List<String>> map = connection.getHeaderFields();
  72.  
  73. // 遍历所有的响应头字段
  74.  
  75. for (String key : map.keySet()) {
  76.  
  77. System.out.println(key + "--->" + map.get(key));
  78.  
  79. }
  80.  
  81. // 定义 BufferedReader输入流来读取URL的响应
  82.  
  83. in = new BufferedReader(new InputStreamReader(
  84.  
  85. connection.getInputStream()));
  86.  
  87. String line;
  88.  
  89. while ((line = in.readLine()) != null) {
  90.  
  91. result += line;
  92.  
  93. }
  94.  
  95. } catch (Exception e) {
  96.  
  97. System.out.println("发送GET请求出现异常!" + e);
  98.  
  99. e.printStackTrace();
  100.  
  101. }
  102.  
  103. // 使用finally块来关闭输入流
  104.  
  105. finally {
  106.  
  107. try {
  108.  
  109. if (in != null) {
  110.  
  111. in.close();
  112.  
  113. }
  114.  
  115. } catch (Exception e2) {
  116.  
  117. e2.printStackTrace();
  118.  
  119. }
  120.  
  121. }
  122.  
  123. return result;
  124.  
  125. }
  126.  
  127. /**
  128.  
  129. * 向指定 URL 发送POST方法的请求
  130.  
  131. *
  132.  
  133. * @param url
  134.  
  135. * 发送请求的 URL
  136.  
  137. * @param param
  138.  
  139. * 请求参数,请求参数应该是 name1=value1&name2=value2 的形式。
  140.  
  141. * @return 所代表远程资源的响应结果
  142.  
  143. */
  144.  
  145. public static String sendPost(String url, String param) {
  146.  
  147. PrintWriter out = null;
  148.  
  149. BufferedReader in = null;
  150.  
  151. String result = "";
  152.  
  153. try {
  154.  
  155. URL realUrl = new URL(url);
  156.  
  157. // 打开和URL之间的连接
  158.  
  159. URLConnection conn = realUrl.openConnection();
  160.  
  161. // 设置通用的请求属性
  162.  
  163. conn.setRequestProperty("accept", "*/*");
  164.  
  165. conn.setRequestProperty("connection", "Keep-Alive");
  166.  
  167. conn.setRequestProperty("user-agent",
  168.  
  169. "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)");
  170.  
  171. // 发送POST请求必须设置如下两行
  172.  
  173. conn.setDoOutput(true);
  174.  
  175. conn.setDoInput(true);
  176.  
  177. // 获取URLConnection对象对应的输出流
  178.  
  179. out = new PrintWriter(conn.getOutputStream());
  180.  
  181. // 发送请求参数
  182.  
  183. out.print(param);
  184.  
  185. // flush输出流的缓冲
  186.  
  187. out.flush();
  188.  
  189. // 定义BufferedReader输入流来读取URL的响应
  190.  
  191. in = new BufferedReader(
  192.  
  193. new InputStreamReader(conn.getInputStream()));
  194.  
  195. String line;
  196.  
  197. while ((line = in.readLine()) != null) {
  198.  
  199. result += line;
  200.  
  201. }
  202.  
  203. } catch (Exception e) {
  204.  
  205. System.out.println("发送 POST 请求出现异常!"+e);
  206.  
  207. e.printStackTrace();
  208.  
  209. }
  210.  
  211. //使用finally块来关闭输出流、输入流
  212.  
  213. finally{
  214.  
  215. try{
  216.  
  217. if(out!=null){
  218.  
  219. out.close();
  220.  
  221. }
  222.  
  223. if(in!=null){
  224.  
  225. in.close();
  226.  
  227. }
  228.  
  229. }
  230.  
  231. catch(IOException ex){
  232.  
  233. ex.printStackTrace();
  234.  
  235. }
  236.  
  237. }
  238.  
  239. return result;
  240.  
  241. }
  242.  
  243. }

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

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

  1. /**
  2.  
  3. * @ClassName WxPayController
  4.  
  5. * @Description 微信支付成功后回调次接口
  6.  
  7. * @author wtao wangtao@eyaoshun.com
  8.  
  9. * @date 2018年1月11日 下午3:10:59
  10.  
  11. */
  12.  
  13. //回调路径是自己在之前已经填写过的
  14.  
  15. @RequestMapping("/pay/")
  16.  
  17. @Controller
  18.  
  19. public class WxPayController {
  20.  
  21. @Autowired
  22.  
  23. private OrdersService ordersService;
  24.  
  25. @Autowired
  26.  
  27. private AccountService accountService;
  28.  
  29. @Autowired
  30.  
  31. private PointService pointService;
  32.  
  33. @RequestMapping("callback")
  34.  
  35. public String callBack(HttpServletRequest request,HttpServletResponse response){
  36.  
  37. //System.out.println("微信支付成功,微信发送的callback信息,请注意修改订单信息");
  38.  
  39. InputStream is = null;
  40.  
  41. try {
  42.  
  43. is = request.getInputStream();//获取请求的流信息(这里是微信发的xml格式所有只能使用流来读)
  44.  
  45. String xml = WXPayUtil.inputStream2String(is, "UTF-8");
  46.  
  47. Map<String, String> notifyMap = WXPayUtil.xmlToMap(xml);//将微信发的xml转map
  48.  
  49. if(notifyMap.get("return_code").equals("SUCCESS")){
  50.  
  51. if(notifyMap.get("result_code").equals("SUCCESS")){
  52.  
  53. String ordersSn = notifyMap.get("out_trade_no");//商户订单号
  54.  
  55. String amountpaid = notifyMap.get("total_fee");//实际支付的订单金额:单位 分
  56.  
  57. BigDecimal amountPay = (new BigDecimal(amountpaid).divide(new BigDecimal("100"))).setScale(2);//将分转换成元-实际支付金额:元
  58.  
  59. //String openid = notifyMap.get("openid"); //如果有需要可以获取
  60.  
  61. //String trade_type = notifyMap.get("trade_type");
  62.  
  63. /*以下是自己的业务处理------仅做参考
  64.  
  65. * 更新order对应字段/已支付金额/状态码
  66.  
  67. */
  68.  
  69. Orders order = ordersService.selectOrdersBySn(ordersSn);
  70.  
  71. if(order != null) {
  72.  
  73. order.setLastmodifieddate(new Date());
  74.  
  75. order.setVersion(order.getVersion().add(BigDecimal.ONE));
  76.  
  77. order.setAmountpaid(amountPay);//已支付金额
  78.  
  79. order.setStatus(2L);//修改订单状态为待发货
  80.  
  81. int num = ordersService.updateOrders(order);//更新order
  82.  
  83. String amount = amountPay.setScale(0, BigDecimal.ROUND_FLOOR).toString();//实际支付金额向下取整-123.23--123
  84.  
  85. /*
  86.  
  87. * 更新用户经验值
  88.  
  89. */
  90.  
  91. Member member = accountService.findObjectById(order.getMemberId());
  92.  
  93. accountService.updateMemberByGrowth(amount, member);
  94.  
  95. /*
  96.  
  97. * 添加用户积分数及添加积分记录表记录
  98.  
  99. */
  100.  
  101. pointService.updateMemberPointAndLog(amount, member, "购买商品,订单号为:"+ordersSn);
  102.  
  103. }
  104.  
  105. }
  106.  
  107. }
  108.  
  109. //告诉微信服务器收到信息了,不要在调用回调action了========这里很重要回复微信服务器信息用流发送一个xml即可
  110.  
  111. response.getWriter().write("<xml><return_code><![CDATA[SUCCESS]]></return_code></xml>");
  112.  
  113. is.close();
  114.  
  115. } catch (Exception e) {
  116.  
  117. e.printStackTrace();
  118.  
  119. }
  120.  
  121. return null;
  122.  
  123. }
  124.  
  125. }

声明:此文章为转载文章

JAVA开发微信支付-公众号支付/微信浏览器支付(JSAPI)的更多相关文章

  1. JAVA版开源微信管家—JeeWx捷微3.2版本发布,支持微信公众号,微信企业号,支付窗、小程序

    JeeWx捷微3.2微信企业号升级版本发布^_^ JeeWx捷微V3.2——多触点管理平台(支持微信公众号,微信企业号,支付窗.小程序)   JeeWx捷微V3.2.0版本引入了更多新特性,支持微信公 ...

  2. JeeWx捷微3.1小程序版本发布,支持微信公众号,微信企业号,支付窗——JAVA版开源微信管家

    支持小程序,JeeWx捷微3.1小程序版本发布^_^ JeeWx捷微V3.1——多触点小程序版本管理平台(支持微信公众号,微信企业号,支付窗)   JeeWx捷微V3.1.0版本紧跟微信小程序更新,在 ...

  3. JAVA版开源微信管家—JeeWx捷微3.1小程序版本发布,支持微信公众号,微信企业号,支付窗

    支持小程序,JeeWx捷微3.1小程序版本发布^_^ JeeWx捷微V3.1--多触点小程序版本管理平台(支持微信公众号,微信企业号,支付窗) JeeWx捷微V3.1.0版本紧跟微信小程序更新,在原有 ...

  4. JAVA开源微信管家平台——JeeWx捷微V3.3版本发布(支持微信公众号,微信企业号,支付窗)

    JeeWx捷微V3.3版本紧跟微信小程序更新,在原有多触点版本基础上,引入了更多的新亮点:支持微信公众号.微信企业号.支付宝服务窗等多触点开发:采用微服务框架实现,可插拔可集成,轻量级开发:对小程序的 ...

  5. 微信支付公众号支付redirect_uri域名与后台配置不一致,错误码10003

    最近弄微信支付,微信支付公众号支付redirect_uri域名与后台配置不一致,错误码10003,最容易出错两个地方 1,appid 对应不到 2,开发者网页授权 填写域名 文章来自http://ww ...

  6. 微信小程序的功能开发工具跟公众号的差别,小程序是一种减负思维对简单APP是巨大打击

    微信小程序的功能开发工具跟公众号的差别,小程序是一种减负思维对简单APP是巨大打击 摘要: 小程序和公众号最大的区别有如下四点:1.小程序没有粉丝,开发者在后台能看到的只能是累计用户访问数以及实时统计 ...

  7. atitit. access token是什么??微信平台公众号开发access_token and Web session保持状态机制

    atitit. access token是什么??微信平台公众号开发access_token and Web session保持状态机制 1. token机制and  session保持状态机制 1 ...

  8. 微信jsSDK公众号开发时网页提示 invalid signature错误的解决方法

    微信公众号开发jsSDK,链接地址不能加?参数,可以通过#传递参数. 不然.页面wx.ready()时就会报错,用 wx.error(function (res) { alert("接口验证 ...

  9. 微信公众号获取微信token

    微信在公众号和小程序的开发都有开放文档一般看文档开发就行,很简单这里写一个小demo获取微信token,之后根据自己的业务获取信息处理即可 package com.demo.ccx; import o ...

随机推荐

  1. CSS - 伪类和伪元素的区别

    伪类和伪元素皆独立于文档结构.它们获取元素的途径也不是基于id.class.属性这些基础的元素特征,而是在处于特殊状态的元素(伪类),或者是元素中特别的内容(伪元素).区别总结如下: CSS伪类 (P ...

  2. ANT DESIGN PRO 脚手架.... 懒人福音

    早上在用蚂蚁组件,看到一个红红的 PRO , 什么鬼,点了看. https://pro.ant.design/index-cn 一脸懵逼, 中台前端??? 预览再看: 后台管理的demo , 脚手架  ...

  3. 润乾V4报表批量打印

     背景说明 在应用中,经常遇到,批量打印的需求,批量打印,顾名思义,就是点击一次打印按钮,能打印多张报表. 下面,我们来介绍一下怎么样实现批量打印的 应用举例: Jsp代码 <% //rep ...

  4. CSS3 响应式web设计,CSS3 Media Queries

    两种方式,一种是直接在link中判断设备的尺寸,然后引用不同的css文件: <link rel="stylesheet" type="text/css" ...

  5. javascript event visualize

    很多时候拿到一个spa,特别是基于jquery的比较复杂的spa时,如果你好奇他是如何工作的,往往没有头绪. 由于spa基本上都是基于事件触发的,一个可行的办法是通过查看事件处理代码能够对spa有一个 ...

  6. 关于3d打印

    3d打印技术是20世纪90年代逐渐兴起的一项先进的制造技术.3D打印——three-dimensional printing,简称3dp.又称三维打印或立体打印,最早由美国麻省理工学院于1993年开发 ...

  7. Oracle EBS 更新客户地点

    --更新客户地点 declare x_return_status ); x_msg_count NUMBER; x_msg_data ); x_profile_id NUMBER; l_locatio ...

  8. bat把npm换成淘宝源

    @echo off echo 开始.. npm config set registry http://registry.npm.taobao.org/ && npm install 注 ...

  9. UML建模中简单消息、同步消息和异步消息

    两种消息在UML图中的表示方法如图: 1.同步方式 两个通信应用服务之间必须要进行同步,两个服务之间必须都是正常运行的.发送程序和接收程序都必须一直处于运行状态,并且随时做好相互通信的准备. 发送程序 ...

  10. 转:asp.net 中的viewstate

    概述 ViewState是一个被误解很深的动物了.我希望通过此文章来澄清人们对ViewState的一些错误认识.为了达到这个目的,我决定从头到尾详细的描述一下整个ViewState的工作机制,其中我会 ...