Alipay scan code payment implementation

Posted by R1der on Sat, 12 Feb 2022 11:02:51 +0100

In a project development, my business module involves Wechat code scanning payment And Alipay scan code payment. After consulting the existing technical articles, I found that many articles did not work, so I read the official documents and formed this concluding article, hoping to help readers.
Alipay platform
Alipay Developer Center
Alipay open platform
API development documentation
Official demo easysdk

Alipay platform information configuration

I believe you must have registered and logged in at the moment Alipay platform I won't repeat it here. The information required for development to be obtained in the platform is as follows:
APPID: apply APPID (applet | applet plug-in | applet template | web page & mobile application | life number)
ALIPAY_PUBLIC_KEY: Alipay public key
MERCHANT_ PRIVATE_ Private key: apply key
SIGN_TYPE: Signature type. Only RSA2 is recommended for Alipay Easy SDK. It is estimated that RSA2 should be filled in here
GATEWAYHOST: gateway domain name, online: OpenAPI alipay. COM, Sandbox: OpenAPI alipaydev. com

About sandbox environment description

Sandbox environment and online environment are good in code writing. There is almost no difference in interface request address, but there is a big gap in platform configuration. In other words, sandbox environment, whether you are a personal account or a merchant account, as long as you apply for sandbox test environment, the core parameters required above will be directly provided to you. Sandbox tool location: Login Alipay Developer Center , click: console → sandbox in turn to the console of sandbox environment.
After entering the sandbox environment, the merchant parameter information listed above is available
be careful:

  1. Sandbox environment in sandbox application page → sandbox application → interface signing method in development information. Here, use the recommended user-defined key → RSA2 key
  2. Manual entry required Capability management Click to get more capabilities on the page to get the required capabilities. Here

Apply for payment products

  1. Sign in Alipay platform (at this time, I need a business account or need to manage authority). I choose to be a business user. Then I am a Alipay / word of mouth merchant. I choose the account to log in.
  2. Find the product center, choose face-to-face payment and open it immediately. At this time, Party A needs to provide information such as business license, website link and authorization letter (whatever is missing is right).
  3. Submit and wait for approval.

Get app AppID

  1. Sign in Alipay open platform (at this time, you need a merchant account or management authority). View my application on the console page. What I develop this time is a web page & mobile application provided by Party A
  2. Sign in Alipay platform
  3. After entering, click: account center → APPID binding → add binding, enter the APPID to be bound, and then contact the merchant's mobile phone verification code for verification.

Add: the above steps are for reference only. There may be various places that need the cooperation of Party A in your development process, which requires the cooperation of Party A according to the situation. For example, the information of Party A in my development process is not perfect, and even the basic information such as business license, company logo and company type has not been uploaded.

Get Alipay public key & private key

  1. Sign in Alipay open platform (at this time, you need a merchant account or management permission). On the console page, view my application and click to enter the application
  2. Enter the application information page to find the application information, set the key in the development information on this page, and you can choose Online generation key You can also choose to download the official platform tool of Alipay. Download tools)

Configuration in code

Main reference API development documentation & Official demo

Introduce dependency

easysdk tool is introduced here

<dependency>
     <groupId>com.alipay.sdk</groupId>
     <artifactId>alipay-easysdk</artifactId>
     <version>2.2.1</version>
 </dependency>

 <dependency>
     <groupId>com.alipay.sdk</groupId>
     <artifactId>alipay-sdk-java</artifactId>
     <version>4.22.0.ALL</version>
 </dependency>

Configure request parameter entity class

