顺晟科技
2021-06-16 11:00:22
536
这两天做微信支付开发。碰到大坑。纠结死我了。好不容做完。
后台java:直接上代码:注意区分前后端的变量大小写。
@RequestMapping(值='/index ')
公共模型索引(@RequestParam(值='openid ',必需=true)字符串openid,模型模型,HttpServletRequest请求)引发异常{
伐木工人。信息(' * * * * * * * * * * * * * * *打开id * * * * * * * * * * * *为:'(OpenID);
//获取预付
MapString,String map=new HashMapString,String();
weixinchinging wcf=weixinchineservice。getweixinchinginig();
String nonceStr=UUID.randomUUID().toString().substring(0,32);
oauthService.shareFactory(请求);
string appid=wcf。getppid();
长时间戳=系统。CurrentiMemillis()/1000;
map.put('appid ',appid);
map.put('mch_id ',Webconfig。获得(支付。mch _ id ');
map.put('nonce_str ',non estr);
map.put('body ',webconfig。获得(支付。body’);
map.put('out_trade_no ',paywxutil。order num());
map.put('total_fee ',webconfig。获得(支付。价格');
map.put('spbill_create_ip ',请求。getremote addr());
map.put('notify_url ',webconfig。获取('主机地址')请求。getcontextpath()'/babyShow/payInfo/info ');
map.put('trade_type ',' JSAPI ');
map.put('openid ',open id);
字符串paySign=signutil。getpaycustomsign(地图,web配置。获得(支付。key’);
map.put('sign ',paySign);
String xml=CommonUtil .ArrayToXml(map);
id=paywxutil之前的字符串。getPredated id(XML);
伐木工人。信息('准备id * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *='先前的id);
//封装h5页面调用参数
MapString,String signMap=new HashMapString,String();
signMap.put('appId ',AppID);
伐木工人。信息(' AppID=' AppID);
标志地图。put(' TiMer ',TiMer ' ');
伐木工人。信息(' TiMer=' TiMer ');
signMap.put('package ','预付款_id='预付款);
伐木工人。信息(' package=' ' prevable _ id=' prevable id ');
signMap.put('signType ',' MD5 ');
伐木工人。信息(' SingType=' ' MD5 ');
标志地图。put('非estr ',非estr);
伐木工人。info(' non estr=' non estr);
模特。AddAttribute(' pay timestamp ',时间戳);
model.addAttribute('paypackage ','预付款_id='预付款);
模特。AddAttribute(' paynon estr ',non estr);
模特。AddAttribute(' paysignType ',' MD5 ');
string paysign 2=signutil。getpaycustomsign(签名映射,web配置。获得(支付。key’);
model.addAttribute('paySign ',paySign 2);
伐木工人。信息(' paySign=' paySign 2 ');
返回模型;
}
以上代码获取信息需要根据网页授权来获取。这里就不多讲了。主要讲讲获取预付和生成h5页面所需参数,
这里面比较麻烦的就是签名的获取
查看方法signutil。getpaycustomsign(SignMap,WebConfig.get('pay.key '))
代码如下
/**
* 获取支付所需签名
* @param票证
* @ param TiMer
* @param card_id
* @param代码
* @返回
* @引发异常
*/
公共静态字符串getPayCustomSign(映射字符串,字符串bizObj,字符串键)引发异常{
字符串bizString=CommonUtil .FormatBizQueryParaMap(bizObj,
false);
伐木工人。信息(BizString);
返回MD5SignUtil.sign(bizString,key);
}
其中CommonUtil .FormatBizQueryParaMap是用来做字典排序的。有参考了网上的例子。就没单独做。
公共静态字符串格式查询参数(映射字符串,字符串参数,
布尔urlencode)引发异常{
字符串缓冲=
尝试{
列表地图.输入字符串,字符串信息标识=新数组映射.输入字符串(
帕拉马普。entry set());
集合。排序(信息标识,
新的比较地图EntryString,String() {
公共整数比较(映射输入字符串o1,
地图EntryString,String o2) {
return (o1.getKey()).toString().compareTo(
O2。getKey());
}
});
for(int I=0;我InfoIdS。size();i ) {
地图输入字符串,字符串项=信息号。get(I);
//系统。出去。println(项目。getKey());
if (item.getKey()!='') {
string key=item。GetKey();
字符串val=item。getVaLue();
if (urlencode) {
val=URLEncoder.encode(val,' utf-8 ');
}
buff=key '=' val
}
}
if (buff.isEmpty()==false) {
buff=buff.substring(0,buff。length()-1);
}
}捕获(例外e) {
抛出新的异常(e . GetMessage());
}
返回缓冲区;
}
其中MD5SignUtil.sign(bizString,key)方法如下
公共静态字符串符号(字符串内容,字符串键)
异常抛出{
字符串signStr=
signStr=content ' key=' key
返回MD5Util .MD5(签名字符串).toUpperCase();
}
其中MD5Util .MD5(签名字符串)方法如下
公共最终静态字符串MD5(字符串)
char hexDigits[]={'0 ',' 1 ',' 2 ',' 3 ',' 4 ',' 5 ',' 6 ',' 7 ',' 8 ',' 9 ',' A ',' B ',' C ',' D ',' E ',' F ' };
尝试{
byte[]btInput=s . GetBytes();
message digest mdInst=message digest。getinstance(' MD5 ');
mdinst。更新(BtInput);
字节[]MD=m inst。digest();
int j=md.length
char str[]=new char[j * 2];
int k=0;
for(int I=0;I j;i ) {
字节字节0=MD[I];
str[k]=HeXdigits[字节0 40xf];
str[k]=HeXdigits[字节00xf];
}
返回新字符串;
}捕获(例外e) {
e .printstacktrace();
返回空
}
}
CommonUtil .ArrayToXml(地图)方法如下
公共静态字符串数组Xml(MapString,String arr) {
字符串xml=' xml
IteratorEntryString,String iter=arr.entrySet().iterator();
while (iter.hasNext()) {
入口串,串入口=ITER。next();
string key=entry。GetKey();
string val=entry。getVaLue();
if (IsNumeric(val)) {
XML=' key ' ' val '/' key ' ';
} else
xml=' ' key '![CDATA[' val ']]/'键"";
}
XML='/XML ';
返回可扩展标记语言
}
公共静态布尔IsNumeric(字符串){
if(str。匹配(' \ \ d * '){
返回真实的
} else {
返回错误的
}
}
发送请求到微信获取预付代码如下
公共静态字符串URL=' https://API。mch。微信。QQ。com/pay/unified order ';
@SuppressWarnings('不赞成)
公共JSON对象GetPredyjson(字符串XML){
http客户端Http客户端=新Http客户端(新Http客户端参数(),新SimpleHttpconnectionmanager(true));
InputStream=null
后方法方法=null
尝试{
字符串url=URL
method=httpclienttutils。post method(URL);
方法。SetRequestBody(XML);
httpClient.executeMethod(方法);
//读取响应
is=方法。getresponsebodyasstream();
JSON对象o=xml2jsonutil。xml2json(is);
返回o;
}捕获(例外e) {
e .printstacktrace();
}最后{
if(method!=null){
方法。release connection();
}
if(is!=null){
尝试{
是。close();
} catch (IOException e1) {
e 1。printstacktrace();
}
}
}
返回空
}
公共字符串get预付费id(字符串xml){
尝试{
JSONObject jo=getdvertejson(XML);
对象元素=jo。getjsonobject(' XML ');
线预付款id=((JSONArray)元素。“get(”预付款_id ').get(0).toString();
预付退货;
}捕获(例外e) {
e .printstacktrace();
}
返回空
}
公共字符串orderNum(){
字符串字符=' 0123456789 ';
字符串顺序=系统。CurrentiMemillis()' ';
字符串res=
for(int I=0;i 19i ) {
Random rd=new Random();
RES=字符。charat(rd。Nextint(字符。length()-1));
}
order=res
退货单;
}
可扩展标记语言转数据方法xml2jsonutil。xml2json(is);摘自网络
/**
* 转换一个可扩展标记语言格式的字符串到数据格式
*
* @param xml
* xml格式的字符串
* @返回成功返回数据格式的字符串;失败反回空
*/
@SuppressWarnings(未选中)
公共静态JSONObject xml2JSON(InputStream为){
JSONObject obj=new JSONObject();
尝试{
SAXReader sb=new SAXReader();
document doc=sb . read(is);
element root=doc . GetRootElement();
obj.put(root.getName(),迭代元素(root));
返回obj
}捕获(例外e) {
错误日志. Error('导入XML后转换JSON时出错====xml2jsongutil-xml2json========',e);
返回null
}
}
/**
*迭代方法
*
* @param元素
* : org.jdom.Element
* @返回java.util.Map实例
*/
@SuppressWarnings(未选中)
私有静态映射迭代元素(Element元素){
list Jie Dian=element . elements();
元素et=null
map obj=new HashMap();
List list=null
for(int I=0;I Jie Dian . size();i ) {
list=new LinkedList();
et=(Element)Jie Dian . get(I);
if(et . GetTextRim()。等于(')){
if (et.elements()。size()==0)
继续;
if(obj . Contains KeY(et . GetName())){
List=(List)obj . get(et . getname());
}
list.add(迭代元素(et));
obj.put(et.getName(),list);
} else {
if(obj . Contains KeY(et . GetName())){
List=(List)obj . get(et . getname());
}
list . add(et . gettexttrim());
obj.put(et.getName(),list);
}
}
返回obj
}
基本上有这么多服务器
前端是微信和我自己挖的,擦了两天
先看微信文档jssdk文档(开始埋坑。)
将js引入页面
加入
wx.config({
Debug : false。//打开调试模式,所有被调用的API的返回值都会在客户端告警上出来。如果您想查看传入的参数,您可以在电脑端打开它们,参数信息将通过日志打印出来,只打印在电脑端。
AppId: '${appid} ',//必选,微信官方账号标识
时间戳:' $ {timestamp} ',//必选,生成签名的时间戳
NonceStr: ' $ { nonceStr } ',//必选,生成随机签名字符串
签名:' $ {signature} ',//必需,已签名,见附录1
jsApiList: [
'选择XPay '
]//必选,要使用的JS接口列表。所有JS接口的列表见附录2
});
嗯。已经配置好了。如果jsconfig的参数被传入。
然后看到jssdk里发的一个微信支付请求?
是啊,补充一下
function pay(){
wx.chooseWXPay({
时间戳: $ {paytimestamp},//支付签名时间戳,注意微信jssdk使用的时间戳字段都是小写。但是,最新版本的支付后台生成签名所使用的时间戳字段名称需要大写其中的S字符
Noncestr: ' $ { paynoncestr } ',//支付签名随机字符串,不超过32位
Package: '${paypackage} ',//统一支付接口返回的预付_id的参数值,提交格式为:预付_id=***)
Signtype:' $ {paysigntype} ',//签名方式,默认为' SHA1 ',使用新版本支付时需要' MD5 '
支付签名: '${paySign} ',//支付签名
成功:功能(res) {
预警('支付成功');
//支付成功后的回拨功能
}
});
}
然后发布调试。尼玛。我什么都付不起。一分钟订单信息不对,一分钟签名不对。寻找n个以上的数据是错误的
然后我想了想。用商家平台提供的文档编写界面,大不了。所以我添加了代码
函数onBridgeReady(){
WeixinJSBridge.invoke(
getBrandWCPayRequest ',{
AppId' : '${appid} ',//微信官方账号名称,商家导入
timestamp ' : ' $ { paytimestamp } ',//timestamp,自1970年以来的秒数
Noncestr ' : ' $ { paynoncestr } ',//随机字符串
套餐' : '${paypackage} ',
Signtype' :' $ {paysigntype} ',//微信签名方式:
PaySign' : '${paySign}' //微信签名
},
功能(res){
alert(RES . err _ msg);//用以上方法判断前端返回,微信团队郑重提醒:res.err_msg在用户支付成功后返回。
}
);
}
函数pay2(){
if(weixinsbridge==' undefined '){
if(document.addEventListener ){
document . addeventlistener(' weixinsbridgeready ',onBridgeReady,false);
}else if (document.attachEvent){
document . attachevent(' weixinsbridgeready ',onBridgeReady);
document . attachevent(' onweixiinsbridgeready ',onBridgeReady);
}
}else{
onbridgeReady();
}
}
发布调试。还是不对。pay()和pay2()两个按钮不对。支付方式仍然是订单信息错误,签名错误。Pay2()方法总是报告签名错误。尼玛。在你的经历上写上你的背景。反正我改不了。签名显然是正确的。一个可以获取预付款的。为Mao封装h5参数时出错。折腾。有n很久了。不是尼玛的错。后来pay method js报告了一个小错误。因此,可以执行pay2方法。Pay 2的js报错后不能再次使用。我靠。我有预感。两种方式有冲突吗?所以我删除了配置和支付方法,并再次尝试。尼玛真的可以。无法加入配置并支付。果然。我靠。折腾。微信在吃爸爸。种方式不能用,是不是误导?正确的结果是商品平台的文档使用方法js如下:
函数onBridgeReady(){
WeixinJSBridge.invoke(
getBrandWCPayRequest ',{
AppId' : '${appid} ',//微信官方账号名称,商家导入
timestamp ' : ' $ { paytimestamp } ',//timestamp,自1970年以来的秒数
Noncestr ' : ' $ { paynoncestr } ',//随机字符串
套餐' : '${paypackage} ',
Signtype' :' $ {paysigntype} ',//微信签名方式:
PaySign' : '${paySign}' //微信签名
},
功能(res){
alert(RES . err _ msg);//用以上方法判断前端返回,微信团队郑重提醒:res.err_msg在用户支付成功后返回。
}
);
}
function pay(){
if(weixinsbridge==' undefined '){
if(document.addEventListener ){
document . addeventlistener(' weixinsbridgeready ',onBridgeReady,false);
}else if (document.attachEvent){
document . attachevent(' weixinsbridgeready ',onBridgeReady);
document . attachevent(' onweixiinsbridgeready ',onBridgeReady);
}
}else{
onbridgeReady();
}
}
至此。最后微信支付结算。保留你的博客。为了防止后代绕过(不能在配置中添加chooseWXPay方法。记住)
04
2022-06
04
2022-06
16
2021-06
16
2021-06
16
2021-06
16
2021-06