天天看點

支付寶當面付(掃碼支付)

一下内容僅為服務端功能,前端業務沒必要

采用證書方式開發

支付寶開發并不難,文檔寫的很清楚,不想隔壁寫的那麼惡心

https://opendocs.alipay.com/open/194/105203

支付寶當面付(掃碼支付)

調用流程

支付寶當面付(掃碼支付)

首先在項目中引入alipay

<!-- https://mvnrepository.com/artifact/com.alipay.sdk/alipay-sdk-java -->
        <dependency>
            <groupId>com.alipay.sdk</groupId>
            <artifactId>alipay-sdk-java</artifactId>
            <version>4.10.209.ALL</version>
        </dependency>
           

接入準備可取官方文檔檢視 https://opendocs.alipay.com/open/01csp3

配置支付寶 AliPayConfig

package com.bootdo.payment.config;

import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
import org.springframework.util.ClassUtils;

import java.io.*;
import java.util.ArrayList;

/**
 * 支付寶支付配置檔案
 */
@Component
@ConfigurationProperties(prefix = "pay.alipay")
public class AliPayConfig {
    //私有構造方法
    private AliPayConfig(){};
    //聲明一個對象的引用
    private static AliPayConfig aliPayConfig = null;
    //判斷一下如果對象為null在建立一個對象
    public static AliPayConfig getInstance(){
        if(aliPayConfig == null){
            aliPayConfig = new AliPayConfig();
        }
        return aliPayConfig;
    }

    // 商戶appid
    private String appID;
    // 支付寶公鑰
    private String getAliPayPublicKey;
    // 私鑰 pkcs8格式的
    private String private_key;

    // 伺服器異步通知頁面路徑 需http://或者https://格式的完整路徑,不能加?id=123這類自定義參數,必須外網可以正常通路
    private String precreate_notify;

    // 請求網關位址
    private String alipay_URL;

    // 編碼
    private String getCharset="UTF-8";

    // 傳回格式
    private String getFormat="json";

    // RSA2
    private String getSignType="RSA2";

    private String getProductCode="QUICK_WAP_WAY";

    // subject
    private String getSubject="WASHER";

    /**
     * 應用公鑰證書路徑
     */
    public String app_cert_path = ClassUtils.getDefaultClassLoader().getResource("").getPath()+"/static/cert/alipay/appCertPublicKey_2019112769464240.crt";

    /**
     * 支付寶公鑰證書檔案路徑
     */
    public String alipay_cert_path = ClassUtils.getDefaultClassLoader().getResource("").getPath()+"/static/cert/alipay/alipayCertPublicKey_RSA2.crt";

    /**
     * 支付寶CA根證書檔案路徑
     */
    public String alipay_root_cert_path = ClassUtils.getDefaultClassLoader().getResource("").getPath()+"/static/cert/alipay/alipayRootCert.crt";

    public String getApp_cert_path() {
        return app_cert_path;
    }

    public void setApp_cert_path(String app_cert_path) {
        this.app_cert_path = app_cert_path;
    }

    public String getAlipay_cert_path() {
        return alipay_cert_path;
    }

    public void setAlipay_cert_path(String alipay_cert_path) {
        this.alipay_cert_path = alipay_cert_path;
    }

    public String getAlipay_root_cert_path() {
        return alipay_root_cert_path;
    }

    public void setAlipay_root_cert_path(String alipay_root_cert_path) {
        this.alipay_root_cert_path = alipay_root_cert_path;
    }

    public String getAppID() {
        return appID;
    }

    public void setAppID(String appID) {
        this.appID = appID;
    }

    public String getGetAliPayPublicKey() {
        return getAliPayPublicKey;
    }

    public void setGetAliPayPublicKey(String getAliPayPublicKey) {
        this.getAliPayPublicKey = getAliPayPublicKey;
    }

    public String getPrivate_key() {
        return private_key;
    }

    public void setPrivate_key(String private_key) {
        this.private_key = private_key;
    }

    public String getPrecreate_notify() {
        return precreate_notify;
    }

    public void setPrecreate_notify(String precreate_notify) {
        this.precreate_notify = precreate_notify;
    }

    public String getAlipay_URL() {
        return alipay_URL;
    }

    public void setAlipay_URL(String alipay_URL) {
        this.alipay_URL = alipay_URL;
    }

    public String getGetCharset() {
        return getCharset;
    }

