对微信支付这个大坑的记录
-
第一次签名 appid 是小写的
-
第二次签名appId 用的是驼峰命名
-
第二次签名后面需要加上商户KEY
paySign = MD5(appId=wxd678efh567hg6787&nonceStr=5K8264ILTKCH16CQ2502SI8ZNMTM67VS&package=prepay_id=wx2017033010242291fcfe0db70013231072&signType=MD5&timeStamp=1490840662&key=qazwsxedcrfvtgbyhnujmikolp111111) = 22D9B4E54AB1950F51E0649E8810ACD6
完整代码
配置
@Value("${weixin.app_id}") // spring配置文件配置了appID
private String appId;
@Value("${weixin.mch_id}") // spring配置文件配置了商户号
private String mchId;
@Value("${weixin.app_secret}") // spring配置文件配置了secret
private String secret;
@Value("${weixin.notify_url}") // spring配置文件配置了notify_url
private String notifyUrl;
@Value("${weixin.pay_key}") // spring配置文件配置了pay_key
private String paykey;
主代码
/**
* 微信预订单
* @return
*/
@GetMapping("wxPayUnifiedorder/{id}")
@LoginRequired
@ResponseBody
public String wxPayUnifiedorder(@CurrentUser User user, @PathVariable Integer id) throws Exception {
OrderList orderList= orderListService.findOne(user.getId(),id);
PayInfo pi = createPayInfo(orderList,"111.58.221.46",user.getOpenId());
//获取第一次签名
String sign = getSign(pi);
//存入统一下单
pi.setSign(sign.toUpperCase());
//将需要发送的数据转XML
String xml=WXUtils.payInfoToXML(pi).replace("__", "_").replace("<![CDATA[", "").replace("]]>","");
//获取微信预订单
xml =HttpUtils.postJson("https://api.mch.weixin.qq.com/pay/unifiedorder",xml);
Map xmlmap= WXUtils.parseXml(xml);
//map转json 返回
String json =gson.toJson(xmlmap);
//将放回的数据转json对象解析
JsonObject jsonObject = gson.fromJson(json,JsonObject.class);
String prepayId="";
if(!jsonObject.get("prepay_id").isJsonNull()){
//获取返回的订单号保存到数据库
prepayId =jsonObject.get("prepay_id").getAsString();
orderList.setPrepayId(prepayId);
//把多了订单号的数据保存到数据库里
orderListService.save(orderList);
}
jsonObject.addProperty("prepay_id",orderList.getPrepayId());
//使用预订单号生成第二次签名发送到小程序
return getPaySign(orderList.getPrepayId()).toString();
}
/**
* 第一次获取签名
* @param payInfo
* @return
* @throws Exception
*/
public String getSign(PayInfo payInfo) {
String signTemp = "appid=" + payInfo.getAppid()
+"&attach="+payInfo.getAttach()
+"&body="+payInfo.getBody()
+"&device_info="+payInfo.getDevice_info()
+"&mch_id="+payInfo.getMch_id()
+"&nonce_str="+payInfo.getNonce_str()
+"¬ify_url="+payInfo.getNotify_url()
+"&openid="+payInfo.getOpenid()
+"&out_trade_no="+payInfo.getOut_trade_no()
+"&spbill_create_ip="+payInfo.getSpbill_create_ip()
+"&total_fee="+payInfo.getTotal_fee()
+"&trade_type="+payInfo.getTrade_type()
+"&key="+paykey; //这个key注意,小程序支付密钥
String sign = DigestUtils.md5DigestAsHex(signTemp.getBytes());
return sign;
}
/**
* 第二次签名
* @param prepayId
* @return
*/
public JsonObject getPaySign(String prepayId){
JsonObject jsonObject = new JsonObject();
jsonObject.addProperty("timeStamp", ""+(System.currentTimeMillis()/1000));
jsonObject.addProperty("nonceStr",UUID.randomUUID().toString().replace("-", "").toUpperCase());
jsonObject.addProperty("prepayId","prepay_id="+prepayId);
jsonObject.addProperty("signType","MD5");
String paysignStr="appId="+appId
+"&nonceStr="+jsonObject.get("nonceStr").getAsString()
+"&package="+jsonObject.get("prepayId").getAsString()
+"&signType="+jsonObject.get("signType").getAsString()
+"&timeStamp="+jsonObject.get("timeStamp").getAsString()
+"&key="+paykey;
String paysignM = DigestUtils.md5DigestAsHex(paysignStr.getBytes());
jsonObject.addProperty("paySign",paysignM);
return jsonObject;
}
/**
* 创建统一下单的xml的java对象
* @param orderList 订单对象
* @param ip 用户的ip地址
* @param openId 用户的openId
* @return
*/
public PayInfo createPayInfo(OrderList orderList, String ip, String openId) {
PayInfo payInfo = new PayInfo();
//小程序ID
payInfo.setAppid(appId);
//附加数据 用来当参数
payInfo.setAttach("购买电动车");
//商品描述
payInfo.setBody("购买电动车");
//设备号
payInfo.setDevice_info("xiaochengxu");
//商户号
payInfo.setMch_id(mchId);
//随机字符串
payInfo.setNonce_str(UUID.randomUUID().toString().replace("-", "").toLowerCase());
//回调地址
payInfo.setNotify_url(notifyUrl);
//商户订单号
payInfo.setOut_trade_no(orderList.getOutTradeNo());
// notifyUrl
payInfo.setOpenid(openId);
//用户IP
payInfo.setSpbill_create_ip(ip);
//商品价格
payInfo.setTotal_fee(orderList.getSettlementAmount().multiply(new BigDecimal(100)).intValue());
return payInfo;
}