/** * */ package jframe.pay.wx.http.client; import java.io.UnsupportedEncodingException; import java.security.MessageDigest; import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.Random; import org.apache.http.NameValuePair; import org.apache.http.message.BasicNameValuePair; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import jframe.pay.domain.TradeType; import jframe.pay.domain.util.IDUtil; import jframe.pay.domain.util.XmlUtil; import jframe.pay.wx.domain.WxConfig; import jframe.pay.wx.domain.WxFields; import jframe.pay.wx.http.util.MD5Util; /** * https://pay.weixin.qq.com/wiki/doc/api/app.php?chapter=9_1 * * @author dzh * @date Oct 16, 2015 3:57:01 PM * @since 1.0 */ public class WxServiceNew { static Logger LOG = LoggerFactory.getLogger(WxServiceNew.class); public static boolean genPrePay(Map<String, String> req, Map<String, Object> rsp) { try { String url = String.format("https://api.mch.weixin.qq.com/pay/unifiedorder"); String orderNo = genOutTradNo(); req.put(WxFields.F_orderNo, orderNo); List<NameValuePair> packageParams = new LinkedList<NameValuePair>(); packageParams.add(new BasicNameValuePair(WxFields.F_appid, WxConfig.getConf(WxConfig.KEY_APP_ID))); if (req.containsKey(WxFields.F_attach)) { packageParams.add(new BasicNameValuePair(WxFields.F_attach, req.get(WxFields.F_attach))); } packageParams.add(new BasicNameValuePair(WxFields.F_body, req.get(WxFields.F_payDesc))); packageParams.add(new BasicNameValuePair(WxFields.F_mch_id, WxConfig.getConf(WxConfig.KEY_PARTNER))); packageParams.add(new BasicNameValuePair(WxFields.F_nonce_str, genNonceStr())); packageParams.add(new BasicNameValuePair(WxFields.F_notify_url, WxConfig.getConf(WxConfig.KEY_NOTIFY_URL))); if (req.containsKey(WxFields.F_openid)) { packageParams.add(new BasicNameValuePair(WxFields.F_openid, req.get(WxFields.F_openid))); } packageParams.add(new BasicNameValuePair(WxFields.F_out_trade_no, orderNo)); packageParams.add(new BasicNameValuePair(WxFields.F_spbill_create_ip, req.get(WxFields.F_remoteIp))); packageParams.add(new BasicNameValuePair(WxFields.F_total_fee, req.get(WxFields.F_payAmount))); packageParams.add(new BasicNameValuePair(WxFields.F_trade_type, req.getOrDefault(WxFields.F_tradeType, TradeType.APP.code))); String sign = genPackageSign(packageParams); packageParams.add(new BasicNameValuePair(WxFields.F_sign, sign)); String entity = toXml(packageParams); // byte[] buf = httpPost(url, entity); TenpayHttpClient httpClient = new TenpayHttpClient(); httpClient.setReqContent(entity); if (httpClient.callHttpPost(url, entity)) { String content = httpClient.getResContent(); if (LOG.isDebugEnabled()) LOG.debug("genPrePay url -> {}, req -> {}, rsp -> {}", url, entity, content); Map<String, String> xml = XmlUtil.fromXml(content); if (xml.get(WxFields.F_return_code).equalsIgnoreCase("SUCCESS")) { // 这些是手机端需要的参数 rsp.put(WxFields.F_appid, WxConfig.getConf(WxConfig.KEY_APP_ID)); rsp.put(WxFields.F_partnerid, WxConfig.getConf(WxConfig.KEY_PARTNER)); rsp.put(WxFields.F_prepayid, xml.get(WxFields.F_prepay_id)); String nonceStr = genNonceStr(); rsp.put(WxFields.F_noncestr, nonceStr); rsp.put(WxFields.F_package, "Sign=WXPay"); String timeStamp = String.valueOf(genTimeStamp()); rsp.put(WxFields.F_timestamp, timeStamp); // app sign List<NameValuePair> signParams = new LinkedList<NameValuePair>(); signParams.add(new BasicNameValuePair(WxFields.F_appid, WxConfig.getConf(WxConfig.KEY_APP_ID))); signParams.add(new BasicNameValuePair(WxFields.F_noncestr, nonceStr)); signParams.add(new BasicNameValuePair(WxFields.F_package, "Sign=WXPay")); signParams .add(new BasicNameValuePair(WxFields.F_partnerid, WxConfig.getConf(WxConfig.KEY_PARTNER))); signParams.add(new BasicNameValuePair(WxFields.F_prepayid, xml.get(WxFields.F_prepay_id))); signParams.add(new BasicNameValuePair(WxFields.F_timestamp, timeStamp)); rsp.put(WxFields.F_sign, genAppSign(signParams)); // rsp.put(WxFields.F_trade_type, // xml.get(WxFields.F_trade_type)); return true; } } } catch (Exception e) { LOG.error(e.getMessage()); } return false; } private static String genAppSign(List<NameValuePair> params) throws Exception { StringBuilder sb = new StringBuilder(); for (int i = 0; i < params.size(); i++) { sb.append(params.get(i).getName()); sb.append('='); sb.append(params.get(i).getValue()); sb.append('&'); } sb.append("key="); sb.append(WxConfig.getConf(WxConfig.KEY_APP_KEY)); String appSign = getMessageDigest(sb.toString().getBytes("UTF-8")).toUpperCase(); return appSign; } /** * 生成签名 * * @throws UnsupportedEncodingException */ public static String genPackageSign(List<NameValuePair> params) throws UnsupportedEncodingException { StringBuilder sb = new StringBuilder(); for (int i = 0; i < params.size(); i++) { sb.append(params.get(i).getName()); sb.append('='); sb.append(params.get(i).getValue()); sb.append('&'); } sb.append("key="); sb.append(WxConfig.getConf(WxConfig.KEY_APP_KEY)); String packageSign = getMessageDigest(sb.toString().getBytes("UTF-8")).toUpperCase(); // String packageSign = MD5Util.MD5Encode(sb.toString(), // "").toUpperCase(); return packageSign; } public final static String getMessageDigest(byte[] buffer) { char hexDigits[] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' }; try { MessageDigest mdTemp = MessageDigest.getInstance("MD5"); mdTemp.update(buffer); byte[] md = mdTemp.digest(); int j = md.length; char str[] = new char[j * 2]; int k = 0; for (int i = 0; i < j; i++) { byte byte0 = md[i]; str[k++] = hexDigits[byte0 >>> 4 & 0xf]; str[k++] = hexDigits[byte0 & 0xf]; } return new String(str); } catch (Exception e) { return null; } } private static String genOutTradNo() { return IDUtil.genOrderNo(); } public static String toXml(List<NameValuePair> params) { StringBuilder sb = new StringBuilder(); sb.append("<xml>"); for (int i = 0; i < params.size(); i++) { sb.append("<" + params.get(i).getName() + ">"); sb.append(params.get(i).getValue()); sb.append("</" + params.get(i).getName() + ">"); } sb.append("</xml>"); return sb.toString(); } private static String genNonceStr() { Random random = new Random(); return MD5Util.MD5Encode(String.valueOf(random.nextInt(10000)), ""); // return // MD5.getMessageDigest(String.valueOf(random.nextInt(10000)).getBytes()); } private static long genTimeStamp() { return System.currentTimeMillis() / 1000; } /** * check sign https://pay.weixin.qq.com/wiki/doc/api/app.php?chapter=4_3 * * @param req * @param rsp * @return */ public static boolean backPay(Map<String, String> req, Map<String, Object> rsp) { // TODO check sign return req.getOrDefault(WxFields.F_result_code, "failure").equalsIgnoreCase("SUCCESS"); } }