您的位置:首页 > 移动开发 > 微信开发

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

2015-10-26 14:38 621 查看


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


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


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 = ne
b84d
w 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
}



5、xml 解析工具类


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
}


5、xml 解析工具类

package com.jim.iweb.haocheok.tenpay.util;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;

import org.dom4j.io.SAXReader;
import org.jdom2.Document;
import org.jdom2.Element;
import org.jdom2.JDOMException;
import org.jdom2.input.SAXBuilder;

/**
 * xml工具类
 * 
 * @author miklchen
 *
 */
public class XMLUtil {

/**
 * 解析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;
}

/**
 * 获取子结点的xml
 * 
 * @param children
 * @return String
 */
public static String getChildrenText(List children) {
StringBuffer sb = new StringBuffer();
if (!children.isEmpty()) {
Iterator it = children.iterator();
while (it.hasNext()) {
Element e = (Element) it.next();
String name = e.getName();
String value = e.getTextNormalize();
List list = e.getChildren();
sb.append("<" + name + ">");
if (!list.isEmpty()) {
sb.append(XMLUtil.getChildrenText(list));
}
sb.append(value);
sb.append("</" + name + ">");
}
}

return sb.toString();
}

/**
 * 将requestxml通知结果转出啊成map
 * @param request
 * @return
 * @throws Exception
 */
public static Map<String, String> parseXml(HttpServletRequest request) throws Exception {
// 解析结果存储在HashMap
Map<String, String> map = new HashMap<String, String>();
InputStream inputStream = request.getInputStream();
// 读取输入流
SAXReader reader = new SAXReader();
org.dom4j.Document document = reader.read(inputStream);
// 得到xml根元素
org.dom4j.Element root = document.getRootElement();
// 得到根元素的所有子节点
List<org.dom4j.Element> elementList = root.elements();
// 遍历所有子节点
for (org.dom4j.Element e : elementList)
map.put(e.getName(), e.getText());
// 释放资源
inputStream.close();
inputStream = null;
return map;
}

}


?
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息