@Data
public class AlipayNotifyParam implements Serializable {
    private String appId;
    /**
     * Alipay transaction No.
    */
    private String tradeNo;
    /**
     * Merchant order number of the original payment request
     */
    private String outTradeNo;
    /**
     * Merchant business ID, mainly the serial number of the refund application returned in the refund notice
     */
    private String outBizNo;
    /**
     * The buyer's Alipay account corresponds to the Alipay unique user number. Pure 16 digit number starting with 2088
     */
    private String buyerId;
    /**
     * Buyer Alipay account
     */
    private String buyerLogonId;
    /**
     * Seller Alipay user number
     */
    private String sellerId;
    /**
     * Seller Alipay account
     */
    private String sellerEmail;
    /**
     * For the current status of the transaction, see the description of transaction status
     */
    private String tradeStatus;
    /**
     * Order amount paid for this transaction
     */
    private BigDecimal totalAmount;
    /**
     * The amount actually received by the merchant in the transaction
     */
    private BigDecimal receiptAmount;
    /**
     * Amount paid by the user in the transaction
     */
    private BigDecimal buyerPayAmount;
    /**
     * In the refund notice, the total refund amount is returned in yuan, and two decimal places are supported
     */
    private BigDecimal refundFee;
    /**
     * Commodity title / transaction title / order title / order keyword, etc
     */
    private String subject;
    /**
     * Remarks, description and details of the order. The body parameter corresponding to the request is notified back as it is
     */
    private String body;
    /**
     * The time when the transaction was created. The format is yyyy MM DD HH: mm: SS
     */
    private Date gmtCreate;
    /**
     * The buyer's payment time of the transaction. The format is yyyy MM DD HH: mm: SS
     */
    private Date gmtPayment;
    /**
     * The refund time of the transaction. The format is yyyy MM DD HH: mm: SS S
     */
    private Date gmtRefund;
    /**
     * The end time of the transaction. The format is yyyy MM DD HH: mm: SS
     */
    private Date gmtClose;
    /**
     * Amount information of each channel for successful payment, array
     */
    private String fundBillList;
    /**
     * Public return parameter. If this parameter is passed during the request, it will be returned to the merchant as it is during asynchronous notification.
     */
    private String passbackParams;
}

Configure payment instrument class

This tool class is for reference only, and the configuration information can also be placed in the yml file according to personal preferences (for ease of reading, it is placed in the class as a constant here).

public class AlipayUtil {
    public static final String APPID = "";

    public static final String MERCHANT_PRIVATE_KEY = "Private key content";
    public static final String ALIPAY_PUBLIC_KEY = "Public key content";
    public static final String NOTIFY_URL = "token url ";
    // For signature type, only RSA2 is recommended for Alipay Easy SDK. It is estimated that RSA2 should be filled in here
    public static final String SIGN_TYPE = "RSA2";
    // The encoding format requested, such as utf-8,gbk,gb2312, etc
    public static final String CHARSET = "utf-8";
    // Host domain name
    public static final String GATEWAYHOST = "openapi.alipay.com";
    // Request agreement
    public static final String PROTOCOL = "https";

    /**
     * @Author Spence_Dou
     * @Description Configuration request configuration
     * @Date 16:49 2021/12/29
     * @return com.alipay.8.kernel.Config
    */
    public static Config getOptions() {
        Config config = new Config();
        config.protocol = PROTOCOL;
        config.gatewayHost = GATEWAYHOST;
        config.signType = SIGN_TYPE;
        config.appId = APPID;
        config.merchantPrivateKey = AlipayUtil.MERCHANT_PRIVATE_KEY;
        // If the non certificate mode is adopted, there is no need to assign three certificate paths, instead of assigning the following Alipay public key string.
        config.alipayPublicKey = AlipayUtil.ALIPAY_PUBLIC_KEY;
        //You can set the asynchronous notification receiving service address (optional)
         config.notifyUrl = NOTIFY_URL;
        //AES key can be set, which is required when calling AES encryption and decryption related interfaces (optional)
        // 32-bit. If necessary, a random string is generated directly. It needs to be configured on the merchant platform and located in the certificate
        config.encryptKey = "*********";
        return config;
    }

    /**
     * @Author Spence_Dou
     * @Description Generate order number
     * @Date 22:05 2021/12/28
     * @Param []
     * @return java.lang.String
     */
    public static String orderNo(){
        return UUID.randomUUID().toString()
                .replaceAll("-", "")
                .substring(0, 32);
    }

