zl程序教程

您现在的位置是:首页 >  后端

当前栏目

微信支付Java开发服务端详解编程语言

JAVA微信编程语言开发 详解 支付 服务端
2023-06-13 09:20:41 时间

想要调用微信支付第一就是获取openid:
获取openid的方法:
首先你需要在前台获取到code,

在确保微信公众账号拥有授权作用域(scope参数)的权限的前提下(服务号获得高级接口后,默认拥有scope参数中的snsapi_base和snsapi_userinfo),引导关注者打开如下页面:
https://open.weixin.qq.com/connect/oauth2/authorize?appid=APPID redirect_uri=REDIRECT_URI response_type=code scope=SCOPE state=STATE#wechat_redirect
若提示“该链接无法访问”,请检查参数是否填写错误,是否拥有scope参数对应的授权作用域权限。

scope两种参数的说明:
1、以snsapi_base为scope发起的网页授权,是用来获取进入页面的用户的openid的,并且是静默授权并自动跳转到回调页的。用户感知的就是直接进入了回调页(往往是业务页面)
2、以snsapi_userinfo为scope发起的网页授权,是用来获取用户的基本信息的。但这种授权需要用户手动同意,并且由于用户同意过,所以无须关注,就可在授权后获取该用户的基本信息。
3、用户管理类接口中的“获取用户基本信息接口”,是在用户和公众号产生消息交互或关注后事件推送后,才能根据用户OpenID来获取用户基本信息。这个接口,包括其他微信接口,都是需要该用户(即openid)关注了公众号后,才能调用成功的。

在公众号的自定义菜单中设置的url为
https://open.weixin.qq.com/connect/oauth2/authorize?appid=APPID redirect_uri=URL response_type=code scope=snsapi_userinfo state=STATE connect_redirect=1#wechat_redirect
其中APPID为公众号ID,URL是你要访问的网址,注意网页要进行URLEncoder编码。

如果用户同意授权,页面将跳转至 redirect_uri/?code=CODE state=STATE。若用户禁止授权,则重定向后不会带上code参数,仅会带上state参数redirect_uri?state=STATE

code说明 :
code作为换取access_token的票据,每次用户授权带上的code将不一样,code只能使用一次,5分钟未被使用自动过期。

这样在前台就可以直接获取到url当中的code值,

var code = getQueryString("code"); 

function getQueryString(name) { 

 var reg = new RegExp("(^| )" + name + "=([^ ]*)( |$)", "i"); 

 var r = window.location.search.substr(1).match(reg); 

 if (r != null) 

 return unescape(r[2]); 

 return null; 

 }

获取到了code的值后,就可以去请求openid了。
尤其注意:由于公众号的secret和获取到的access_token安全级别都非常高,必须只保存在服务器,不允许传给客户端。后续刷新access_token、通过access_token获取用户信息等步骤,也必须从服务器发起。

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

正确时返回的JSON数据包如下:

{
“access_token”:”ACCESS_TOKEN”,
“expires_in”:7200,
“refresh_token”:”REFRESH_TOKEN”,
“openid”:”OPENID”,
“scope”:”SCOPE”
}

这样就获取到了access_token和openid了。
有了openid,我们就可以去获取到pre_id。
获取pre_id的接口地址为:https://api.mch.weixin.qq.com/pay/unifiedorder

请求参数详见微信支付官方文档
https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=9_1

其中注意attach参数,这个是附加数据,在查询API和支付通知中原样返回,可作为自定义参数使用。这个字段可以传我们的业务数据,用来后续的业务处理。

notify_url参数,这个回调地址一定要写外网能直接访问的地址(可以直接把网址放到浏览器上,看看是不是能直接访问),如果写内网地址是收不到回调信息的哦。

spbill_create_ip参数,这个参数笔者也不清楚应该怎么传,笔者就传的192.168.1.1,如果你们传这个不好使我要找我。

sign参数,详情见微信支付签名生成规则:
https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=4_3
其实微信给的demo中就有现成的sign生成方法
首先先把所有参数放入一个map中

public Map String, Object toMap() 

 Map String, Object map = new HashMap String, Object 

 Field[] fields = this.getClass().getDeclaredFields(); 

 for (Field field : fields) 

 Object obj; 

 try 

 obj = field.get(this); 

 if (obj != null) 

 map.put(field.getName(), obj); 

 catch (IllegalArgumentException e) 

 e.printStackTrace(); 

 catch (IllegalAccessException e) 

 e.printStackTrace(); 

 return map; 

String sign = Signature.getSign(toMap()); 

