SpringBoot は Alipay 支払いを統合します - 寄り道せずにこの記事をお読みください

最近 Web サイトを作成しているのですが、バックエンドで SpringBoot を使用しているため、オンライン決済に Alipay を統合する必要があります。その過程で、Alipay の統合に関する情報をたくさん勉強し、寄り道もしました。今回はそれをまとめます。これを読めば簡単に導入できると思います, Ali-Pay で支払います。

Alipay 決済の統合を開始する前に、Alipay マーチャント アカウントを準備する必要があります。個人開発者の場合は、企業資格を持つ会社または単位を登録することで承認できます。これらの情報は、関連する API を統合するときに提供する必要があります。

コンピューターの Web ページでのオンライン決済を例として、統合、テスト、立ち上げまでのプロセス全体を紹介します。

1. 期待効果表示

始める前に、次のように、達成したい最終的な効果を見てみましょう。

  1. フロントエンドのクリック決済でAlipayインターフェースにジャンプ
  2. Alipay インターフェースの表示支払い QR コード
  3. ユーザーのモバイル決済
  4. 支払いが完了すると、Alipay は開発者が指定した URL にコールバックします。

2. 開発プロセス

2.1 サンドボックスのデバッグ

Alipay は完全なサンドボックス開発環境を用意しており、最初にサンドボックス環境でプログラムをデバッグし、新しいアプリケーションを作成して正常に起動した後、プログラム内の対応するパラメーターをオンライン パラメーターに置き換えることができます。

1.サンドボックスアプリケーションを作成する

http://open.alipay.com/develop/san ...に直接アクセスして サンドボックス アプリケーションを作成します。

ここでは、テスト環境なので、システムのデフォルトのキーを選択します。次に、公開キー モードを選択します。また、アプリケーション ゲートウェイ アドレスは、ユーザーが支払いを完了した後に Alipay からコールバックされる URL です。開発環境では、イントラネット侵入メソッドを使用して、ローカル ポートをパブリック ネットワーク アドレスに公開できます。ここでは、  無料で登録して使用できるhttp://natapp.cn/をお勧めします。

2. SpringBoot コードの実装

サンドボックス アプリケーションを作成し、キー、APPID、マーチャント アカウント PID などの情報を取得した後、対応する API を開発してテスト環境に統合できます。ここでは、コンピュータ側の決済 API を例として、統合方法を紹介します。

コンピューター Web サイトでの支払いに関する詳細な製品紹介と API アクセス文書については、http: //opendocs.alipay.com/open/repo-0 … および  http://opendocs.alipay.com/open/270/01 … を参照してください。
  • ステップ 1. alipay SDK に対応する Maven 依存関係を追加します。
<!-- alipay -->  
<dependency>  
   <groupId>com.alipay.sdk</groupId>  
   <artifactId>alipay-sdk-java</artifactId>  
   <version>4.35.132.ALL</version>  
</dependency>
  • ステップ 2、支払いが成功した後、Alipay の注文、同期通話、および非同期通話インターフェイスを追加します。
ここで、同期インターフェイスはユーザーが支払いを完了した後に自動的にジャンプするアドレスであるため、Get リクエストである必要があることに注意してください。非同期インターフェイスは、ユーザーが支払いを完了した後に Alipay が支払い結果を通知するためにコールバックするアドレスであり、POST リクエストになります。
@RestController  
@RequestMapping("/alipay")  
public class AliPayController {  
  
    @Autowired  
    AliPayService aliPayService;  
  
    @PostMapping("/order")  
    public GenericResponse<Object> placeOrderForPCWeb(@RequestBody AliPayRequest aliPayRequest) {  
        try {  
            return aliPayService.placeOrderForPCWeb(aliPayRequest);  
        } catch (IOException e) {  
            throw new RuntimeException(e);  
        }  
    }  
  
    @PostMapping("/callback/async")  
    public String asyncCallback(HttpServletRequest request) {  
        return aliPayService.orderCallbackInAsync(request);  
    }  
  
    @GetMapping("/callback/sync")  
    public void syncCallback(HttpServletRequest request, HttpServletResponse response) {  
        aliPayService.orderCallbackInSync(request, response);  
    }  

}
  • ステップ 3、サービス層コードを実装する

