Explorar o código

20190529第三方支付接入

suochencheng %!s(int64=6) %!d(string=hai) anos
pai
achega
37f2c192a1

+ 58 - 0
src/main/java/com/izouma/agpay/bean/ApiHead.java

@@ -0,0 +1,58 @@
+package com.izouma.agpay.bean;
+
+public class ApiHead {
+	private String platmerid;
+	private String tranflow;
+	private String trancode;
+	private String clienttime;
+	private String respcode;
+	private String respmsg;
+
+	public String getPlatmerid() {
+		return platmerid;
+	}
+
+	public void setPlatmerid(String platmerid) {
+		this.platmerid = platmerid;
+	}
+
+	public String getTranflow() {
+		return tranflow;
+	}
+
+	public void setTranflow(String tranflow) {
+		this.tranflow = tranflow;
+	}
+
+	public String getTrancode() {
+		return trancode;
+	}
+
+	public void setTrancode(String trancode) {
+		this.trancode = trancode;
+	}
+
+	public String getClienttime() {
+		return clienttime;
+	}
+
+	public void setClienttime(String clienttime) {
+		this.clienttime = clienttime;
+	}
+
+	public String getRespcode() {
+		return respcode;
+	}
+
+	public void setRespcode(String respcode) {
+		this.respcode = respcode;
+	}
+
+	public String getRespmsg() {
+		return respmsg;
+	}
+
+	public void setRespmsg(String respmsg) {
+		this.respmsg = respmsg;
+	}
+}

+ 60 - 0
src/main/java/com/izouma/agpay/bean/ApiMessage.java

@@ -0,0 +1,60 @@
+package com.izouma.agpay.bean;
+
+//@JSONType(orders={"message"})
+public class ApiMessage<T> {
+
+	private Message message;
+
+	public Message getMessage() {
+		return message;
+	}
+
+	public void setMessage(Message message) {
+		this.message = message;
+	}
+
+	public class Message<T> {
+		private Data<T> data;
+		private String sign;
+
+		public Data<T> getData() {
+			return data;
+		}
+
+		public void setData(Data<T> data) {
+			this.data = data;
+		}
+
+		public String getSign() {
+			return sign;
+		}
+
+		public void setSign(String sign) {
+			this.sign = sign;
+		}
+
+		//@JSONType(orders={"head","body"})
+		public class Data<T> {
+			private ApiHead head;
+			private T body;
+
+			public ApiHead getHead() {
+				return head;
+			}
+
+			public void setHead(ApiHead head) {
+				this.head = head;
+			}
+
+			public T getBody() {
+				return body;
+			}
+
+			public void setBody(T body) {
+				this.body = body;
+			}
+		}
+	}
+
+
+}

+ 17 - 0
src/main/java/com/izouma/agpay/bean/DemoReqBody.java

@@ -0,0 +1,17 @@
+package com.izouma.agpay.bean;
+
+/**
+ * @author cuishilei
+ * 创建时间:17-9-26下午2:45
+ */
+public class DemoReqBody {
+	private String originflowno;
+
+	public String getOriginflowno() {
+		return originflowno;
+	}
+
+	public void setOriginflowno(String originflowno) {
+		this.originflowno = originflowno;
+	}
+}

+ 164 - 0
src/main/java/com/izouma/agpay/bean/QR1008ReqBody.java

@@ -0,0 +1,164 @@
+package com.izouma.agpay.bean;
+
+/**
+ * 统一下单 QR1008 请求报文
+ */
+public class QR1008ReqBody {
+    /**
+     * 二级商户
+     */
+    private String merid;
+
+    /**
+     * AppId
+     */
+    private String subappid;
+
+    /**
+     * 实际支付金额
+     */
+    private String payamount;
+
+    /**
+     * 订单金额
+     */
+    private String amount;
+
+
+    /**
+     * 支付人ID
+     */
+    private String subpayuserid;
+
+    /**
+     * 支付方式
+     */
+    private String agentid;
+
+    /**
+     * 备注
+     */
+    private String remark;
+
+    /**
+     * 商品名称
+     */
+    private String commodityname;
+
+    /**
+     * 异步通知地址
+     */
+    private String notifyurl;
+
+    /**
+     * 终端IP
+     */
+    private String spbillcreateip;
+
+    /**
+     * 限制支付方式
+     */
+    private String limitpay;
+
+    /**
+     * 订单失效时间
+     */
+    private String orderExpireTime;
+
+    public String getMerid() {
+        return merid;
+    }
+
+    public void setMerid(String merid) {
+        this.merid = merid;
+    }
+
+    public String getSubappid() {
+        return subappid;
+    }
+
+    public void setSubappid(String subappid) {
+        this.subappid = subappid;
+    }
+
+    public String getPayamount() {
+        return payamount;
+    }
+
+    public void setPayamount(String payamount) {
+        this.payamount = payamount;
+    }
+
+    public String getAmount() {
+        return amount;
+    }
+
+    public void setAmount(String amount) {
+        this.amount = amount;
+    }
+
+
+    public String getSubpayuserid() {
+        return subpayuserid;
+    }
+
+    public void setSubpayuserid(String subpayuserid) {
+        this.subpayuserid = subpayuserid;
+    }
+
+    public String getAgentid() {
+        return agentid;
+    }
+
+    public void setAgentid(String agentid) {
+        this.agentid = agentid;
+    }
+
+    public String getRemark() {
+        return remark;
+    }
+
+    public void setRemark(String remark) {
+        this.remark = remark;
+    }
+
+    public String getCommodityname() {
+        return commodityname;
+    }
+
+    public void setCommodityname(String commodityname) {
+        this.commodityname = commodityname;
+    }
+
+    public String getNotifyurl() {
+        return notifyurl;
+    }
+
+    public void setNotifyurl(String notifyurl) {
+        this.notifyurl = notifyurl;
+    }
+
+    public String getSpbillcreateip() {
+        return spbillcreateip;
+    }
+
+    public void setSpbillcreateip(String spbillcreateip) {
+        this.spbillcreateip = spbillcreateip;
+    }
+
+    public String getLimitpay() {
+        return limitpay;
+    }
+
+    public void setLimitpay(String limitpay) {
+        this.limitpay = limitpay;
+    }
+
+    public String getOrderExpireTime() {
+        return orderExpireTime;
+    }
+
+    public void setOrderExpireTime(String orderExpireTime) {
+        this.orderExpireTime = orderExpireTime;
+    }
+}

