對接支付寶接口

對接【支付寶】支付接口

場景

最近在做支付寶的接口對接,之前做過一個版本,但是由於申請了新的賬號以前舊的的接口對接就不能使用了
所以就開始對接新的版本接口對接,在這裏也記錄一下讓那些還沒有對接的兄弟少走點彎路。

準備

先申請一個企業賬戶

https://memberprod.alipay.com/account/reg/enterpriseIndex.htm

創建應用

去支付寶的開放平臺
https://open.alipay.com/platform/home.htm
添加應用:
https://docs.open.alipay.com/200/105310
按照這個鏈接的文檔一步一步操作;

賬號準備好之後,就可以瞭解相關的接口了,以(即時到賬)支付接口爲例。

閱讀接口文檔

https://docs.open.alipay.com/270/alipay.trade.page.pay/

下載SDK

https://docs.open.alipay.com/54/103419
選擇java版本

將sdk集成進入項目中

sdk中有一個jar包

將這個jar包上傳到私服上去。
參考這個:
http://blog.csdn.net/huchunlinnk/article/details/17789175

項目引入sdk中的關鍵jar包

這裏的gav的寫法取決於你上傳私服的時候的填寫

<dependency>
          <groupId>com.alipay</groupId>
          <artifactId>alipay-api</artifactId>
          <version>1.0.0</version>
        </dependency>

處理AlipayConfig對象

取消AlipayConfig配置文件中的部分常量
打開下載sdk應該可以找到

將這個類中的前幾個靜態常量變成非靜態的,以便可以支持多個配置對象。

/* *
 *類名:AlipayConfig
 *功能:基礎配置類
 *詳細:設置帳戶有關信息及返回路徑
 *修改日期:2017-04-05
 *說明:
 *以下代碼只是爲了方便商戶測試而提供的樣例代碼,商戶可以根據自己網站的需要,按照技術文檔編寫,並非一定要使用該代碼。
 *該代碼僅供學習和研究支付寶接口使用,只是提供一個參考。
 */
@Data
public class AlipayConfig {
    //↓↓↓↓↓↓↓↓↓↓請在這裏配置您的基本信息↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓
    // 應用ID,您的APPID,收款賬號既是您的APPID對應支付寶賬號
    public String app_id = "";
    // 商戶私鑰,您的PKCS8格式RSA2私鑰
    public String merchant_private_key = "";
    // 支付寶公鑰,查看地址:https://openhome.alipay.com/platform/keyManage.htm 對應APPID下的支付寶公鑰。
    public String alipay_public_key = "";
    // 服務器異步通知頁面路徑  需http://格式的完整路徑,不能加?id=123這類自定義參數,必須外網可以正常訪問
    public String notify_url = "";
    // 頁面跳轉同步通知頁面路徑 需http://格式的完整路徑,不能加?id=123這類自定義參數,必須外網可以正常訪問
    public String return_url = "";
    // 簽名方式
    public static String sign_type = "RSA2";
    // 字符編碼格式
    public static String charset = "utf-8";
    // 支付寶網關
    public static String gatewayUrl = "https://openapi.alipay.com/gateway.do";
    //日誌路徑
    public static String log_path = "C:\\";
}

編寫請求支付的接口

後端向支付寶發起支付的請求,在這個同時需要傳遞必要參數,下面我們就來編寫
如何向支付寶發起支付。

編寫conroller層

/**
 * 阿里支付控制器
 *
 * @author   WangSen([email protected])
 * @Date     2017年8月16日      
 */
@Controller
@RequestMapping("/alipay")
public class AliPayController {
    @Autowired
    private AlipayViewService alipayViewService;
    /**
     * 跳轉到去支付的jsp頁面
     *
     * @param orderId 訂單號
     * 
     * @param payAccountType 支付賬號類型
     * 
     * @param model 模型
     * 
     * @throws Exception
    */
    @RequestMapping
    public void gotopay(long orderId, Model model) throws Exception {
        alipayViewService.setGoToPayInfo(orderId, model);
    }
}

編寫viewService層


/**
 * 阿里支付頁面服務類
 * 
 * @author   WangSen([email protected])
 * @Date     2017年8月16日      
 */
@Service
public class AlipayViewService {
    @Autowired
    private NewAlipayBusinessService newAlipayBusinessService;
    /**
     * 設置去支付信息
     * 
     * @param orderId 訂單id
     * @param model 模型
     * @param payAccountType 支付賬號類型
     * 
     * @return 構建的字符串
    */
    public void setGoToPayInfo(long orderId, Model model) throws Exception {
        model.addAttribute("htmlStr", newAlipayBusinessService.buildPayRequest(orderId, payPrice, "報名費", "略"));
    }
}

