WXPayUtil
package example.wx;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import java.io.*;
import java.net.HttpURLConnection;
import java.net.URL;
import java.security.MessageDigest;
import java.util.*;
public class WXPayUtil {
private static String APP_ID;
private static String MCH_ID;
private static String API_KEY;
private static String NOTIFY_URL;
public static void initWxPay(String appId, String mchId, String apiKey, String notifyUrl) {
APP_ID = appId;
MCH_ID = mchId;
API_KEY = apiKey;
NOTIFY_URL = notifyUrl;
}
private static final String UNIFIEDORDER_ADDRESS = "https://api.mch.weixin.qq.com/pay/unifiedorder";
public static class WXPayReq {
private String appid;
private String partnerid;
private String prepayid;
private String packageValue; // package
private String noncestr;
private String timestamp;
private String sign;
private String getAppid() {
return appid;
}
private void setAppid(String appid) {
this.appid = appid;
}
private String getPartnerid() {
return partnerid;
}
private void setPartnerid(String partnerid) {
this.partnerid = partnerid;
}
private String getPrepayid() {
return prepayid;
}
private void setPrepayid(String prepayid) {
this.prepayid = prepayid;
}
private String getPackageValue() {
return packageValue;
}
private void setPackageValue(String packageValue) {
this.packageValue = packageValue;
}
private String getNoncestr() {
return noncestr;
}
private void setNoncestr(String noncestr) {
this.noncestr = noncestr;
}
private String getTimestamp() {
return timestamp;
}
private void setTimestamp(String timestamp) {
this.timestamp = timestamp;
}
public String getSign() {
return sign;
}
public void setSign(String sign) {
this.sign = sign;
}
}
public static WXPayReq requestPayReq(String subject, String body, String price, String paymentCode, String ip) {
List<KeyValue<String, String>> orderInfo = generateOrderInfo(subject, body, price, paymentCode, ip);
String orderInfoStr = toXml(orderInfo);
WXPayReq payReq = new WXPayReq();
try {
URL httpUrl = new URL(UNIFIEDORDER_ADDRESS);
HttpURLConnection httpURLConnection = (HttpURLConnection) httpUrl.openConnection();
httpURLConnection.setRequestProperty("Host", "api.mch.weixin.qq.com");
httpURLConnection.setDoOutput(true);
httpURLConnection.setRequestMethod("POST");
httpURLConnection.setConnectTimeout(10 * 1000);
httpURLConnection.setReadTimeout(10 * 1000);
httpURLConnection.connect();
OutputStream outputStream = httpURLConnection.getOutputStream();
outputStream.write(orderInfoStr.getBytes("UTF-8"));
//获取内容
InputStream inputStream = httpURLConnection.getInputStream();
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream, "UTF-8"));
final StringBuffer stringBuffer = new StringBuffer();
String line;
while ((line = bufferedReader.readLine()) != null) {
stringBuffer.append(line);
}
String result = stringBuffer.toString();
bufferedReader.close();
inputStream.close();
outputStream.close();
Map<String, String> xml = decodeXml(result);
payReq.setAppid(APP_ID);
payReq.setNoncestr(genNonceStr());
payReq.setPackageValue("Sign=WXPay");
payReq.setPartnerid(MCH_ID);
payReq.setPrepayid(xml.get("prepay_id"));
payReq.setTimestamp(String.valueOf(System.currentTimeMillis() / 1000));
payReq.setSign(generateSign(payReq));
return payReq;
} catch (Exception e) {
return null;
}
}
private static String generateSign(WXPayReq payReq) {
List<KeyValue<String, String>> signParams = new LinkedList<KeyValue<String, String>>();
signParams.add(new KeyValue<>("appid", payReq.getAppid()));
signParams.add(new KeyValue<>("noncestr", payReq.getNoncestr()));
signParams.add(new KeyValue<>("package", payReq.getPackageValue()));
signParams.add(new KeyValue<>("partnerid", payReq.getPartnerid()));
signParams.add(new KeyValue<>("prepayid", payReq.getPrepayid()));
signParams.add(new KeyValue<>("timestamp", payReq.getTimestamp()));
StringBuilder sb = new StringBuilder();
for (KeyValue<String, String> keyValue : signParams) {
sb.append(keyValue.getKey()).append('=').append(keyValue.getValue()).append('&');
}
sb.append("key=");
sb.append(API_KEY);
return MD5.getMessageDigest(sb.toString().getBytes()).toUpperCase();
}
private static Map<String, String> decodeXml(String strXML) {
try {
Map<String, String> data = new HashMap<>();
DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
DocumentBuilder documentBuilder = documentBuilderFactory.newDocumentBuilder();
InputStream stream = new ByteArrayInputStream(strXML.getBytes("UTF-8"));
org.w3c.dom.Document doc = documentBuilder.parse(stream);
doc.getDocumentElement().normalize();
NodeList nodeList = doc.getDocumentElement().getChildNodes();
for (int idx = 0; idx < nodeList.getLength(); ++idx) {
Node node = nodeList.item(idx);
if (node.getNodeType() == Node.ELEMENT_NODE) {
org.w3c.dom.Element element = (org.w3c.dom.Element) node;
data.put(element.getNodeName(), element.getTextContent());
}
}
try {
stream.close();
} catch (Exception ex) {
}
return data;
} catch (Exception ex) {
return null;
}
}
private static List<KeyValue<String, String>> generateOrderInfo(String subject, String body, String price, String paymentCode, String ip) {
String nonceStr = genNonceStr();
List<KeyValue<String, String>> orderInfo = new LinkedList<>();
try {
orderInfo.add(new KeyValue<>("appid", APP_ID));
orderInfo.add(new KeyValue<>("body", new String(subject.getBytes("UTF-8"))));
orderInfo.add(new KeyValue<>("detail", new String(body.getBytes("UTF-8"))));
orderInfo.add(new KeyValue<>("mch_id", MCH_ID));
orderInfo.add(new KeyValue<>("nonce_str", nonceStr));
orderInfo.add(new KeyValue<>("notify_url", NOTIFY_URL));
orderInfo.add(new KeyValue<>("out_trade_no", paymentCode));
orderInfo.add(new KeyValue<>("spbill_create_ip", ip));
orderInfo.add(new KeyValue<>("total_fee", price));
orderInfo.add(new KeyValue<>("trade_type", "APP"));
orderInfo.add(new KeyValue<>("sign", genPackageSign(orderInfo)));
} catch (Exception e) {
}
return orderInfo;
}
/**
* 生成签名
*/
private static String genPackageSign(List<KeyValue<String, String>> orderInfo) {
StringBuilder sb = new StringBuilder();
for (KeyValue<String, String> keyValue : orderInfo) {
sb.append(keyValue.getKey());
sb.append('=');
sb.append(keyValue.getValue());
sb.append('&');
}
sb.append("key=");
sb.append(API_KEY);
return MD5.getMessageDigest(sb.toString().getBytes()).toUpperCase();
}
private static String toXml(List<KeyValue<String, String>> params) {
StringBuilder sb = new StringBuilder();
sb.append("<xml>");
for (KeyValue<String, String> keyValue : params) {
sb.append("<").append(keyValue.getKey()).append(">").append(keyValue.getValue()).append("</").append(keyValue.getKey()).append(">");
}
sb.append("</xml>");
return sb.toString();
}
private static String genNonceStr() {
Random random = new Random();
return MD5.getMessageDigest(String.valueOf(random.nextInt(10000)).getBytes());
}
private static class MD5 {
private final static String[] hexDigits = {"0", "1", "2", "3", "4", "5", "6", "7",
"8", "9", "a", "b", "c", "d", "e", "f"};
private MD5() {
}
private 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;
}
}
/**
* MD5编码
*
* @param origin 原始字符串
* @return 经过MD5加密之后的结果
*/
public static String MD5Encode(String origin) {
String resultString = null;
try {
resultString = origin;
MessageDigest md = MessageDigest.getInstance("MD5");
md.update(resultString.getBytes("UTF-8"));
resultString = byteArrayToHexString(md.digest());
} catch (Exception e) {
e.printStackTrace();
}
return resultString;
}
/**
* 转换字节数组为16进制字串
*
* @param b 字节数组
* @return 16进制字串
*/
public static String byteArrayToHexString(byte[] b) {
StringBuilder resultSb = new StringBuilder();
for (byte aB : b) {
resultSb.append(byteToHexString(aB));
}
return resultSb.toString();
}
/**
* 转换byte到16进制
*
* @param b 要转换的byte
* @return 16进制格式
*/
private static String byteToHexString(byte b) {
int n = b;
if (n < 0) {
n = 256 + n;
}
int d1 = n / 16;
int d2 = n % 16;
return hexDigits[d1] + hexDigits[d2];
}
}
private static class KeyValue<K, V> implements Map.Entry<K, V> {
private K key;
private V value;
public KeyValue(K key, V value) {
this.key = key;
this.value = value;
}
@Override
public K getKey() {
return key;
}
@Override
public V getValue() {
return value;
}
@Override
public V setValue(V value) {
return this.value = value;
}
}
}
使用方法
WXPayUtil.initWxPay(APP_ID, MCH_ID, API_KEY, NOTIFY_URL);
WXPayUtil.WXPayReq req = WXPayUtil.requestPayReq("Subject", "Body", "2", "hhh" + System.currentTimeMillis(), "127.0.0.1");
System.out.println(new Gson().toJson(req));