前言
這是博主的第一篇博客,剛剛畢業,打算把工作中遇到的一些比較普遍的問題記錄下來,如果有寫的不好的地方或者寫錯的地方歡迎指出,一定會改!嘿嘿嘿。先來立個flag,我希望三年之後能夠成爲一名不怕bug,熱愛生活,健康快樂的富婆!
這篇博客主要介紹如何在Java web項目中集成支付寶的電腦支付接口(會稍微介紹一下服務器集成APP支付接口)。目前支付寶接口更新很快,在博主查找資料的時候,很多都是即時到賬接口,APP支付則是移動支付接口等,所以想結合現在的電腦支付接口寫一篇博文。如果項目要正式接入支付寶接口的話,是要企業與支付寶創建應用以及簽約獲取APPID等等的,如果我們只是個人想要學習或者測試的話,可以使用沙箱環境,不需要創建應用和簽約,默認有很多應用!!正式環境的開發順序是:創建應用—簽約(電腦支付、APP支付、當面付、手機網站支付等等都需要單獨簽約!!)
配置沙箱環境
一、如果你是一個新手小白想要在項目中接入支付寶接口,首先你要做的是,進入支付寶官網開放平臺。點擊“快速開發”下的“開發接入”,跳轉到新頁面後點擊“開發服務”下的“沙箱”。
二、新頁面就是支付寶配置沙箱環境的文檔以及使用說明,這裏告訴我們沙箱環境默認給了我們一個APPID,需要我們自己配置RSA2(SHA256)的應用公鑰,需要先下載支付寶生成祕鑰的工具,如果是RSA2簽名格式的話,記住要生成2048位的!!不要被示例圖給迷惑了,當初博主就是這裏弄錯了!生成之後,進入沙箱應用,上傳剛剛生成的應用公鑰,上傳成功後會生成支付寶公鑰,應用私鑰以及支付寶公鑰會在代碼配置中用到。如需要更改祕鑰,使用下載的工具重新生成再上傳即可!上傳應用公鑰並獲取支付寶公鑰,沙箱環境與鏈接中的示例圖略有不同!
導入支付寶電腦支付的demo
一、在沙箱應用的鏈接中,點擊最下面的功能中的電腦網站支付,選擇左側SDK&DEMO的菜單項,下載Java版的demo。
二、解壓剛剛下載的demo,導入到eclipse中,目錄結構如下圖
三、修改AlipayConfig.java文件,記住是商戶私鑰和支付寶公鑰!不要寫成應用公鑰!應用私鑰即商戶私鑰!
這裏的notify_url和return_url改成自己項目要返回頁面的地址,由於是沙箱環境,所以支付寶網關也有修改。return_url是指付款成功之後返回給用戶查看的界面,如付款成功之後返回到商品詳情或者網站首頁等等。notify_url則是支付包與服務器交互的頁面,用戶看不到,支付成功以notify_url返回的參數或者查詢訂單返回的參數爲準。電腦網站支付快速接入。
四、修改配置成功之後,運行項目。
頁面如下:
1.
2.
3.**使用沙箱應用下面的沙箱賬號裏的買家賬號登錄,付款!**錢會直接打到賣家賬戶中!這裏面的錢可以自己手動添加,很有滿足感 !!!!瞬間變富婆啊!!如果想用二維碼支付,則到沙箱應用中掃描二維碼下載沙箱版的支付寶,再用沙箱的買家賬號登錄就可以付款了!目前支持安卓版。
4.由於博主並沒有寫頁面,使用的是支付寶默認的,所以返回的是一串json數據。
5.沙箱調試常見的錯誤如下圖,如果報的錯誤不在這裏面,請自行百度!
到這裏如果能夠成功付款或者查詢訂單等等,就可以看出我們的配置是沒有問題的!接下來就要與我們的Java web項目整合並且存訂單數據到數據庫中!
整合接口到Java web項目
一、博主的框架是公司同事搭的SSM框架,但是與我在網上看的也有點不太一樣,不過沒關係,整合起來就那麼幾個文件。首先把上面那個demo裏的Alipayconfig.java放在項目中(目錄隨項目而定),然後導入alipay-sdk-javaXXX.jar、commons-logging-1.1.1.jar這兩個jar包到WebContent\WEB-INF\lib中,(具體路徑隨項目不同而改變)。
二、寫支付接口。這裏面可以對自己項目中的訂單表進行操作,先增加一條訂單,但是狀態爲未付款。然後調用支付寶付款接口。
/**
* 獲取訂單數據接口
* @param request
* @param response
* @throws AlipayApiException
* @throws IOException
*/
@RequestMapping("viewOrder")
public void viewOrder(HttpServletRequest req, Model mod, HttpServletResponse rep,
@RequestParam(value = "goodId", required = true)Integer goodId) throws AlipayApiException, IOException{
CommonResponse cr = new CommonResponse();
User cu = ViewSessionManager.getUserSession();
if(cu == null){ //需要登錄才能買東西
cr.setMessage("未登錄");
cr.setData(null);
cr.setCode(3109);
}
//系統下單
OrderInfo param = new OrderInfo();
param.setGoodId(goodId);
payService.alipayOrder(cu, param); //生成訂單信息,根據自己項目改動
//獲得初始化的AlipayClient
AlipayClient alipayClient = new DefaultAlipayClient(AlipayConfig.gatewayUrl, AlipayConfig.app_id, AlipayConfig.merchant_private_key, "json", AlipayConfig.charset, AlipayConfig.alipay_public_key, AlipayConfig.sign_type);
//設置請求參數
AlipayTradePagePayRequest alipayRequest = new AlipayTradePagePayRequest();
alipayRequest.setReturnUrl(AlipayConfig.return_url);
alipayRequest.setNotifyUrl(AlipayConfig.notify_url);
//商戶訂單號,商戶網站訂單系統中唯一訂單號,必填
String out_trade_no = param.getTradeCode();
//付款金額,必填
String total_amount = param.getMoney().toString();
//訂單名稱,必填
String subject = param.getSubject();
//商品描述,可空
String body = param.getRemark();
alipayRequest.setBizContent("{\"out_trade_no\":\""+ out_trade_no +"\","
+ "\"total_amount\":\""+ total_amount +"\","
+ "\"subject\":\""+ subject +"\","
+ "\"body\":\""+ body +"\","
+ "\"product_code\":\"FAST_INSTANT_TRADE_PAY\"}");
//請求
String result = alipayClient.pageExecute(alipayRequest).getBody();
rep.setContentType("text/html;charset=" + AlipayConfig.charset);
rep.getWriter().write(result);//直接將完整的表單html輸出到頁面
rep.getWriter().flush();
rep.getWriter().close();
}
三、寫同步通知return_url接口。這裏面可以更改訂單狀態,但是不以這個爲準(若網速太卡或者用戶付完款關掉頁面,則不會跳到這個接口,所以訂單狀態可能就不會更改)
/**
* 回調路徑return_url
* @param request
* @param response
* @throws AlipayApiException
* @throws UnsupportedEncodingException
*/
@RequestMapping("return_url.view")
public String returnUrl(HttpServletRequest request, HttpServletResponse response) throws AlipayApiException, UnsupportedEncodingException{
//獲取支付寶POST過來反饋信息
Map<String,String> params = new HashMap<String,String>();
Map requestParams = request.getParameterMap();
for (Iterator iter = requestParams.keySet().iterator(); iter.hasNext();) {
String name = (String) iter.next();
String[] values = (String[]) requestParams.get(name);
String valueStr = "";
for (int i = 0; i < values.length; i++) {
valueStr = (i == values.length - 1) ? valueStr + values[i]
: valueStr + values[i] + ",";
}
//亂碼解決,這段代碼在出現亂碼時使用。
//valueStr = new String(valueStr.getBytes("ISO-8859-1"), "utf-8");
params.put(name, valueStr);
}
//切記alipaypublickey是支付寶的公鑰,請去open.alipay.com對應應用下查看。
//boolean AlipaySignature.rsaCheckV1(Map<String, String> params, String publicKey, String charset, String sign_type)
boolean signVerified = AlipaySignature.rsaCheckV1(params, AlipayConfig.alipay_public_key, AlipayConfig.charset,AlipayConfig.sign_type);
if(signVerified) {
//商戶訂單號
String out_trade_no = new String(request.getParameter("out_trade_no").getBytes("ISO-8859-1"),"UTF-8");
//支付寶交易號
String trade_no = new String(request.getParameter("trade_no").getBytes("ISO-8859-1"),"UTF-8");
//付款金額
String total_amount = new String(request.getParameter("total_amount").getBytes("ISO-8859-1"),"UTF-8");
request.setAttribute("out_trade_no", out_trade_no);
request.setAttribute("trade_no", trade_no);
request.setAttribute("total_amount", total_amount);
log.info("訂單處理:系統訂單號" + out_trade_no + "支付寶交易號:" + trade_no);
//系統處理根據支付寶回調更改訂單狀態或者其他關聯表的數據
OrderInfo order = payService.findOneByTradeCode(out_trade_no);
if(order == null){
signVerified = false;
request.setAttribute("signVerified", signVerified);
request.setAttribute("reason", "商戶訂單號不存在");
log.error("系統訂單:"+ out_trade_no + "不存在。");
}else{
if(!order.getMoney().toString().equals(total_amount)){
signVerified = false;
request.setAttribute("signVerified", signVerified);
request.setAttribute("reason", "付款金額不對");
return "notify_url";
}
if(order.getTradeStatus() == 1){//判斷當前訂單是否已處理,避免重複處理
log.info("系統訂單:"+ out_trade_no + "無需重複處理。");
}else{
order.setTradeStatus(1);//修改訂單狀態爲已支付
Date payedAt = new Date();
order.setTransactionId(trade_no);
order.setPayedAt(payedAt);
payService.payOrder(order);
log.info("系統訂單:"+ out_trade_no + "成功支付。");
}
}
}else{
request.setAttribute("reason", "驗籤失敗");
}
request.setAttribute("signVerified", signVerified);
return "return_url";
}
四、異步通知notify_url接口,與上面return_url的幾乎相同,只是最後輸出:
response.setContentType("text/html;charset=" + AlipayConfig.charset);
response.getWriter().write("success");//直接將完整的表單html輸出到頁面
response.getWriter().flush();
response.getWriter().close();
方法爲void,還有一點需要注意的是:必須保證服務器異步通知頁面(notify_url)上無任何字符,如空格、HTML標籤、開發系統自帶拋出的異常提示信息等
電腦網站支付結果異步通知
數據庫中訂單狀態的更新以這個接口中的爲準!
五、查詢訂單接口。這裏的返回類型CommonResponse 是我們公司自己的,你們改成自己的返回類型就好.我們這個是ajax調用接口,然後將orderString的數據返回,實際上是json數據。
/**
* 支付寶交易查詢接口
* @param request
* @param response
* @throws UnsupportedEncodingException
* @throws AlipayApiException
*/
@RequestMapping("queryOrder")
@ResponseBody
public CommonResponse queryOrder(HttpServletRequest req, Model mod, HttpServletResponse rep,
@RequestParam(value = "tradeCode", required = true)String tradeCode,
@RequestParam(value = "tradeNo", required = true)String tradeNo) throws UnsupportedEncodingException, AlipayApiException{
CommonResponse cr = new CommonResponse();
AlipayClient alipayClient = new DefaultAlipayClient(AlipayConfig.gatewayUrl, AlipayConfig.app_id, AlipayConfig.merchant_private_key, "json", AlipayConfig.charset, AlipayConfig.alipay_public_key, AlipayConfig.sign_type); //獲得初始化的AlipayClient
AlipayTradeQueryRequest request = new AlipayTradeQueryRequest();//創建API對應的request類
request.setBizContent("{" +
" \"out_trade_no\":\""+tradeCode+"\"," +
" \"trade_no\":\""+tradeNo+"\"" +
" }");//設置業務參數
//根據response中的結果繼續業務邏輯處理
String orderString = null;
try {
//調用查詢方法
AlipayTradeQueryResponse response = alipayClient.execute(request);//通過alipayClient調用API,獲得對應的response類
orderString = response.getBody();//就是orderString 可以直接給客戶端請求,無需再做處理。
} catch (AlipayApiException e) {
e.printStackTrace();
}
cr.setData(orderString); //返回orderString
return cr;
}
服務器端添加APP支付接口
與電腦支付接口類似,可以直接使用同一個jar包,不過在付款接口的入參裏需要添加token。下面是部分代碼。我相信你們足夠聰明能夠改成自己的!
CommonResponse cr = new CommonResponse();
Cache<String, User> apiAccessTokenCache = cacheManager.getCache("apiAccessTokenCache");
User cu = apiAccessTokenCache.get(token);//登錄時候產生的token,通過token獲得User
if(cu == null){
cr.setMessage("token值不對或已失效");
cr.setData(null);
cr.setCode(3109);
return cr;
}
//系統下單
OrderInfo param = new OrderInfo();
param.setGoodId(goodId);
payService.order(cu, param); //生成訂單信息
//實例化客戶端
AlipayClient alipayClient = new DefaultAlipayClient(AlipayConfig.gatewayUrl, AlipayConfig.app_id, AlipayConfig.merchant_private_key, "json", AlipayConfig.charset, AlipayConfig.alipay_public_key, AlipayConfig.sign_type);
//實例化具體API對應的request類,類名稱和接口名稱對應,當前調用接口名稱:alipay.trade.app.pay
AlipayTradeAppPayRequest request = new AlipayTradeAppPayRequest();
//SDK已經封裝掉了公共參數,這裏只需要傳入業務參數。以下方法爲sdk的model入參方式(model和biz_content同時存在的情況下取biz_content)。
AlipayTradeAppPayModel model = new AlipayTradeAppPayModel();
String time = Long.toString(System.currentTimeMillis()/1000);
model.setBody(param.getRemark());
model.setSubject(param.getSubject());
model.setOutTradeNo(param.getTradeCode());
model.setTimeoutExpress(time);
model.setTotalAmount(param.getMoney()+"");
model.setProductCode("QUICK_MSECURITY_PAY");
request.setBizModel(model);
request.setReturnUrl(AlipayConfig.return_url);
request.setNotifyUrl(AlipayConfig.notify_url);
String orderString = null;
try {
//這裏和普通的接口調用不同,使用的是sdkExecute
AlipayTradeAppPayResponse response = alipayClient.sdkExecute(request);
orderString = response.getBody();//就是orderString 可以直接給客戶端請求,無需再做處理。
} catch (AlipayApiException e) {
e.printStackTrace();
}
cr.setData(orderString); //返回orderString
return cr;
轉換成正式環境
需要修改配置文件中的APPID,支付寶公鑰,應用私鑰,以及支付寶網關!有時改了網關之後跳轉的還是沙箱環境的網關,需要clean一下服務器(我的是Tomcat)
結語
上面就是博主總結的Java web項目集成支付寶電腦支付接口!希望這一篇博文能夠解決你的問題,祝好運!如果有疑問可以給我留言,看到了如果我會的問題就會回答!☺☺
本文來自 Amo_lt 的CSDN 博客 ,全文地址請點擊:https://blog.csdn.net/Amo_lt/article/details/77435545?utm_source=copy