Alipay development supports both production and sandbox environments. The sandbox is used for testing.
1. Alipay Sandbox Environment Setup
When using the sandbox environment, Alipay automatically generates an APPID and a merchant UID. The sandbox gateway URL is https://openapi.alipaydev.com/gateway.do. For production, the gateway URL changes to https://openapi.alipay.com/gateway.do.
2. Key Configuration
2.1 Generate Application Keys
You need to add an application public key for you're project. This key is generated using the key tool provided by the Alipay platform. It is recommended to use RSA2 with 2048-bit keys. The Alipay public key is provided by Alipay. These keys are used for encryption and decryption.
- Private key encryption, public key decryption: The private key encrypts data, and the public key dercypts it.
- Private key signing, public key verification: The private key creates a signature, and the public key verifies it.
Key Usage Rules
- Encryption: Use the public key to encrypt. The private key decrypts.
- Signature Verification:
- When receiving data from Alipay, use the Alipay public key to verify the signature. This confirms that the data sender is Alipay.
- The client signs the merchant's signature string with the private key and uploads it to the server. The server verifies the signature using the application public key uploaded by the developer, confirming the sender's identity.
2.2 Key Roles
- Merchant Backend:
- Must import the Alipay public key to verify signatures on data returned by Alipay.
- Must import the application private key to encrypt data.
- Public Platform:
- Holds the Alipay public key and the merchant's application public key. Both parties can access them.
- Alipay Backend:
- Uses the application public key to verify signatures and decrypt merchant data.
- Similarly, the merchant backend uses the Alipay public key to verify signatures and decrypt returned data.
When generating keys, Alipay requires signature verification on the public platform.
3. Verify Key Correctness
Download the signature tool to validate the keys.
4. Test Signature Generation
Place the application private key corresponding to the application public key into the left box of the verification tool. Generate a signature on the right side.
5. Validate Signature
Paste the generated signature into the verification field. Click verify. If successful, save the configuration.
6. Configure Application Gateway and Authorization Callback URL
- Application Gateway: Set this to your merchant server.
- Authorization Callback URL: Must be publicly accessible. The merchant backend should intercept and verify this callback to confirm successful payment.
7. Create Web Application
After completing the above steps, your web application is created. You can then write the merchant backend program to prepare data for Alipay and initiate paymants. For reference, see the repository: https://github.com/egzosn/pay-java-parent
8. Backend Alipay Configuration
The following Java code example shows how to configure Alipay storage settings:
package verticleTest;
import reference.AliPayConfigStorage;
public class AliPayStorageSetting {
AliPayConfigStorage aliPayConfigStorage;
public static AliPayConfigStorage getAliPayConfigStorage() {
String app_id = "2016091200494690"; // appid
// Application private key for encryption
String APP_PRIVATE_KEY = "MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQCrjJrvXTZubckZqlOjD/V+VyMmAvDuD++rT6sAjM6X1J3gAXkcOotO8WWTXo/zcFHfbtSZjte0xoTz1RFkobWu0RRXJcM7+khCYbjxo/x0nkoqMQuwviikWKDoyxwbkUYEWmdKVcC7rg5tiyBbFGwIywjfo9ztDE7fklDCcDbhSCBlxrOG9Y8xjq/3V0xtvHSQiw+y/966SH+l1ZvnT/RTVb3tKlkSWEvgOJv/c4xz5yuXimFJp1gVKS118O6NRO7PM86Lvqz4GLb6RJ6wrGdwqwig6QTbCPxC9mmONaUE6WQOjhyuvEejoSh8T3GZSUKaMqO/gmAKJWnBAlpnOKt5AgMBAAECggEBAIpZAZZq0Pvr1BO7tmm59BzovzLnilAjUAETZfAynmX6FTxTU829NR38NhPMXkFQYubTZedVOIbU1uIiAj3q4C/U9Bd4H+Rd6yqFzvYpbu7JvTwbg7cNFI+93j7/lnJxDUtzcPuU/rMdIwua+QQbCyloPIbHiuMtWuqZAEJe5xN0mlEH2kKaOjvHvwaBUAC5w3gy/RswTBKOe4n1XaFXUmzuwWD6ECmHjGbKtooPwjuGPKsLYTINCu047uGjzyA0nd8+1dWDdWiWBDflWQRpYWR1zHINftiedHVSuhrKsprPI3/bJE1DV/0+8MbNY2lfIrh54d9e1OKpO+FqoXmrd/UCgYEA2cDo2Lxw7QvT/zEmv1q6q0LUwPhOo9K7lPNW7kB82uaeAdKrei9BC7hJwMfP4cA0J9wHLzOUMnnlSp90hVZmyefV+RkJdxCmNwnRZIRGo1YVEuCLU1stosKE5CxY9dZQNkkIFL3AFkRku82hVVoEJDm+nCKT9wpKYNir0FYlS6MCgYEAya4pJHwPCS5OsrNilBF5AZ7cJ3TQ9ZuEdZh+prjLcBXmVXG3qBfYGE5Mfxj6TaKdETODVIH9U5S1JN5Adm17GLaKFbE0JdPwn7HJEPwDPO3Fi08GhyujqYAFagSkhAcZj/dj8NrMV2uwd8t7/gnj/6zH7eWhctbbzWQNJ3Q0njMCgYASAVR/j11bDG5UHJFSo0LqJFWJOz7tZuBh2ZknjCeGxijsh6nsKXocaPmYOi1jQkxNu3DQo1gusEuYVwUAfXt0WHol5b8VnEfSJzqsMA/TM6v8apq6osBsQ99PKqeUdEsfofxMEsCOVstpiAA+GXpcMHYlXOqVM8GgrmnOiUD+NwKBgE64wWxxVDkkLynHpWngbBg61vo7ubi0zH5OWNlg9l+43KBrc+GT9RB/t5JAwKr/F0n4joG0/5nZSN+sNQNE9rCNx9ZxxcYiNSFQdwg/JlBpCxu2a/jlCswFoZdhWooCb3LngMYp0WsqKMaJ0cs2Nx28ZomwgVVfEorYS94jmMpLAoGBAM8htyte48bv98JqQzCe453ajwq4XfB+hpDvz2DiiotX7tPmaPGnn1ugOSrfnPs5ZSCOZPEZOuCKofwDd4U/RH/7L60+a8QeBIfOYZf4YzGzfcVevhXmPBqfFHwM1oy1SGYPichx8YgeqkPGQ5CRSpGt62e7+LFV1QWELFK5VMHf";
String ALIPAY_PUBLIC_KEY = "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAwt9rjnmpGrOQXsYzuNIs24cPgvFKpXRHRrvuKeViBDmsuk/xzhHGG3aFnN+TH2vXlqkzaDtjmohguRHRf1C8r27lPySmgb5SRoHBVSoxkxE5wt8GkItYfvAc2BtcFZtweWrkQaVVHC1smBxmfxhqyURZIObaAVrfzzEMBRiVy5pCugKhJB9YeIQsxnWTa8wwD9IiGWtfZJNKMmu95O0cpx1Vy0HRZEF0uABvhOnZxflqg4c1U9lffEQ/QWKEzFZKyBui/pNE9CR069eYjS4IIii0ZXQUewpCMDJB1xlTYCVl0a73eGnszl58KzFDWDGZkZeGqumvCCGZ3IK11YqXtQIDAQAB";
String notify_url = "http://k19847n443.51mypc.cn:37169/static/index.html"; // URL where Alipay sends payment result
String return_url = "http://k19847n443.51mypc.cn:37169/notifyalipay"; // Page to redirect user after payment
String sign_type = "RSA2";
String charset = "utf-8";
String gatewayUrl = "https://openapidev.alipay.com/gateway.do"; // Sandbox gateway
String log_path = "C:\\";
String uid = "2088102175307622";
AliPayConfigStorage aliPayConfigStorage = new AliPayConfigStorage();
aliPayConfigStorage.setPid(uid);
aliPayConfigStorage.setAppId(app_id);
aliPayConfigStorage.setKeyPublic(ALIPAY_PUBLIC_KEY);
aliPayConfigStorage.setKeyPrivate(APP_PRIVATE_KEY);
aliPayConfigStorage.setNotifyUrl(return_url);
aliPayConfigStorage.setSignType(sign_type);
aliPayConfigStorage.setSeller(uid);
aliPayConfigStorage.setInputCharset(charset);
// Set to true for sandbox environment
aliPayConfigStorage.setTest(true);
return aliPayConfigStorage;
}
public void setAliPayConfigStorage(AliPayConfigStorage aliPayConfigStorage) {
this.aliPayConfigStorage = aliPayConfigStorage;
}
}
9. Backend Development with Vert.x
Below is a Vert.x verticle that handles Alipay payment requests, including instant WAP payment, QR code payment, and callback handling.
package aliPay;
import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.math.BigDecimal;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import java.util.UUID;
import javax.imageio.ImageIO;
import org.apache.logging.log4j.LogManager;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.egzosn.pay.common.api.PayService;
import com.egzosn.pay.common.bean.MethodType;
import com.egzosn.pay.common.bean.PayOrder;
import aliPay.test.AliPayTestStorageSetting;
import aliPay.utils.AliPayConfigStorage;
import aliPay.utils.AliPayService;
import aliPay.utils.AliTransactionType;
import io.vertx.core.AbstractVerticle;
import io.vertx.core.Future;
import io.vertx.core.MultiMap;
import io.vertx.core.Vertx;
import io.vertx.core.buffer.Buffer;
import io.vertx.core.http.HttpServerRequest;
import io.vertx.ext.web.Router;
import io.vertx.ext.web.handler.BodyHandler;
import io.vertx.ext.web.handler.StaticHandler;
public class AliPayVerticle extends AbstractVerticle {
private AliPayConfigStorage aliPayConfigStorage = AliPayTestStorageSetting.getAliPayConfigStorage();
public void start() {
org.apache.logging.log4j.Logger logger1 = LogManager.getLogger(AliPayVerticle.class);
Router router = Router.router(vertx);
router.route().handler(BodyHandler.create());
// Instant WAP payment route
router.route("/AliInstanceWebPay").handler(ctx -> {
logger1.debug("AliInstanceWebPay instant WAP web payment");
HttpServerRequest request = ctx.request();
PayService service = new AliPayService(aliPayConfigStorage);
logger1.debug("AliInstanceWebPay creating order");
PayOrder payOrder = new PayOrder("Order Title", "Order Summary", new BigDecimal(0.01),
UUID.randomUUID().toString().replace("-", ""));
payOrder.setTransactionType(AliTransactionType.WAP);
payOrder.setSpbillCreateIp(request.getHeader("X-Real-IP"));
String requestURL = request.absoluteURI();
payOrder.setWapUrl(requestURL.substring(0,
requestURL.indexOf("/") > 0 ? requestURL.indexOf("/") : requestURL.length()));
payOrder.setWapName("Online Recharge");
logger1.debug("AliInstanceWebPay order created");
Map directOrderInfo = service.orderInfo(payOrder);
logger1.debug("Sending request to Alipay");
String directHtml = service.buildRequest(directOrderInfo, MethodType.POST);
logger1.debug("Returning HTML page");
ctx.response().setStatusCode(400).putHeader("content-type", "text/html").end(directHtml);
});
// QR code payment route
router.route("/AliSweepPay").handler(ctx -> {
logger1.debug("AliSweepPay QR code payment");
HttpServerRequest request = ctx.request();
PayService service = new AliPayService(aliPayConfigStorage);
logger1.debug("AliSweepPay creating order");
PayOrder payOrder = new PayOrder("Order Title", "Order Summary", new BigDecimal(0.01),
UUID.randomUUID().toString().replace("-", ""));
String requestURL = request.absoluteURI();
payOrder.setWapUrl(requestURL.substring(0,
requestURL.indexOf("/") > 0 ? requestURL.indexOf("/") : requestURL.length()));
payOrder.setWapName("Online Recharge");
payOrder.setTransactionType(AliTransactionType.SWEEPPAY);
logger1.debug("AliSweepPay order created");
logger1.debug("Generating QR code");
BufferedImage image = service.genQrPay(payOrder);
ByteArrayOutputStream baos = new ByteArrayOutputStream();
try {
ImageIO.write(image, "JPEG", baos);
} catch (Exception e) {
e.printStackTrace();
}
byte[] imageByteDataArray = baos.toByteArray();
Buffer buffer = Buffer.buffer();
buffer.appendBytes(imageByteDataArray);
logger1.debug("Returning QR code image");
ctx.response()
.setStatusCode(400)
.putHeader("Pragma", "No-cache")
.putHeader("Cache-Control", "no-cache")
.putHeader("Expires", "0")
.putHeader("content-type", "image/jpeg");
ctx.response().end(buffer);
});
// Alipay callback handler
router.route("/notifyalipay").handler(ctx -> {
logger1.debug("notifyalipay callback service");
PayService service = new AliPayService(aliPayConfigStorage);
HttpServerRequest request = ctx.request();
Map params = new HashMap();
MultiMap params2 = request.params();
Set<String> names = params2.names();
Iterator<String> iterator = names.iterator();
while (iterator.hasNext()) {
String key = iterator.next();
params.put(key, params2.get(key));
}
logger1.debug("notifyalipay verifying callback");
if (service.verify(params)) {
logger1.info("notifyalipay verification succeeded");
return;
}
logger1.error("notifyalipay verification failed");
});
router.route("/html/*").handler(StaticHandler.create("html"));
vertx.createHttpServer().requestHandler(router::accept).listen(8080);
}
}
This implementation covers key aspects of Alipay integration: sandbox setup, key management, signature verification, and building payment requests using Vert.x.