java开发微信公众号支付

最近做了微信公众号支付的开发,由于是第一次做也摸索了几天的时间,也只是达到了实现功能的水平,并没有太多考虑到性能问题,所以这篇文章比较适合初学者。

    微信公众号支付的总体其实很简单,大致就分为三步。第一步需要获取用户授权;第二步调用统一下单接口获取预支付id;第三步H5调起微信支付的内置的js。下面介绍具体每一步的开发流程。

一    首先要明确微信公众号支付属于网页版支付,所以相较于app的直接调取微信支付要多一步微信授权。也就是需要获取用户的openid。微信公众号使用的交易类型是JSAPI,所以统一下单接口的文档明确的写到

因此我们必须去获取openid,同时也可以处理一些我们需要的逻辑。获取用户授权有两种方式:1.scope=snsapi_base;2.scope=snsapi_userinfo.我使用的是snsapi_base

Scope为snsapi_base

https://open.weixin.qq.com/connect/oauth2/authorize?appid=wx520c15f417810387&redirect_uri=http%3A%2F%2Fchong.qq.com%2Fphp%2Findex.php%3Fd%3D%26c%3DwxAdapter%26m%3DmobileDeal%26showwxpaytitle%3D1%26vb2ctag%3D4_2030_5_1194_60&response_type=code&scope=snsapi_base&state=123#wechat_redirect

Scope为snsapi_userinfo

https://open.weixin.qq.com/connect/oauth2/authorize?appid=wxf0e81c3bee622d60&redirect_uri=http%3A%2F%2Fnba.bluewebgame.com%2Foauth_response.php&response_type=code&scope=snsapi_userinfo&state=STATE#wechat_redirect

微信的官方文档也有对各个参数的详细说明,我就关键的参数仔细的说明一下。首先appid就不多说了就是你微信公众号的appid固定写死的,redirect_uri这个参数是最重要的,这个地址是访问你处理的接口地址。你可以在这个链接上拼接上你所需要的参数,一般你是要把订单的金额传到这个接口里的,访问这个链接的时候微信会给你code你需要用它去获取openid,记得要对其进行urlencode处理。state参数可以理解为扩展字段,其他的参数都是固定写法就不在多做介绍了。下面是获取openid的代码片段。

?
1
2
3
4
5
6
7
8
9
10
//获取openId
             HttpClientUtil util = HttpClientUtil.getInstance();
             Map<String, String> map = new HashMap<String, String>();
             map.put( "appid" , WxPayConfig.APPID);
             map.put( "secret" , WxPayConfig.APPSECRET);
             map.put( "code" , code);
             map.put( "grant_type" , WxPayConfig.GRANT_TYPE);
             String returnStr = util.doPostRetString( "https://api.weixin.qq.com/sns/oauth2/access_token" , null ,map);
             logger.info( "returnStr:[" + returnStr + "]" );
             AccessToken at = JSON.parseObject(returnStr, AccessToken. class );

AccessToken.java

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
public class AccessToken {
    
   private String access_token;
   private String expires_in;
   private String refresh_token;
   private String openid;
   private String scope;
   private String unionid;
    
   public String getAccess_token() {
     return access_token;
   }
   public void setAccess_token(String access_token) {
     this .access_token = access_token;
   }
   public String getExpires_in() {
     return expires_in;
   }
   public void setExpires_in(String expires_in) {
     this .expires_in = expires_in;
   }
   public String getRefresh_token() {
     return refresh_token;
   }
   public void setRefresh_token(String refresh_token) {
     this .refresh_token = refresh_token;
   }
   public String getOpenid() {
     return openid;
   }
   public void setOpenid(String openid) {
     this .openid = openid;
   }
   public String getScope() {
     return scope;
   }
   public void setScope(String scope) {
     this .scope = scope;
   }
   public String getUnionid() {
     return unionid;
   }
   public void setUnionid(String unionid) {
     this .unionid = unionid;
   }
   @Override
   public String toString() {
     return "AccessToken [access_token=" + access_token + ", expires_in="
         + expires_in + ", refresh_token=" + refresh_token + ", openid="
         + openid + ", scope=" + scope + ", unionid=" + unionid + "]" ;
   }
    
    
  
}