public static String getSign(Map String,Object map){ 

 ArrayList String list = new ArrayList String 

 for(Map.Entry String,Object entry:map.entrySet()){ 

 if(entry.getValue()!=""){ 

 list.add(entry.getKey() + "=" + entry.getValue() + " "); 

 int size = list.size(); 

 String [] arrayToSort = list.toArray(new String[size]); 

 Arrays.sort(arrayToSort, String.CASE_INSENSITIVE_ORDER); 

 StringBuilder sb = new StringBuilder(); 

 for(int i = 0; i size; i ++) { 

 sb.append(arrayToSort[i]); 

 String result = sb.toString(); 

 result += "key=" + Configure.getKey();//自己保管的私钥 

 //Util.log("Sign Before MD5:" + result); 

 result = MD5.MD5Encode(result).toUpperCase(); 

 //Util.log("Sign Result:" + result); 

 return result; 

 }

然后把这个sign放入参数中就可以啦。

请求成功后,微信会返回一段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 

这里提供一个把XML转换成Map的方法:

public static Map String,Object getMapFromXML(String xmlString) throws ParserConfigurationException, IOException, SAXException { 

 //这里用Dom的方式解析回包的最主要目的是防止API新增回包字段 

 DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); 

 DocumentBuilder builder = factory.newDocumentBuilder(); 

 InputStream is = Util.getStringStream(xmlString); 

 Document document = builder.parse(is); 

 //获取到document里面的全部结点 

 NodeList allNodes = document.getFirstChild().getChildNodes(); 

 Node node; 

 Map String, Object map = new HashMap String, Object (); 

 int i=0; 

 while (i allNodes.getLength()) { 

 node = allNodes.item(i); 

 if(node instanceof Element){ 

 map.put(node.getNodeName(),node.getTextContent()); 

 i++; 

 return map; 

 }

到这里我们拿到了prepay_id,这里顺便说一下,如果是扫码支付前面的trade_type参数为NATIVE,再返回的时候会有一个code_url,在前台直接用这个url生成二维码图片就可以了。

下面继续说公众号支付。
前台H5调用微信支付的参数说明见:
https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=7_7 index=6

这里什么时间戳,随机字符串最后在服务端生成再传到前台来。

String timestamp = Long.toString(System.currentTimeMillis() / 1000); // 必填,生成签名的时间戳 

String nonceStr = UUID.randomUUID().toString(); // 必填,生成签名的随机串 

注意package参数为prepay_id=PRERAY_ID一定要带上prepay_id=。
同时生成签名的时候也注意要带着prepay_id=,这块算个坑。

具体前台调起微信支付的代码直接复制微信文档

function onBridgeReady(){ 

 WeixinJSBridge.invoke( 

 getBrandWCPayRequest, { 

 "appId":"wx2421b1c4370ec43b", //公众号名称,由商户传入 

 "timeStamp":"1395712654", //时间戳,自1970年以来的秒数 

 "nonceStr":"e61463f8efa94090b1f366cccfbbb444", //随机串 

 "package":"prepay_id=u802345jgfjsdfgsdg888", 

 "signType":"MD5", //微信签名方式: 

 "paySign":"70EA570631E4BB79628FBCA90534C63FF7FADD89" //微信签名 

 function(res){ 

 if(res.err_msg == "get_brand_wcpay_request:ok" ) {} // 使用以上方式判断前端返回,微信团队郑重提示:res.err_msg将在用户支付成功后返回 ok,但并不保证它绝对可靠。 

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(); 

}

这里注意支付成功后那里的判断res.err_msg == “get_brand_wcpay_request:ok”,坑爹的是那里的:是中文的分号,我说回调咋一直都不进呢!!
还有补充,要注意在商户后台配置支付授权目录,否则支付页面是出不来的,我当时没配是一闪而过。

至此能够成功调起微信支付,支付成功后会向notify_url发送支付信息。例如:

 xml 

 appid ![CDATA[wx2421b1c4370ec43b]] /appid 

 attach ![CDATA[支付测试]] /attach 

 bank_type ![CDATA[CFT]] /bank_type 

 fee_type ![CDATA[CNY]] /fee_type 

 is_subscribe ![CDATA[Y]] /is_subscribe 

 mch_id ![CDATA[10000100]] /mch_id 

 nonce_str ![CDATA[5d2b6c2a8db53831f7eda20af46e531c]] /nonce_str 

 openid ![CDATA[oUpF8uMEb4qRXf22hE3X68TekukE]] /openid 

 out_trade_no ![CDATA[1409811653]] /out_trade_no 

 result_code ![CDATA[SUCCESS]] /result_code 

 return_code ![CDATA[SUCCESS]] /return_code 

 sign ![CDATA[B552ED6B279343CB493C5DD0D78AB241]] /sign 

 sub_mch_id ![CDATA[10000100]] /sub_mch_id 

 time_end ![CDATA[20140903131540]] /time_end 

 total_fee 1 /total_fee 

 trade_type ![CDATA[JSAPI]] /trade_type 

 transaction_id ![CDATA[1004400740201409030005092168]] /transaction_id 

 /xml 

具体参数说明见:https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=9_7
其中attach参数就是传输的业务数据,这样就可以进行业务处理了。

原创文章,作者:ItWorker,如若转载,请注明出处:https://blog.ytso.com/13978.html

cjavaphpxml