+ 32 - 0
src/main/java/com/izouma/agpay/bean/QR1010ReqBody.java

@@ -0,0 +1,32 @@
+package com.izouma.agpay.bean;
+
+/**
+ * 交易查询 QR1010 请求报文
+ */
+public class QR1010ReqBody {
+    /**
+     * 二级商户
+     */
+    private String merid;
+
+    /**
+     * 原交易流水
+     */
+    private String origtranflow;
+
+    public String getMerid() {
+        return merid;
+    }
+
+    public void setMerid(String merid) {
+        this.merid = merid;
+    }
+
+    public String getOrigtranflow() {
+        return origtranflow;
+    }
+
+    public void setOrigtranflow(String origtranflow) {
+        this.origtranflow = origtranflow;
+    }
+}

+ 88 - 0
src/main/java/com/izouma/agpay/demo.java

@@ -0,0 +1,88 @@
+package com.izouma.agpay;
+
+import cfca.org.bouncycastle.util.encoders.Base64;
+import cfca.x509.certificate.X509Cert;
+import com.alibaba.fastjson.JSON;
+import com.izouma.agpay.bean.ApiHead;
+import com.izouma.agpay.bean.ApiMessage;
+import com.izouma.agpay.bean.DemoReqBody;
+import com.izouma.agpay.util.HttpClient431Util;
+import com.izouma.agpay.util.MessageUtil;
+import com.izouma.agpay.util.RsaP1Util;
+
+import java.io.FileInputStream;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * @author cuishilei
+ * 创建时间:17-9-26下午1:53
+ */
+public class demo {
+	public static void main(String[] args) {
+		String url = "http://ip:port/gateway/agpay/apiservice.do";
+		String merchantPfxPath = "/app/platform/merchant.pfx";
+		String publicKeyPath = "/app/platform/platform.cer";
+
+
+		RsaP1Util rsaP1Util = new RsaP1Util();
+		try {
+			//按照要求组装好报文
+			ApiHead head = new ApiHead();
+			DemoReqBody body = new DemoReqBody();
+
+			head.setClienttime("20171025175923");
+			head.setPlatmerid("CF2000417315");
+			head.setTrancode("QR1007");
+			head.setTranflow("TEST20171025175923002");
+
+			body.setOriginflowno("CF200041731513540367");
+			//head和body组装对应的报文
+			ApiMessage father = new ApiMessage();
+			ApiMessage.Message message = father.new Message();
+			ApiMessage.Message.Data data = message.new Data();
+			data.setHead(head);
+			data.setBody(body);
+			message.setData(data);
+
+			String bodyStr = JSON.toJSONString(data.getBody());
+			//生成对应的待签名串 只签名报文体
+			String signMessage = MessageUtil.getSignStr(bodyStr);
+			//生成签名
+			String sign = rsaP1Util.rsaP1Sign(signMessage, merchantPfxPath, "umbpay");
+			//得到sign后继续组装对应报文,然后加密
+			message.setSign(sign);
+			father.setMessage(message);
+			String messageStr = JSON.toJSONString(father);
+			String reqMsg = new String(rsaP1Util.envelopMessage(messageStr, publicKeyPath));
+			Map<String, String> params = new HashMap<String, String>();
+			params.put("data", reqMsg);
+			params.put("formatType", "json");
+			params.put("cryptType", "cert");
+			params.put("signType", "cert");
+			//发送请求得到结果
+			String result = HttpClient431Util.doPost(params, url, "UTF-8", "UTF-8");
+			//解密得到明文
+			String platinMsg = new String(rsaP1Util.openMessage(result, merchantPfxPath, "umbpay"));
+			System.out.println(platinMsg);
+			//在返回报文明文 platinMsg中获取系统返回的签名
+			//在返回报文明文 platinMsg中自己重新组装待签名串
+
+			ApiMessage resfather = JSON.parseObject(platinMsg, ApiMessage.class);
+			System.out.println(resfather);
+			//准备验签
+			FileInputStream is = new FileInputStream(publicKeyPath);
+			X509Cert x509Cert = new X509Cert(is);
+			String cert = new String(Base64.encode(x509Cert.getEncoded()), "UTF-8");
+			//验签
+			String signdata = MessageUtil.getSignStr(JSON.toJSONString(resfather.getMessage().getData().getBody()));
+			if (rsaP1Util.rsaP1Verify(resfather.getMessage().getSign(), signdata, cert.getBytes("UTF-8"))) {
+				//验签成功,业务处理
+			} else {
+				//验签失败,数据可能被篡改
+			}
+		} catch (Exception e) {
+			e.printStackTrace();
+		}
+	}
+}

