package com.jade.laiding.client.util;
import java.util.*;
import com.jade.laiding.order.order.Order;
import org.apache.commons.lang3.StringUtils;
import org.apache.http.NameValuePair;
import org.apache.http.message.BasicNameValuePair;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;
import javax.servlet.http.HttpServletRequest;
/**
* Created by tusm on 公元15-10-27.
*/
public class WeChatPayUtil {
private static final String WeChat_APP_ID="#####################";
private static final String WeChat_MCH_ID="#####################";
private static final String WeChat_API_KEY="####################";
//微信支付第一步,先从微信的服务器获取prepayId
public static String getPrepayId(String url,Order order){
Map<String,String> xml=new HashMap<String,String>();
String prePayId = "";
if(order != null){
String entity = genProductArgs(order);
byte[] buf = Util.httpPost(url, entity);
if(buf != null){
String content = new String(buf);
//Log.e("orion", content);
try {
Document doc = (Document)DocumentHelper.parseText(content);
Element root = doc.getRootElement();
List<Element> list = root.elements();
for (Element e : list) {
xml.put(e.getName(), e.getText());
}
} catch (DocumentException e) {
e.printStackTrace();
}
if(xml != null){
prePayId = xml.get("prepay_id");
return prePayId;
}
}
}
return null;
}
//第二步,根据prepayId生成签名参数
public static PayReq genPayReq(PayReq req,String prePayId) {
req.setAppId(WeChatPayUtil.WeChat_APP_ID);
req.setPartnerId(WeChatPayUtil.WeChat_MCH_ID);
req.setPrepayId(prePayId);
req.setPackageValue("Sign=WXPay");
req.setNonceStr(genNonceStr());
req.setTimeStamp(String.valueOf(genTimeStamp()));
List<NameValuePair> signParams = new LinkedList<NameValuePair>();
signParams.add(new BasicNameValuePair("appid", req.getAppId()));
signParams.add(new BasicNameValuePair("noncestr", req.getNonceStr()));
signParams.add(new BasicNameValuePair("package",req.getPackageValue()));
signParams.add(new BasicNameValuePair("partnerid",req.getPartnerId()));
signParams.add(new BasicNameValuePair("prepayid",req.getPrepayId()));
signParams.add(new BasicNameValuePair("timestamp", req.getTimeStamp()));
req.setSign(genAppSign(signParams));
return req;
//Log.i("orion", signParams.toString());
}
//第三步,调用支付接口支付
/* public static void Pay(IWXAPI msgApi,PayReq req){
msgApi.sendReq(req);
}*/
/**
* 拼接参数
* @param order
* @return
*/
private static String genProductArgs(Order order) {
StringBuffer xml = new StringBuffer();
try {
String nonceStr = genNonceStr();
xml.append("</xml>");
List<NameValuePair> packageParams = new LinkedList<NameValuePair>();
packageParams.add(new BasicNameValuePair("appid", WeChatPayUtil.WeChat_APP_ID));
packageParams.add(new BasicNameValuePair("body", "测试"));//商品描述,商品或支付单简要描述,必填
packageParams.add(new BasicNameValuePair("mch_id", WeChatPayUtil.WeChat_MCH_ID));
packageParams.add(new BasicNameValuePair("nonce_str", nonceStr));//随机字符串,不长于32位。必填
packageParams.add(new BasicNameValuePair("notify_url", "http://外网IP:8182/client/order/editOrderWxPayStatus"));//接收微信支付异步通知回调地址.必填
packageParams.add(new BasicNameValuePair("out_trade_no",order.getId()+""));//商户系统内部的订单号,32个字符内、可包含字母,必填
packageParams.add(new BasicNameValuePair("spbill_create_ip",order.getIp()));//APP和网页支付提交用户端ip.必填
packageParams.add(new BasicNameValuePair("total_fee", (int)(order.getFinalAmount()*100)+""));//订单总金额,只能为整数.必填
packageParams.add(new BasicNameValuePair("trade_type", "APP"));//取值如下:JSAPI,NATIVE,APP,WAP,必填
String sign = genPackageSign(packageParams);
packageParams.add(new BasicNameValuePair("sign", sign));//签名
String xmlstring =toXml(packageParams);
xmlstring = new String(xmlstring.getBytes("UTF-8"), "ISO-8859-1");
return xmlstring;
} catch (Exception e) {
//Log.e("e", "genProductArgs fail, ex = " + e.getMessage());
return null;
}
}
/**
* 拼接异步通知成功通知微信参数
* @return
*/
public static String returnCodeSUCCESS() {
StringBuffer xml = new StringBuffer();
try {
xml.append("</xml>");
List<NameValuePair> packageParams = new LinkedList<NameValuePair>();
packageParams.add(new BasicNameValuePair("return_code", "SUCCESS"));//SUCCESS表示商户接收通知成功并校验成功必填
String xmlstring =toXml(packageParams);
xmlstring = new String(xmlstring.getBytes("UTF-8"), "ISO-8859-1");
return xmlstring;
} catch (Exception e) {
return null;
}
}
/**
* 拼接异步通知失败通知微信参数
* @return
*/
public static String returnCodeFAIL() {
StringBuffer xml = new StringBuffer();
try {
xml.append("</xml>");
List<NameValuePair> packageParams = new LinkedList<NameValuePair>();
packageParams.add(new BasicNameValuePair("return_code", "FAIL"));//FAIL失败
String xmlstring =toXml(packageParams);
xmlstring = new String(xmlstring.getBytes("UTF-8"), "ISO-8859-1");
return xmlstring;
} catch (Exception e) {
return null;
}
}
/**
生成签名
*/
private 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(WeChatPayUtil.WeChat_API_KEY);
String packageSign = MD5.getMessageDigest(sb.toString().getBytes()).toUpperCase();
//Log.e("orion",packageSign);
return packageSign;
}
/**
* 转换成String格式的xml
* @param params
* @return
*/
private 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>");
//Log.e("orion",sb.toString());
return sb.toString();
}
/**
* 生成有key的app签名
* @param params
* @return
*/
private 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(WeChatPayUtil.WeChat_API_KEY);
String appSign = MD5.getMessageDigest(sb.toString().getBytes()).toUpperCase();
//Log.e("orion",appSign);
return appSign;
}
/**
* 时间戳
* @return
*/
private static long genTimeStamp() {
return System.currentTimeMillis() / 1000;
}
/**
* 随机字符串
* @return
*/
private static String genNonceStr() {
Random random = new Random();
return MD5.getMessageDigest(String.valueOf(random.nextInt(10000)).getBytes());
}
public static String getIp2(HttpServletRequest request) {
String ip = request.getHeader("X-Forwarded-For");
if(StringUtils.isNotEmpty(ip) && !"unKnown".equalsIgnoreCase(ip)){
//多次反向代理后会有多个ip值,第一个ip才是真实ip
int index = ip.indexOf(",");
if(index != -1){
return ip.substring(0,index);
}else{
return ip;
}
}
ip = request.getHeader("X-Real-IP");
if(StringUtils.isNotEmpty(ip) && !"unKnown".equalsIgnoreCase(ip)){
return ip;
}
return request.getRemoteAddr();
}
}
有些类可能没用到的,看情况删掉,这段代码 我本人测试可用,大家只需要关注核心——怎么将string 类型的xml 参数封装成 entity,并且以 http请求post方式传递给微信服务端,然后使用Dom4j解析返回的XML,再封装成Map!
package com.jade.laiding.client.util;
import java.security.MessageDigest;
public class MD5 {
private MD5() {}
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;
}
}
}
package com.jade.laiding.client.util;
import java.security.MessageDigest;
public class MD5Util {
private static String byteArrayToHexString(byte b[]) {
StringBuffer resultSb = new StringBuffer();
for (int i = 0; i < b.length; i++)
resultSb.append(byteToHexString(b[i]));
return resultSb.toString();
}
private static String byteToHexString(byte b) {
int n = b;
if (n < 0)
n += 256;
int d1 = n / 16;
int d2 = n % 16;
return hexDigits[d1] + hexDigits[d2];
}
public static String MD5Encode(String origin, String charsetname) {
String resultString = null;
try {
resultString = new String(origin);
MessageDigest md = MessageDigest.getInstance("MD5");
if (charsetname == null || "".equals(charsetname))
resultString = byteArrayToHexString(md.digest(resultString
.getBytes()));
else
resultString = byteArrayToHexString(md.digest(resultString
.getBytes(charsetname)));
} catch (Exception exception) {
}
return resultString;
}
private static final String hexDigits[] = { "0", "1", "2", "3", "4", "5",
"6", "7", "8", "9", "a", "b", "c", "d", "e", "f" };
}
package com.jade.laiding.client.util;
/**
* @author <a href="mailto:haoran.zhang@basung.com">zhanghaoran</a>
* @version 1.0
* @date 15/10/29 上午11:22
* 支付请求辅助类,这个类本来应该是Jar自带的功能,结果我没找到Jar,所以自己新建了这个辅助类,只是为了存数据而已<pre name="code" class="java">package com.jade.laiding.client.util;
import org.apache.http.HttpResponse;
import org.apache.http.HttpStatus;
import org.apache.http.HttpVersion;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.conn.ClientConnectionManager;
import org.apache.http.conn.scheme.PlainSocketFactory;
import org.apache.http.conn.scheme.Scheme;
import org.apache.http.conn.scheme.SchemeRegistry;
import org.apache.http.conn.ssl.SSLSocketFactory;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.impl.conn.tsccm.ThreadSafeClientConnManager;
import org.apache.http.params.BasicHttpParams;
import org.apache.http.params.HttpParams;
import org.apache.http.params.HttpProtocolParams;
import org.apache.http.protocol.HTTP;
import org.apache.http.util.EntityUtils;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.net.Socket;
import java.net.UnknownHostException;
import java.security.KeyManagementException;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.UnrecoverableKeyException;
import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.List;
import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
public class Util {
private static final String TAG = "SDK_Sample.Util";
public static byte[] httpGet(final String url) {
if (url == null || url.length() == 0) {
//Log.e(TAG, "httpGet, url is null");
return null;
}
HttpClient httpClient = getNewHttpClient();
HttpGet httpGet = new HttpGet(url);
try {
HttpResponse resp = httpClient.execute(httpGet);
if (resp.getStatusLine().getStatusCode() != HttpStatus.SC_OK) {
//Log.e(TAG, "httpGet fail, status code = " + resp.getStatusLine().getStatusCode());
return null;
}
return EntityUtils.toByteArray(resp.getEntity());
} catch (Exception e) {
//Log.e(TAG, "httpGet exception, e = " + e.getMessage());
e.printStackTrace();
return null;
}
}
public static byte[] httpPost(String url, String entity) {
if (url == null || url.length() == 0) {
//Log.e(TAG, "httpPost, url is null");
return null;
}
HttpClient httpClient = getNewHttpClient();
HttpPost httpPost = new HttpPost(url);
try {
httpPost.setEntity(new StringEntity(entity));
httpPost.setHeader("Accept", "application/json");
httpPost.setHeader("Content-type", "application/json");
HttpResponse resp = httpClient.execute(httpPost);
if (resp.getStatusLine().getStatusCode() != HttpStatus.SC_OK) {
//Log.e(TAG, "httpGet fail, status code = " + resp.getStatusLine().getStatusCode());
return null;
}
return EntityUtils.toByteArray(resp.getEntity());
} catch (Exception e) {
//Log.e(TAG, "httpPost exception, e = " + e.getMessage());
e.printStackTrace();
return null;
}
}
private static class SSLSocketFactoryEx extends SSLSocketFactory {
SSLContext sslContext = SSLContext.getInstance("TLS");
public SSLSocketFactoryEx(KeyStore truststore) throws NoSuchAlgorithmException, KeyManagementException, KeyStoreException, UnrecoverableKeyException {
super(truststore);
TrustManager tm = new X509TrustManager() {
public X509Certificate[] getAcceptedIssuers() {
return null;
}
public void checkClientTrusted(X509Certificate[] chain, String authType) throws java.security.cert.CertificateException {
}
public void checkServerTrusted(X509Certificate[] chain, String authType) throws java.security.cert.CertificateException {
}
};
sslContext.init(null, new TrustManager[] { tm }, null);
}
@Override
public Socket createSocket(Socket socket, String host, int port, boolean autoClose) throws IOException, UnknownHostException {
return sslContext.getSocketFactory().createSocket(socket, host, port, autoClose);
}
@Override
public Socket createSocket() throws IOException {
return sslContext.getSocketFactory().createSocket();
}
}
private static HttpClient getNewHttpClient() {
try {
KeyStore trustStore = KeyStore.getInstance(KeyStore.getDefaultType());
trustStore.load(null, null);
SSLSocketFactory sf = new SSLSocketFactoryEx(trustStore);
sf.setHostnameVerifier(SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);
HttpParams params = new BasicHttpParams();
HttpProtocolParams.setVersion(params, HttpVersion.HTTP_1_1);
HttpProtocolParams.setContentCharset(params, HTTP.UTF_8);
SchemeRegistry registry = new SchemeRegistry();
registry.register(new Scheme("http", PlainSocketFactory.getSocketFactory(), 80));
registry.register(new Scheme("https", sf, 443));
ClientConnectionManager ccm = new ThreadSafeClientConnManager(params, registry);
return new DefaultHttpClient(ccm, params);
} catch (Exception e) {
return new DefaultHttpClient();
}
}
public static byte[] readFromFile(String fileName, int offset, int len) {
if (fileName == null) {
return null;
}
File file = new File(fileName);
if (!file.exists()) {
//Log.i(TAG, "readFromFile: file not found");
return null;
}
if (len == -1) {
len = (int) file.length();
}
//Log.d(TAG, "readFromFile : offset = " + offset + " len = " + len + " offset + len = " + (offset + len));
if(offset <0){
//Log.e(TAG, "readFromFile invalid offset:" + offset);
return null;
}
if(len <=0 ){
//Log.e(TAG, "readFromFile invalid len:" + len);
return null;
}
if(offset + len > (int) file.length()){
//Log.e(TAG, "readFromFile invalid file len:" + file.length());
return null;
}
byte[] b = null;
try {
RandomAccessFile in = new RandomAccessFile(fileName, "r");
b = new byte[len]; // ´´½¨ºÏÊÊÎļþ´óСµÄÊý×é
in.seek(offset);
in.readFully(b);
in.close();
} catch (Exception e) {
//Log.e(TAG, "readFromFile : errMsg = " + e.getMessage());
e.printStackTrace();
}
return b;
}
public static String sha1(String str) {
if (str == null || str.length() == 0) {
return null;
}
char hexDigits[] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };
try {
MessageDigest mdTemp = MessageDigest.getInstance("SHA1");
mdTemp.update(str.getBytes());
byte[] md = mdTemp.digest();
int j = md.length;
char buf[] = new char[j * 2];
int k = 0;
for (int i = 0; i < j; i++) {
byte byte0 = md[i];
buf[k++] = hexDigits[byte0 >>> 4 & 0xf];
buf[k++] = hexDigits[byte0 & 0xf];
}
return new String(buf);
} catch (Exception e) {
return null;
}
}
public static List<String> stringsToList(final String[] src) {
if (src == null || src.length == 0) {
return null;
}
final List<String> result = new ArrayList<String>();
for (int i = 0; i < src.length; i++) {
result.add(src[i]);
}
return result;
}
}
package com.jade.laiding.client.util;
import java.util.List;
/**
* @author <a href="mailto:haoran.zhang@basung.com">zhanghaoran</a>
* @version 1.0
* @date 15/10/29 下午1:20
* 微信支付辅助类
*/
public class WxPay {
private List<Long> idList;
private long paymentId;
public List<Long> getIdList() {
return idList;
}
public void setIdList(List<Long> idList) {
this.idList = idList;
}
public long getPaymentId() {
return paymentId;
}
public void setPaymentId(long paymentId) {
this.paymentId = paymentId;
}
}
/**
* @api {post} /order/editOrderPayStatus 修改订单支付状态(支付宝)
* @apiName editOrderPayStatus API
* @apiGroup Order
* @apiDescription 修改订单支付状态(支付宝)
* @apiVersion 0.1.0
* @apiParam {String} id 订单编号.
* @apiParam {String} orderStatus 订单状态
* @apiParam {String} PayStatus 支付状态 Paying,Paied,PartPaied,PartRefund,Refund
* @apiParam {String} ShipStatus Pending("0"),Shipped("1"),PartPending("2"),PartShipped("3"),Returned("4")
*/
@RequestMapping(value = "/editOrderPayStatus", method = RequestMethod.POST)
public @ResponseBody DisplayData editOrderPayStatus(HttpServletRequest request,HttpServletResponse response) {
Order oldorder = null;
try {
String trade_status=request.getParameter("trade_status");//交易状态
Long trade_no=Long.parseLong(request.getParameter("out_trade_no"));//交易订单号
float total_fee=Float.parseFloat(request.getParameter("total_fee"));//订单总金额
oldorder=orderManager.get(Order.class,trade_no);
float FinalAmount=oldorder.getFinalAmount();//数据库订单金额
if("TRADE_SUCCESS".equals(trade_status)&&trade_status!=null){
if(null!=oldorder){
if(total_fee==FinalAmount){
//待支付订单状态条件
if ((oldorder.getOrderStatus() == OrderStatus.Active) && (oldorder.getPayStatus() == PayStatus.Paying || oldorder.getPayStatus() == PayStatus.PartPaied) && (oldorder.getShipStatus() == ShipStatus.Pending)) {
oldorder.setOrderStatus(OrderStatus.Active);//已支付
oldorder.setPayStatus(PayStatus.Paied);
oldorder.setShipStatus(oldorder.getShipStatus());
orderManager.update(oldorder);
response.getWriter().println("success"); //请不要修改或删除
}
}else{
response.getWriter().println("fail");//请不要修改或删除
}
}
}else{
response.getWriter().println("fail");//请不要修改或删除
}
return new DisplayData(request,StatusCode.SUCCESS,"inf.jade.bss.commons.success",oldorder);
} catch (Exception e) {
return new DisplayData(request, StatusCode.FAIL,e.getMessage());
}
}
/**
* @api {post} /order/editOrderWxPayStatus 修改订单支付状态(微信)
* @apiName editOrderWxPayStatus API
* @apiGroup Order
* @apiDescription 修改订单支付状态(微信)
* @apiVersion 0.1.0
* @apiParam {String} id 订单编号.
* @apiParam {String} orderStatus 订单状态
* @apiParam {String} PayStatus 支付状态 Paying,Paied,PartPaied,PartRefund,Refund
* @apiParam {String} ShipStatus Pending("0"),Shipped("1"),PartPending("2"),PartShipped("3"),Returned("4")
*/
@RequestMapping(value = "/editOrderWxPayStatus", method = RequestMethod.POST)
public @ResponseBody DisplayData editOrderWxPayStatus(HttpServletRequest request,HttpServletResponse response) {
Order oldorder = null;
try {
// 将解析结果存储在HashMap中
Map map = new HashMap();
// 从request中取得输入流
InputStream inputStream = request.getInputStream();
// 读取输入流
SAXReader reader = new SAXReader();
Document document =reader.read(inputStream);
// 得到xml根元素
Element root = document.getRootElement();
// 得到根元素的所有子节点
List<Element> list = root.elements();
// 遍历所有子节点
for (Element e : list){
map.put(e.getName(), e.getText());
}
inputStream.close();
inputStream=null;
if("SUCCESS".equals(map.get("result_code"))){
Long trade_no=Long.parseLong(map.get("out_trade_no").toString());//订单号
float total_fee=Float.parseFloat(map.get("total_fee").toString());//订单金额
oldorder=orderManager.get(Order.class,trade_no);
float FinalAmount=oldorder.getFinalAmount();//数据库订单金额
if(null!=oldorder){
if((total_fee/100)==FinalAmount){
//待支付订单状态条件
if ((oldorder.getOrderStatus() == OrderStatus.Active) && (oldorder.getPayStatus() == PayStatus.Paying || oldorder.getPayStatus() == PayStatus.PartPaied) && (oldorder.getShipStatus() == ShipStatus.Pending)) {
oldorder.setOrderStatus(OrderStatus.Active);//已支付
oldorder.setPayStatus(PayStatus.Paied);
oldorder.setShipStatus(oldorder.getShipStatus());
orderManager.update(oldorder);
String entity = WeChatPayUtil.returnCodeSUCCESS();
response.getWriter().println(entity); //请不要修改或删除
//return entity;
}else{
String entity = WeChatPayUtil.returnCodeFAIL();
response.getWriter().println(entity); //请不要修改或删除
//return entity;
}
}
}else{
String entity = WeChatPayUtil.returnCodeFAIL();
response.getWriter().println(entity); //请不要修改或删除
//return entity;
}
}
} catch (Exception e) {
return new DisplayData(request, StatusCode.FAIL,e.getMessage());
}
return new DisplayData(request,StatusCode.SUCCESS,"inf.jade.bss.commons.success",oldorder);
}
如果使用我以上代码在centos6.5系统报如下错误,
请不要用系统自带的openJDK,自己下载在oracle的JDK安装并配置环境,重启 OK~~
上面还少了一步验证签名的过程,异步回调result_code 是SUCCESS,则开始验证签名,验签成功,修改订单状态为已支付