app集成微信支付服务器端开发(java)

一、微信支付太坑爹,废话不说了,下面是我的服务端微信支付开发过程和代码记录

二、首先去微信申请账户,这里有两个平台 

1、微信公众平台
2、微信开放平台(https://open.weixin.qq.com)这里选择第二个

三、账户开通、开发者认证之后就可以进行微信支付开发了

1、微信统一下单接口调用获取预支付id
/**
	 * 获取微信支付所需信息(统一下单接口调用)
	 * @param backURL
	 * @param mDealerOrderEntity
	 * @param mCarInfoEntity
	 * @return
	 * @throws JSONException 
	 * @throws IOException 
	 * @throws JDOMException 
	 */
	public Map<String, String> getWechatOrderInfo(String notifyUrl, MDealerOrderEntity mDealerOrderEntity, String body, HttpServletRequest request, HttpServletResponse response) throws Exception {
		Map<String, String> resultMap = new HashMap<String, String>();
		//生成payPreId
		Map<String, String> payPreIdMap = WechatUtil.getPayPreId(mDealerOrderEntity.getGoodorderno(), body, notifyUrl, request.getRemoteAddr(), String.valueOf((int)(mDealerOrderEntity.getMoney()*100)));
		String prePayId = payPreIdMap.get("prepay_id");
		if(StringUtils.isNotEmpty(prePayId)) {
			//生成调用微信APP参数
			resultMap =  WechatUtil.genPayReq(prePayId);
		}
		return resultMap;
	}

此方法返回的数据如下

{
        "appid": "123132131",
        "noncestr": "416e5cf0acb7e553a880b7647903da6e",
        "packageValue ": "Sign=WXPay",
        "partnerid ": "1276000000",
        "prepayid ": "wx2015101611341514a3cbbbf90572184370",
        "timestamp ": "1444966497",
        "sign": "1DD72B07607B0B41D2827954150D89E9" 
    }
2、服务器端接受微信支付结果通知
/**
	 * 处理微信支付通知
	 * @param request
	 * @return
	 * @throws Exception
	 */
	public String saveWechatNotify(HttpServletRequest request, HttpServletResponse response) throws Exception {
		Map<String, String> noticeMap = XMLUtil.parseXml(request);
		String transactionId = noticeMap.get("transaction_id");
		MWechatInfoEntity wechatInfoEntity = this.findEntityByProperty(MWechatInfoEntity.class, "transactionId", transactionId);
		//如果wechatInfoEntity存在,说明请求已经处理过,直接返回
		if(wechatInfoEntity != null) {
			return "SUCCESS";
		}
		String sign = noticeMap.get("sign");
		noticeMap.remove("sign");
		// 验签通过
		if (WechatUtil.getSignVeryfy(noticeMap, sign)) {
			// 通信成功此字段是通信标识,非交易标识,交易是否成功需要查看result_code来判断
			if ("SUCCESS".equals(noticeMap.get("return_code"))) {
				// 交易成功
				if ("SUCCESS".equals(noticeMap.get("result_code"))) {
					// 商户订单号
					String goodorderno = noticeMap.get("out_trade_no");
					MDealerOrderEntity mDealerOrderEntity = this.findEntityByProperty(MDealerOrderEntity.class, "goodorderno", goodorderno);
					MCarInfoEntity mCarInfoEntity = this.get(MCarInfoEntity.class, mDealerOrderEntity.getCarid());
					// 订单更新时间
					mDealerOrderEntity.setUpdatetime(new Date());
					// ------------------------------
					// 处理业务开始
					// ------------------------------
					// 这里写自己业务相关
					// ------------------------------
					// 处理业务完毕
					// ------------------------------
					noticeMap.put("sign", sign);
					this.common99Service.saveWechatInfo(noticeMap, mDealerOrderEntity.getId());
				} else {
					// 错误时,返回结果未签名,记录retcode、retmsg看失败详情。
					System.out.println("查询验证签名失败或业务错误");
					System.out.println("retcode:" + noticeMap.get("retcode") + " retmsg:" + noticeMap.get("retmsg"));
				}
				return "SUCCESS";
			} else {
				System.out.println("后台调用通信失败");
			}
			return "SUCCESS";
		} else {
			System.out.println("通知签名验证失败");
		}
		return null;
	}
3、上面代码用到的工具方法都在WechatUtil.java工具类中
package com.jim.iweb.haocheok.tenpay.util;

import java.io.IOException;
import java.net.URISyntaxException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Random;

import org.apache.commons.httpclient.HttpStatus;
import org.apache.http.NameValuePair;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.utils.URIBuilder;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.util.EntityUtils;
import org.jdom2.JDOMException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class WechatUtil {

	private static Logger logger = LoggerFactory.getLogger(WechatUtil.class);
	public static final String TAG = "Wechat.Util";
	private static final int timeout = 5000;

	public static byte[] httpPost(String url, String entity) throws URISyntaxException, IOException {
		if (url == null || url.length() == 0) {
			logger.info(TAG, "httpPost, url is null");
			return null;
		}
		CloseableHttpClient httpClient = HttpClients.createDefault();
		URIBuilder uriBuilder = new URIBuilder(url);
		HttpPost httpPost = new HttpPost(uriBuilder.build());
		RequestConfig requestConfig = RequestConfig.custom().setSocketTimeout(timeout).setConnectionRequestTimeout(timeout).setConnectTimeout(timeout).build();
		httpPost.setConfig(requestConfig);
		// 避免汉字乱码导致请求失败,
		httpPost.setEntity(new StringEntity(entity, "UTF-8"));
		CloseableHttpResponse resp = null;
		try {
			resp = httpClient.execute(httpPost);
			if (resp.getStatusLine().getStatusCode() != HttpStatus.SC_OK) {
				logger.info(TAG, "httpGet fail, status code = " + resp.getStatusLine().getStatusCode());
				return null;
			}
			return EntityUtils.toByteArray(resp.getEntity());
		} catch (Exception e) {
			logger.info(TAG, "httpPost exception, e = " + e.getMessage());
			e.printStackTrace();
			return null;
		} finally {
			if (httpClient != null) {
				httpClient.close();
			}
			if (resp != null) {
				resp.close();
			}
		}
	}

	/**
	 * 把数组所有元素排序,并按照“参数=参数值”的模式用“&”字符拼接成字符串
	 * 
	 * @param params
	 *            需要排序并参与字符拼接的参数组
	 * @return 拼接后字符串
	 */
	public static String createLinkString(Map<String, String> params) {

		List<String> keys = new ArrayList<String>(params.keySet());
		Collections.sort(keys);

		String prestr = "";

		for (int i = 0; i < keys.size(); i++) {
			String key = keys.get(i);
			String value = params.get(key);

			if (i == keys.size() - 1) {// 拼接时,不包括最后一个&字符
				prestr = prestr + key + "=" + value;
			} else {
				prestr = prestr + key + "=" + value + "&";
			}
		}

		return prestr;
	}

	/**
	 * 根据反馈回来的信息,生成签名结果
	 * 
	 * @param Params
	 *            通知返回来的参数数组
	 * @param sign
	 *            比对的签名结果
	 * @return 生成的签名结果
	 */
	public static boolean getSignVeryfy(Map<String, String> Params, String sign) {
		// 过滤空值、sign与sign_type参数
		// Map<String, String> sParaNew = AlipayCore.paraFilter(Params);
		// 获取待签名字符串
		String preSignStr = createLinkString(Params);
		preSignStr += "&key=" + ConstantUtil.API_KEY;
		// 获得签名验证结果
		String resultSign = MD5.getMessageDigest(preSignStr.getBytes()).toUpperCase();
		// String resultSign = MD5Util.MD5Encode(preSignStr.toString(), "UTF-8").toLowerCase();
		if (sign.equals(resultSign)) {
			return true;
		} else {
			return false;
		}
	}

	/**
	 * 装配xml,生成请求prePayId所需参数
	 * 
	 * @param params
	 * @return
	 */
	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();
	}

	/**
	 * 生成签名
	 */
	public static String genPackageSign(List<NameValuePair> params) {
		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(ConstantUtil.API_KEY);
		String packageSign = MD5.getMessageDigest(sb.toString().getBytes()).toUpperCase();
		return packageSign;
	}

	/**
	 * 
	 * @param goodOrderNo
	 * @param body
	 * @param noticeUrl
	 * @param ip
	 * @param totalFee
	 * @return
	 */
	public static String genProductArgs(String goodOrderNo, String body, String noticeUrl, String ip, String totalFee) {
		StringBuffer xml = new StringBuffer();
		try {
			String nonceStr = getNonceStr();
			xml.append("</xml>");
			List<NameValuePair> packageParams = new LinkedList<NameValuePair>();
			packageParams.add(new BasicNameValuePair("appid", ConstantUtil.APP_ID));
			packageParams.add(new BasicNameValuePair("body", body));
			packageParams.add(new BasicNameValuePair("mch_id", ConstantUtil.MCH_ID));
			packageParams.add(new BasicNameValuePair("nonce_str", nonceStr));
			packageParams.add(new BasicNameValuePair("notify_url", noticeUrl));
			packageParams.add(new BasicNameValuePair("out_trade_no", goodOrderNo));
			packageParams.add(new BasicNameValuePair("spbill_create_ip", ip));
			packageParams.add(new BasicNameValuePair("total_fee", totalFee));
			packageParams.add(new BasicNameValuePair("trade_type", "APP"));
			String sign = genPackageSign(packageParams);
			packageParams.add(new BasicNameValuePair("sign", sign));
			String xmlstring = toXml(packageParams);
			return xmlstring;
		} catch (Exception e) {
			logger.info("genProductArgs fail, ex = " + e.getMessage());
			return null;
		}
	}

	/**
	 * 生成app支付签名
	 * 
	 * @param params
	 * @return
	 */
	public static String genAppSign(List<NameValuePair> params) {
		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(ConstantUtil.API_KEY);
		String appSign = MD5.getMessageDigest(sb.toString().getBytes()).toUpperCase();
		logger.info("orion", appSign);
		return appSign;
	}

	/**
	 * 生成调用微信app支付所需参数
	 * 
	 * @param prepayId
	 * @return
	 */
	public static Map<String, String> genPayReq(String prepayId) {
		Map<String, String> resultMap = new HashMap<String, String>();
		String timeStamp = getTimeStamp();
		String nonceStr = getNonceStr();
		List<NameValuePair> signParams = new LinkedList<NameValuePair>();
		signParams.add(new BasicNameValuePair("appid", ConstantUtil.APP_ID));
		signParams.add(new BasicNameValuePair("noncestr", nonceStr));
		signParams.add(new BasicNameValuePair("package", "Sign=WXPay"));
		signParams.add(new BasicNameValuePair("partnerid", ConstantUtil.MCH_ID));
		signParams.add(new BasicNameValuePair("prepayid", prepayId));
		signParams.add(new BasicNameValuePair("timestamp", timeStamp));
		String sign = genAppSign(signParams);
		resultMap.put("appid", ConstantUtil.APP_ID);
		resultMap.put("noncestr", nonceStr);
		resultMap.put("packageValue", "Sign=WXPay");
		resultMap.put("partnerid", ConstantUtil.MCH_ID);
		resultMap.put("prepayid", prepayId);
		resultMap.put("timestamp", timeStamp);
		resultMap.put("sign", sign);
		return resultMap;
	}

	/**
	 * 微信支付生成预支付订单
	 * 
	 * @throws IOException
	 * @throws JDOMException
	 */
	public static Map<String, String> getPayPreId(String goodOrderNo, String body, String noticeUrl, String ip, String totalFee) throws Exception {
		String paramsXml = genProductArgs(goodOrderNo, body, noticeUrl, ip, totalFee);
		logger.info("orion", paramsXml);
		byte[] buf = WechatUtil.httpPost(ConstantUtil.URL, paramsXml);
		String contentXml = new String(buf);
		Map<String, String> resultMap = XMLUtil.doXMLParse(contentXml);
		return resultMap;
	}

	public static String getNonceStr() {
		Random random = new Random();
		return MD5.getMessageDigest(String.valueOf(random.nextInt(10000)).getBytes());
	}

	public static String getTimeStamp() {
		return String.valueOf(System.currentTimeMillis() / 1000);
	}
}
4、下面是用到的配置类
package com.jim.iweb.haocheok.tenpay.util;

public class ConstantUtil {
	/**
	 * 商家可以考虑读取配置文件
	 */
	
	//初始化
	public static String APP_ID = "wxsdfsdfsf5fdbc";//微信开发平台应用id
	public static String APP_SECRET = "aab95csdfsdfsffdcsdfsfs0df34";//应用对应的凭证
	//商户号
	public static String MCH_ID = "1233312201";
	public static String PARTNER = "1233312201";//财付通商户号
	public static String API_KEY = "KgjyjirmjajdfjsdjfsjffVpT6RMbrB";
	public static String PARTNER_KEY = "KgjyjirmjajdfjsdjfsjffVpT6RMbrB";//商户号对应的密钥
	public static String URL = "https://api.mch.weixin.qq.com/pay/unifiedorder";//获取预支付id的接口url
}


你可能感兴趣的:(java,APP,微信支付,微信支付服务器实现)