    public void setGetCharset(String getCharset) {
        this.getCharset = getCharset;
    }

    public String getGetFormat() {
        return getFormat;
    }

    public void setGetFormat(String getFormat) {
        this.getFormat = getFormat;
    }

    public String getGetSignType() {
        return getSignType;
    }

    public void setGetSignType(String getSignType) {
        this.getSignType = getSignType;
    }

    public String getGetProductCode() {
        return getProductCode;
    }

    public void setGetProductCode(String getProductCode) {
        this.getProductCode = getProductCode;
    }

    public String getGetSubject() {
        return getSubject;
    }

    public void setGetSubject(String getSubject) {
        this.getSubject = getSubject;
    }
    /**
     * 取出公匙檔案裡面的公匙
     * @return
     */
    public String aliPayPublicKey(){
        String publicKey="";
        ArrayList<String> list = new ArrayList<>();
        try {

            InputStreamReader inputStreamReader  = new InputStreamReader(getClass().getClassLoader().getResourceAsStream(getAliPayPublicKey));
            BufferedReader br =new BufferedReader(inputStreamReader);
            String str =null;
            while ((str = br.readLine())!=null){
                list.add(str);
            }
            //掐頭去尾
            for (int i = 0; i < list.size(); i++) {
                if(i!=0&&i!=list.size()-1){
                    publicKey += list.get(i).trim();
                }
            }
            br.close();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return publicKey;
    }


}

           

接口 AliPayService

package com.bootdo.payment.service;

import com.bootdo.common.utils.R;

import javax.servlet.http.HttpServletRequest;
import java.util.Map;

/**
 * 支付寶支付接口
 */
public interface AliPayService {

    /**
     * 支付寶 統一收單線下交易預建立
     * 商家可調用 alipay.trade.precreate(統一收單線下交易預建立)接口,傳入訂單商品及金額的資訊建立訂單。支付寶将傳回支付二維碼資訊用于使用者掃碼支付
     * @param orderNo: 訂單編号
     * @param amount: 實際支付金額
     * @param body: 訂單描述
     * @param paymentType  支付類型
     * @return
     */
    R precreate(String orderNo, double amount, String body,Integer paymentType);

    /**
     * 支付寶 統一收單線下交易查詢
     * 商家可調用 alipay.trade.query(統一收單線下交易查詢)接口,通過商戶網站唯一訂單号 out_trade_no 或支付寶交易号 trade_no 查詢對應訂單支付情況。
     * @param orderNo  訂單編号
     * @return
     */
    R orderQuery(String orderNo);

    /**
     * 支付寶 統一收單交易撤銷接口
     * 支付交易傳回失敗或支付系統逾時,商家可調用 alipay.trade.cancel(統一收單交易撤銷接口)通過商戶網站唯一訂單号 out_trade_no 或支付寶交易号 trade_no 撤銷交易。
     * @param orderNo
     * @return
     */
    R cancel(String orderNo);

    /**
     * 支付寶 統一收單交易退款接口
     * 當交易發生之後一段時間内,由于業務原因(如金額錯誤,使用者退款或者對賬不平等等)需要退款時,
     * 商家可以調用 alipay.trade.refund(統一收單交易退款接口)通過商戶網站唯一訂單号 out_trade_no
     * 或支付寶交易号 trade_no,将對應訂單支付款退還給買家,支付寶将在收到退款請求并且驗證成功之後,
     * 按照退款規則将支付款按原路退到買家帳号上。支援全額或部分退款。
     * @param orderNo  訂單編号
     * @param amount: 實際支付金額
    * @param refundReason: 退款原因
     * @return
     */
    R refund(String orderNo, double amount, String refundReason);