編寫service層

/**
 * 新的阿里支付頁面服務類
 * <p>
 * 阿里升級接口之後使用這個服務類
 * 
 * @author   WangSen([email protected])
 * @Date     2017年8月16日      
 */
@Data
public class NewAlipayBusinessService {
    /**
     * 阿里的配置文件對象
     */
    private AlipayConfig alipayConfig;
    /**
     * 構建支付請求
     *
     * @param orderId 訂單號
     * @param payPrice 付款金額
     * @param orderName 訂單名稱
     * @param body 商品描述
     * 
     * @return html字符串
    */
    public String buildPayRequest(long orderId, long payPrice, String orderName, String body) throws Exception {
        //獲得初始化的AlipayClient
        AlipayClient alipayClient = getAlipayClient();
        //設置請求參數
        String bizContent = getBizContent(ConvertUtil.obj2str(orderId), AmountUtils.changeF2Y(payPrice), orderName,
                body);
        return alipayClient.pageExecute(setAlipayRequestParameters(bizContent)).getBody();
    }
    /**
     * 設置阿里支付請求參數
     *
     * @param bizContent 包含關鍵參數的json字符串
     * 
     * @return AlipayTradePagePayRequest對象
    */
    private AlipayTradePagePayRequest setAlipayRequestParameters(String bizContent) {
        AlipayTradePagePayRequest alipayRequest = new AlipayTradePagePayRequest();
        alipayRequest.setReturnUrl(alipayConfig.getReturn_url());
        alipayRequest.setNotifyUrl(alipayConfig.getNotify_url());
        alipayRequest.setBizContent(bizContent);
        return alipayRequest;
    }
    private AlipayClient getAlipayClient() {
        AlipayClient alipayClient = new DefaultAlipayClient(AlipayConfig.gatewayUrl, alipayConfig.getApp_id(),
                alipayConfig.getMerchant_private_key(), "json", AlipayConfig.charset,
                alipayConfig.getAlipay_public_key(), AlipayConfig.sign_type);
        return alipayClient;
    }
    /**
     * 獲取業務的關鍵內容
     *
     * @param out_trade_no 訂單號
     * @param total_amount 付款金額
     * @param subject 訂單名稱
     * @param body 商品描述
     * 
     * @return 拼接之後的json字符串
    */
    private String getBizContent(String out_trade_no, String total_amount, String subject, String body) {
        ExceptionUtil.checkEmpty(out_trade_no, "訂單號不能爲空");
        ExceptionUtil.checkEmpty(total_amount, "價格不能爲空");
        ExceptionUtil.checkEmpty(subject, "訂單名稱不能爲空");
        ExceptionUtil.checkEmpty(body, "商品描述不能爲空");
        StringBuffer sb = new StringBuffer();
        sb.append("{");
        sb.append("\"out_trade_no\":\"").append(out_trade_no).append("\",");
        sb.append("\"total_amount\":\"").append(total_amount).append("\",");
        sb.append("\"subject\":\"").append(subject).append("\",");
        sb.append("\"body\":\"").append(body).append("\",");
        sb.append("\"product_code\":\"FAST_INSTANT_TRADE_PAY\"");
        sb.append("}");
        return sb.toString();
    }

}

通過xml文件配置支付對象

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:context="http://www.springframework.org/schema/context" xmlns:mvc="http://www.springframework.org/schema/mvc"
    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.1.xsd
        http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.1.xsd
        http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.1.xsd">
    <!-- 數理化支付配置對象 -->
    <bean id="alipayConfig" class="com.we.business.pay.newalipay.config.AlipayConfig">
        <property name="app_id" value="你的appId"/>
        <property name="merchant_private_key" value="你的私鑰"/>
        <property name="alipay_public_key" value="支付寶公鑰"/>
        <property name="notify_url" value="支付完成的異步通知地址"/>
        <property name="return_url" value="支付完成跳轉的地址"/>
    </bean>
    <!-- 阿里支付業務服務類 -->
    <bean id="newAlipayBusinessService" class="com.we.business.pay.service.NewAlipayBusinessService">
        <property name="alipayConfig" ref="alipayConfig"/>
    </bean>
</beans> 

編寫jsp頁面

<%@page import="com.we.core.common.util.DateTimeUtil"%>
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
        <title>支付寶即時到賬交易接口</title>
    </head>
    ${htmlStr }
    <body>
    </body>
</html>

測試

頁面訪問:localhost:8091/alipay/gotopay.json?orderId=232323
就可以看到支付頁面了;

編寫支付的異步通知接口

用戶支付完成之後支付寶會通過你配置的的notify_url的值進行回調,
我需要編寫這個邏輯,以完成整個的支付流程。

