The realization of Alipay's three party payment function

The realization of Alipay's three party payment function

Alipay payment environment preparation

1.1 sandbox environment preparation

Because we are testing the environment, we first use the sandbox environment provided by Alipay (simulation payment scenario).
We need to generate our private key and public key on Alipay open platform assistant client.

Then we provide our public key to Alipay sandbox environment.

Click this on the sandbox page

Then we need to store Alipay's public key and our private key in the database we get.
Because we use AES2 to encrypt (asymmetric reversible encryption algorithm)

1.2 AES2 encryption algorithm
1 Irreversible encryption algorithm: it can only be encrypted but not decrypted md5  Generally, the login password is processed
2 Reversible encryption algorithm: it can be encrypted or decrypted, and can be divided into whether it is symmetrical, mainly depending on whether the secret key is the same,It's symmetry, otherwise it's asymmetry
	2.1 Symmetric encryption algorithm: DES,AES Wait for the database password to be encrypted
			Ciphertext is s The encryption and decryption algorithm is AES The secret key is k,Plaintext c ;
					Encryption: s = AES(k,c)
					decrypt: c = AES(k,s)
	2.2 Asymmetric encryption algorithm: RSA   Network transmission data encryption
		    Passwords appear in pairs. A private key corresponds to a public key. If you use private key encryption, you can only use the corresponding public key. On the contrary, if public key encryption is used, only the corresponding private key can be used for decryption.

Ciphertext is s The encryption and decryption algorithm is RSA Private key is k1 Public key is k2,Plaintext c ;
   Group 1: private key encryption and public key decryption
    Encryption: s= rsa(k1,c)
	decrypt: c=rsa(k2,s)
   Group I: public key encryption and private key solution
    Encryption: s= rsa(k2,c)
	decrypt: c=rsa(k1,s)


Exchange public key

1.3 intranet penetration

Preparation 2: asynchronous notification is a controller method to visit our site in httppost request mode. It is Alipay request from external network payment, so that we can access it by external network.
  online: buy servers and domain names
  development: intranet penetration nat123 (18) peanut shell (6) natapp (free)

https://natapp.cn/

1) Register and purchase free tunnel token
2) Download the software and create config. In the current directory in the extracted folder INI file
3) In config INI file writes the obtained token in the file
4) Note: because we use the free tunnel of natapp, the token will be changed from time to time


Cannot close when running a successful test project

code implementation

2.1 initiate payment request
2.1.1 packaging tools
<!-- https://mvnrepository.com/artifact/com.alipay.sdk/alipay-sdk-java -->
<dependency>
    <groupId>com.alipay.sdk</groupId>
    <artifactId>alipay-sdk-java</artifactId>
    <version>3.7.4.ALL</version>
</dependency>

Used to set synchronous and asynchronous callback address

package cn.many.pay.constants;

public class AlipayConfig {

    // Server asynchronous notification page path
    public static String notify_url = "http://xrs456.natappfree.cc/notify";
    // Page Jump synchronization notification page path
    public static String return_url = "http://localhost/success.html";
    // Signature method
    public static String sign_type = "RSA2";
    // Character encoding format
    public static String charset = "utf-8";
    // Alipay gateway
    public static String gatewayUrl = "https://openapi.alipaydev.com/gateway.do";
}

The tool class returned to us is the String type Alipay data package.
We need to return the background to the foreground to display the QR code interface

package cn.many.pay.utils;
import cn.many.pay.constants.AlipayConfig;
import cn.many.pay.domain.AlipayInfo;
import cn.many.pay.domain.PayBill;
import com.alipay.api.AlipayClient;
import com.alipay.api.DefaultAlipayClient;
import com.alipay.api.request.AlipayTradePagePayRequest;

public class AlipayUtils {
    /**
     * @param info To which merchant
     * @param bill  Payment order
     * @return Payment request packet-
     */
    public static String pay(AlipayInfo info, PayBill bill){
        try {
            //Get the initialized AlipayClient
            AlipayClient alipayClient = new DefaultAlipayClient(AlipayConfig.gatewayUrl,
                    info.getAppid(), info.getMerchant_private_key(), "json",
                    AlipayConfig.charset, info.getAlipay_public_key(), AlipayConfig.sign_type);

            //Set request parameters
            AlipayTradePagePayRequest alipayRequest = new AlipayTradePagePayRequest();
            alipayRequest.setReturnUrl(AlipayConfig.return_url);
            alipayRequest.setNotifyUrl(AlipayConfig.notify_url);

            //Merchant Order No., which is the only order No. in the order system on the merchant's website. It is required. / / it is the unified payment doc No
            String out_trade_no = bill.getUnionPaySn();
            //Payment amount, required
            String total_amount = bill.getMoney().toString();
            //Order name, required
            String subject = bill.getDigest();
            //Product description; can be blank
            String body = bill.getDigest();

            alipayRequest.setBizContent("{\"out_trade_no\":\""+ out_trade_no +"\","
                    + "\"total_amount\":\""+ total_amount +"\","
                    + "\"subject\":\""+ subject +"\","
                    + "\"body\":\""+ body +"\","
                    + "\"product_code\":\"FAST_INSTANT_TRADE_PAY\"}");

            //request
            String result = alipayClient.pageExecute(alipayRequest).getBody();
            return result;
        } catch (Exception e) {
            e.printStackTrace();
        }

        return null;
    }
}