    /**
     * 驗證回調簽名
     * @param request  請求資訊
     * @return
     */
    String notify(HttpServletRequest request);
}

           

實作類 AliPayServiceImpl

package com.bootdo.payment.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.alipay.api.AlipayApiException;
import com.alipay.api.AlipayClient;
import com.alipay.api.CertAlipayRequest;
import com.alipay.api.DefaultAlipayClient;
import com.alipay.api.domain.AlipayTradeCancelModel;
import com.alipay.api.domain.AlipayTradePrecreateModel;
import com.alipay.api.domain.AlipayTradeQueryModel;
import com.alipay.api.domain.AlipayTradeRefundModel;
import com.alipay.api.internal.util.AlipaySignature;
import com.alipay.api.request.AlipayTradeCancelRequest;
import com.alipay.api.request.AlipayTradePrecreateRequest;
import com.alipay.api.request.AlipayTradeQueryRequest;
import com.alipay.api.request.AlipayTradeRefundRequest;
import com.alipay.api.response.AlipayTradeCancelResponse;
import com.alipay.api.response.AlipayTradePrecreateResponse;
import com.alipay.api.response.AlipayTradeQueryResponse;
import com.alipay.api.response.AlipayTradeRefundResponse;
import com.bootdo.common.utils.R;
import com.bootdo.payment.config.AliPayConfig;
import com.bootdo.payment.domain.SelfmachineDO;
import com.bootdo.payment.service.AliPayService;
import com.bootdo.payment.service.SelfmachineService;
import com.bootdo.payment.util.QrCodeUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.servlet.http.HttpServletRequest;
import java.io.File;
import java.math.BigDecimal;
import java.util.*;

/**
 * @author snow
 */
@Service
public class AliPayServiceImpl implements AliPayService {
    private static final Logger logger = LoggerFactory.getLogger(AliPayServiceImpl.class);

    @Autowired
    private AliPayConfig aliPayConfig=AliPayConfig.getInstance();

    @Autowired
    private SelfmachineService selfmachineService;

    @Override
    public R precreate(String orderNo, double amount, String body, Integer paymentType) {
        //建立API對應的 request
        AlipayTradePrecreateRequest request = new AlipayTradePrecreateRequest();
        //拼裝訂單參數
        AlipayTradePrecreateModel model = new AlipayTradePrecreateModel();
        //商戶訂單号。64 個字元以内的大小,可包含字母、數字、下劃線。需保證該參數在商戶端不重複
        model.setOutTradeNo(orderNo);
        //訂單總金額,機關為元,精确到小數點後兩位
        model.setTotalAmount(String.valueOf(amount));
        //訂單标題
        model.setSubject(body);
        //該筆訂單允許的最晚付款時間,逾期将關閉交易,從生成二維碼開始計時。
        model.setTimeoutExpress("2m");
        //該筆訂單允許的最晚付款時間,逾期将關閉交易,從生成二維碼開始計時。
        model.setQrCodeTimeoutExpress("2m");
        request.setBizModel(model);
        //回調位址
        request.setNotifyUrl(aliPayConfig.getPrecreate_notify());
        try {
            AlipayClient alipayClient = new DefaultAlipayClient(certAlipayRequest());

            logger.info("發起AliPay下單請求");
            AlipayTradePrecreateResponse execute = alipayClient.certificateExecute(request);
            //将傳回資料轉換格式
            JSONObject jsonObject = JSON.parseObject(execute.getBody());
            Map response = (Map) jsonObject.get("alipay_trade_precreate_response");
            //列印傳回資訊
            response.forEach((k,v) -> logger.info("訂單key={},訂單val={}",k,v));
            Map<String,Object> map = new HashMap<>();
            if (execute.isSuccess()) {
                //訂單建立成功
                //儲存訂單資訊,前台輪詢訂單狀态
                SelfmachineDO selfmachineDO = new SelfmachineDO(orderNo,paymentType,new BigDecimal(Double.valueOf(amount)),1,new Date());
                if(selfmachineService.save(selfmachineDO)<0){
                    logger.error("支付寶預建立訂單資訊儲存失敗");
                    return R.error("訂單資訊儲存失敗,請重新整理重試");
                }
                //将傳回的 qr_code 生成二維碼圖檔
                map.put("qrCode_img",QrCodeUtil.generateQrCode(response.get("qr_code").toString()));
                return R.ok().put("data",map);
            }else{
                return R.error(response.get("sub_msg").toString());
            }

        } catch (AlipayApiException e) {
            e.printStackTrace();
            logger.error("支付寶統一下單失敗");
            return R.error().put("data","支付寶統一下單失敗");
        }
    }

