javaspringboot实现⽀付
⽀付模块终于告⼀段落,由于之前没做过⽀付,踩过⼀些坑,在此我想分享⾃⼰的⼀些⼼得,希望对同⾏们有所帮助,话不多说,直接进⼊正题。
⾸先,我们要完成⽀付功能(此处是java springboot版),那么我们需要⽤到和商户号其中的⼀些配置信息,选择服务号,
#⽀付信息配置
weixin:
#appid
appid: ***********      #这是appid,在的基本配置中可以到
#商户id
partner: **********    #商户号id,在商户号中可以到
#api秘钥
partnerkey: ***********    #商户秘钥,也是在商户号中到,不会请百度
#⽀付回调地址
notifyurlBuyCar: *********    #⽀付回调地址,⽀付完成之后会⾃动调⽤这个地址
  以上是在springboot项⽬中yml⽂件的基本配置信息,此外,请注意:
1:商户号需要绑定
2:商户号需要开通JSAPI⽀付
3:⾥⾯的功能设置需要绑定JS安全域名和⽹页授权域名
4:如果需要使⽤开发者⼯具进⾏调试的话,需要在中绑定当前开发者的
  因为我的⽀付功能和购物车⽀付⽤的是同⼀套接⼝,所以数据格式上会有所差异,直接上代码:
/**
* 购物车⽀付
* @param parameterMap
* @param request
* @return
*/
@PostMapping("buyCarPay")
public ResponseResult buyCarPay(@RequestParam Map<String,Object> parameterMap,HttpServletRequest request){
//参数:需要⼀个goods_list的json格式的集合,以及⽤户的openid,openid是⽤户在本中的唯⼀标识,不会的请百度或者查看官⽅⽂档获取
//这个request没啥⽤,只是为了获取当前终端的ip地址
//parameterMap:
  // goods_list:[
  //  {"goods_id":10015,"goods_num":2,"goods_price":0.01},
  //  {"goods_id":10016,"goods_num":3,"goods_price":0.01}
  //            ],
  // openid:  ********
Map<String,Object> resultMap = buyCarService.buyCarPay(parameterMap,request);
if(resultMap!=null){
return Result.SUCCESS(1,"success",resultMap);
}
return new ResponseResult(500,"error",null);
}
  这篇帖⼦只关⼼⽀付的功能,不关⼼其中的业务逻辑的处理,所以我会删掉其中的⼀些逻辑,嘿嘿嘿....... 统⼀下单可以去官⽅⽂档中调⽤api接⼝,