2.1.2 implementation of foreground code

adoptOrder.html


Modify the method triggered by the foreground submit order button. At this time, we are in the Ajax result object
The resultObj attribute encapsulates the Alipay packets returned by the AlipayUtils tool class.
That is to say, a form form is used to display Alipay's payment two-dimensional code.

 orderSubmit(){
                this.$http.post("/adopt/submit",this.order)
                    .then(result=>{
                        result = result.data;
                        if(result.success){
                            if(this.order.pay_method==1){
                                //Get payment data - to ensure that our payment form is the first form, put it first
                                console.log(result.resultObj)
                                $("#payDiv").html(result.resultObj);
                            }
                        }else{
                            alert(result.message);
                        }
                    })
}
2.1.3 background code implementation

Controller

@RestController
@RequestMapping("/adopt")
public class AdoptOrderController {

    @Autowired
    private IAdoptOrderService orderService;
    @PostMapping("/submit")
    public AjaxResult submit(@RequestBody Map<String,Object> params, HttpServletRequest request){

        try{
            String payData = orderService.submit(params, LoginContext.getLoginInfo(request));
            System.out.println(payData);
            return AjaxResult.me().setResultObj(payData);
        }catch (Exception e){
            e.printStackTrace();
            return AjaxResult.me().setSuccess(false).setMessage("Order failed!"+e.getMessage());
        }
    }
}

Service

@Override
public String submit(Map<String, Object> params, LoginInfo loginInfo) {
    //Receive parameters
    Long petId = Long.valueOf(params.get("pet_id").toString());
    Long addressId = Long.valueOf(params.get("address_id").toString());//Receiving address: t_ user_ id of address
    Long payMethod = Long.valueOf(params.get("pay_method").toString());//1 Alipay 2 WeChat 3 UnionPay 0 balance
    Long serviceMethod = Long.valueOf(params.get("service_method").toString());//Delivery method
    //1. Change pet status to off shelf
    Pet pet = petMapper.loadById(petId);
    pet.setState(0);
    //2. Bind the buyer
    User user = userMapper.loadByLoginInfoId(loginInfo.getId());
    pet.setUser_id(user.getId());
    petMapper.update(pet);
    //3. Generate order
    //3.1 saving the adoption order form
    AdoptOrder order = initAdoptOrder(pet, user);
    //Tool class generates unique payment order number
    String unionPaySn = CodeGenerateUtils.generateUnionPaySn();
    order.setPaySn(unionPaySn);
    adoptOrderMapper.save(order);
    //3.2 save order address table
    OrderAddress orderAddress =userAddress2AoptAddress(addressId, order);
    orderAddressMapper.save(orderAddress);
    //4. Generate payment document
    PayBill payBill = innitPayBill(payMethod, pet, user, order);
    payBillMapper.save(payBill);
    //Call the unified payment interface to complete the payment task

    return payBillService.pay(payBill);


    //5. Set order scheduled task @ TODO
}

Other calling methods in the Service initialize the table object 𞓜 object attribute replication

/**
 * Initialize object for payment order
 * @param payMethod
 * @param pet
 * @param user
 * @param order
 * @return
 */
private PayBill innitPayBill(Long payMethod, Pet pet, User user, AdoptOrder order) {
    PayBill payBill = new PayBill();
    payBill.setDigest(order.getDigest());
    payBill.setMoney(order.getPrice());
    payBill.setUnionPaySn(order.getPaySn());
    payBill.setState(0);//To be paid
    payBill.setLastPayTime(new Date(System.currentTimeMillis()+ PayConstants.LAST_TIME));
    payBill.setPayChannel(payMethod);//Payment method from the front desk
    payBill.setBusinessType(PayConstants.BUSINESS_TYPE_ADOPT);//Order type
    payBill.setBusinessKey(order.getId());//Query the unique order by order type + order number. Here, the id of order is used
    payBill.setUser_id(user.getId());
    payBill.setShop_id(pet.getShop_id());
    payBill.setNickName(user.getUsername());
    return payBill;
}

/**
 * Convert user address to adoption order address
 * @param addressId
 * @param order
 * @return
 */