    @Override
    public R orderQuery(String orderNo) {
        Map<String,Object> map = new HashMap<>();
        //構造API請求
        AlipayTradeQueryRequest request = new AlipayTradeQueryRequest();
        //發送請求
        //拼裝訂單參數
        AlipayTradeQueryModel model = new AlipayTradeQueryModel();
        //設定業務參數
        //商戶網站唯一訂單号
        model.setOutTradeNo(orderNo);
        request.setBizModel(model);
        //回調位址
        request.setNotifyUrl(aliPayConfig.getPrecreate_notify());
        try {
            AlipayClient alipayClient = new DefaultAlipayClient(certAlipayRequest());
            //通過alipayClient調用API,獲得對應的response類
            AlipayTradeQueryResponse execute = alipayClient.certificateExecute(request);
            //将傳回資料轉換格式
            JSONObject jsonObject = JSON.parseObject(execute.getBody());
            Map response = (Map) jsonObject.get("alipay_trade_query_response");
            //列印傳回資訊
            response.forEach((k,v) -> logger.info("訂單key={},訂單val={}",k,v));
            if (execute.isSuccess()) {
                logger.error("支付寶訂單查詢成功");
                return R.ok("支付寶訂單查詢成功").put("data",response);
            }else{
                switch (response.get("sub_code").toString()){
                    case "ACQ.SYSTEM_ERROR":
                        //系統錯誤
                        logger.error("系統錯誤");
                        return R.error("支付寶系統錯誤,請重新整理重試!");
                    case "ACQ.INVALID_PARAMETER":
                        //參數無效
                        logger.error("參數無效");
                        return R.error("支付寶系統錯誤,請重新整理重試!");
                    case "ACQ.TRADE_NOT_EXIST":
                        //查詢的交易不存在
                        logger.error("查詢的交易不存在");
                        return R.ok();
                    default:
                        return R.ok();
                }
            }
        } catch (AlipayApiException e) {
            e.printStackTrace();
            logger.error("支付寶訂單查詢失敗2");
            return R.ok("支付寶訂單查詢失敗");
        }
    }

    @Override
    public R cancel(String orderNo) {
        //建立 API 對應的request 類
        AlipayTradeCancelRequest request = new AlipayTradeCancelRequest();
        //設定業務參數
        AlipayTradeCancelModel model = new AlipayTradeCancelModel();
        //商戶網站唯一訂單号
        model.setOutTradeNo(orderNo);
        request.setBizModel(model);
        //回調位址
        request.setNotifyUrl(aliPayConfig.getPrecreate_notify());
        try {
            AlipayClient alipayClient = new DefaultAlipayClient(certAlipayRequest());
            AlipayTradeCancelResponse execute = alipayClient.certificateExecute(request);
            //将傳回資料轉換格式
            JSONObject jsonObject = JSON.parseObject(execute.getBody());
            Map response = (Map) jsonObject.get("alipay_trade_cancel_response");
            logger.info("支付寶撤銷");
            //列印傳回資訊
            response.forEach((k,v) -> logger.info("訂單key={},訂單val={}",k,v));
            if(execute.isSuccess()){
                //action
                // 本次撤銷觸發的交易動作,接口調用成功且交易存在時傳回。可能的傳回值:
                //close:交易未支付,觸發關閉交易動作,無退款;
                //refund:交易已支付,觸發交易退款動作;
                //未傳回:未查詢到交易,或接口調用失敗;
                logger.info("支付寶訂單撤銷成功={}",orderNo);

                return R.ok("支付寶訂單撤銷成功");
            }else{
                logger.error("支付寶撤銷交易失敗"+response.get("sub_msg").toString());
                return R.error(response.get("sub_msg").toString());
            }

        } catch (AlipayApiException e) {
            e.printStackTrace();
            logger.error("支付寶撤銷錯誤");
            return R.error("支付寶撤銷錯誤");
        }

    }

    @Override
    public R refund(String orderNo, double amount, String refundReason) {
        //建立 API 對應的request 類
        AlipayTradeRefundRequest request = new AlipayTradeRefundRequest();
        //設定業務參數
        AlipayTradeRefundModel model = new AlipayTradeRefundModel();
        //商戶網站唯一訂單号
        model.setOutTradeNo(orderNo);
        //需要退款的金額,該金額不能大于訂單金額,機關為元,支援兩位小數
        model.setRefundAmount(String.valueOf(amount));
        request.setBizModel(model);
        //回調位址
        request.setNotifyUrl(aliPayConfig.getPrecreate_notify());
        try {
            AlipayClient alipayClient = new DefaultAlipayClient(certAlipayRequest());
            AlipayTradeRefundResponse execute = alipayClient.certificateExecute(request);
            //将傳回資料轉換格式
            JSONObject jsonObject = JSON.parseObject(execute.getBody());
            Map response = (Map) jsonObject.get("alipay_trade_cancel_response");
            //列印傳回資訊
            logger.info("支付寶退款");
            response.forEach((k,v) -> logger.info("訂單key={},訂單val={}",k,v));
            if(execute.isSuccess()){
                logger.info("支付寶退款成功={}",orderNo);
                return R.ok();
            }else{
                logger.error("支付寶撤銷交易"+response.get("sub_msg").toString());
                return R.error(response.get("sub_msg").toString());
            }

        } catch (AlipayApiException e) {
            e.printStackTrace();
            logger.info("支付寶退款失敗={}",orderNo);
            return R.error("支付寶退款失敗");
        }
    }