@Value("${weixin.appid}")
private String appid;
@Value("${weixin.partner}")
private String partner;
@Value("${weixin.partnerkey}")
private String partnerkey;
@Value("${ifyurlBuyCar}")
private String notifyurlBuyCar
/**
* 购物车⽀付
* @param parameterMap
* @param request
* @return
*/
public Map<String, Object> buyCarPay(Map<String, Object> parameterMap,HttpServletRequest request) {
// "goods_list":[
//                  {"goods_id":10015,"goods_num":2,"goods_price":0.01},
//                  {"goods_id":10016,"goods_num":3,"goods_price":0.01}
//              ],
// "openid":  ajshdasnoasdasdas
String goods_list = (("goods_list");  //获取goods_list
String openid = (("openid");    //获取openid
List list = JSONArray.parseArray(goods_list);    //将字符串格式的goods_list转为list集合
double totalPrice=0.00;    //总价格
Map<String,String> paramMap = new HashMap<>();
//以下paramMap设置的参数都是为了获取签名
paramMap.put("appid",appid);    //appid,配置⽂件中获取
paramMap.put("mch_id",partner);  //商户id,配置⽂件中获取
paramMap.put("nonce_str", ateNonceStr());    //随机字符串,这个WXPayUtil⼯具类可以在官⽅⽂档中获取,这个相当有⽤,针对⽀付这⼀块    paramMap.put("body","body");    //商品的body信息,相当于详情描述吧
paramMap.put("sign_type","MD5");    //签名类型,⼀般就写MD5
//获取时间,获取随机数,拼接在⼀起⽣成订单号
SimpleDateFormat sdf=new SimpleDateFormat("yyyyMMddHHmmss");
String newDate=sdf.format(new Date());
String result1="";
Random random=new Random();
for(int i=0;i<4;i++){
result1+=Int(10);
}
String str=newDate+result1;
paramMap.put("out_trade_no",str);  //订单号
for (int i = 0; i < list.size(); i++) {
Map<String, Object> m = (Map<String, Object>) (i);
double goods_price = Double.parseDouble(String.("goods_price")));  //商品单价
totalPrice=totalPrice+goods_num*goods_price;
}
int d = (totalPrice*100).intValue();
paramMap.put("total_fee",d+"");    //总价格,单位是分
paramMap.put("spbill_create_ip", IpAddr(request));  //IPUtils是获取当前ip的⼯具类,在⽹上可以到
paramMap.put("notify_url",notifyurlBuyCar);    //⽀付回调地址,提交⽀付后,会⾛这个⽹址,这个⽹址是可以通过外⽹直接访问到的
paramMap.put("trade_type","JSAPI");  //交易类型,⽬前是⽀付,需要些JSAPI,商户号中⼀定要开通JSAPI⽀付
paramMap.put("openid",openid);    //openid,⽤户在此的唯⼀标识
String xmlParameters= null;
try {
//这⼀步操作就是将⼀个map集合加上秘钥通过MD5加密的⽅式⽣成⼀个签名,签名可验证
xmlParameters = ateSignedXml(paramMap,partnerkey);    //partnerkey秘钥,在配置⽂件中获取
//URL地址
String url="h.weixin.qq/pay/unifiedorder";
//URL地址
HttpClient httpClient=new HttpClient(url);
//提交⽅式
httpClient.setHttps(true);
//提交参数
httpClient.setXmlParam(xmlParameters);
//执⾏请求
httpClient.post();
//获取返回的参数
String result = Content();
//返回数据转为map
Map<String, String> resultMap = lToMap(result);  //Map格式转为xml格式,xmlToMap⽅法在WXPayUtil中可以到
System.out.println("调⽤统⼀下单result=========="+resultMap);
Map response=new HashMap();
response.put("appId",appid);
response.put("timeStamp",("out_trade_no"));  //订单号
response.put("nonceStr",("nonce_str"));  //随机字符串
response.put("package","prepay_id="+("prepay_id"));    //拼接预⽀付id
支付分怎么开通
response.put("signType","MD5");  //加密⽅式
String paySign1 = ateSignedXml(response, partnerkey);  //加密获取签名
Map<String, String> map11 = lToMap(paySign1);    //将xml格式转为map集合
String paySign = ("sign");  //获取最后的⽀付签名,这个很重要
     Map<String,Object> payMap=new HashMap<>();    //最终响应的参数map
payMap.put("appId",appid);
payMap.put("timeStamp",("out_trade_no"));
payMap.put("nonceStr",("nonce_str"));
payMap.put("package","prepay_id="+("prepay_id"));
payMap.put("signType","MD5");
payMap.put("paySign",paySign);
payMap.put("out_trade_no",("out_trade_no"));
payMap.put("openid",openid);
return payMap;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
(⽀付完成后,会把相关⽀付结果及⽤户信息通过数据流的形式发送给商户,商户需要接收处理,并按⽂档规范返回应答。)
注意:
1、同样的通知可能会多次发送给商户系统。商户系统必须能够正确处理重复的通知。
2、后台通知交互时,如果收到商户的应答不符合规范或超时,会判定本次通知失败,重新发送通知,直到成功为⽌(在通知⼀直不成功的情况下,总共会发起多次通知,通知频率为15s/15s/30s/3m/10m/20m/30m/30m/30m/60m/3h/3h/3h/6h/6h - 总计 24h4m),但不保证通知最终⼀定能成功。
3、在订单状态不明或者没有收到⽀付结果通知的情况下,建议商户主动调⽤⽀付【】确认订单状态。
上⾯这⼀块可以完成⽀付的功能,但是⽀付成功之后需要进⾏⼀些业务逻辑的处理,之前配置的⽀付回调地址派上了⽤场,请看配置中的notifyurlBuyCar路径,这个notifyurl接⼝如果报错,获取超时,⽅会循环调⽤此接⼝,
/**
* ⽀付结果通知回调⽅法
* @param request
* @return
*/
@RequestMapping("notifyurl")
public String notifyurl(HttpServletRequest request) throws Exception{
//以流的⽅式获取
ServletInputStream is = InputStream();
ByteArrayOutputStream baos=new ByteArrayOutputStream();
byte[] buffer=new byte[1024];
int len=0;
while ((ad(buffer))!=-1){
baos.write(buffer,0,len);}
byte[] bytes = ByteArray();
String xmlresult=new String(bytes,"UTF-8");
Map<String, String> resultMap = lToMap(xmlresult);
System.out.println("⽀付响应参数:"+resultMap);  //可以查询⼀下⽬前⽀付响应的参数,
String out_trade_("out_trade_no");  //平台⽣成的订单号
String time_("time_end");    //获取在⽀付的最终时间
String transaction_("transaction_id");  //获取交易号
Map map = buyCarService.queryStatus(out_trade_no);
String trade_state = (("trade_state");
if(ains("SUCCESS")){
    当交易状态是SUCCESS的时候,代表⽀付成功,接下来就是业务逻辑的处理
String result="SUCCESS";
return result;
}
String result="SUCCESS";  //⽬前返回的是SUCCESS,
return result;
}
/**
* 查询⽀付状态
* @param outtradeno
* @return
*/
public Map queryStatus(String outtradeno){
Map<String,String> paramMap= null;
try {
//参数
paramMap = new HashMap<>();
paramMap.put("appid",appid);
paramMap.put("mch_id",partner);
paramMap.put("nonce_str", ateNonceStr());
paramMap.put("out_trade_no",outtradeno);
//Map转出xml字符串,可以携带签名
String xmlParameters= ateSignedXml(paramMap,partnerkey);
//URL地址
String url="h.weixin.qq/pay/orderquery";
HttpClient httpClient=new HttpClient(url);
//提交⽅式
httpClient.setHttps(true);
//提交参数
httpClient.setXmlParam(xmlParameters);
//执⾏请求
httpClient.post();
//获取返回的参数
String result = Content();
//返回数据转为map
Map<String, String> resultMap = lToMap(result);
return resultMap;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
以上代码执⾏的是Controller和Service层,可以查看⼀下后续:敬请期待 !!!