项目里要使用到微信收款和付款.
微信收款分二部分,一部分向微信发起支付申请获取支付参数让用户触发支付申请,另部分是获取用户支付成功后的结果做业务处理,第一部分是主动的,第二部分是微信调我们的接口的,第一部分的核心代码为:
String path = request.getContextPath();
String basePath = request.getScheme() + "://" + request.getServerName() + ":" + request.getServerPort() + path + "/";
log.info("basePath=" + basePath);
/** 总金额(分为单位) */
int total = (int) (totalPrice * 100);
SortedMap<Object, Object> parameters = new TreeMap<Object, Object>();
/** 公众号APPID */
parameters.put("appid", APPID);
/** 商户号 */
parameters.put("mch_id", MCH_ID);
/** 随机字符串 */
parameters.put("nonce_str", WXUtil.getNonceStr());
/** 商品名称 */
parameters.put("body", commodityName);
/** 当前时间 yyyyMMddHHmmss */
String currTime = TenpayUtil.getCurrTime();
/** 8位日期 */
String strTime = currTime.substring(8, currTime.length());
/** 四位随机数 */
String strRandom = TenpayUtil.buildRandom(4) + "";
/** 订单号 */
parameters.put("out_trade_no", strTime + strRandom);
/** 订单金额以分为单位,只能为整数 */
parameters.put("total_fee", total);
/** 客户端本地ip */
parameters.put("spbill_create_ip", request.getRemoteAddr());
/** 支付回调地址 */
parameters.put("notify_url", basePath + NOTIFY_URL);
/** 支付方式为JSAPI支付 */
parameters.put("trade_type", "JSAPI");
/** 用户微信的openid,当trade_type为JSAPI的时候,该属性字段必须设置 */
parameters.put("openid", openId);
/** MD5进行签名,必须为UTF-8编码,注意上面几个参数名称的大小写 */
String sign = createSign("UTF-8", parameters);
parameters.put("sign", sign);
/** 生成xml结构的数据,用于统一下单接口的请求 */
String requestXML = getRequestXml(parameters);
log.info("requestXML:" + requestXML);
/** 开始请求统一下单接口,获取预支付prepay_id */
HttpClient client = new HttpClient();
PostMethod myPost = new PostMethod(UNI_URL);
client.getParams().setSoTimeout(300 * 1000);
String result = null;
try {
myPost.setRequestEntity(new StringRequestEntity(requestXML, "text/xml", "utf-8"));
int statusCode = client.executeMethod(myPost);
if (statusCode == HttpStatus.SC_OK) {
BufferedInputStream bis = new BufferedInputStream(myPost.getResponseBodyAsStream());
byte[] bytes = new byte[1024];
ByteArrayOutputStream bos = new ByteArrayOutputStream();
int count = 0;
while ((count = bis.read(bytes)) != -1) {
bos.write(bytes, 0, count);
}
byte[] strByte = bos.toByteArray();
result = new String(strByte, 0, strByte.length, "utf-8");
bos.close();
bis.close();
}
} catch (Exception e) {
e.printStackTrace();
}
/** 需要释放掉、关闭连接 */
myPost.releaseConnection();
client.getHttpConnectionManager().closeIdleConnections(0);
log.info("请求统一支付接口的返回结果:");
log.info(result);
try {
/** 解析微信返回的信息,以Map形式存储便于取值 */
Map<String, String> map = XMLUtil.doXMLParse(result);
SortedMap<Object, Object> params = new TreeMap<Object, Object>();
params.put("appId", APPID);
params.put("timeStamp", "\"" + new Date().getTime() + "\"");
params.put("nonceStr", WXUtil.getNonceStr());
/**
* 获取预支付单号prepay_id后,需要将它参与签名。
* 微信支付最新接口中,要求package的值的固定格式为prepay_id=...
*/
params.put("package", "prepay_id=" + map.get("prepay_id"));
/** 微信支付新版本签名算法使用MD5,不是SHA1 */
params.put("signType", "MD5");
/**
* 获取预支付prepay_id之后,需要再次进行签名,参与签名的参数有:appId、timeStamp、nonceStr、package、signType.
* 主意上面参数名称的大小写.
* 该签名用于前端js中WeixinJSBridge.invoke中的paySign的参数值
*/
String paySign = createSign("UTF-8", params);
params.put("paySign", paySign);
/** 预支付单号,前端ajax回调获取。由于js中package为关键字,所以,这里使用packageValue作为key。 */
params.put("packageValue", "prepay_id=" + map.get("prepay_id"));
/** 付款成功后,微信会同步请求我们自定义的成功通知页面,通知用户支付成功 */
// params.put("sendUrl", basePath + "pay/paysuccess?totalPrice=" + totalPrice);
params.put("sendUrl", "https://frontend2.csq.im/caishenquan/weigu/"+gohref+".html?success=1&"+param);
/** 获取用户的微信客户端版本号,用于前端支付之前进行版本判断,微信版本低于5.0无法使用微信支付 */
String userAgent = request.getHeader("user-agent");
char agent = userAgent.charAt(userAgent.indexOf("MicroMessenger") + 15);
params.put("agent", new String(new char[] { agent }));
String json = JSONArray.fromObject(params).toString();
return json;
} catch (JDOMException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return "";
-------------------------------------------------此为分界线----------------------------------------------------
第二部分的核心代码为:
log.info("微信支付成功调用回调URL");
InputStream inStream = request.getInputStream();
ByteArrayOutputStream outSteam = new ByteArrayOutputStream();
byte[] buffer = new byte[1024];
int len = 0;
while ((len = inStream.read(buffer)) != -1) {
outSteam.write(buffer, 0, len);
}
log.info("~~~~~~~~~~~~~~~~付款成功~~~~~~~~~");
outSteam.close();
inStream.close();
/** 支付成功后,微信回调返回的信息 */
String result = new String(outSteam.toByteArray(), "utf-8");
log.info("微信返回的订单支付信息:" + result);
Map<Object, Object> map = XMLUtil.doXMLParse(result);
// 用于验签
SortedMap<Object, Object> parameters = new TreeMap<Object, Object>();
for (Object keyValue : map.keySet()) {
/** 输出返回的订单支付信息 */
log.info(keyValue + "=" + map.get(keyValue));
if (!"sign".equals(keyValue)) {
parameters.put(keyValue, map.get(keyValue));
}
}
if (map.get("result_code").toString().equalsIgnoreCase("SUCCESS")) {
// 先进行校验,是否是微信服务器返回的信息
String checkSign = createSign("UTF-8", parameters);
log.info("对服务器返回的结果进行签名:" + checkSign);
log.info("服务器返回的结果签名:" + map.get("sign"));
if (checkSign.equals(map.get("sign"))) {// 如果签名和服务器返回的签名一致,说明数据没有被篡改过
log.info("签名校验成功,信息合法,未被篡改过");
/** 告诉微信服务器,我收到信息了,不要再调用回调方法了 */
/**如果不返回SUCCESS的信息给微信服务器,则微信服务器会在一定时间内,多次调用该回调方法,如果最终还未收到回馈,微信默认该订单支付失败*/
/** 微信默认会调用8次该回调地址 */
response.getWriter().write(setXML("SUCCESS", ""));
log.info("-------------" + setXML("SUCCESS", ""));
//业务处理
//log.info("我去掉了发送SUCCESS给微信服务器");
}
}