|
@@ -0,0 +1,335 @@
|
|
|
+package com.alipay.util;
|
|
|
+
|
|
|
+import com.alipay.config.AlipayConfig;
|
|
|
+import com.alipay.sign.MD5;
|
|
|
+import com.alipay.sign.RSA;
|
|
|
+import com.alipay.util.httpClient.HttpProtocolHandler;
|
|
|
+import com.alipay.util.httpClient.HttpRequest;
|
|
|
+import com.alipay.util.httpClient.HttpResponse;
|
|
|
+import com.alipay.util.httpClient.HttpResultType;
|
|
|
+import org.apache.commons.httpclient.NameValuePair;
|
|
|
+import org.dom4j.Document;
|
|
|
+import org.dom4j.DocumentException;
|
|
|
+import org.dom4j.DocumentHelper;
|
|
|
+import org.dom4j.Node;
|
|
|
+import org.dom4j.io.SAXReader;
|
|
|
+import org.slf4j.Logger;
|
|
|
+import org.slf4j.LoggerFactory;
|
|
|
+
|
|
|
+import java.io.IOException;
|
|
|
+import java.net.MalformedURLException;
|
|
|
+import java.net.URL;
|
|
|
+import java.net.URLDecoder;
|
|
|
+import java.util.ArrayList;
|
|
|
+import java.util.HashMap;
|
|
|
+import java.util.List;
|
|
|
+import java.util.Map;
|
|
|
+
|
|
|
+
|
|
|
+ *类名:AlipaySubmit
|
|
|
+ *功能:支付宝各接口请求提交类
|
|
|
+ *详细:构造支付宝各接口表单HTML文本,获取远程HTTP数据
|
|
|
+ *版本:3.3
|
|
|
+ *日期:2012-08-13
|
|
|
+ *说明:
|
|
|
+ *以下代码只是为了方便商户测试而提供的样例代码,商户可以根据自己网站的需要,按照技术文档编写,并非一定要使用该代码。
|
|
|
+ *该代码仅供学习和研究支付宝接口使用,只是提供一个参考。
|
|
|
+ */
|
|
|
+
|
|
|
+public class AlipaySubmit {
|
|
|
+ public static Logger log = LoggerFactory.getLogger(AlipaySubmit.class);
|
|
|
+
|
|
|
+
|
|
|
+ static private final String ALIPAY_GATEWAY_NEW = "http://wappaygw.alipay.com/service/rest.htm?";
|
|
|
+
|
|
|
+
|
|
|
+ static public String createHtmlContent(String sessionId, String orderId, String price, String description) {
|
|
|
+
|
|
|
+
|
|
|
+ String req_dataToken = "<direct_trade_create_req><notify_url>" + AlipayConfig.notify_url +
|
|
|
+ "</notify_url><call_back_url>" + AlipayConfig.return_url + "</call_back_url><seller_account_name>" +
|
|
|
+ AlipayConfig.seller_email + "</seller_account_name><out_trade_no>"
|
|
|
+ + orderId + "</out_trade_no><subject>" + description + "</subject><total_fee>" + price +
|
|
|
+ "</total_fee><merchant_url>" + AlipayConfig.merchant_url + "</merchant_url></direct_trade_create_req>";
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+ Map<String, String> sParaTempToken = new HashMap<String, String>();
|
|
|
+ sParaTempToken.put("service", "alipay.wap.trade.create.direct");
|
|
|
+ sParaTempToken.put("partner", AlipayConfig.partner);
|
|
|
+ sParaTempToken.put("_input_charset", AlipayConfig.input_charset);
|
|
|
+ sParaTempToken.put("sec_id", AlipayConfig.sign_type);
|
|
|
+ sParaTempToken.put("format", "xml");
|
|
|
+ sParaTempToken.put("v", "2.0");
|
|
|
+ sParaTempToken.put("req_id", orderId);
|
|
|
+ sParaTempToken.put("req_data", req_dataToken);
|
|
|
+ String request_token = "";
|
|
|
+ try {
|
|
|
+
|
|
|
+ String sHtmlTextToken = AlipaySubmit.buildRequest(ALIPAY_GATEWAY_NEW, "", "", sParaTempToken);
|
|
|
+
|
|
|
+ sHtmlTextToken = URLDecoder.decode(sHtmlTextToken, AlipayConfig.input_charset);
|
|
|
+
|
|
|
+ request_token = AlipaySubmit.getRequestToken(sHtmlTextToken);
|
|
|
+ } catch (Exception e) {
|
|
|
+ e.printStackTrace();
|
|
|
+ log.error("request error,like request_token get failed");
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+ String req_data = "<auth_and_execute_req><request_token>" + request_token + "</request_token></auth_and_execute_req>";
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+ Map<String, String> sParaTemp = new HashMap<String, String>();
|
|
|
+ sParaTemp.put("service", "alipay.wap.auth.authAndExecute");
|
|
|
+ sParaTemp.put("partner", AlipayConfig.partner);
|
|
|
+ sParaTemp.put("_input_charset", AlipayConfig.input_charset);
|
|
|
+ sParaTemp.put("sec_id", AlipayConfig.sign_type);
|
|
|
+ sParaTemp.put("format", "xml");
|
|
|
+ sParaTemp.put("v", "2.0");
|
|
|
+ sParaTemp.put("req_data", req_data);
|
|
|
+
|
|
|
+
|
|
|
+ return AlipaySubmit.buildRequest(ALIPAY_GATEWAY_NEW, sParaTemp, "get", "确认");
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ * 生成签名结果
|
|
|
+ *
|
|
|
+ * @param sPara 要签名的数组
|
|
|
+ * @return 签名结果字符串
|
|
|
+ */
|
|
|
+ public static String buildRequestMysign(Map<String, String> sPara) {
|
|
|
+ String prestr = AlipayCore.createLinkString(sPara);
|
|
|
+ String mysign = "";
|
|
|
+ if (AlipayConfig.sign_type.equals("MD5")) {
|
|
|
+ mysign = MD5.sign(prestr, AlipayConfig.key, AlipayConfig.input_charset);
|
|
|
+ }
|
|
|
+ if (AlipayConfig.sign_type.equals("0001")) {
|
|
|
+ mysign = RSA.sign(prestr, AlipayConfig.private_key, AlipayConfig.input_charset);
|
|
|
+ }
|
|
|
+ return mysign;
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ * 生成要请求给支付宝的参数数组
|
|
|
+ *
|
|
|
+ * @param sParaTemp 请求前的参数数组
|
|
|
+ * @return 要请求的参数数组
|
|
|
+ */
|
|
|
+ private static Map<String, String> buildRequestPara(Map<String, String> sParaTemp) {
|
|
|
+
|
|
|
+ Map<String, String> sPara = AlipayCore.paraFilter(sParaTemp);
|
|
|
+
|
|
|
+ String mysign = buildRequestMysign(sPara);
|
|
|
+
|
|
|
+
|
|
|
+ sPara.put("sign", mysign);
|
|
|
+ if (!sPara.get("service").equals("alipay.wap.trade.create.direct") && !sPara.get("service").equals("alipay.wap.auth.authAndExecute")) {
|
|
|
+ sPara.put("sign_type", AlipayConfig.sign_type);
|
|
|
+ }
|
|
|
+
|
|
|
+ return sPara;
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ * 建立请求,以表单HTML形式构造(默认)
|
|
|
+ *
|
|
|
+ * @param sParaTemp 请求参数数组
|
|
|
+ * @param strMethod 提交方式。两个值可选:post、get
|
|
|
+ * @param strButtonName 确认按钮显示文字
|
|
|
+ * @return 提交表单HTML文本
|
|
|
+ * @paramALIPAY_GATEWAY_NEW 支付宝网关地址
|
|
|
+ */
|
|
|
+ public static String buildRequest(String ALIPAY_GATEWAY_NEW, Map<String, String> sParaTemp, String strMethod, String strButtonName) {
|
|
|
+
|
|
|
+ Map<String, String> sPara = buildRequestPara(sParaTemp);
|
|
|
+ List<String> keys = new ArrayList<String>(sPara.keySet());
|
|
|
+
|
|
|
+ StringBuffer sbHtml = new StringBuffer();
|
|
|
+
|
|
|
+ sbHtml.append("<form id=\"alipaysubmit\" name=\"alipaysubmit\" action=\"" + ALIPAY_GATEWAY_NEW
|
|
|
+ + "_input_charset=" + AlipayConfig.input_charset + "\" method=\"" + strMethod
|
|
|
+ + "\">");
|
|
|
+
|
|
|
+ for (int i = 0; i < keys.size(); i++) {
|
|
|
+ String name = (String) keys.get(i);
|
|
|
+ String value = (String) sPara.get(name);
|
|
|
+
|
|
|
+ sbHtml.append("<input type=\"hidden\" name=\"" + name + "\" value=\"" + value + "\"/>");
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ sbHtml.append("<input type=\"submit\" value=\"" + strButtonName + "\" style=\"display:none;\"></form>");
|
|
|
+ sbHtml.append("<script>document.forms['alipaysubmit'].submit();</script>");
|
|
|
+
|
|
|
+ return sbHtml.toString();
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ * 建立请求,以表单HTML形式构造,带文件上传功能
|
|
|
+ *
|
|
|
+ * @param sParaTemp 请求参数数组
|
|
|
+ * @param strMethod 提交方式。两个值可选:post、get
|
|
|
+ * @param strButtonName 确认按钮显示文字
|
|
|
+ * @param strParaFileName 文件上传的参数名
|
|
|
+ * @return 提交表单HTML文本
|
|
|
+ * @paramALIPAY_GATEWAY_NEW 支付宝网关地址
|
|
|
+ */
|
|
|
+ public static String buildRequest(String ALIPAY_GATEWAY_NEW, Map<String, String> sParaTemp, String strMethod, String strButtonName, String strParaFileName) {
|
|
|
+
|
|
|
+ Map<String, String> sPara = buildRequestPara(sParaTemp);
|
|
|
+ List<String> keys = new ArrayList<String>(sPara.keySet());
|
|
|
+
|
|
|
+ StringBuffer sbHtml = new StringBuffer();
|
|
|
+
|
|
|
+ sbHtml.append("<form id=\"alipaysubmit\" name=\"alipaysubmit\" enctype=\"multipart/form-data\" action=\"" + ALIPAY_GATEWAY_NEW
|
|
|
+ + "_input_charset=" + AlipayConfig.input_charset + "\" method=\"" + strMethod
|
|
|
+ + "\">");
|
|
|
+
|
|
|
+ for (int i = 0; i < keys.size(); i++) {
|
|
|
+ String name = (String) keys.get(i);
|
|
|
+ String value = (String) sPara.get(name);
|
|
|
+
|
|
|
+ sbHtml.append("<input type=\"hidden\" name=\"" + name + "\" value=\"" + value + "\"/>");
|
|
|
+ }
|
|
|
+
|
|
|
+ sbHtml.append("<input type=\"file\" name=\"" + strParaFileName + "\" />");
|
|
|
+
|
|
|
+
|
|
|
+ sbHtml.append("<input type=\"submit\" value=\"" + strButtonName + "\" style=\"display:none;\"></form>");
|
|
|
+
|
|
|
+ return sbHtml.toString();
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ * 建立请求,以模拟远程HTTP的POST请求方式构造并获取支付宝的处理结果
|
|
|
+ * 如果接口中没有上传文件参数,那么strParaFileName与strFilePath设置为空值
|
|
|
+ * 如:buildRequest("", "",sParaTemp)
|
|
|
+ *
|
|
|
+ * @param strParaFileName 文件类型的参数名
|
|
|
+ * @param strFilePath 文件路径
|
|
|
+ * @param sParaTemp 请求参数数组
|
|
|
+ * @return 支付宝处理结果
|
|
|
+ * @throws Exception
|
|
|
+ * @paramALIPAY_GATEWAY_NEW 支付宝网关地址
|
|
|
+ */
|
|
|
+ public static String buildRequest(String ALIPAY_GATEWAY_NEW, String strParaFileName, String strFilePath, Map<String, String> sParaTemp) throws Exception {
|
|
|
+
|
|
|
+ Map<String, String> sPara = buildRequestPara(sParaTemp);
|
|
|
+
|
|
|
+ HttpProtocolHandler httpProtocolHandler = HttpProtocolHandler.getInstance();
|
|
|
+
|
|
|
+ HttpRequest request = new HttpRequest(HttpResultType.BYTES);
|
|
|
+
|
|
|
+ request.setCharset(AlipayConfig.input_charset);
|
|
|
+
|
|
|
+ request.setParameters(generatNameValuePair(sPara));
|
|
|
+ request.setUrl(ALIPAY_GATEWAY_NEW + "_input_charset=" + AlipayConfig.input_charset);
|
|
|
+
|
|
|
+ HttpResponse response = httpProtocolHandler.execute(request, strParaFileName, strFilePath);
|
|
|
+ if (response == null) {
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+
|
|
|
+ String strResult = response.getStringResult();
|
|
|
+
|
|
|
+ return strResult;
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ * MAP类型数组转换成NameValuePair类型
|
|
|
+ *
|
|
|
+ * @param properties MAP类型数组
|
|
|
+ * @return NameValuePair类型数组
|
|
|
+ */
|
|
|
+ private static NameValuePair[] generatNameValuePair(Map<String, String> properties) {
|
|
|
+ NameValuePair[] nameValuePair = new NameValuePair[properties.size()];
|
|
|
+ int i = 0;
|
|
|
+ for (Map.Entry<String, String> entry : properties.entrySet()) {
|
|
|
+ nameValuePair[i++] = new NameValuePair(entry.getKey(), entry.getValue());
|
|
|
+ }
|
|
|
+
|
|
|
+ return nameValuePair;
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ * 解析远程模拟提交后返回的信息,获得token
|
|
|
+ *
|
|
|
+ * @param text 要解析的字符串
|
|
|
+ * @return 解析结果
|
|
|
+ * @throws Exception
|
|
|
+ */
|
|
|
+ public static String getRequestToken(String text) throws Exception {
|
|
|
+ String request_token = "";
|
|
|
+
|
|
|
+ String[] strSplitText = text.split("&");
|
|
|
+
|
|
|
+ Map<String, String> paraText = new HashMap<String, String>();
|
|
|
+ for (int i = 0; i < strSplitText.length; i++) {
|
|
|
+
|
|
|
+
|
|
|
+ int nPos = strSplitText[i].indexOf("=");
|
|
|
+
|
|
|
+ int nLen = strSplitText[i].length();
|
|
|
+
|
|
|
+ String strKey = strSplitText[i].substring(0, nPos);
|
|
|
+
|
|
|
+ String strValue = strSplitText[i].substring(nPos + 1, nLen);
|
|
|
+
|
|
|
+ paraText.put(strKey, strValue);
|
|
|
+ }
|
|
|
+
|
|
|
+ if (paraText.get("res_data") != null) {
|
|
|
+ String res_data = paraText.get("res_data");
|
|
|
+
|
|
|
+ if (AlipayConfig.sign_type.equals("0001")) {
|
|
|
+ res_data = RSA.decrypt(res_data, AlipayConfig.private_key, AlipayConfig.input_charset);
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ Document document = DocumentHelper.parseText(res_data);
|
|
|
+ request_token = document.selectSingleNode("//direct_trade_create_res/request_token").getText();
|
|
|
+ }
|
|
|
+ return request_token;
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ * 用于防钓鱼,调用接口query_timestamp来获取时间戳的处理函数
|
|
|
+ * 注意:远程解析XML出错,与服务器是否支持SSL等配置有关
|
|
|
+ *
|
|
|
+ * @return 时间戳字符串
|
|
|
+ * @throws IOException
|
|
|
+ * @throws DocumentException
|
|
|
+ * @throws MalformedURLException
|
|
|
+ */
|
|
|
+ public static String query_timestamp() throws MalformedURLException,
|
|
|
+ DocumentException, IOException {
|
|
|
+
|
|
|
+
|
|
|
+ String strUrl = "https://mapi.alipay.com/gateway.do?service=query_timestamp&partner=" + AlipayConfig.partner;
|
|
|
+ StringBuffer result = new StringBuffer();
|
|
|
+
|
|
|
+ SAXReader reader = new SAXReader();
|
|
|
+ Document doc = reader.read(new URL(strUrl).openStream());
|
|
|
+
|
|
|
+ List<Node> nodeList = doc.selectNodes("//alipay/*");
|
|
|
+
|
|
|
+ for (Node node : nodeList) {
|
|
|
+
|
|
|
+ if (node.getName().equals("is_success") && node.getText().equals("T")) {
|
|
|
+
|
|
|
+ List<Node> nodeList1 = doc.selectNodes("//response/timestamp/*");
|
|
|
+ for (Node node1 : nodeList1) {
|
|
|
+ result.append(node1.getText());
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ return result.toString();
|
|
|
+ }
|
|
|
+}
|