    @Override
    public String notify(HttpServletRequest request) {
        // 将異步通知中收到的待驗證所有參數都存放到map中
        Map<String, String> params = convertRequestParamsToMap(request);
        String paramsJson = JSON.toJSONString(params);
        logger.info("支付寶回調,{}", paramsJson);
        try {
            // 調用SDK驗證簽名
            boolean signVerified = AlipaySignature.rsaCertCheckV1(params, aliPayConfig.getAlipay_cert_path(),
                    aliPayConfig.getGetCharset(), aliPayConfig.getGetSignType());
            if (signVerified) {
                logger.info("支付寶回調成功");
                // 按照支付結果異步通知中的描述,對支付結果中的業務内容進行1\2\3\4二次校驗,校驗成功後在response中傳回success,校驗失敗傳回failure
                this.check(params);
                //校驗通過修改訂單狀态可根據自己業務需求編寫業務代碼
                
                if(selfmachineService.update(selfmachineDO)>0){
                    logger.info("支付寶回調簽名認證成功");
                    // 如果簽名驗證正确,立即傳回success
                    return "success";
                }else{
                    logger.info("支付寶回調儲存業務失敗,傳回失敗讓支付寶重試");
                    return "failure";
                }
            } else {
                logger.info("支付寶回調簽名認證失敗,signVerified=false, paramsJson:{}", paramsJson);
                return "failure";
            }
        } catch (AlipayApiException e) {

            logger.error("支付寶回調簽名認證失敗,paramsJson:{},errorMsg:{}", paramsJson, e.getMessage());
            return "failure";
        }
    }

    /**
     * 将request中的參數轉換成Map
     * @param request
     * @return
     */
    private static Map<String, String> convertRequestParamsToMap(HttpServletRequest request) {
        Map<String, String> retMap = new HashMap<String, String>();

        Set<Map.Entry<String, String[]>> entrySet = request.getParameterMap().entrySet();

        for (Map.Entry<String, String[]> entry : entrySet) {
            String name = entry.getKey();
            String[] values = entry.getValue();
            int valLen = values.length;

            if (valLen == 1) {
                retMap.put(name, values[0]);
            } else if (valLen > 1) {
                StringBuilder sb = new StringBuilder();
                for (String val : values) {
                    sb.append(",").append(val);
                }
                retMap.put(name, sb.toString().substring(1));
            } else {
                retMap.put(name, "");
            }
        }

        return retMap;
    }
    /**
     * 1、商戶需要驗證該通知資料中的out_trade_no是否為商戶系統中建立的訂單号,
     * 2、判斷total_amount是否确實為該訂單的實際金額(即商戶訂單建立時的金額),
     * 3、校驗通知中的seller_id(或者seller_email)是否為out_trade_no這筆單據的對應的操作方(有的時候,一個商戶可能有多個seller_id/seller_email),
     * 4、驗證app_id是否為該商戶本身。上述1、2、3、4有任何一個驗證不通過,則表明本次通知是異常通知,務必忽略。
     * 在上述驗證通過後商戶必須根據支付寶不同類型的業務通知,正确的進行不同的業務處理,并且過濾重複的通知結果資料。
     * 在支付寶的業務通知中,隻有交易通知狀态為TRADE_SUCCESS或TRADE_FINISHED時,支付寶才會認定為買家付款成功。
     *
     * @param params
     * @throws AlipayApiException
     */
    private void check(Map<String, String> params) throws AlipayApiException {
        String outTradeNo = params.get("out_trade_no");

        // 1、商戶需要驗證該通知資料中的out_trade_no是否為商戶系統中建立的訂單号,
        SelfmachineDO selfmachineDO = selfmachineService.get(outTradeNo);
        if (selfmachineDO == null) {
            throw new AlipayApiException("out_trade_no錯誤");
        }

        // 2、判斷total_amount是否确實為該訂單的實際金額(即商戶訂單建立時的金額),
        if (!String.valueOf(selfmachineDO.getAmount()).equals(params.get("total_amount"))) {
            throw new AlipayApiException("error total_amount");
        }

        // 3、校驗通知中的seller_id(或者seller_email)是否為out_trade_no這筆單據的對應的操作方(有的時候,一個商戶可能有多個seller_id/seller_email),
        // 第三步可根據實際情況省略

        // 4、驗證app_id是否為該商戶本身。
        if (!params.get("app_id").equals(aliPayConfig.getAppID())) {
            throw new AlipayApiException("app_id不一緻");
        }
    }