ここでは、上記のコントローラーの 3 つのインターフェイスについて、サービス層に対応するメソッドを完了します。以下は決済全体の中核となるプロセスですが、場合によっては注文をDBに保存したり、実際の状況に応じて注文状況を確認したりする必要があるため、実際のビジネスニーズに合わせて設計できます。

public class AliPayService {  
  
    @Autowired  
    AliPayHelper aliPayHelper;  
  
    @Resource  
    AlipayConfig alipayConfig;  
  
    @Transactional(rollbackFor = Exception.class)  
    public GenericResponse<Object> placeOrderForPCWeb(AliPayRequest aliPayRequest) throws IOException {  
        log.info("【请求开始-在线购买-交易创建】*********统一下单开始*********");  
  
        String tradeNo = aliPayHelper.generateTradeNumber();  
    
        String subject = "购买套餐1";  
        Map<String, Object> map = aliPayHelper.placeOrderAndPayForPCWeb(tradeNo, 100, subject);  
  
        if (Boolean.parseBoolean(String.valueOf(map.get("isSuccess")))) {  
            log.info("【请求开始-在线购买-交易创建】统一下单成功,开始保存订单数据");  
  
            //保存订单信息  
            // 添加你自己的业务逻辑,主要是保存订单数据
  
            log.info("【请求成功-在线购买-交易创建】*********统一下单结束*********");  
            return new GenericResponse<>(ResponseCode.SUCCESS, map.get("body"));  
        }else{  
            log.info("【失败:请求失败-在线购买-交易创建】*********统一下单结束*********");  
            return new GenericResponse<>(ResponseCode.INTERNAL_ERROR, String.valueOf(map.get("subMsg")));  
        }  
    }  
  
    // sync return page  
    public void orderCallbackInSync(HttpServletRequest request, HttpServletResponse response) {  
        try {  
            OutputStream outputStream = response.getOutputStream();  
            //通过设置响应头控制浏览器以UTF-8的编码显示数据,如果不加这句话,那么浏览器显示的将是乱码  
            response.setHeader("content-type", "text/html;charset=UTF-8");  
            String outputData = "支付成功,请返回网站并刷新页面。";  
  
            /**  
             * data.getBytes()是一个将字符转换成字节数组的过程,这个过程中一定会去查码表,  
             * 如果是中文的操作系统环境,默认就是查找查GB2312的码表,  
             */  
            byte[] dataByteArr = outputData.getBytes("UTF-8");//将字符转换成字节数组,指定以UTF-8编码进行转换  
            outputStream.write(dataByteArr);//使用OutputStream流向客户端输出字节数组  
        } catch (IOException e) {  
            throw new RuntimeException(e);  
        }  
    }  
  
    public String orderCallbackInAsync(HttpServletRequest request) {  
        try {  
            Map<String, String> map = aliPayHelper.paramstoMap(request);  
            String tradeNo = map.get("out_trade_no");  
            String sign = map.get("sign");  
            String content = AlipaySignature.getSignCheckContentV1(map);  
            boolean signVerified = aliPayHelper.CheckSignIn(sign, content);  
  
            // check order status  
            // 这里在DB中检查order的状态,如果已经支付成功,无需再次验证。
            if(从DB中拿到order,并且判断order是否支付成功过){  
                log.info("订单:" + tradeNo + " 已经支付成功,无需再次验证。");  
                return "success";  
            }  
  
            //验证业务数据是否一致  
            if(!checkData(map, order)){  
                log.error("返回业务数据验证失败,订单:" + tradeNo );  
                return "返回业务数据验证失败";  
            }  
            //签名验证成功  
            if(signVerified){  
                log.info("支付宝签名验证成功,订单:" + tradeNo);  
                // 验证支付状态  
                String tradeStatus = request.getParameter("trade_status");  
                if(tradeStatus.equals("TRADE_SUCCESS")){  
                    log.info("支付成功,订单:"+tradeNo);  
			        // 更新订单状态,执行一些业务逻辑

                    return "success";  
                }else{  
                    System.out.println("支付失败,订单:" + tradeNo );  
                    return "支付失败";  
                }  
            }else{  
                log.error("签名验证失败,订单:" + tradeNo );  
                return "签名验证失败.";  
            }  
        } catch (IOException e) {  
            log.error("IO exception happened ", e);  
            throw new RuntimeException(ResponseCode.INTERNAL_ERROR, e.getMessage());  
        }  
    }  
  
  
    public boolean checkData(Map<String, String> map, OrderInfo order) {  
        log.info("【请求开始-交易回调-订单确认】*********校验订单确认开始*********");  
  
        //验证订单号是否准确,并且订单状态为待支付  
        if(验证订单号是否准确,并且订单状态为待支付){  
            float amount1 = Float.parseFloat(map.get("total_amount"));  
            float amount2 = (float) order.getOrderAmount();  
            //判断金额是否相等  
            if(amount1 == amount2){  
                //验证收款商户id是否一致  
                if(map.get("seller_id").equals(alipayConfig.getPid())){  
                    //判断appid是否一致  
                    if(map.get("app_id").equals(alipayConfig.getAppid())){  
                        log.info("【成功:请求开始-交易回调-订单确认】*********校验订单确认成功*********");  
                        return true;                    }  
                }  
            }  
        }  
        log.info("【失败:请求开始-交易回调-订单确认】*********校验订单确认失败*********");  
        return false;    }  
}
  • ステップ 4、alipayHelper クラスを実装します。このクラスは、Alipay のインターフェイスをカプセル化します。