編寫controller層

/**
 * 阿里支付控制器
 *
 * @author   WangSen([email protected])
 * @Date     2017年8月16日      
 */
@Controller
@RequestMapping("/alipay")
public class AliPayController {
    @Autowired
    private AlipayViewService alipayViewService;
    /**
     * 支付完成
     */
    @Void
    @NotSso
    @ResponseBody
    @RequestMapping
    public void payFinish() throws Exception {
        alipayViewService.payFinish();
    }
}

編寫viewService層

/**
 * 阿里支付頁面服務類
 * 
 * @author   WangSen([email protected])
 * @Date     2017年8月16日      
 */
@Service
public class AlipayViewService {
    @Autowired
    private NewAlipayBusinessService newAlipayBusinessService;
    /**
     * 支付完成
     *
     * @throws IOException io異常
    */
    public void payFinish() throws Exception {
        newAlipayBusinessService.payFinish();
    }
}

編寫處理支付完成的servie

/**
 * 新的阿里支付頁面服務類
 * <p>
 * 阿里升級接口之後使用這個服務類
 * 
 * @author   WangSen([email protected])
 * @Date     2017年8月16日      
 */
@Data
public class NewAlipayBusinessService {
    /**
     * 阿里的配置文件對象
     */
    private AlipayConfig alipayConfig;
    /**
     * 支付完成
     *
     * @throws Exception 異常對象
    */
    public void payFinish() throws Exception {
        HttpServletRequest request = MvcUtil.getRequest();
        PrintWriter out = MvcUtil.getResponse().getWriter();
        //獲取支付寶POST過來反饋信息
        Map<String, String> params = getParames(request);
        if (!isSuccess(params)) {
            fail(out);
            return;
        }
        long orderId = getOrderId(params);
        long payPrice = getTotalFee(params);
        try {
            //編輯你支付完成之後的邏輯
            success(out);
        } catch (Exception e) {
            fail(out);
        }
    }
   
    /**
     * 獲取訂單id
     *
     * @param params 請求參數  
     * @return 訂單id
    */
    private long getOrderId(Map<String, String> params) {
        String order_no = params.get("out_trade_no");
        return ConvertUtil.obj2long(order_no);
    }
    /**
     * 獲取總金額
     *
     * @param params 請求參數
     * @return 總金額
    */
    private long getTotalFee(Map<String, String> params) {
        String total_fee = params.get("total_amount");
        return ConvertUtil.obj2long(AmountUtils.changeY2F(total_fee));
    }
    /**
     * 校驗支付寶支付是否成功
     *
     * @param params http請求
     * @return 成功即爲真
     * @throws AlipayApiException 
     */
    private boolean isSuccess(final Map<String, String> params) throws AlipayApiException {
        boolean signVerified = AlipaySignature.rsaCheckV1(params, alipayConfig.getAlipay_public_key(),
                AlipayConfig.charset, AlipayConfig.sign_type); //調用SDK驗證簽名
        if (!signVerified) {
            return false;
        }
        //交易狀態
        String trade_status = params.get("trade_status");
        if (!trade_status.equals("TRADE_FINISHED") && !trade_status.equals("TRADE_SUCCESS")) {
            return false;
        }
        return true;
    }
    /**
     * 成功
     *
     * TODO 重構方法名
     * @param out 輸出流
    */
    private void success(PrintWriter out) {
        out.println("success");
    }
    /**
     * 失敗
     *
     * TODO 重構方法名
     * @param out 輸出流
    */
    private void fail(PrintWriter out) {
        out.println("fail");
    }
    /**
     * 獲取參數
     *
     * @param request HttpServletRequest對象
     * 
     * @return 返回支付寶攜帶的參數
    */
    private Map<String, String> getParames(HttpServletRequest request) {
        Map<String, String> params = new HashMap<String, String>();
        @SuppressWarnings("unchecked")
        Map<String, String[]> requestParams = request.getParameterMap();
        for (Iterator<String> iter = requestParams.keySet().iterator(); iter.hasNext();) {
            String name = ConvertUtil.obj2str(iter.next());
            @SuppressWarnings("cast")
            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);
        }
        return params;
    }
}

做的過程可能用到的資源

支付接口以及異步通知接口的參數詳解:

https://docs.open.alipay.com/270/105902/

生成公鑰私鑰的步驟

https://doc.open.alipay.com/docs/doc.htm?treeId=291&articleId=105971&docType=1

服務端的sdk

https://docs.open.alipay.com/203/105910

即時到賬新老版本接口對比

https://docs.open.alipay.com/270/106759

轉載自:https://www.cnblogs.com/wangsen/p/7512391.html

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章