+ 143 - 0
src/main/java/com/izouma/agpay/util/HttpClient431Util.java

@@ -0,0 +1,143 @@
+package com.izouma.agpay.util;
+
+import java.io.IOException;
+import java.security.cert.CertificateException;
+import java.security.cert.X509Certificate;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+import javax.net.ssl.SSLContext;
+
+import org.apache.http.Header;
+import org.apache.http.HttpEntity;
+import org.apache.http.NameValuePair;
+import org.apache.http.client.config.RequestConfig;
+import org.apache.http.client.entity.UrlEncodedFormEntity;
+import org.apache.http.client.methods.CloseableHttpResponse;
+import org.apache.http.client.methods.HttpPost;
+import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
+import org.apache.http.conn.ssl.SSLContextBuilder;
+import org.apache.http.conn.ssl.TrustStrategy;
+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;
+
+public class HttpClient431Util {
+
+    private static final RequestConfig config;
+    
+    public static final String DEFAULT_SEND_CHARSET = "UTF-8";
+    
+    public static final String DEFAULT_RES_CHARSET = "UTF-8";
+ 
+    static {
+        config = RequestConfig.custom().setConnectTimeout(60000).setSocketTimeout(60000).build();
+    }
+
+    
+    public static String doPost(Map<String, String> params,String url) throws Exception{
+        return doPost(params,url,DEFAULT_SEND_CHARSET,DEFAULT_RES_CHARSET);
+    }
+
+    
+    
+    /**
+     * HTTP Post 获取内容
+     * @param params 请求的参数
+     * @param url  请求的url地址 ?之前的地址
+     * @param reqCharset    编码格式
+ 	* @param resCharset    编码格式
+     * @return    页面内容
+     * @throws Exception 
+     */
+    public static String doPost(Map<String,String> params,String url,String reqCharset,String resCharset) throws Exception{
+    	CloseableHttpClient httpClient = getSingleSSLConnection();
+    	CloseableHttpResponse response = null;
+        if(isBlank(url)){
+            return null;
+        }
+        try {
+            List<NameValuePair> pairs = null;
+            if(params != null && !params.isEmpty()){
+                pairs = new ArrayList<NameValuePair>(params.size());
+                for(Map.Entry<String,String> entry : params.entrySet()){
+                    String value = entry.getValue();
+                    if(value != null){
+                        pairs.add(new BasicNameValuePair(entry.getKey(),value));
+                    }
+                }
+            }
+            HttpPost httpPost = new HttpPost(url);
+            httpPost.addHeader("User-Agent","Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1)");
+            httpPost.addHeader("Connection" , "close");
+            if(pairs != null && pairs.size() > 0){
+                httpPost.setEntity(new UrlEncodedFormEntity(pairs,reqCharset==null?DEFAULT_SEND_CHARSET:reqCharset));
+            }
+            response = httpClient.execute(httpPost);
+            int statusCode = response.getStatusLine().getStatusCode();
+            if (statusCode != 200) {
+         	   Header header = response.getFirstHeader("location");
+         	   return header.getValue();
+            }
+            HttpEntity entity = response.getEntity();
+            String result = null;
+            if (entity != null){
+                result = EntityUtils.toString(entity, resCharset==null?DEFAULT_RES_CHARSET:resCharset);
+            }
+            EntityUtils.consume(entity);
+            response.close();
+            return result;
+        }
+        catch (Exception e) {
+            e.printStackTrace();
+            throw new Exception (e);
+        } finally{
+         	if(response!=null)
+             try {
+ 				response.close();
+ 			} catch (IOException e) {
+ 				throw new Exception (e);
+ 			}
+         }
+    }
+
+    
+	 /**
+	  * 创建单向ssl的连接
+	  * @return
+	 * @throws Exception 
+	  */
+	private static CloseableHttpClient getSingleSSLConnection() throws Exception{
+	 	CloseableHttpClient httpClient = null;
+	 	try {
+				SSLContext sslContext = new SSLContextBuilder().loadTrustMaterial(null,new TrustStrategy() {
+					@Override
+					public boolean isTrusted(X509Certificate[] paramArrayOfX509Certificate,
+							String paramString) throws CertificateException {
+						return true;
+					}
+				}).build();
+				SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(sslContext,SSLConnectionSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);
+				httpClient =  HttpClients.custom().setSSLSocketFactory(sslsf).setDefaultRequestConfig(config).build();
+				return httpClient;
+			} catch (Exception e) {
+			     e.printStackTrace();
+			     throw new Exception(e);
+			}
+	}
+    
+    public static boolean isBlank(String str) {
+        int strLen;
+        if (str == null || (strLen = str.length()) == 0) {
+            return true;
+        }
+        for (int i = 0; i < strLen; i++) {
+            if ((Character.isWhitespace(str.charAt(i)) == false)) {
+                return false;
+            }
+        }
+        return true;
+    }
+}

+ 29 - 0
src/main/java/com/izouma/agpay/util/MessageUtil.java