二    我们获取了openid后,就可以进行下一步的统一下单的开发了。微信上统一下单接口的文档写的比较详细了,具体的参数含义我就不多做介绍了。下面直接贴最直观的代码,特别提醒的是一定要注意签名的正确。签名所使用的key并不是AppSecret而是你申请时自己定义的商户key。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
//统一下单
  
             WxPaySendData data = new WxPaySendData();
             data.setAppid(WxPayConfig.APPID);
             data.setAttach( "微信支付" );
             data.setBody( "微信公众号支付" );
             data.setMch_id(WxPayConfig.MCHID);
             data.setNonce_str(nonceStr);
             data.setNotify_url(WxPayConfig.NOTIFY_URL);
             data.setOut_trade_no(tradeNo);
             data.setTotal_fee(( int )(fee* 100 )); //单位:分
             data.setTrade_type( "JSAPI" );
             data.setSpbill_create_ip(ip);
             data.setOpenid(at.getOpenid());
             String returnXml = UnifiedorderService.unifiedOrder(data,WxPayConfig.KEY);
             WxPayReturnData reData = new WxPayReturnData();
             XStream xs1 = new XStream( new DomDriver());
             xs1.alias( "xml" , WxPayReturnData. class );
             reData = (WxPayReturnData) xs1.fromXML(returnXml);

UnifiedorderService.java

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
public class UnifiedorderService {
    
   private final static Logger logger = LoggerFactory.getLogger(UnifiedorderService. class );
    
   public static String unifiedOrder(WxPaySendData data,String key){
     //统一下单支付
     String returnXml = null ;
     try {
       //生成sign签名
       SortedMap<Object,Object> parameters = new TreeMap<Object,Object>();
       parameters.put( "appid" , data.getAppid());
       parameters.put( "attach" , data.getAttach());
       parameters.put( "body" , data.getBody());
       parameters.put( "mch_id" , data.getMch_id());
       parameters.put( "nonce_str" , data.getNonce_str());
       parameters.put( "notify_url" , data.getNotify_url());
       parameters.put( "out_trade_no" , data.getOut_trade_no());
       parameters.put( "total_fee" , data.getTotal_fee());
       parameters.put( "trade_type" , data.getTrade_type());
       parameters.put( "spbill_create_ip" , data.getSpbill_create_ip());
       parameters.put( "openid" , data.getOpenid());
       parameters.put( "device_info" , data.getDevice_info());
       logger.info( "SIGN:" +WxSign.createSign(parameters,key));
       data.setSign(WxSign.createSign(parameters,key));
       XStream xs = new XStream( new DomDriver( "UTF-8" , new XmlFriendlyNameCoder( "-_" , "_" )));
       xs.alias( "xml" , WxPaySendData. class );
       String xml = xs.toXML(data);
       logger.info( "统一下单xml为:\n" + xml);
       HttpClientUtil util = HttpClientUtil.getInstance();
       returnXml = util.doPostForString( "https://api.mch.weixin.qq.com/pay/unifiedorder" , null , xml);
       logger.info( "返回结果:" + returnXml);
     } catch (Exception e) {
       e.printStackTrace();
     }
     return returnXml;
   }
    
}

WxSign

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
public class WxSign {
    
    
   private static String characterEncoding = "UTF-8" ;
  
   @SuppressWarnings ( "rawtypes" )
   public static String createSign(SortedMap<Object,Object> parameters,String key){
     StringBuffer sb = new StringBuffer();
     Set es = parameters.entrySet(); //所有参与传参的参数按照accsii排序(升序)
     Iterator it = es.iterator();
     while (it.hasNext()) {
       Map.Entry entry = (Map.Entry)it.next();
       String k = (String)entry.getKey();
       Object v = entry.getValue();
       if ( null != v && ! "" .equals(v) 
           && ! "sign" .equals(k) && ! "key" .equals(k)) {
         sb.append(k + "=" + v + "&" );
       }
     }
     sb.append( "key=" + key);
     String sign = MD5Util.MD5Encode(sb.toString(), characterEncoding).toUpperCase();
     return sign;
   }
    