    /**
     * 初始化構造 CertAlipayRequest
     * @return
     */
    private CertAlipayRequest certAlipayRequest(){
        //構造client
        CertAlipayRequest certAlipayRequest = new CertAlipayRequest();
        //設定網關位址
        certAlipayRequest.setServerUrl(aliPayConfig.getAlipay_URL());
        //設定應用Id
        certAlipayRequest.setAppId(aliPayConfig.getAppID());
        //設定應用私鑰
        certAlipayRequest.setPrivateKey(aliPayConfig.getPrivate_key());
        //設定請求格式,固定值json
        certAlipayRequest.setFormat("json");
        //設定字元集
        certAlipayRequest.setCharset(aliPayConfig.getGetCharset());
        //設定簽名類型
        certAlipayRequest.setSignType(aliPayConfig.getGetSignType());
        //設定應用公鑰證書路徑
        certAlipayRequest.setCertPath(aliPayConfig.getApp_cert_path());
        //設定支付寶公鑰證書路徑
        certAlipayRequest.setAlipayPublicCertPath(aliPayConfig.getAlipay_cert_path());
        //設定支付寶根證書路徑
        certAlipayRequest.setRootCertPath(aliPayConfig.getAlipay_root_cert_path());
        return certAlipayRequest;
    }
}

           

控制器層 AliPayController

package com.bootdo.payment.controller;

import com.bootdo.common.utils.R;
import com.bootdo.payment.domain.SelfmachineDO;
import com.bootdo.payment.service.AliPayService;
import com.bootdo.payment.service.SelfmachineService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletRequest;
import java.util.HashMap;
import java.util.Map;

/**
 * 支付寶支付
 * @author snow
 */
@RestController
@RequestMapping("/api/aliPay")
@CrossOrigin
public class AliPayController {
   
    @Autowired
    private SelfmachineService selfmachineService;
    @Autowired
    private AliPayService aliPayService;

    //支付寶當面付  開始

    /**
     * 支付寶 統一收單線下交易預建立
     * 商家可調用 alipay.trade.precreate(統一收單線下交易預建立)接口,傳入訂單商品及金額的資訊建立訂單。支付寶将傳回支付二維碼資訊用于使用者掃碼支付
     * @param orderNo  訂單編号
     * @param amount  金額
     * @param body  商品資訊
     * @param paymentType  支付類型 1微信支付,2支付寶支付
     * @return
     */
    @RequestMapping("/precreate")
    public R precreate(@RequestParam String orderNo,@RequestParam double amount,@RequestParam String body,@RequestParam Integer paymentType){

        //1.驗證訂單是否存在、
         R rs = aliPayService.orderQuery(orderNo);
        if(Integer.parseInt(rs.get("code").toString())!=0){
            return rs;
        }
        //2.統一收單線下交易預建立
        R r = aliPayService.precreate(orderNo,amount,body,paymentType);
        if(Integer.parseInt(r.get("code").toString())==0){
            return r;
        }
        return r.error(r.get("sub_msg").toString().equals("")?r.get("sub_msg").toString():"訂單建立失敗");
    }