public class AliPayHelper {  
  
    @Resource  
    private AlipayConfig alipayConfig;  
  
    //返回数据格式  
    private static final String FORMAT = "json";  
    //编码类型  
    private static final String CHART_TYPE = "utf-8";  
    //签名类型  
    private static final String SIGN_TYPE = "RSA2";  
  
    /*支付销售产品码,目前支付宝只支持FAST_INSTANT_TRADE_PAY*/  
    public static final String PRODUCT_CODE = "FAST_INSTANT_TRADE_PAY";  
  
    private static AlipayClient alipayClient = null;  
  
    private static final SimpleDateFormat dateFormat = new SimpleDateFormat("yyyyMMddHHmmssSSS");  
    private static final Random random = new Random();  
  
    @PostConstruct  
    public void init(){  
        alipayClient = new DefaultAlipayClient(  
                alipayConfig.getGateway(),  
                alipayConfig.getAppid(),  
                alipayConfig.getPrivateKey(),  
                FORMAT,  
                CHART_TYPE,  
                alipayConfig.getPublicKey(),  
                SIGN_TYPE);  
    };  
  
    /*================PC网页支付====================*/  
    /**  
     * 统一下单并调用支付页面接口  
     * @param outTradeNo  
     * @param totalAmount  
     * @param subject  
     * @return  
     */  
    public Map<String, Object> placeOrderAndPayForPCWeb(String outTradeNo, float totalAmount, String subject){  
        AlipayTradePagePayRequest request = new AlipayTradePagePayRequest();  
        request.setNotifyUrl(alipayConfig.getNotifyUrl());  
        request.setReturnUrl(alipayConfig.getReturnUrl());  
        JSONObject bizContent = new JSONObject();  
        bizContent.put("out_trade_no", outTradeNo);  
        bizContent.put("total_amount", totalAmount);  
        bizContent.put("subject", subject);  
        bizContent.put("product_code", PRODUCT_CODE);  
  
        request.setBizContent(bizContent.toString());  
        AlipayTradePagePayResponse response = null;  
        try {  
            response = alipayClient.pageExecute(request);  
        } catch (AlipayApiException e) {  
            e.printStackTrace();  
        }  
        Map<String, Object> resultMap = new HashMap<>();  
        resultMap.put("isSuccess", response.isSuccess());  
        if(response.isSuccess()){  
            log.info("调用成功");  
            log.info(JSON.toJSONString(response));  
            resultMap.put("body", response.getBody());  
        } else {  
            log.error("调用失败");  
            log.error(response.getSubMsg());  
            resultMap.put("subMsg", response.getSubMsg());  
        }  
        return resultMap;  
    }  
  
    /**  
     * 交易订单查询  
     * @param out_trade_no  
     * @return  
     */  
    public Map<String, Object> tradeQueryForPCWeb(String out_trade_no){  
        AlipayTradeQueryRequest request = new AlipayTradeQueryRequest();  
        JSONObject bizContent = new JSONObject();  
        bizContent.put("trade_no", out_trade_no);  
        request.setBizContent(bizContent.toString());  
        AlipayTradeQueryResponse response = null;  
        try {  
            response = alipayClient.execute(request);  
        } catch (AlipayApiException e) {  
            e.printStackTrace();  
        }  
        Map<String, Object> resultMap = new HashMap<>();  
        resultMap.put("isSuccess", response.isSuccess());  
        if(response.isSuccess()){  
            System.out.println("调用成功");  
            System.out.println(JSON.toJSONString(response));  
            resultMap.put("status", response.getTradeStatus());  
        } else {  
            System.out.println("调用失败");  
            System.out.println(response.getSubMsg());  
            resultMap.put("subMsg", response.getSubMsg());  
        }  
        return resultMap;  
    }  
  