   public static String getNonceStr() {
     Random random = new Random();
     return MD5Util.MD5Encode(String.valueOf(random.nextInt( 10000 )), "UTF-8" );
   }
  
   public static String getTimeStamp() {
     return String.valueOf(System.currentTimeMillis() / 1000 );
   }
  
}

最后要提一下的是NOTIFY_URL回调地址,接收微信支付异步通知回调地址。

三    通过上面的操作我们获得了预支付交易会话标识prepay_id,这样我们就可以进行最后一步的操作了。使用H5调起支付api。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
//H5调起支付
               attr.addAttribute( "appId" , reData.getAppid());
               attr.addAttribute( "timeStamp" , WxSign.getTimeStamp());
               attr.addAttribute( "nonceStr" , reData.getNonce_str());
               attr.addAttribute( "package" , "prepay_id=" +reData.getPrepay_id());
               attr.addAttribute( "signType" , "MD5" );
               SortedMap<Object,Object> signMap = new TreeMap<Object,Object>();
               signMap.put( "appId" , reData.getAppid());
               signMap.put( "timeStamp" , WxSign.getTimeStamp());
               signMap.put( "nonceStr" , reData.getNonce_str());
               signMap.put( "package" , "prepay_id=" +reData.getPrepay_id());
               signMap.put( "signType" , "MD5" );
               logger.info( "PaySIGN:" +WxSign.createSign(signMap,WxPayConfig.KEY));
               attr.addAttribute( "paySign" , WxSign.createSign(signMap,WxPayConfig.KEY));

将需要的参数传给页面后,使用微信提供方法调起支付。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
<script>
   function getUrlParam(name) {
     //构造一个含有目标参数的正则表达式对象
     var reg = new RegExp( "(^|&)" + name + "=([^&]*)(&|$)" );
     //匹配目标参数
     var r = window.location.search.substr(1).match(reg);
     //返回参数值
     if (r != null )
       return unescape(r[2]);
     return null ;
   }
  
   function onBridgeReady() {
     var appId = getUrlParam( 'appId' );
     var timeStamp = getUrlParam( 'timeStamp' );
     var nonceStr = getUrlParam( 'nonceStr' );
     var Package = getUrlParam( 'package' );
     var signType = getUrlParam( 'signType' );
     var paySign = getUrlParam( 'paySign' );
     WeixinJSBridge.invoke( 'getBrandWCPayRequest' , {
       "appId" : appId, //"wx2421b1c4370ec43b", //公众号名称,由商户传入  
       "timeStamp" : timeStamp, //"1395712654", //时间戳,自1970年以来的秒数  
       "nonceStr" : nonceStr, //"e61463f8efa94090b1f366cccfbbb444", //随机串  
       "package" : Package, //"prepay_id=u802345jgfjsdfgsdg888",
       "signType" : signType, //"MD5", //微信签名方式:  
       "paySign" : paySign, //"70EA570631E4BB79628FBCA90534C63FF7FADD89" //微信签名
     }, function (res) { // 使用以上方式判断前端返回,微信团队郑重提示:res.err_msg将在用户支付成功后返回  ok,但并不保证它绝对可靠。 
       //alert(res.err_msg);
       if (res.err_msg == "get_brand_wcpay_request:ok" ) {
         alert( "支付成功" );
       }
       if (res.err_msg == "get_brand_wcpay_request:cancel" ) {
         alert( "交易取消" );
       }
       if (res.err_msg == "get_brand_wcpay_request:fail" ) {
         alert( "支付失败" );
       }
     });
   }
  
   function callPay() {
     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();
     }
   }
</script>

在返回结果的地方可以自定义一些自己的返回页面。

    总结:由于我也是第一次做,写这篇文章是想记录一下自己的工作成果,和分享给一下也是新手的朋友们可以有一些帮助,最后希望有好的见解朋友可以留言讨论,大家一起学习进步。

以上就是关于java开发微信公众支付的所有内容了,希望大家能够喜欢。

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值