@@ -0,0 +1,29 @@
+package com.izouma.agpay.util;
+
+import com.alibaba.fastjson.JSON;
+import com.alibaba.fastjson.JSONObject;
+
+import java.util.Map;
+import java.util.Set;
+import java.util.TreeMap;
+
+public class MessageUtil {
+
+	public static String getSignStr(String body) {
+		JSONObject jsonObject = JSON.parseObject(body);
+		Set<Map.Entry<String, Object>> entries = jsonObject.entrySet();
+		TreeMap<String, Object> map = new TreeMap<String, Object>();
+		for (Map.Entry<String, Object> entry : entries) {
+			map.put(entry.getKey(), entry.getValue());
+		}
+		if (map.size() == 0) {
+			//这个……,比较蛋疼等有在优化吧,如果有时间的话
+			map.put("emptybody", "emptybodysignvalue");
+		}
+		StringBuffer buf = new StringBuffer();
+		for (String key : map.keySet()) {
+			buf.append(key).append("=").append((String) map.get(key)).append("&");
+		}
+		return buf.toString();
+	}
+}

+ 203 - 0
src/main/java/com/izouma/agpay/util/RsaP1Util.java

@@ -0,0 +1,203 @@
+package com.izouma.agpay.util;
+
+import java.io.FileInputStream;
+import java.io.InputStream;
+import java.io.UnsupportedEncodingException;
+import java.security.Key;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+
+
+import cfca.sm2rsa.common.Mechanism;
+import cfca.sm2rsa.common.PKIException;
+import cfca.util.Base64;
+import cfca.util.CertUtil;
+import cfca.util.EnvelopeUtil;
+import cfca.util.KeyUtil;
+import cfca.util.SignatureUtil2;
+import cfca.util.cipher.lib.JCrypto;
+import cfca.util.cipher.lib.Session;
+import cfca.x509.certificate.X509Cert;
+import cfca.x509.certificate.X509CertHelper;
+
+public class RsaP1Util {
+	public static Session session = null;
+
+	static {
+		//软库初始化
+		try {
+			JCrypto.getInstance().initialize(JCrypto.JSOFT_LIB, null);
+			session = JCrypto.getInstance().openSession(JCrypto.JSOFT_LIB);
+		} catch (PKIException e) {
+			System.out.println("CFCA软库初始化异常:" + e);
+		}
+
+	}
+
+	/*
+	 * 将base64证书信息转换为证书
+	 */
+	public X509Cert parseCert(String certStr) throws PKIException, UnsupportedEncodingException {
+
+		X509Cert cert = X509CertHelper.parse(certStr.getBytes("UTF-8"));
+		return cert;
+
+	}
+
+	/**
+	 * 6.1 RSA消息签名(PKCS#1)
+	 *
+	 * @throws Exception
+	 */
+	public String rsaP1Sign(String srcData, String pfxPath, String pwd) throws Exception {
+		PrivateKey priKey = (PrivateKey) getRSAPriKey(pfxPath, pwd);
+		System.out.println(priKey);
+		String alg = Mechanism.SHA256_RSA;
+		byte[] signature = new SignatureUtil2().p1SignMessage(alg, srcData.getBytes("UTF-8"), priKey, session);
+		return new String(signature, "UTF-8");
+	}
+
+	public String rsaP1Sign(String srcData, PrivateKey priKey) throws Exception {
+		String alg = Mechanism.SHA256_RSA;
+		byte[] signature = new SignatureUtil2().p1SignMessage(alg, srcData.getBytes("UTF-8"), priKey, session);
+		return new String(signature, "UTF-8");
+	}
+
+	private Key getRSAPriKey(String pfxPath, String pwd) throws Exception {
+		Key priKey = KeyUtil.getPrivateKeyFromPFX(pfxPath, pwd);
+		return priKey;
+	}
+
+	/**
+	 * RSA消息验签(PKCS#1)--通过路径获取公钥信息
+	 *
+	 * @param signData
+	 * @param srcData
+	 * @param cerPath
+	 * @return
+	 * @throws Exception
+	 */
+	public boolean rsaP1Verify(String signData, String srcData, String cerPath) throws Exception {
+		String alg = Mechanism.SHA256_RSA;
+		PublicKey pubKey = (PublicKey) getRSAPubKey(cerPath);
+		boolean ret = new SignatureUtil2().p1VerifyMessage(alg, srcData.getBytes("UTF-8"), signData.getBytes(), pubKey, session);
+		System.out.println("verify=" + ret);
+		return ret;
+	}
+
+	/**
+	 * RSA消息验签(PKCS#1)--直接获取公钥信息
+	 *
+	 * @param signData
+	 * @param srcData
+	 * @param cert
+	 * @return
+	 * @throws Exception
+	 */
+	public boolean rsaP1Verify(String signData, String srcData, byte[] cert) throws Exception {
+		String alg = Mechanism.SHA256_RSA;
+		PublicKey pubKey = (PublicKey) getRSAPubKey(cert);
+		boolean ret = new SignatureUtil2().p1VerifyMessage(alg, srcData.getBytes("UTF-8"), signData.getBytes(), pubKey, session);
+		System.out.println("verify=" + ret);
+		return ret;
+	}
+
+	public boolean rsaP1Verify(String signData, String srcData, PublicKey pubKey) throws Exception {
+		String alg = Mechanism.SHA256_RSA;
+		boolean ret = new SignatureUtil2().p1VerifyMessage(alg, srcData.getBytes("UTF-8"), signData.getBytes(), pubKey, session);
+		System.out.println("verify=" + ret);
+		return ret;
+	}
+
+	private Key getRSAPubKey(String cerPath) throws Exception {
+		X509Cert cert = X509CertHelper.parse(cerPath);
+		Key pubKey = cert.getPublicKey();
+		return pubKey;
+	}
+
+	private Key getRSAPubKey(byte[] cert) throws Exception {
+		X509Cert x509cert = X509CertHelper.parse(cert);
+		Key pubKey = x509cert.getPublicKey();
+		return pubKey;
+	}
+
+	/**
+	 * 7.1 PKCS#7消息加密(数字信封)
+	 *
+	 * @throws Exception
+	 */
+	public byte[] envelopMessage(String srcData, String cerPath) throws Exception {
+		FileInputStream is = null;
+		try {
+			X509Cert[] certs = new X509Cert[1];
+			is = new FileInputStream(cerPath);
+			X509Cert cert = new X509Cert(is);
+			certs[0] = cert;
+			byte[] encryptedData = EnvelopeUtil.envelopeMessage(srcData.getBytes("UTF-8"), Mechanism.DES3_CBC, certs);
+			return encryptedData;
+		} finally {
+			if (is != null) try {
+				is.close();
+			} catch (Exception e) {
+			}
+		}
+	}
+
+	public byte[] envelopMessageByCert(String srcData, String cer) throws Exception {
+
+		X509Cert[] certs = new X509Cert[1];
+		X509Cert cert = new X509Cert(cer.getBytes("UTF-8"));
+		certs[0] = cert;
+		byte[] encryptedData = EnvelopeUtil.envelopeMessage(srcData.getBytes("UTF-8"), Mechanism.DES3_CBC, certs);
+		return encryptedData;
+	}
+
+	/**
+	 * 7.1.1 消息解密(数字信封)
+	 *
+	 * @throws Exception
+	 */
+	public byte[] openMessage(String encryptedData, String pfxPath, String pfxPwd) throws Exception {
+
+		PrivateKey priKey = (PrivateKey) KeyUtil.getPrivateKeyFromPFX(pfxPath, pfxPwd);
+		X509Cert cert = CertUtil.getCertFromPfx(pfxPath, pfxPwd);
+		byte[] sourceData = EnvelopeUtil.openEvelopedMessage(encryptedData.getBytes(), priKey, cert, session);
+		return sourceData;
+	}
+
+	public String getCertFromPfxByPath(String pfxPath, String pfxPwd) throws PKIException, UnsupportedEncodingException {
+		X509Cert cert = CertUtil.getCertFromPfx(pfxPath, pfxPwd);
+		return new String(Base64.encode(cert.getEncoded()), "UTF-8");
+	}
+
+	public String getCertFromPfxByInputStream(InputStream inputStream, String pfxPwd) throws PKIException, UnsupportedEncodingException {
+		X509Cert cert = CertUtil.getCertFromPfx(inputStream, pfxPwd);
+		return new String(Base64.encode(cert.getEncoded()), "UTF-8");
+	}
+
+	public static void main(String args[]) throws UnsupportedEncodingException, PKIException {
+		String srcData = "asdfsadfasfasdf";
+		String merchantPfxFile = "F:/chrise/doc/三方支付/docs/第三方证书/merchant.pfx";
+		String merchantCerFile = "F:/chrise/doc/三方支付/docs/第三方证书/merchant.cer";
+		String umbpayPfxFile = "F:/chrise/doc/三方支付/docs/第三方证书/umbpay.pfx";
+		String umbpayCerFile = "F:/chrise/doc/三方支付/docs/第三方证书/umbpay.cer";
+		String cert = "-----BEGIN CERTIFICATE-----MIIDhTCCAm2gAwIBAgIFECFhIFUwDQYJKoZIhvcNAQEFBQAwITELMAkGA1UEBhMCQ04xEjAQBgNVBAoTCUNGQ0EgT0NBMTAeFw0xNDExMjYwNTEwMjVaFw0xNzExMjYwNTEwMjVaMH8xCzAJBgNVBAYTAmNuMRIwEAYDVQQKEwlDRkNBIE9DQTExEzARBgNVBAsTCkJKWkhPTkdUT1UxFDASBgNVBAsTC0VudGVycHJpc2VzMTEwLwYDVQQDFCgwNDFAMzExMDEwODAxNTQ1NTgwOEBCSlpIT05HVE9VQDAwMDAwMDAxMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCrZGdvj0PEYVMKoxBlr5YnET4RfdyMeqZ7u9So0Ru+AXUKPTQeXqV6MYUJVPybOZMP/oKOxqiNcj+Zj/rOf4hnpmfw/o0eUmeeaMydSZm0RQLRQtZ400opeyJDxpNJJpDWiPCurV6S4ex2PwBAuChB4ys17fCn17uJCeBqDGEbSwIDAQABo4HpMIHmMB8GA1UdIwQYMBaAFNHb6YiC5d0aj0yqAIy+fPKrG/bZMEgGA1UdIARBMD8wPQYIYIEchu8qAQEwMTAvBggrBgEFBQcCARYjaHR0cDovL3d3dy5jZmNhLmNvbS5jbi91cy91cy0xNC5odG0wOAYDVR0fBDEwLzAtoCugKYYnaHR0cDovL2NybC5jZmNhLmNvbS5jbi9SU0EvY3JsMjc1MTQuY3JsMAsGA1UdDwQEAwID6DAdBgNVHQ4EFgQUa9O4JW4rI8s+rpSOH3SgqWoxpRIwEwYDVR0lBAwwCgYIKwYBBQUHAwIwDQYJKoZIhvcNAQEFBQADggEBAD8Q1irdxID0iCkQAH2MLCcBZaS7jfMiLdBmALGT0q4KhG8BtTaXkUadjoA4eIViuh+5KRxbhac4VWQjhOAtTvwHpVWPJkK4P5OB97pux7tT7jjpzOcJ6HDSApAJQQbgyacsuuZF3DAZ4MvZmktnSzQY/+GgY3eGnPMFcVCFKNByt/4TzZjbMYV8sz2xUGFUE5a6kbQKnN7T01V8raJ3K+0i41vQ9z8NUaEKJK5wPjd6jQU13nNVZkUS569+OKIaSSDJ2O6m6eFSYUelFeYG7xOYNW4LEzsvau4jygcCs4YQzY0Qo2kZXiDOB2gXfWDQL1oEzUjr1zVHTanuX1MANPo=-----END CERTIFICATE-----";
+		RsaP1Util rsa = new RsaP1Util();
+		try {
+			String sign = rsa.rsaP1Sign(srcData, umbpayPfxFile, "umbpay");
+			System.out.println("签名:" + sign);
+			String envelopdata = new String(rsa.envelopMessage(srcData, merchantCerFile));
+			System.out.println("加密:" + envelopdata);
+
+			String opendata = new String(rsa.openMessage(envelopdata, merchantPfxFile, "umbpay"));
+			System.out.println("解密:" + opendata);
+
+			boolean verify = rsa.rsaP1Verify(sign, srcData, cert.getBytes());
+
+			System.out.println("验签:" + verify);
+		} catch (Exception e) {
+			// TODO Auto-generated catch block
+			e.printStackTrace();
+		}
+	}
+}