    /**
     * 支付寶 統一收單線下交易查詢
     * 商家可調用 alipay.trade.query(統一收單線下交易查詢)接口,通過商戶網站唯一訂單号 out_trade_no 或支付寶交易号 trade_no 查詢對應訂單支付情況。
     * @param orderNo  訂單編号
     * @return
     */
    @RequestMapping("/orderQuery")
    public R orderQuery(String orderNo){
        Map<String,Object> map = aliPayService.orderQuery(orderNo);
        if(new Boolean(map.get("success").toString())){
            return R.ok();
        }
        return R.error(map.get("sub_msg").toString());
    }
    /**
     * 支付寶 統一收單交易撤銷接口
     * 支付交易傳回失敗或支付系統逾時,商家可調用 alipay.trade.cancel(統一收單交易撤銷接口)通過商戶網站唯一訂單号 out_trade_no 或支付寶交易号 trade_no 撤銷交易。
     * @param orderNo
     * @return
     */
    @RequestMapping("/cancel")
    public R cancel(String orderNo){
        R r = aliPayService.cancel(orderNo);
        if(Integer.parseInt(r.get("code").toString())==0){
            //自己的業務
            return r.ok("支付寶訂單撤銷成功");
        }
        return r.error(r.get("sub_msg").toString());
    }

    /**
     * 支付寶 統一收單交易退款接口
     * 當交易發生之後一段時間内,由于業務原因(如金額錯誤,使用者退款或者對賬不平等等)需要退款時,
     * 商家可以調用 alipay.trade.refund(統一收單交易退款接口)通過商戶網站唯一訂單号 out_trade_no
     * 或支付寶交易号 trade_no,将對應訂單支付款退還給買家,支付寶将在收到退款請求并且驗證成功之後,
     * 按照退款規則将支付款按原路退到買家帳号上。支援全額或部分退款。
     * @param orderNo  訂單編号
     * @param amount: 實際支付金額
     * @param refundReason: 退款原因
     * @return
     */
    @RequestMapping("/refund")
    public R refund(String orderNo, double amount, String refundReason){
        R r = aliPayService.refund(orderNo,amount,refundReason);
        if(Integer.parseInt(r.get("code").toString())==0){
            return r.ok();
        }
        return r.error(r.get("sub_msg").toString());
    }

    /**
     * 驗證回調簽名
     * @param request  請求資訊
     * @return
     */
    @PostMapping("/notify")
    public String notify(HttpServletRequest request){
        return aliPayService.notify(request);
    }


    /**
     * 放棄支付
     * @param orderNo
     * @return
     */
    @PostMapping("/giveUpPayMent")
    public R giveUpPayMent(@RequestParam String orderNo){
        //1·查詢支付訂單狀态
        Map<String,Object> map = aliPayService.orderQuery(orderNo);
        if(Integer.parseInt(map.get("code").toString())==0){
            //2·撤銷訂單
            if(aliPayService.cancel(orderNo).get("code").equals("0")){
                //閉單成功修改自己的業務
                return R.ok("支付寶訂單撤銷成功!");
            }
            return R.ok("支付寶訂單撤銷成功!");
        }
        return R.error(map.get("trade_state").toString());
    }
    //支付寶當面付  結束
}

           

QrCodeUtil工具類

<!--        二維碼生成-->
        <dependency>
            <groupId>com.google.zxing</groupId>
            <artifactId>javase</artifactId>
            <version>3.3.3</version>
            <scope>compile</scope>
        </dependency>
           

QrCodeUtil

package com.bootdo.payment.util;

import com.google.zxing.BarcodeFormat;
import com.google.zxing.WriterException;
import com.google.zxing.client.j2se.MatrixToImageWriter;
import com.google.zxing.common.BitMatrix;
import com.google.zxing.qrcode.QRCodeWriter;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.Base64;

/**
 * 二維碼生成
 */
public class QrCodeUtil {

    public static String generateQrCode(String code_url){
        String code="data:image/png;base64,";
        Base64.Encoder encoder = Base64.getEncoder();
        try {
            QRCodeWriter qrCodeWriter = new QRCodeWriter();
            //傳回給應用層的 tempToken 是經過base64加密傳回後端需要解密
            BitMatrix bitMatrix = qrCodeWriter.encode(code_url, BarcodeFormat.QR_CODE, 430, 430);

            ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
            MatrixToImageWriter.writeToStream(bitMatrix, "PNG", outputStream);
            code += encoder.encodeToString(outputStream.toByteArray());
        } catch (IOException | WriterException e) {
            e.printStackTrace();
        }

        return code;
    }
}

           

到此支付寶當面付完成,此文章僅作為自己的開發經驗記錄,如有不合理之處還請給位指點一二,謝謝

繼續閱讀