    /**
     * @Author Spence_Dou
     * @Description Convert the parameters in the request to Map
     * @Date 18:01 2021/12/29
     * @Param request Callback Request 
     * @return java.util.Map<java.lang.String,java.lang.String>
    */
    public static Map<String, String> convertRequestParamsToMap(HttpServletRequest request){
        HashMap<String, String> retMap = new HashMap<>();
        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;
    }

    /**
     * @Author Spence_Dou
     * @Description Verify AppID
     * @Date 20:32 2021/12/29
     * @Param params Callback information
     * @return void
    */
    public static void check(Map<String, String> params) throws AlipayApiException {
        if (!params.get("app_id").equals(APPID)) {
            throw new AlipayApiException("app_id atypism");
        }
    }

	/**
     * @Author Spence_Dou
     * @Description Generate request entity class
     * @Date 17:51 2022/2/12
     * @Param params Response body parameter to map
     * @return marchsoft.modules.spiritdeerpush.common.utils.pay.alipay.AlipayNotifyParam
    */
    public static AlipayNotifyParam buildAlipayNotifyParam(Map<String, String> params) {
        String json = JSON.toJSONString(params);
        return JSON.parseObject(json, AlipayNotifyParam.class);
    }
}

Payment request

  • Different product functions should be referred to Official demo easysdk Here, take face-to-face payment as an example
		// Generate system order number
		String outTradeNo = AlipayUtil.orderNo();
		// 1. Set parameters (only need to be set once globally)
		Factory.setOptions(AlipayUtil.getOptions());
		try {
			// 2. Initiate API call, Description: product description; total: amount (yuan)
			// What are the parameters of the response? Go to the document yourself. There are too many parameters to describe one by one
			AlipayTradePrecreateResponse response = Factory.Payment.FaceToFace()
					.preCreate(description, outTradeNo, total.toString());
			// 3. Handle response or exception
			if (ResponseChecker.success(response)) {
				// Payment QR code
				String qrCode = response.getQrCode();
				/**
				 * Business logic operations such as order information receipt can be performed here
				*/
				return;
			} else {
				System.err.println("Call failed, reason:" + response.msg + "," + response.subMsg);
				// The custom exception thrown here is encapsulated by the company framework
				throw new BadRequestException(response.msg);
			}
		} catch (Exception e) {
			System.err.println("The call encountered an exception, reason:" + e.getMessage());
			// Manually close transactions
			throw new RuntimeException(e.getMessage(), e);
		}

Callback interface

This interface address corresponds to the request parameter notify in payment request_ URL. The specific functions are not described here

		// Convert the parameters in the request to Map
		Map<String, String> stringStringMap = AlipayUtil.convertRequestParamsToMap(request);
		try {
			// Call SDK to verify signature
			boolean signVerified = AlipaySignature.rsaCheckV1(stringStringMap, AlipayUtil.ALIPAY_PUBLIC_KEY, AlipayUtil.CHARSET, AlipayUtil.SIGN_TYPE);
			if (signVerified){
				AlipayUtil.check(stringStringMap);
				AlipayNotifyParam param = AlipayUtil.buildAlipayNotifyParam(stringStringMap);
				// Order status
				String trade_status = param.getTradeStatus();
				// Payment successful
				if (trade_status.equals("TRADE_SUCCESS")
						|| trade_status.equals("TRADE_FINISHED")){
					/**
				 	* Business logic operations such as order information maintenance can be performed here
					*/
				}else {
					// The custom exception thrown here is encapsulated by the company framework
					throw new BadRequestException("Payment failed!");
				}
				return "success";
			}else {
				// If you don't understand what failure means, go to the document
				return "failure";
			}
		} catch (AlipayApiException e) {
			e.printStackTrace();
			//Force manual transaction rollback
			TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
			return "failure";
		}

Topics: Java oneAPI