+ 7 - 0
src/main/java/com/izouma/awesomeadmin/constant/AppConstant.java

@@ -97,6 +97,13 @@ public interface AppConstant {
          * 电子币
          */
         Integer COIN = 2;
+
+
+        /**
+         * 第三方支付
+         */
+        Integer AG_PAY = 3;
+
     }
 
     public interface InergralUpdateType {

+ 0 - 1
src/main/java/com/izouma/weixin/util/WeixinUtil.java

@@ -3,7 +3,6 @@ package com.izouma.weixin.util;
 import com.izouma.weixin.dto.WxPaySendData;
 import com.izouma.weixin.wxpay.MyConfig;
 import com.izouma.weixin.wxpay.WXPay;
-import com.izouma.weixin.wxpay.WXPayConstants;
 import org.apache.commons.lang.StringUtils;
 import org.apache.log4j.Logger;
 import org.json.JSONObject;

+ 325 - 0
src/main/java/com/izouma/weixin/web/AGController.java

@@ -0,0 +1,325 @@
+package com.izouma.weixin.web;
+
+import cfca.org.bouncycastle.util.encoders.Base64;
+import cfca.x509.certificate.X509Cert;
+import com.alibaba.fastjson.JSON;
+import com.alibaba.fastjson.JSONObject;
+import com.izouma.agpay.bean.ApiHead;
+import com.izouma.agpay.bean.ApiMessage;
+import com.izouma.agpay.bean.QR1008ReqBody;
+import com.izouma.agpay.util.HttpClient431Util;
+import com.izouma.agpay.util.MessageUtil;
+import com.izouma.agpay.util.RsaP1Util;
+import com.izouma.awesomeadmin.constant.AppConstant;
+import com.izouma.awesomeadmin.service.UserOrderService;
+import com.izouma.awesomeadmin.util.PropertiesFileLoader;
+import com.izouma.weixin.dao.WxpayTempMapper;
+import com.izouma.weixin.model.WxpayTemp;
+import com.izouma.weixin.util.WeixinUtil;
+import org.apache.commons.lang.StringUtils;
+import org.apache.log4j.Logger;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Controller;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestMethod;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.ResponseBody;
+import org.springframework.web.context.request.RequestContextHolder;
+import org.springframework.web.context.request.ServletRequestAttributes;
+import org.springframework.web.servlet.ModelAndView;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import javax.servlet.http.HttpSession;
+import java.io.BufferedOutputStream;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.math.BigDecimal;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.Map;
+
+@Controller
+@RequestMapping("/agpay")
+public class AGController {
+
+    private static Logger logger = Logger.getLogger(AGController.class);
+
+    String url = PropertiesFileLoader.getProperties("agpay_api_url");
+    String merchantPfxPath = PropertiesFileLoader.getProperties("agpay_merchantPfxPath");
+    String publicKeyPath = PropertiesFileLoader.getProperties("agpay_publicKeyPath");
+    String agpay_platmerid = PropertiesFileLoader.getProperties("agpay_platmerid");
+    String agpay_pwd = PropertiesFileLoader.getProperties("agpay_pwd");
+
+
+    @Autowired
+    private UserOrderService userOrderService;
+
+
+    @Autowired
+    private WxpayTempMapper wxpayTempMapper;
+
+
+    @RequestMapping(value = "/notify", method = RequestMethod.POST)
+    @ResponseBody
+    public ModelAndView notify(HttpServletRequest request, HttpServletResponse response) {
+
+
+        try {
+            ApiMessage m = notifyMap(request, response);
+            if (m != null && "C000000000".equals(m.getMessage().getData().getHead().getRespcode())) {
+
+                JSONObject bodyJson = JSON.parseObject(JSON.toJSONString(m.getMessage().getData().getBody()));
+
+                String tranflow = m.getMessage().getData().getHead().getTranflow();
+                String payamount = bodyJson.getString("payamount");
+
+                if (Double.valueOf(payamount) > 0) {
+
+                    WxpayTemp wxpayTemp = new WxpayTemp();
+                    wxpayTemp.setTransactionId(tranflow);
+                    wxpayTemp = wxpayTempMapper.queryWxpayTemp(wxpayTemp);
+                    if (wxpayTemp != null) {
+
+                        userOrderService.payOrder(wxpayTemp.getOrderId(), wxpayTemp.getCoin().doubleValue(),
+                                wxpayTemp.getPoint().doubleValue(), wxpayTemp.getCash().doubleValue(), AppConstant.PayMode.AG_PAY);
+                    }
+
+                }
+
+
+            }
+        } catch (Exception e) {
+            logger.error("agpay支付回调异常", e);
+        }
+
+
+        return null;
+    }
+
+
+    @RequestMapping(value = "/unifiedOrder", method = RequestMethod.GET)
+    @ResponseBody
+    public Map<String, String> unifiedOrder(@RequestParam(required = true, value = "orderId") String orderId, @RequestParam(required = true, value = "coin") double coin,
+                                            @RequestParam(required = true, value = "point") double point) {
+        Map<String, String> resultMap = new HashMap<>();
+
+
+        RsaP1Util rsaP1Util = new RsaP1Util();
+
+        try {
+
+            HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
+
+            String ip = WeixinUtil.getIpAdderss(request);
+
+
+            double cash = userOrderService.calculatedPrice(orderId, coin, point);
+            double total = 0;
+
+
+            total = cash;
+
+            //测试为一分
+            total = 0.01;
+
+
+            //按照要求组装好报文
+            ApiHead head = new ApiHead();
+            QR1008ReqBody body = new QR1008ReqBody();
+
+            final SimpleDateFormat formatter = new SimpleDateFormat("yyyyMMddHHmmss");
+            final String timeStr = formatter.format(new Date());
+
+            head.setClienttime(timeStr);
+            head.setPlatmerid(agpay_platmerid);
+            head.setTrancode("QR1008");
+            head.setTranflow(agpay_platmerid + timeStr + WeixinUtil.getRandomNum(6));
+
+            body.setPayamount("0.01");
+            body.setAmount(String.valueOf(cash));
+            body.setAgentid("API_WXAPP");
+            body.setCommodityname("一米世界-导游包");
+            body.setNotifyurl(PropertiesFileLoader.getProperties("agpay_notify_url"));
+            body.setSpbillcreateip(ip);
+
+
+            //head和body组装对应的报文
+            ApiMessage father = new ApiMessage();
+            ApiMessage.Message message = father.new Message();
+            ApiMessage.Message.Data data = message.new Data();
+            data.setHead(head);
+            data.setBody(body);
+            message.setData(data);
+
+            String bodyStr = JSON.toJSONString(data.getBody());
+            //生成对应的待签名串 只签名报文体
+            String signMessage = MessageUtil.getSignStr(bodyStr);
+            //生成签名
+            String sign = rsaP1Util.rsaP1Sign(signMessage, merchantPfxPath, "umbpay");
+            //得到sign后继续组装对应报文,然后加密
+            message.setSign(sign);
+            father.setMessage(message);
+            String messageStr = JSON.toJSONString(father);
+            String reqMsg = new String(rsaP1Util.envelopMessage(messageStr, publicKeyPath));
+            Map<String, String> params = new HashMap<String, String>();
+            params.put("data", reqMsg);
+            params.put("formatType", "json");
+            params.put("cryptType", "cert");
+            params.put("signType", "cert");
+            //发送请求得到结果
+            String result = HttpClient431Util.doPost(params, url, "UTF-8", "UTF-8");
+            //解密得到明文
+            String platinMsg = new String(rsaP1Util.openMessage(result, merchantPfxPath, "umbpay"));
+            System.out.println(platinMsg);
+            //在返回报文明文 platinMsg中获取系统返回的签名
+            //在返回报文明文 platinMsg中自己重新组装待签名串
+
+            ApiMessage resfather = JSON.parseObject(platinMsg, ApiMessage.class);
+            System.out.println(resfather);
+            //准备验签
+            FileInputStream is = new FileInputStream(publicKeyPath);
+            X509Cert x509Cert = new X509Cert(is);
+            String cert = new String(Base64.encode(x509Cert.getEncoded()), "UTF-8");
+            //验签
+            String signdata = MessageUtil.getSignStr(JSON.toJSONString(resfather.getMessage().getData().getBody()));
+
+            if (rsaP1Util.rsaP1Verify(resfather.getMessage().getSign(), signdata, cert.getBytes("UTF-8"))) {
+
+                //验签成功,业务处理
+                WxpayTemp wxpayTemp = new WxpayTemp();
+                wxpayTemp.setOrderId(orderId);
+                wxpayTemp.setCoin(BigDecimal.valueOf(coin));
+                wxpayTemp.setPoint(BigDecimal.valueOf(point));
+                wxpayTemp.setCash(BigDecimal.valueOf(cash));
+                wxpayTemp.setTotalAmount(BigDecimal.valueOf(total));
+                wxpayTemp.setTransactionId(head.getTranflow());
+                wxpayTemp.setOutTradeNo("agpay_order");
+                wxpayTemp.setTypeFlag(AppConstant.Aliapi.BUY);
+
+                wxpayTempMapper.insertSelective(wxpayTemp);
+                JSONObject bodyJson = JSON.parseObject((JSON.toJSONString(resfather.getMessage().getData().getBody())));
+
+                JSONObject payinfo = JSON.parseObject((bodyJson.getString("payinfo")));
+
+
+                resultMap.put("appId", StringUtils.isNotEmpty(payinfo.getString("appId"))?payinfo.getString("appId"):PropertiesFileLoader.getProperties("agpay_wx_appid"));
+                resultMap.put("partnerid", payinfo.getString("partnerId"));
+                resultMap.put("prepayid", payinfo.getString("prepayId"));
+                resultMap.put("timestamp", payinfo.getString("timeStamp"));
+                resultMap.put("noncestr", payinfo.getString("nonceStr"));
+                resultMap.put("package", "Sign=WXPay");
+                resultMap.put("sign", payinfo.getString("sign"));
+
+
+            } else {
+                //验签失败,数据可能被篡改
+            }
+
+
+            //result.put("code_url", unified.get("code_url"));
+        } catch (Exception e) {
+            logger.error("", e);
+        }
+
+
+        return resultMap;
+
+    }
+
+
+    /**
+     * 解析微信支付回调结果
+     *
+     * @param request
+     * @param response
+     * @return
+     */
+    public ApiMessage notifyMap(HttpServletRequest request, HttpServletResponse response) {
+
+        RsaP1Util rsaP1Util = new RsaP1Util();
+
+        logger.info("payOrder:支付订单");
+        ApiMessage notifyMap = null;
+        try {
+
+            System.out.print("agpay支付回调数据开始");
+            String inputLine;
+            String notityXml = "";
+            String resXml = "";
+
+            try {
+                while ((inputLine = request.getReader().readLine()) != null) {
+                    notityXml += inputLine;
+                }
+                request.getReader().close();
+            } catch (Exception e) {
+                e.printStackTrace();
+            }
+
+            System.out.println("接收到的报文:" + notityXml);
+
+
+            //解密得到明文
+            String platinMsg = new String(rsaP1Util.openMessage(notityXml, merchantPfxPath, "umbpay"));
+            System.out.println(platinMsg);
+            //在返回报文明文 platinMsg中获取系统返回的签名
+            //在返回报文明文 platinMsg中自己重新组装待签名串
+
+            ApiMessage resfather = JSON.parseObject(platinMsg, ApiMessage.class);
+            System.out.println(resfather);
+            //准备验签
+            FileInputStream is = new FileInputStream(publicKeyPath);
+            X509Cert x509Cert = new X509Cert(is);
+            String cert = new String(Base64.encode(x509Cert.getEncoded()), "UTF-8");
+            //验签
+            String signdata = MessageUtil.getSignStr(JSON.toJSONString(resfather.getMessage().getData().getBody()));
+
+            if (rsaP1Util.rsaP1Verify(resfather.getMessage().getSign(), signdata, cert.getBytes("UTF-8"))) {
+
+                //验签成功,业务处理
+
+
+                notifyMap = resfather;
+
+
+                // 进行处理。
+                // 注意特殊情况:订单已经退款,但收到了支付结果成功的通知,不应把商户侧订单状态从退款改成支付成功
+                if ("C000000000".equals(notifyMap.getMessage().getData().getHead().getRespcode())) {
+                    //支付成功
+                    resXml = "SUCC";
+                } else {
+                    resXml = "FAIL";
+                }
+
+
+            } else {
+                resXml = "FAIL";
+            }
+
+
+            System.out.println("agpay支付回调数据结束");
+
+            HttpSession session = request.getSession();
+            session.setAttribute("notify", "agpay支付回调");
+            try {
+                BufferedOutputStream out = new BufferedOutputStream(response.getOutputStream());
+                out.write(resXml.getBytes());
+                out.flush();
+                out.close();
+            } catch (IOException e) {
+                // TODO Auto-generated catch block
+                e.printStackTrace();
+            }
+
+
+        } catch (Exception e) {
+            logger.error("payOrder:支付订单异常", e);
+        }
+        return notifyMap;
+
+    }
+
+
+}

+ 10 - 1
src/main/resources/properties/outsidews.properties

@@ -22,4 +22,13 @@ weixin_mch_id=1533580721
 weixin_mch_secret=liuhuohuyu6666666666688888888888
 weixin_notify_url=http://www.liuhuohuyu.com/wx/notify
 weixin_cert_path=/home/cert/apiclient_cert.p12
-weixin_notify_url_recharge=
+weixin_notify_url_recharge=
+#第三方支付
+agpay_api_url=http://test.umbpay.com.cn:12080/qrpay/apitrans/service.do
+agpay_platmerid=CF3000048210
+agpay_pwd=umbpay
+agpay_merchantPfxPath=/home/app/platform/testmer.pfx
+agpay_publicKeyPath=/home/app/platform/testplat.cer
+agpay_notify_url=http://www.liuhuohuyu.com/agpay/notify
+agpay_wx_appid=wx2421b1c4370ec43b
+

BIN=BIN
src/main/webapp/WEB-INF/lib/SADK3.1.0.7-0.0.1.jar