获取prepayId:
public Map<String, String> getAppPayInfo(String openId, String outTradeNo, double amt, String body, String tradeType, String ip, String callbackUrl) {
WxMpPrepayIdResult wxMpPrepayIdResult = getPrepayId(openId, outTradeNo, amt, body, tradeType, ip, callbackUrl);
String prepayId = wxMpPrepayIdResult.getPrepay_id();
if (prepayId == null || prepayId.equals("")) {
throw new RuntimeException("get prepayid error");
}
Map<String, String> payInfo = new HashMap<String, String>();
payInfo.put("appid", wxMpConfigStorage.getAppId());
payInfo.put("noncestr", wxMpPrepayIdResult.getNonce_str());
payInfo.put("package", "Sign=WXPay");
payInfo.put("partnerid", wxMpConfigStorage.getPartnerId());
payInfo.put("prepayid", prepayId);
payInfo.put("timestamp", String.valueOf(System.currentTimeMillis() / 1000));
String finalSign = WxCryptUtil.createSign(payInfo, wxMpConfigStorage.getPartnerKey());
payInfo.put("sign", finalSign);
return payInfo;
}
签名:
/**
* 微信公众号支付签名算法(详见:http://pay.weixin.qq.com/wiki/doc/api/index.php?chapter=4_3)
* @param packageParams 原始参数
* @param signKey 加密Key(即 商户Key)
* @param charset 编码
* @return 签名字符串
*/
public static String createSign(Map<String, String> packageParams, String signKey) {
SortedMap<String, String> sortedMap = new TreeMap<String, String>();
sortedMap.putAll(packageParams);
List<String> keys = new ArrayList<String>(packageParams.keySet());
Collections.sort(keys);
StringBuffer toSign = new StringBuffer();
for (String key : keys) {
String value = packageParams.get(key);
if (null != value && !"".equals(value) && !"sign".equals(key)
&& !"key".equals(key)) {
toSign.append(key + "=" + value + "&");
}
}
toSign.append("key=" + signKey);
System.out.println(toSign.toString());
String sign = DigestUtils.md5Hex(toSign.toString())
.toUpperCase();
return sign;
}
getPrepayId<span style="font-family: Arial, Helvetica, sans-serif; font-size: 12px; background-color: rgb(255, 255, 255);">:</span>
getPrepayId<span style="font-family: Arial, Helvetica, sans-serif; font-size: 12px; background-color: rgb(255, 255, 255);">:</span>
public WxMpPrepayIdResult getPrepayId(String openId, String outTradeNo, double amt, String body, String tradeType, String ip, String callbackUrl) {
String nonce_str = System.currentTimeMillis() + "";
SortedMap<String, String> packageParams = new TreeMap<String, String>();
packageParams.put("appid", wxMpConfigStorage.getAppId());
packageParams.put("mch_id", wxMpConfigStorage.getPartnerId());
packageParams.put("nonce_str", nonce_str);
packageParams.put("body", body);
packageParams.put("out_trade_no", outTradeNo);
packageParams.put("total_fee", (int)(amt*100) + "");
packageParams.put("spbill_create_ip", ip);
packageParams.put("notify_url", callbackUrl);
packageParams.put("trade_type", tradeType);
packageParams.put("openid", openId);
String sign = WxCryptUtil.createSign(packageParams, wxMpConfigStorage.getPartnerKey());
String xml = "<xml>" +
"<appid>" + wxMpConfigStorage.getAppId() + "</appid>" +
"<mch_id>" + wxMpConfigStorage.getPartnerId() + "</mch_id>" +
"<nonce_str>" + nonce_str + "</nonce_str>" +
"<sign>" + sign + "</sign>" +
"<body><![CDATA[" + body + "]]></body>" +
"<out_trade_no>" + outTradeNo + "</out_trade_no>" +
"<total_fee>" + packageParams.get("total_fee") + "</total_fee>" +
"<spbill_create_ip>" + ip + "</spbill_create_ip>" +
"<notify_url>" + callbackUrl + "</notify_url>" +
"<trade_type>" + tradeType + "</trade_type>" +
"<openid>" + openId + "</openid>" +
"</xml>";
HttpPost httpPost = new HttpPost("https://api.mch.weixin.qq.com/pay/unifiedorder");
if (httpProxy != null) {
RequestConfig config = RequestConfig.custom().setProxy(httpProxy).build();
httpPost.setConfig(config);
}
StringEntity entity = new StringEntity(xml, Consts.UTF_8);
httpPost.setEntity(entity);
try {
CloseableHttpResponse response = getHttpclient().execute(httpPost);
String responseContent = Utf8ResponseHandler.INSTANCE.handleResponse(response);
XStream xstream = XStreamInitializer.getInstance();
xstream.alias("xml", WxMpPrepayIdResult.class);
WxMpPrepayIdResult wxMpPrepayIdResult = (WxMpPrepayIdResult) xstream.fromXML(responseContent);
return wxMpPrepayIdResult;
} catch (IOException e) {
e.printStackTrace();
}
return new WxMpPrepayIdResult();
}
/**
* 处理微信支付请求
*
* @param tradeNo
* @param amt
* @param request
* @return
*/
private Map<String, String> dealWxPay(String tradeNo, Double amt, HttpServletRequest request) {
// 用户app ip
String ip = PayUtil.getClientIp(request);
logger.info("get payment user ip : {}", ip);
// 通知地址
String notifyUrl = PropertiesUtil.getString("notifyUrl");
logger.info("get payment notifyUrl : {}", notifyUrl);
Map<String, String> prepayIdResult = wxMpService.getAppPayInfo("", tradeNo, amt, "APP充值", "APP", ip,
notifyUrl);
logger.info("get weixin prepayId info : {}", prepayIdResult);
return prepayIdResult;
}
处理通知(这里要注意验证微信传来消息):
/**
* 微信支付返回消息验证
*
* @param request
* @param response
* @return
*/
@RequestMapping("/wx/payNotify")
@ResponseBody
public void wxPayNotify(HttpServletRequest request, HttpServletResponse response) {
Map<String, String> payInfo = null;
try {
String inputLine;
StringBuffer notityXml = new StringBuffer("");
BufferedReader reader = request.getReader();
while ((inputLine = reader.readLine()) != null) {
notityXml.append(inputLine);
}
payInfo = XMLUtil.doXMLParse(notityXml.toString());
logger.info("解析微信支付结果:{}", payInfo);
} catch (Exception e) {
logger.error("解析微信支付通知有误:{}", e);
return;
}
String returnCode = payInfo.get("return_code");
if (returnCode.isEmpty()) {
logger.warn("从微信获取支付结果错误:returnCode is empty.");
return;
}
if (returnCode.equals("FAIL")) {
logger.warn("微信支付失败");
return;
}
logger.info("get payInfo:{}", payInfo);
String finalSign = WxCryptUtil.createSign(payInfo, wxMpConfigStorage.getPartnerKey());
logger.info("get sign:{},tenpaySign:{}", finalSign, payInfo.get("sign"));
// 判断签名
if (payInfo.get("sign").toUpperCase().equals(finalSign)) {
String tradeNo = payInfo.get("out_trade_no");
logger.info("tradeNo : " + tradeNo);
Integer amt = Integer.parseInt(payInfo.get("total_fee"));
boolean dealResult = dealPayResult(tradeNo, amt, payInfo);
if (dealResult) {
String wxResponse = TenpayUtil.setXML("SUCCESS", "OK");
logger.info("weixin pay result : " + wxResponse);
try {
PrintWriter out = response.getWriter();
out.write(wxResponse);
out.flush();
logger.info("微信充值成功:{}", payInfo.toString());
return;
} catch (IOException e) {
logger.error("回复微信支付消息失败:{}", e);
return;
}
} else {
String wxResponse = TenpayUtil.setXML("FAIL", "");
logger.info("weixin pay result : " + wxResponse);
try {
PrintWriter out = response.getWriter();
out.write(wxResponse);
out.flush();
logger.warn("系统错误,充值失败");
return;
} catch (IOException e) {
logger.error("回复微信支付消息失败:{}", e);
return;
}
}
} else {
logger.warn("签名验证不通过");
}
}
解析微信XML通知方法:
/**
* 解析xml,返回第一级元素键值对。如果第一级元素有子节点,则此节点的值是子节点的xml数据。
* @param strxml
* @return
* @throws JDOMException
* @throws IOException
*/
public static Map doXMLParse(String strxml) throws JDOMException, IOException {
strxml = strxml.replaceFirst("encoding=\".*\"", "encoding=\"UTF-8\"");
if(null == strxml || "".equals(strxml)) {
return null;
}
Map m = new HashMap();
InputStream in = new ByteArrayInputStream(strxml.getBytes("UTF-8"));
SAXBuilder builder = new SAXBuilder();
Document doc = builder.build(in);
Element root = doc.getRootElement();
List list = root.getChildren();
Iterator it = list.iterator();
while(it.hasNext()) {
Element e = (Element) it.next();
String k = e.getName();
String v = "";
List children = e.getChildren();
if(children.isEmpty()) {
v = e.getTextNormalize();
} else {
v = XMLUtil.getChildrenText(children);
}
m.put(k, v);
}
//关闭流
in.close();
return m;
}
给微信返回处理结果。
/**
* @author cxy
* @Description:返回给微信的参数
* @param return_code 返回编码
* @param return_msg 返回信息
* @return
*/
public static String setXML(String return_code, String return_msg) {
return "<xml><return_code><![CDATA[" + return_code
+ "]]></return_code><return_msg><![CDATA[" + return_msg
+ "]]></return_msg></xml>";
}
推荐一个微信开发的现成代码: