1.相关变量设置:
微信支付相关配置
应用appid(在开发者中心设置)
wx.appid=wxe754*****b7
商户号(在开发者中心设置)
wx.mchid=1488***152
支付密钥((在开发者中心设置)长度32)
wx.apikey=mCuqsC********susvLa
统一下单接口,这里不需要修改,由系统自动调用
wx.uniurl=https://api.mch.weixin.qq.com/pay/unifiedorder
2.统一下单部分代码:
/***
* 微信统一下单
*
*@param request
*@param response
*@throws IOException
*@throws JDOMException
*@date: 2017年9月1日
*@author: smallz
*
*/
@RequestMapping("/prePay")
public void wxPrePay(String data, HttpServletRequest request,
HttpServletResponse response) {
Map<String, Object> resultMap = new HashMap<String, Object>();
StatusData statusObject = null;
JsonModel jsonModel = new JsonModel();
jsonModel.setHeaderValue("flag", "0");
SortedMap<Object, Object> parameterMap2 = new TreeMap<Object, Object>();
// jsonModel.setHeaderValue("flag", "0");
if (requestHandle(data, jsonModel) == true) {
try {
//支付类型
Integer payType=Integer.valueOf(jsonModel.getBodyValue("payType"));
Long memberId=Long.valueOf(jsonModel.getBodyValue("memberId"));
String orderId="";
String body="";
String price="";
String noncestr=WeChatUtils.CreateNoncestr();
if(payType.equals(WeChatPayTypeEnum.serviceFee.getStatus())){//服务费
//计算服务费规则
orderId=jsonModel.getBodyValue("orderId");
body=WeChatPayTypeEnum.serviceFee.getName();
price=PropertiesUtil.getPropertiesValue("serviceFeeCost");
}else if(payType.equals(WeChatPayTypeEnum.transaction.getStatus())///交易会员
){
orderId=String.valueOf(System.currentTimeMillis());
price=PropertiesUtil.getPropertiesValue("trascationFeeCost");
body=WeChatPayTypeEnum.transaction.getName();
}else if(payType.equals(WeChatPayTypeEnum.limitInFee.getStatus())){//准入金
orderId=jsonModel.getBodyValue("orderId");
body=WeChatPayTypeEnum.limitInFee.getName();
price=PropertiesUtil.getPropertiesValue("limitInFeeCost");
}else if(payType.equals(WeChatPayTypeEnum.orderFee.getStatus())){//订单结算
orderId=jsonModel.getBodyValue("orderId");
body=/*"2401_"+*/WeChatPayTypeEnum.orderFee.getName();
//价格先写死
price=PropertiesUtil.getPropertiesValue("limitInFeeCost");
}
int price100 = new BigDecimal(price).multiply(
new BigDecimal(100)).intValue();
if (price100 <= 0) {
statusObject = AppInteractiveState.MONEY_FMT_ERROR;
returnJson(response, statusObject, resultMap);
return;
}
LogUtils.info(getClass(), "===此次预支付的订单Id==="+orderId);
LogUtils.info(getClass(), "===此次预支付的订单内容==="+body);
LogUtils.info(getClass(), "===此次预支付的订单价格==="+price100);
// 设置回调地址-获取当前的地址拼接回调地址
String url = request.getRequestURL().toString();
String domain = url.substring(0, url.length() - 9);
System.out.println("====微信回调URL:"+domain+"wxNotify.do");
// 测试、正式环境
String notify_url= domain+"wxNotify.do";
SortedMap<Object, Object> parameters = new TreeMap<Object, Object>();
//封装请求参数
setSignParameters(request, jsonModel, price100, notify_url,
parameters,orderId,body,WeChatUtils.CreateNoncestr(),payType,memberId);
// 封装请求参数结束
String requestXML = WeChatUtils.getRequestXml(parameters);
// 调用统一下单接口
String result = WeChatUtils.httpsRequest(UNI_URL, "POST", requestXML);
LogUtils.info(getClass(), "===请求微信统一支付返回结果===:");
LogUtils.info(getClass(),result);
//System.out.println("\n" + result);
try {
/**
* 统一下单接口返回正常的prepay_id,再按签名规范重新生成签名后,将数据传输给APP。
* 参与签名的字段名为appId
* ,partnerId,prepayId,nonceStr,timeStamp,package
* 。注意:package的值格式为Sign=WXPay
**/
Map<String, String> map = XMLUtil.doXMLParse(result);
if (map.get("return_code").equals("SUCCESS")) {
statusObject = new StatusData(
Integer.valueOf(AppInteractiveState.SUCCESS),
"请求统一下单成功!");
} else {
statusObject = new StatusData(
Integer.valueOf(AppInteractiveState.ERROR_BUSINESS),
"请求统一下单失败!");
LogUtils.error(getClass(), "微信统一下单错误,return_msg:"+map.get("return_msg"));
returnJson(response, statusObject, resultMap);
return;
}
//System.out.println(map);
// parameterMap2 = new TreeMap<Object, Object>();
parameterMap2.put("appid", APPID);
//parameterMap2.put("attach", "*****");//这里二次签名无需对attach再签名(不然就是支付验证签名失败,本人已经填坑)
parameterMap2.put("partnerid", MCH_ID);
parameterMap2.put("prepayid", map.get("prepay_id"));
parameterMap2.put("package", "Sign=WXPay");//这个key(package),绝对不能改,为了图方便我以为能省去parameterMap2.put("packageValue", "Sign=WXPay");这一句代码,结果填了一坑,导致签名失败。
parameterMap2.put("noncestr", WeChatUtils.CreateNoncestr());
// 本来生成的时间戳是13位,但是ios必须是10位,所以截取了一下
parameterMap2.put(
"timestamp",
Long.parseLong(String
.valueOf(System.currentTimeMillis())
.toString().substring(0, 10)));
//这里是二次签名
String sign2 = WeChatUtils.createSign("UTF-8",parameterMap2);
parameterMap2.put("tradeNo", orderId);
//避免安卓package关键字字段
parameterMap2.put("packageValue", "Sign=WXPay");
parameterMap2.put("sign", sign2);
System.out.println("二次签名参数:———————"+parameterMap2);
} catch (JDOMException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
} catch (Exception e) {
e.printStackTrace();
}
}
//将统一下单的map返回给客户端
returnJson(response, statusObject, parameterMap2);
}
//生成签名
private void setSignParameters(HttpServletRequest request,
JsonModel jsonModel, int price100, String notify_url,
SortedMap<Object, Object> parameters,String orderId,String body,String dateStr,Integer payType,Long memberId) {
parameters.put("appid", APPID);
parameters.put("attach", payType+"|"+memberId+"|"+orderId);
parameters.put("mch_id", MCH_ID);
parameters.put("nonce_str",dateStr);
parameters.put("body", body);
parameters.put("out_trade_no",orderId); // 订单id
parameters.put("fee_type", "CNY");
parameters.put("total_fee", String.valueOf(price100));
//本机测试Ip
//parameters.put("spbill_create_ip", "220.202.152.37");
parameters.put("spbill_create_ip", getIpAddr(request));
parameters.put("notify_url", notify_url);
parameters.put("trade_type", "APP");
// 设置签名
String sign = WeChatUtils.createSign("UTF-8", parameters);
parameters.put("sign", sign);
}
/***
* 微信异步回调方法
*
*@param request
*@param response
*@throws IOException
*@throws JDOMException
*@date: 2017年9月1日
*@author: smallz
*
*/
@SuppressWarnings("unchecked")
@RequestMapping("/wxNotify")
public void wxNotify(HttpServletRequest request,
HttpServletResponse response/*,String data*//*调试用*/) throws IOException, JDOMException {
try {
// 读取参数
InputStream inputStream;
StringBuffer sb = new StringBuffer();
inputStream = request.getInputStream();
String s;
BufferedReader in = new BufferedReader(new InputStreamReader(
inputStream, "UTF-8"));
while ((s = in.readLine()) != null) {
sb.append(s);
}
in.close();
inputStream.close();
// 解析xml成map
Map<String, String> m = new HashMap<String, String>();
m = XMLUtil.doXMLParse(sb.toString());
System.out.println("微信服务器返回的xml:"+sb.toString());
//m = XMLUtil.doXMLParse(data);
for (Object keyValue : m.keySet()) {
System.out.println(keyValue + "=" + m.get(keyValue));
}
// 过滤空 设置 TreeMap
SortedMap<Object, Object> packageParams = new TreeMap<Object, Object>();
Iterator it = m.keySet().iterator();
while (it.hasNext()) {
String parameter = (String) it.next();
String parameterValue = m.get(parameter);
String v = "";
if (null != parameterValue) {
v = parameterValue.trim();
}
packageParams.put(parameter, v);
}
// 判断签名是否正确
String resXml = "";
if (WeChatUtils.isTenpaySign("UTF-8", packageParams)) {
LogUtils.info(this.getClass(), "签名校验成功,信息合法,未被篡改过");
if ("SUCCESS".equals((String) packageParams.get("result_code"))) {
String mch_id = (String) packageParams.get("mch_id"); // 商户号
String openid = (String) packageParams.get("openid"); // 用户标识
String out_trade_no = (String) packageParams
.get("out_trade_no"); // 商户订单号
String total_fee = (String) packageParams.get("total_fee");
String transaction_id = (String) packageParams
.get("transaction_id"); // 微信支付订单号
WxPayResult trade = null;
//比对app端的数据(金额、商户号...)
if (!MCH_ID.equals(mch_id)
|| trade == null
|| new BigDecimal(total_fee).compareTo(new BigDecimal(
trade.getTotal_fee()).multiply(new BigDecimal(
100))) != 0) {
LogUtils.error(this.getClass(), "支付失败,错误信息:"
+ packageParams.get("err_code"));
resXml = "<xml>"
+ "<return_code><![CDATA[FAIL]]></return_code>"
+ "<return_msg><![CDATA[通知支付失败]]></return_msg>"
+ "</xml> ";
}
} else {
System.out.println("支付成功");
LogUtils.info(getClass(), "支付成功");
resXml = "<xml>"
+ "<return_code><![CDATA[SUCCESS]]></return_code>"
+ "<return_msg><![CDATA[OK]]></return_msg>"
+ "</xml> ";
}
// 保存微信支付信息
try {
wxPayResultService.savePayResult(packageParams);
} catch (Exception e) {
// TODO: handle exception
}
// ------------------------------
// 处理业务完毕
// ------------------------------
BufferedOutputStream out = new BufferedOutputStream(
response.getOutputStream());
out.write(resXml.getBytes());
out.flush();
out.close();
}else {
resXml = "<xml>"
+ "<return_code><![CDATA[FAIL]]></return_code>"
+ "<return_msg><![CDATA[通知签名验证失败]]></return_msg>"
+ "</xml> ";
LogUtils.error(this.getClass(), "通知签名验证失败");
}
} catch (Exception e) {
e.printStackTrace();
LogUtils.error(getClass(), "异步交互异常:"+e.getMessage());
}
}
如有不妥之处 请指出。