    /**  
     * 验证签名是否正确  
     * @param sign  
     * @param content  
     * @return  
     */  
    public boolean CheckSignIn(String sign, String content){  
        try {  
            return AlipaySignature.rsaCheck(content, sign, alipayConfig.getPublicKey(), CHART_TYPE, SIGN_TYPE);  
        } catch (AlipayApiException e) {  
            e.printStackTrace();  
        }  
        return false;  
    }  
  
    /**  
     * 将异步通知的参数转化为Map  
     * @return  
     */  
    public Map<String, String> paramstoMap(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 = (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);  
        }  
        return params;  
    }  

}
  • ステップ 5、すべての構成属性を保管するために使用される構成クラスをカプセル化します。
@Data  
@Component  
@ConfigurationProperties(prefix = "alipay")  
public class AlipayConfig {  
  
    private String gateway;  
  
    private String appid;  
  
    private String pid;  
  
    private String privateKey;  
  
    private String publicKey;  
  
    private String returnUrl;  
  
    private String notifyUrl;  
  
}

さらに、application.properties に上記の対応するプロパティを準備する必要があります。

# alipay config  
alipay.gateway=https://openapi.alipaydev.com/gateway.do  
alipay.appid=your_appid
alipay.pid=your_pid  
alipay.privatekey=your_private_key
alipay.publickey=your_public_key
alipay.returnurl=完成支付后的同步跳转地址 
alipay.notifyurl=完成支付后,支付宝会异步回调的地址

3. フロントエンドコードの実装

フロントエンド コードは 2 つの関数を完了するだけで済みます。

  1. ユーザーのリクエストに従ってバックエンドへの支払いリクエストを開始します。
  2. 返されたデータを直接送信してジャンプを完了します。

次の例では、ユーザーが支払いをクリックした後に typescript を使用して関数を実装します。

async function onPositiveClick() {  
   paymentLoading.value = true  
  
   const { data } = await placeAlipayOrder<string>({  
	//你的一些请求参数,例如金额等等
   })  
  
   const div = document.createElement('divform')  
   div.innerHTML = data  
   document.body.appendChild(div)  
   document.forms[0].setAttribute('target', '_blank')  
   document.forms[0].submit()  
  
   showModal.value = false  
   paymentLoading.value = false  
}

2.2 アプリの作成と起動

サンドボックスのデバッグが完了したら、対応する Alipay Web アプリケーションを作成して起動する必要があります。

http://open.alipay.com/develop/man…にログインし 、[Web アプリケーションの作成] を選択します。

関連するアプリケーション情報を入力します。

アプリケーションを作成したら、まず開発設定でインターフェイスの署名方法とアプリケーション ゲートウェイを設定します。

キーは RSA2 であることに注意してください。他の人は上記の操作ガイドに段階的に従って、秘密キーと公開キーを管理できます。

次に、製品バインディング ページで、対応する API をバインドします。たとえば、ここでは PC Web ページで支払いを行っており、対応する API バインディングを見つけるだけです。初めてバインドする場合は、レビューのために関連情報の入力が必要になる場合があります。必要に応じて入力するだけで、通常は 1 日以内にレビューが完了します。

最後に、すべての準備ができたら、オンラインで APP を送信できます。オンラインが成功したら、次の SpringBoot のプロパティをオンライン APP の情報に置き換える必要があります。その後、Alipay インターフェイスを呼び出して、支払いを行うことができます。本番環境。

# alipay config  
alipay.gateway=https://openapi.alipaydev.com/gateway.do  
alipay.appid=your_appid
alipay.pid=your_pid  
alipay.privatekey=your_private_key
alipay.publickey=your_public_key
alipay.returnurl=完成支付后的同步跳转地址 
alipay.notifyurl=完成支付后,支付宝会异步回调的地址

おすすめ

転載: blog.csdn.net/mxt51220/article/details/131248176