1. 程式人生 > >Java 從零開始實現支付寶支付(後臺)

Java 從零開始實現支付寶支付(後臺)

框架使用的是spring boot
我們整合支付寶支付 也就需要提供兩個接口出來.一個是給前端 作用是拿到請求引數加簽返回給前端

前端拿到我們返回的資料.進行調起支付就行了,第二個介面是提供給支付寶的伺服器,支付成功或者失敗的時候.支付寶的伺服器會回撥我們的這個介面.非同步通知我們支付結果

好了.廢話不哆嗦,直接上程式碼:(此時,公鑰 私鑰環境都已經配好)

@RestController
@RequestMapping("/payment")
public class PaymentController {
	// 支付寶重要引數
	private static String APP_ID = "";
	private static String APP_PRIVATE_KEY = "";
	private static String CHARSET = "utf-8";
	private static String ALIPAY_PUBLIC_KEY = "";

	/**
	 * 對支付寶支付資訊進行簽名
	 * 
	 * @param info
	 *            資料類
	 * @return
	 * @throws AlipayApiException
	 * @throws UnsupportedEncodingException
	 */
	@PostMapping("/sign")
	public Object sign(@RequestBody SignInfo info) throws AlipayApiException, UnsupportedEncodingException {
		SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
		String appID = APP_ID;
		String bizContent = toJson(info.Content);
		String charset = CHARSET;
		String method = "alipay.trade.app.pay";
		String signType = "RSA";
		String timestamp = sdf.format(new Date());
		String version = "1.0";
		String notify_url = "https://pay.ytbapp.com/payment/notify";// 增加支付非同步通知回撥,記住上下notify_url的位置,全在sign_type之前,很重要,同樣放在最後都不行
		String content = "app_id=" + appID + "&biz_content=" + bizContent + "&charset=" + charset + "&method=" + method
				+ "¬ify_url=" + (notify_url) + "&sign_type=" + signType + "×tamp=" + timestamp + "&version="
				+ version;

		String sign = AlipaySignature.rsaSign(content, APP_PRIVATE_KEY, charset);

		return "{\"Result\": \"app_id=" + encode(appID) + "&biz_content=" + encode(bizContent) + "&charset="
				+ encode(charset) + "&method=" + encode(method) + "¬ify_url=" + encode(notify_url) + "&sign_type="
				+ encode(signType) + "×tamp=" + encode(timestamp) + "&version=" + encode(version) + "&sign="
				+ encode(sign) + "\"}";
	}

	private String encode(String sign) throws UnsupportedEncodingException {
		return URLEncoder.encode(sign, "utf-8").replace("+", "%20");
	}

	private String toJson(BizContent content) {
		String context = "";
		context += "{" + "\"timeout_express\":\"" + content.timeout_express + "\"," + "\"seller_id\":\""
				+ content.seller_id + "\"," + "\"product_code\":\"" + content.product_code + "\","
				+ "\"total_amount\":\"" + content.total_amount + "\"," + "\"subject\":\"" + content.subject + "\","
				+ "\"body\":\"" + content.body + "\"," + "\"out_trade_no\":\"" + content.out_trade_no + "\"}";

		return context;
	}

	/**
	 * 支付寶支付成功後.會回撥該介面
	 * 
	 * @param request
	 * @return
	 * @throws UnsupportedEncodingException
	 */
	@PostMapping("/notify")
	public String notify(HttpServletRequest request) throws UnsupportedEncodingException {
		Map<String, String> params = new HashMap<String, String>();
		Map<String, String[]> requestParams = request.getParameterMap();
		for (Iterator<String> iter = requestParams.keySet().iterator(); iter.hasNext();) {
			String name = iter.next();
			String[] values = requestParams.get(name);
			String valueStr = "";
			for (int i = 0; i < values.length; i++) {
				valueStr = (i == values.length - 1) ? valueStr + values[i] : valueStr + values[i] + ",";
			}
			// 亂碼解決,這段程式碼在出現亂碼時使用。如果mysign和sign不相等也可以使用這段程式碼轉化
			// valueStr = new String(valueStr.getBytes("ISO-8859-1"), "gbk");
			params.put(name, valueStr);
		}
		String out_trade_no = request.getParameter("out_trade_no");// 商戶訂單號
		boolean signVerified = false;
		try {
			signVerified = AlipaySignature.rsaCheckV1(params, ALIPAY_PUBLIC_KEY, CHARSET);
		} catch (AlipayApiException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
			return ("fail");// 驗簽發生異常,則直接返回失敗
		}
		// 呼叫SDK驗證簽名
		if (signVerified) {
			// TODO 驗籤成功後
			// 按照支付結果非同步通知中的描述,對支付結果中的業務內容進行1\2\3\4二次校驗,校驗成功後在response中返回success,校驗失敗返回failure
			String result = updateALiPayOrderStatus(out_trade_no);
			System.out.println("驗證成功,去更新狀態 \t訂單號:" + out_trade_no + "來自支付寶支付,更新結果:" + result);
			BaseResponse baseResponse = GsonUtils.getGson().fromJson(result, BaseResponse.class);
			if (null != baseResponse && baseResponse.isSucceeded) {
				return ("success");
			} else {
				return ("fail");// 更新狀態失敗
			}
		} else {
			// TODO 驗籤失敗則記錄異常日誌,並在response中返回failure.
			System.out.println("驗證失敗,不去更新狀態");
			return ("fail");
		}
	}
}
給兩個相關model

SignInfo:

public class SignInfo
{
    public BizContent Content;
}

BizContent:
public class BizContent
{
    public String body = "";
    public String subject = "";
    public String out_trade_no = "";
    public String timeout_express = "";
    public String total_amount = "";
    public String seller_id = "";
    public String product_code = "";
}