private OrderAddress userAddress2AoptAddress(Long addressId, AdoptOrder order) {
    OrderAddress orderAddress = new OrderAddress();
    UserAddress userAddress = userAddressMapper.loadById(addressId);
    BeanUtils.copyProperties(userAddress, orderAddress);
    orderAddress.setId(null);
    orderAddress.setOrder_id(order.getId());
    orderAddress.setOrderSn(order.getOrderSn());
    return orderAddress;
}


/**
 * Initialize order object
 * @param pet
 * @param user
 * @return
 */
private AdoptOrder initAdoptOrder(Pet pet, User user) {
    AdoptOrder order = new AdoptOrder();
    order.setDigest("[abstract]adopt"+pet.getName());
    order.setPrice(pet.getSaleprice());
    order.setOrderSn(CodeGenerateUtils.generateOrderSn(user.getId()));
    order.setLastConfirmTime(new Date(System.currentTimeMillis()+15*60*1000));
    order.setPet_id(pet.getId());
    order.setUser_id(user.getId());
    order.setShop_id(pet.getShop().getId());
    return order;
}

Implementation of unified payment interface
All orders call their own business interface - > and then call the unified payment interface in each business interface
The payment interface is only responsible for integrating the implementation of all payment methods and the return value is irrelevant. Business orders only distinguish payment methods
Here we realize the Alipay payment.

@Override
public String pay(PayBill payBill) {
    //It is judged to be empty to prevent the foreground from transmitting empty data
    if(payBill==null){
        throw new BusinessException("Please pay after generating the payment document!!!");
    }
    //Go to the database to query whether there is this payball object
    PayBill payBill1 = payBillMapper.loadByUnionPaySn(payBill.getUnionPaySn());
    if(payBill1==null){
        throw new BusinessException("Please pay after generating the payment document!!!");
    }
    //Get the payment method in the payment form 0 balance 1 Alipay 2 WeChat 3 UnionPay
    Long payChannel = payBill1.getPayChannel();
    String resultData = "";
    switch(payChannel.intValue()){
        case 1 ://Alipay
            AlipayInfo info = alipayInfoMapper.loadByShopId(payBill1.getShop_id());
            resultData =  AlipayUtils.pay(info, payBill1);
            break;
        case 2 ://WeChat
            //TODO
            break;
        case 3 ://UnionPay
            //TODO
            break;
        default : //0 balance
            //TODO
    }
    return resultData;//Return Alipay packets
}

Asynchronous callback
What asynchronous callbacks need to do
->Modify payment doc status
->Modify order status
Background implementation

@RestController
public class AlipayController {
    @Autowired
    private IPayBillService payBillService;
    @Autowired
    private IAlipayInfoService alipayInfoService;
    @Autowired
    private IAdoptOrderService adoptOrderService;

    @PostMapping("/notify")
    public void notify(HttpServletRequest request){
        System.out.println("Alipay asynchronous callback!");
        //Get feedback from Alipay POST
        try {
            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);
                params.put(name, valueStr);
            }
            String unionPaySn = params.get("out_trade_no");
            PayBill payBill = payBillService.loadByUnionPaySn(unionPaySn);
            if(payBill != null){
                AlipayInfo info = alipayInfoService.getByShopId(payBill.getShop_id());
                boolean signVerified = AlipaySignature.rsaCheckV1(params,
                        info.getAlipay_public_key(),
                        AlipayConfig.charset,
                        AlipayConfig.sign_type); //Call SDK to verify signature

                if(signVerified) {//Validation succeeded
                    //Merchant order number
                    String out_trade_no = unionPaySn;
                    //Alipay transaction number
                    String trade_no = request.getParameter("trade_no");
                    //Transaction status
                    String trade_status = request.getParameter("trade_status");

                    if(trade_status.equals("TRADE_FINISHED")){
                        //User confirmation
                    }else if (trade_status.equals("TRADE_SUCCESS")){
                        //1. Change payment doc status
                        payBill.setState(1);
                        payBill.setUpdateTime(new Date());
                        payBillService.update(payBill);
                        String businessType = payBill.getBusinessType();
                        //2. Modify the corresponding (adopted) order status businesstype businesskey order
                        if(PayConstants.BUSINESS_TYPE_ADOPT.equals(businessType)){//Adoption order
                            Long orderId = payBill.getBusinessKey();
                            AdoptOrder order = adoptOrderService.getById(orderId);
                            order.setState(1);
                            adoptOrderService.update(order);
                        }
                    }
                }else {//Validation failed
                    System.out.println("Lao song, don't make trouble");

                    //Debug and try to write a text function to record whether the program is running normally
                    //String sWord = AlipaySignature.getSignCheckContentV1(params);
                    //AlipayConfig.logResult(sWord);
                }
            }
        } catch (AlipayApiException e) {
            e.printStackTrace();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

Keywords: Java

Added by SilverFoxDesign on Wed, 26 Jan 2022 01:53:39 +0200